1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3 /* 4 * Copyright (C) 2014 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 "fd4_texture.h" 36 #include "fd4_format.h" 37 38 static enum a4xx_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 A4XX_TEX_REPEAT; 50 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 51 return A4XX_TEX_CLAMP_TO_EDGE; 52 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 53 *needs_border = true; 54 return A4XX_TEX_CLAMP_TO_BORDER; 55 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 56 /* only works for PoT.. need to emulate otherwise! */ 57 return A4XX_TEX_MIRROR_CLAMP; 58 case PIPE_TEX_WRAP_MIRROR_REPEAT: 59 return A4XX_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 a4xx_tex_filter 72 tex_filter(unsigned filter, bool aniso) 73 { 74 switch (filter) { 75 case PIPE_TEX_FILTER_NEAREST: 76 return A4XX_TEX_NEAREST; 77 case PIPE_TEX_FILTER_LINEAR: 78 return aniso ? A4XX_TEX_ANISO : A4XX_TEX_LINEAR; 79 default: 80 DBG("invalid filter: %u", filter); 81 return 0; 82 } 83 } 84 85 static void * 86 fd4_sampler_state_create(struct pipe_context *pctx, 87 const struct pipe_sampler_state *cso) 88 { 89 struct fd4_sampler_stateobj *so = CALLOC_STRUCT(fd4_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(miplinear, A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) | 120 A4XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 121 A4XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 122 A4XX_TEX_SAMP_0_ANISO(aniso) | 123 A4XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, clamp_to_edge, &so->needs_border)) | 124 A4XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, clamp_to_edge, &so->needs_border)) | 125 A4XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, clamp_to_edge, &so->needs_border)); 126 127 so->texsamp1 = 128 // COND(miplinear, A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) | 129 COND(!cso->seamless_cube_map, A4XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) | 130 COND(!cso->normalized_coords, A4XX_TEX_SAMP_1_UNNORM_COORDS); 131 132 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { 133 so->texsamp0 |= A4XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias); 134 so->texsamp1 |= 135 A4XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 136 A4XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 137 } 138 139 if (cso->compare_mode) 140 so->texsamp1 |= A4XX_TEX_SAMP_1_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 141 142 return so; 143 } 144 145 static void 146 fd4_sampler_states_bind(struct pipe_context *pctx, 147 enum pipe_shader_type shader, unsigned start, 148 unsigned nr, void **hwcso) 149 { 150 struct fd_context *ctx = fd_context(pctx); 151 struct fd4_context *fd4_ctx = fd4_context(ctx); 152 uint16_t saturate_s = 0, saturate_t = 0, saturate_r = 0; 153 unsigned i; 154 155 if (!hwcso) 156 nr = 0; 157 158 for (i = 0; i < nr; i++) { 159 if (hwcso[i]) { 160 struct fd4_sampler_stateobj *sampler = 161 fd4_sampler_stateobj(hwcso[i]); 162 if (sampler->saturate_s) 163 saturate_s |= (1 << i); 164 if (sampler->saturate_t) 165 saturate_t |= (1 << i); 166 if (sampler->saturate_r) 167 saturate_r |= (1 << i); 168 } 169 } 170 171 fd_sampler_states_bind(pctx, shader, start, nr, hwcso); 172 173 if (shader == PIPE_SHADER_FRAGMENT) { 174 fd4_ctx->fsaturate = 175 (saturate_s != 0) || 176 (saturate_t != 0) || 177 (saturate_r != 0); 178 fd4_ctx->fsaturate_s = saturate_s; 179 fd4_ctx->fsaturate_t = saturate_t; 180 fd4_ctx->fsaturate_r = saturate_r; 181 } else if (shader == PIPE_SHADER_VERTEX) { 182 fd4_ctx->vsaturate = 183 (saturate_s != 0) || 184 (saturate_t != 0) || 185 (saturate_r != 0); 186 fd4_ctx->vsaturate_s = saturate_s; 187 fd4_ctx->vsaturate_t = saturate_t; 188 fd4_ctx->vsaturate_r = saturate_r; 189 } 190 } 191 192 static enum a4xx_tex_type 193 tex_type(unsigned target) 194 { 195 switch (target) { 196 default: 197 assert(0); 198 case PIPE_BUFFER: 199 case PIPE_TEXTURE_1D: 200 case PIPE_TEXTURE_1D_ARRAY: 201 return A4XX_TEX_1D; 202 case PIPE_TEXTURE_RECT: 203 case PIPE_TEXTURE_2D: 204 case PIPE_TEXTURE_2D_ARRAY: 205 return A4XX_TEX_2D; 206 case PIPE_TEXTURE_3D: 207 return A4XX_TEX_3D; 208 case PIPE_TEXTURE_CUBE: 209 case PIPE_TEXTURE_CUBE_ARRAY: 210 return A4XX_TEX_CUBE; 211 } 212 } 213 214 static bool 215 use_astc_srgb_workaround(struct pipe_context *pctx, enum pipe_format format) 216 { 217 return (fd_screen(pctx->screen)->gpu_id == 420) && 218 (util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_ASTC); 219 } 220 221 static struct pipe_sampler_view * 222 fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 223 const struct pipe_sampler_view *cso) 224 { 225 struct fd4_pipe_sampler_view *so = CALLOC_STRUCT(fd4_pipe_sampler_view); 226 struct fd_resource *rsc = fd_resource(prsc); 227 unsigned lvl, layers; 228 uint32_t sz2 = 0; 229 230 if (!so) 231 return NULL; 232 233 so->base = *cso; 234 pipe_reference(NULL, &prsc->reference); 235 so->base.texture = prsc; 236 so->base.reference.count = 1; 237 so->base.context = pctx; 238 239 so->texconst0 = 240 A4XX_TEX_CONST_0_TYPE(tex_type(cso->target)) | 241 A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(cso->format)) | 242 fd4_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, 243 cso->swizzle_b, cso->swizzle_a); 244 245 if (util_format_is_srgb(cso->format)) { 246 if (use_astc_srgb_workaround(pctx, cso->format)) 247 so->astc_srgb = true; 248 so->texconst0 |= A4XX_TEX_CONST_0_SRGB; 249 } 250 251 if (cso->target == PIPE_BUFFER) { 252 unsigned elements = cso->u.buf.size / util_format_get_blocksize(cso->format); 253 254 lvl = 0; 255 so->texconst1 = 256 A4XX_TEX_CONST_1_WIDTH(elements) | 257 A4XX_TEX_CONST_1_HEIGHT(1); 258 so->texconst2 = 259 A4XX_TEX_CONST_2_FETCHSIZE(fd4_pipe2fetchsize(cso->format)) | 260 A4XX_TEX_CONST_2_PITCH(elements * rsc->cpp); 261 so->offset = cso->u.buf.offset; 262 } else { 263 unsigned miplevels; 264 265 lvl = fd_sampler_first_level(cso); 266 miplevels = fd_sampler_last_level(cso) - lvl; 267 layers = cso->u.tex.last_layer - cso->u.tex.first_layer + 1; 268 269 so->texconst0 |= A4XX_TEX_CONST_0_MIPLVLS(miplevels); 270 so->texconst1 = 271 A4XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | 272 A4XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); 273 so->texconst2 = 274 A4XX_TEX_CONST_2_FETCHSIZE(fd4_pipe2fetchsize(cso->format)) | 275 A4XX_TEX_CONST_2_PITCH( 276 util_format_get_nblocksx( 277 cso->format, rsc->slices[lvl].pitch) * rsc->cpp); 278 so->offset = fd_resource_offset(rsc, lvl, cso->u.tex.first_layer); 279 } 280 281 switch (cso->target) { 282 case PIPE_TEXTURE_1D_ARRAY: 283 case PIPE_TEXTURE_2D_ARRAY: 284 so->texconst3 = 285 A4XX_TEX_CONST_3_DEPTH(layers) | 286 A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); 287 break; 288 case PIPE_TEXTURE_CUBE: 289 case PIPE_TEXTURE_CUBE_ARRAY: 290 so->texconst3 = 291 A4XX_TEX_CONST_3_DEPTH(layers / 6) | 292 A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); 293 break; 294 case PIPE_TEXTURE_3D: 295 so->texconst3 = 296 A4XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | 297 A4XX_TEX_CONST_3_LAYERSZ(rsc->slices[lvl].size0); 298 while (lvl < cso->u.tex.last_level && sz2 != rsc->slices[lvl+1].size0) 299 sz2 = rsc->slices[++lvl].size0; 300 so->texconst4 = A4XX_TEX_CONST_4_LAYERSZ(sz2); 301 break; 302 default: 303 so->texconst3 = 0x00000000; 304 break; 305 } 306 307 return &so->base; 308 } 309 310 static void 311 fd4_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader, 312 unsigned start, unsigned nr, 313 struct pipe_sampler_view **views) 314 { 315 struct fd_context *ctx = fd_context(pctx); 316 struct fd4_context *fd4_ctx = fd4_context(ctx); 317 uint16_t astc_srgb = 0; 318 unsigned i; 319 320 for (i = 0; i < nr; i++) { 321 if (views[i]) { 322 struct fd4_pipe_sampler_view *view = 323 fd4_pipe_sampler_view(views[i]); 324 if (view->astc_srgb) 325 astc_srgb |= (1 << i); 326 } 327 } 328 329 fd_set_sampler_views(pctx, shader, start, nr, views); 330 331 if (shader == PIPE_SHADER_FRAGMENT) { 332 fd4_ctx->fastc_srgb = astc_srgb; 333 } else if (shader == PIPE_SHADER_VERTEX) { 334 fd4_ctx->vastc_srgb = astc_srgb; 335 } 336 } 337 338 void 339 fd4_texture_init(struct pipe_context *pctx) 340 { 341 pctx->create_sampler_state = fd4_sampler_state_create; 342 pctx->bind_sampler_states = fd4_sampler_states_bind; 343 pctx->create_sampler_view = fd4_sampler_view_create; 344 pctx->set_sampler_views = fd4_set_sampler_views; 345 } 346