1/* 2 * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#include "pipe/p_state.h" 28#include "util/format/u_format.h" 29#include "util/u_inlines.h" 30#include "util/u_memory.h" 31#include "util/u_string.h" 32 33#include "fd4_format.h" 34#include "fd4_texture.h" 35 36static enum a4xx_tex_clamp 37tex_clamp(unsigned wrap, bool *needs_border) 38{ 39 switch (wrap) { 40 case PIPE_TEX_WRAP_REPEAT: 41 return A4XX_TEX_REPEAT; 42 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 43 return A4XX_TEX_CLAMP_TO_EDGE; 44 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 45 *needs_border = true; 46 return A4XX_TEX_CLAMP_TO_BORDER; 47 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 48 /* only works for PoT.. need to emulate otherwise! */ 49 return A4XX_TEX_MIRROR_CLAMP; 50 case PIPE_TEX_WRAP_MIRROR_REPEAT: 51 return A4XX_TEX_MIRROR_REPEAT; 52 case PIPE_TEX_WRAP_MIRROR_CLAMP: 53 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 54 /* these two we could perhaps emulate, but we currently 55 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP 56 */ 57 default: 58 DBG("invalid wrap: %u", wrap); 59 return 0; 60 } 61} 62 63static enum a4xx_tex_filter 64tex_filter(unsigned filter, bool aniso) 65{ 66 switch (filter) { 67 case PIPE_TEX_FILTER_NEAREST: 68 return A4XX_TEX_NEAREST; 69 case PIPE_TEX_FILTER_LINEAR: 70 return aniso ? A4XX_TEX_ANISO : A4XX_TEX_LINEAR; 71 default: 72 DBG("invalid filter: %u", filter); 73 return 0; 74 } 75} 76 77static void * 78fd4_sampler_state_create(struct pipe_context *pctx, 79 const struct pipe_sampler_state *cso) 80{ 81 struct fd4_sampler_stateobj *so = CALLOC_STRUCT(fd4_sampler_stateobj); 82 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8)); 83 bool miplinear = false; 84 85 if (!so) 86 return NULL; 87 88 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) 89 miplinear = true; 90 91 so->base = *cso; 92 93 so->needs_border = false; 94 so->texsamp0 = 95 COND(miplinear, A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) | 96 A4XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 97 A4XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 98 A4XX_TEX_SAMP_0_ANISO(aniso) | 99 A4XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias) | 100 A4XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, &so->needs_border)) | 101 A4XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, &so->needs_border)) | 102 A4XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, &so->needs_border)); 103 104 so->texsamp1 = 105 // COND(miplinear, A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) | 106 COND(!cso->seamless_cube_map, A4XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) | 107 COND(!cso->normalized_coords, A4XX_TEX_SAMP_1_UNNORM_COORDS); 108 109 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { 110 so->texsamp1 |= A4XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 111 A4XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 112 } else { 113 /* If we're not doing mipmap filtering, we still need a slightly > 0 114 * LOD clamp so the HW can decide between min and mag filtering of 115 * level 0. 116 */ 117 so->texsamp1 |= A4XX_TEX_SAMP_1_MIN_LOD(MIN2(cso->min_lod, 0.125f)) | 118 A4XX_TEX_SAMP_1_MAX_LOD(MIN2(cso->max_lod, 0.125f)); 119 } 120 121 if (cso->compare_mode) 122 so->texsamp1 |= 123 A4XX_TEX_SAMP_1_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 124 125 return so; 126} 127 128static bool 129use_astc_srgb_workaround(struct pipe_context *pctx, enum pipe_format format) 130{ 131 return (fd_screen(pctx->screen)->gpu_id == 420) && 132 (util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_ASTC); 133} 134 135static struct pipe_sampler_view * 136fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 137 const struct pipe_sampler_view *cso) 138{ 139 struct fd4_pipe_sampler_view *so = CALLOC_STRUCT(fd4_pipe_sampler_view); 140 struct fd_resource *rsc = fd_resource(prsc); 141 enum pipe_format format = cso->format; 142 unsigned lvl, layers = 0; 143 144 if (!so) 145 return NULL; 146 147 if (format == PIPE_FORMAT_X32_S8X24_UINT) { 148 rsc = rsc->stencil; 149 format = rsc->b.b.format; 150 } 151 152 so->base = *cso; 153 pipe_reference(NULL, &prsc->reference); 154 so->base.texture = prsc; 155 so->base.reference.count = 1; 156 so->base.context = pctx; 157 158 so->swizzle = fd4_tex_swiz(format, cso->swizzle_r, cso->swizzle_g, 159 cso->swizzle_b, cso->swizzle_a); 160 161 so->texconst0 = A4XX_TEX_CONST_0_TYPE(fd4_tex_type(cso->target)) | 162 A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(format)) | 163 so->swizzle; 164 165 if (util_format_is_srgb(format)) { 166 if (use_astc_srgb_workaround(pctx, format)) 167 so->astc_srgb = true; 168 so->texconst0 |= A4XX_TEX_CONST_0_SRGB; 169 } 170 171 if (cso->target == PIPE_BUFFER) { 172 unsigned elements = cso->u.buf.size / util_format_get_blocksize(format); 173 174 lvl = 0; 175 so->texconst1 = 176 A4XX_TEX_CONST_1_WIDTH(elements & MASK(15)) | 177 A4XX_TEX_CONST_1_HEIGHT(elements >> 15); 178 so->texconst2 = A4XX_TEX_CONST_2_BUFFER; 179 so->offset = cso->u.buf.offset; 180 } else { 181 unsigned miplevels; 182 183 lvl = fd_sampler_first_level(cso); 184 miplevels = fd_sampler_last_level(cso) - lvl; 185 layers = cso->u.tex.last_layer - cso->u.tex.first_layer + 1; 186 187 so->texconst0 |= A4XX_TEX_CONST_0_MIPLVLS(miplevels); 188 so->texconst1 = A4XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | 189 A4XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); 190 so->texconst2 = A4XX_TEX_CONST_2_PITCHALIGN(rsc->layout.pitchalign - 5) | 191 A4XX_TEX_CONST_2_PITCH(fd_resource_pitch(rsc, lvl)); 192 so->offset = fd_resource_offset(rsc, lvl, cso->u.tex.first_layer); 193 } 194 195 /* NOTE: since we sample z24s8 using 8888_UINT format, the swizzle 196 * we get isn't quite right. Use SWAP(XYZW) as a cheap and cheerful 197 * way to re-arrange things so stencil component is where the swiz 198 * expects. 199 * 200 * Note that gallium expects stencil sampler to return (s,s,s,s) 201 * which isn't quite true. To make that happen we'd have to massage 202 * the swizzle. But in practice only the .x component is used. 203 */ 204 if (format == PIPE_FORMAT_X24S8_UINT) 205 so->texconst2 |= A4XX_TEX_CONST_2_SWAP(XYZW); 206 207 switch (cso->target) { 208 case PIPE_TEXTURE_1D_ARRAY: 209 case PIPE_TEXTURE_2D_ARRAY: 210 so->texconst3 = A4XX_TEX_CONST_3_DEPTH(layers) | 211 A4XX_TEX_CONST_3_LAYERSZ(rsc->layout.layer_size); 212 break; 213 case PIPE_TEXTURE_CUBE: 214 case PIPE_TEXTURE_CUBE_ARRAY: 215 so->texconst3 = A4XX_TEX_CONST_3_DEPTH(layers / 6) | 216 A4XX_TEX_CONST_3_LAYERSZ(rsc->layout.layer_size); 217 break; 218 case PIPE_TEXTURE_3D: 219 so->texconst3 = 220 A4XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | 221 A4XX_TEX_CONST_3_LAYERSZ(fd_resource_slice(rsc, lvl)->size0); 222 so->texconst4 = A4XX_TEX_CONST_4_LAYERSZ( 223 fd_resource_slice(rsc, prsc->last_level)->size0); 224 break; 225 default: 226 so->texconst3 = 0x00000000; 227 break; 228 } 229 230 return &so->base; 231} 232 233static void 234fd4_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader, 235 unsigned start, unsigned nr, 236 unsigned unbind_num_trailing_slots, 237 bool take_ownership, 238 struct pipe_sampler_view **views) 239{ 240 struct fd_context *ctx = fd_context(pctx); 241 struct fd4_context *fd4_ctx = fd4_context(ctx); 242 uint16_t astc_srgb = 0; 243 uint16_t *sampler_swizzles; 244 unsigned i; 245 246 if (shader == PIPE_SHADER_FRAGMENT) { 247 sampler_swizzles = fd4_ctx->fsampler_swizzles; 248 } else if (shader == PIPE_SHADER_VERTEX) { 249 sampler_swizzles = fd4_ctx->vsampler_swizzles; 250 } else if (shader == PIPE_SHADER_COMPUTE) { 251 sampler_swizzles = fd4_ctx->csampler_swizzles; 252 } else { 253 assert(0); 254 sampler_swizzles = fd4_ctx->csampler_swizzles; 255 } 256 257 for (i = 0; i < nr; i++) { 258 if (views[i]) { 259 struct fd4_pipe_sampler_view *view = fd4_pipe_sampler_view(views[i]); 260 if (view->astc_srgb) 261 astc_srgb |= (1 << (start + i)); 262 sampler_swizzles[start + i] = view->swizzle >> 4; 263 264 const struct util_format_description *desc = 265 util_format_description(view->base.format); 266 int c = util_format_get_first_non_void_channel(desc->format); 267 if (c >= 0 && desc->channel[c].pure_integer) { 268 switch (desc->channel[c].size) { 269 case 8: 270 sampler_swizzles[start + i] |= 0x1000; 271 break; 272 case 16: 273 sampler_swizzles[start + i] |= 0x2000; 274 break; 275 case 32: 276 sampler_swizzles[start + i] |= 0x3000; 277 break; 278 case 10: 279 sampler_swizzles[start + i] |= 0x4000; 280 break; 281 default: 282 assert(0); 283 } 284 } 285 } 286 } 287 288 fd_set_sampler_views(pctx, shader, start, nr, unbind_num_trailing_slots, 289 take_ownership, views); 290 291 for (i = 0; i < unbind_num_trailing_slots; i++) { 292 astc_srgb &= ~(1 << (start + nr + i)); 293 sampler_swizzles[start + nr + i] = 0x688; 294 } 295 296 if (shader == PIPE_SHADER_FRAGMENT) { 297 fd4_ctx->fastc_srgb = astc_srgb; 298 } else if (shader == PIPE_SHADER_VERTEX) { 299 fd4_ctx->vastc_srgb = astc_srgb; 300 } else if (shader == PIPE_SHADER_COMPUTE) { 301 fd4_ctx->castc_srgb = astc_srgb; 302 } 303} 304 305void 306fd4_texture_init(struct pipe_context *pctx) 307{ 308 pctx->create_sampler_state = fd4_sampler_state_create; 309 pctx->bind_sampler_states = fd_sampler_states_bind; 310 pctx->create_sampler_view = fd4_sampler_view_create; 311 pctx->set_sampler_views = fd4_set_sampler_views; 312} 313