1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3 /* 4 * Copyright (C) 2013 Rob Clark <robclark (at) freedesktop.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Rob Clark <robclark (at) freedesktop.org> 27 */ 28 29 #include "pipe/p_state.h" 30 #include "util/u_string.h" 31 #include "util/u_memory.h" 32 #include "util/u_inlines.h" 33 #include "util/u_format.h" 34 35 #include "fd3_texture.h" 36 #include "fd3_format.h" 37 38 static enum a3xx_tex_clamp 39 tex_clamp(unsigned wrap, bool clamp_to_edge, bool *needs_border) 40 { 41 /* Hardware does not support _CLAMP, but we emulate it: */ 42 if (wrap == PIPE_TEX_WRAP_CLAMP) { 43 wrap = (clamp_to_edge) ? 44 PIPE_TEX_WRAP_CLAMP_TO_EDGE : PIPE_TEX_WRAP_CLAMP_TO_BORDER; 45 } 46 47 switch (wrap) { 48 case PIPE_TEX_WRAP_REPEAT: 49 return A3XX_TEX_REPEAT; 50 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 51 return A3XX_TEX_CLAMP_TO_EDGE; 52 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 53 *needs_border = true; 54 return A3XX_TEX_CLAMP_TO_BORDER; 55 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 56 /* only works for PoT.. need to emulate otherwise! */ 57 return A3XX_TEX_MIRROR_CLAMP; 58 case PIPE_TEX_WRAP_MIRROR_REPEAT: 59 return A3XX_TEX_MIRROR_REPEAT; 60 case PIPE_TEX_WRAP_MIRROR_CLAMP: 61 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 62 /* these two we could perhaps emulate, but we currently 63 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP 64 */ 65 default: 66 DBG("invalid wrap: %u", wrap); 67 return 0; 68 } 69 } 70 71 static enum a3xx_tex_filter 72 tex_filter(unsigned filter, bool aniso) 73 { 74 switch (filter) { 75 case PIPE_TEX_FILTER_NEAREST: 76 return A3XX_TEX_NEAREST; 77 case PIPE_TEX_FILTER_LINEAR: 78 return aniso ? A3XX_TEX_ANISO : A3XX_TEX_LINEAR; 79 default: 80 DBG("invalid filter: %u", filter); 81 return 0; 82 } 83 } 84 85 static void * 86 fd3_sampler_state_create(struct pipe_context *pctx, 87 const struct pipe_sampler_state *cso) 88 { 89 struct fd3_sampler_stateobj *so = CALLOC_STRUCT(fd3_sampler_stateobj); 90 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8)); 91 bool miplinear = false; 92 bool clamp_to_edge; 93 94 if (!so) 95 return NULL; 96 97 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) 98 miplinear = true; 99 100 so->base = *cso; 101 102 /* 103 * For nearest filtering, _CLAMP means _CLAMP_TO_EDGE; for linear 104 * filtering, _CLAMP means _CLAMP_TO_BORDER while additionally 105 * clamping the texture coordinates to [0.0, 1.0]. 106 * 107 * The clamping will be taken care of in the shaders. There are two 108 * filters here, but let the minification one has a say. 109 */ 110 clamp_to_edge = (cso->min_img_filter == PIPE_TEX_FILTER_NEAREST); 111 if (!clamp_to_edge) { 112 so->saturate_s = (cso->wrap_s == PIPE_TEX_WRAP_CLAMP); 113 so->saturate_t = (cso->wrap_t == PIPE_TEX_WRAP_CLAMP); 114 so->saturate_r = (cso->wrap_r == PIPE_TEX_WRAP_CLAMP); 115 } 116 117 so->needs_border = false; 118 so->texsamp0 = 119 COND(!cso->normalized_coords, A3XX_TEX_SAMP_0_UNNORM_COORDS) | 120 COND(!cso->seamless_cube_map, A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF) | 121 COND(miplinear, A3XX_TEX_SAMP_0_MIPFILTER_LINEAR) | 122 A3XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 123 A3XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 124 A3XX_TEX_SAMP_0_ANISO(aniso) | 125 A3XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, clamp_to_edge, &so->needs_border)) | 126 A3XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, clamp_to_edge, &so->needs_border)) | 127 A3XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, clamp_to_edge, &so->needs_border)); 128 129 if (cso->compare_mode) 130 so->texsamp0 |= A3XX_TEX_SAMP_0_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 131 132 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { 133 so->texsamp1 = 134 A3XX_TEX_SAMP_1_LOD_BIAS(cso->lod_bias) | 135 A3XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 136 A3XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 137 } else { 138 so->texsamp1 = 0x00000000; 139 } 140 141 return so; 142 } 143 144 static void 145 fd3_sampler_states_bind(struct pipe_context *pctx, 146 enum pipe_shader_type shader, unsigned start, 147 unsigned nr, void **hwcso) 148 { 149 struct fd_context *ctx = fd_context(pctx); 150 struct fd3_context *fd3_ctx = fd3_context(ctx); 151 uint16_t saturate_s = 0, saturate_t = 0, saturate_r = 0; 152 unsigned i; 153 154 if (!hwcso) 155 nr = 0; 156 157 for (i = 0; i < nr; i++) { 158 if (hwcso[i]) { 159 struct fd3_sampler_stateobj *sampler = 160 fd3_sampler_stateobj(hwcso[i]); 161 if (sampler->saturate_s) 162 saturate_s |= (1 << i); 163 if (sampler->saturate_t) 164 saturate_t |= (1 << i); 165 if (sampler->saturate_r) 166 saturate_r |= (1 << i); 167 } 168 } 169 170 fd_sampler_states_bind(pctx, shader, start, nr, hwcso); 171 172 if (shader == PIPE_SHADER_FRAGMENT) { 173 fd3_ctx->fsaturate = 174 (saturate_s != 0) || 175 (saturate_t != 0) || 176 (saturate_r != 0); 177 fd3_ctx->fsaturate_s = saturate_s; 178 fd3_ctx->fsaturate_t = saturate_t; 179 fd3_ctx->fsaturate_r = saturate_r; 180 } else if (shader == PIPE_SHADER_VERTEX) { 181 fd3_ctx->vsaturate = 182 (saturate_s != 0) || 183 (saturate_t != 0) || 184 (saturate_r != 0); 185 fd3_ctx->vsaturate_s = saturate_s; 186 fd3_ctx->vsaturate_t = saturate_t; 187 fd3_ctx->vsaturate_r = saturate_r; 188 } 189 } 190 191 static enum a3xx_tex_type 192 tex_type(unsigned target) 193 { 194 switch (target) { 195 default: 196 assert(0); 197 case PIPE_BUFFER: 198 case PIPE_TEXTURE_1D: 199 case PIPE_TEXTURE_1D_ARRAY: 200 return A3XX_TEX_1D; 201 case PIPE_TEXTURE_RECT: 202 case PIPE_TEXTURE_2D: 203 case PIPE_TEXTURE_2D_ARRAY: 204 return A3XX_TEX_2D; 205 case PIPE_TEXTURE_3D: 206 return A3XX_TEX_3D; 207 case PIPE_TEXTURE_CUBE: 208 case PIPE_TEXTURE_CUBE_ARRAY: 209 return A3XX_TEX_CUBE; 210 } 211 } 212 213 static struct pipe_sampler_view * 214 fd3_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 215 const struct pipe_sampler_view *cso) 216 { 217 struct fd3_pipe_sampler_view *so = CALLOC_STRUCT(fd3_pipe_sampler_view); 218 struct fd_resource *rsc = fd_resource(prsc); 219 unsigned lvl; 220 uint32_t sz2 = 0; 221 222 if (!so) 223 return NULL; 224 225 so->base = *cso; 226 pipe_reference(NULL, &prsc->reference); 227 so->base.texture = prsc; 228 so->base.reference.count = 1; 229 so->base.context = pctx; 230 231 so->texconst0 = 232 A3XX_TEX_CONST_0_TYPE(tex_type(prsc->target)) | 233 A3XX_TEX_CONST_0_FMT(fd3_pipe2tex(cso->format)) | 234 fd3_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, 235 cso->swizzle_b, cso->swizzle_a); 236 237 if (prsc->target == PIPE_BUFFER || util_format_is_pure_integer(cso->format)) 238 so->texconst0 |= A3XX_TEX_CONST_0_NOCONVERT; 239 if (util_format_is_srgb(cso->format)) 240 so->texconst0 |= A3XX_TEX_CONST_0_SRGB; 241 242 if (prsc->target == PIPE_BUFFER) { 243 lvl = 0; 244 so->texconst1 = 245 A3XX_TEX_CONST_1_FETCHSIZE(fd3_pipe2fetchsize(cso->format)) | 246 A3XX_TEX_CONST_1_WIDTH(cso->u.buf.size / util_format_get_blocksize(cso->format)) | 247 A3XX_TEX_CONST_1_HEIGHT(1); 248 } else { 249 unsigned miplevels; 250 251 lvl = fd_sampler_first_level(cso); 252 miplevels = fd_sampler_last_level(cso) - lvl; 253 254 so->texconst0 |= A3XX_TEX_CONST_0_MIPLVLS(miplevels); 255 so->texconst1 = 256 A3XX_TEX_CONST_1_FETCHSIZE(fd3_pipe2fetchsize(cso->format)) | 257 A3XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | 258 A3XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); 259 } 260 /* when emitted, A3XX_TEX_CONST_2_INDX() must be OR'd in: */ 261 so->texconst2 = 262 A3XX_TEX_CONST_2_PITCH(fd3_pipe2nblocksx(cso->format, rsc->slices[lvl].pitch) * rsc->cpp); 263 switch (prsc->target) { 264 case PIPE_TEXTURE_1D_ARRAY: 265 case PIPE_TEXTURE_2D_ARRAY: 266 so->texconst3 = 267 A3XX_TEX_CONST_3_DEPTH(prsc->array_size - 1) | 268 A3XX_TEX_CONST_3_LAYERSZ1(rsc->slices[0].size0); 269 break; 270 case PIPE_TEXTURE_3D: 271 so->texconst3 = 272 A3XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | 273 A3XX_TEX_CONST_3_LAYERSZ1(rsc->slices[lvl].size0); 274 while (lvl < cso->u.tex.last_level && sz2 != rsc->slices[lvl+1].size0) 275 sz2 = rsc->slices[++lvl].size0; 276 so->texconst3 |= A3XX_TEX_CONST_3_LAYERSZ2(sz2); 277 break; 278 default: 279 so->texconst3 = 0x00000000; 280 break; 281 } 282 283 return &so->base; 284 } 285 286 void 287 fd3_texture_init(struct pipe_context *pctx) 288 { 289 pctx->create_sampler_state = fd3_sampler_state_create; 290 pctx->bind_sampler_states = fd3_sampler_states_bind; 291 pctx->create_sampler_view = fd3_sampler_view_create; 292 pctx->set_sampler_views = fd_set_sampler_views; 293 } 294