1/* 2 * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org> 3 * Copyright © 2018 Google, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * Authors: 25 * Rob Clark <robclark@freedesktop.org> 26 */ 27 28#include "pipe/p_state.h" 29#include "util/format/u_format.h" 30#include "util/hash_table.h" 31#include "util/u_inlines.h" 32#include "util/u_memory.h" 33#include "util/u_string.h" 34 35#include "freedreno_dev_info.h" 36#include "fd6_emit.h" 37#include "fd6_resource.h" 38#include "fd6_texture.h" 39 40static void 41remove_tex_entry(struct fd6_context *fd6_ctx, struct hash_entry *entry) 42{ 43 struct fd6_texture_state *tex = entry->data; 44 _mesa_hash_table_remove(fd6_ctx->tex_cache, entry); 45 fd6_texture_state_reference(&tex, NULL); 46} 47 48static enum a6xx_tex_clamp 49tex_clamp(unsigned wrap, bool *needs_border) 50{ 51 switch (wrap) { 52 case PIPE_TEX_WRAP_REPEAT: 53 return A6XX_TEX_REPEAT; 54 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 55 return A6XX_TEX_CLAMP_TO_EDGE; 56 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 57 *needs_border = true; 58 return A6XX_TEX_CLAMP_TO_BORDER; 59 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 60 /* only works for PoT.. need to emulate otherwise! */ 61 return A6XX_TEX_MIRROR_CLAMP; 62 case PIPE_TEX_WRAP_MIRROR_REPEAT: 63 return A6XX_TEX_MIRROR_REPEAT; 64 case PIPE_TEX_WRAP_MIRROR_CLAMP: 65 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 66 /* these two we could perhaps emulate, but we currently 67 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP 68 */ 69 default: 70 DBG("invalid wrap: %u", wrap); 71 return 0; 72 } 73} 74 75static enum a6xx_tex_filter 76tex_filter(unsigned filter, bool aniso) 77{ 78 switch (filter) { 79 case PIPE_TEX_FILTER_NEAREST: 80 return A6XX_TEX_NEAREST; 81 case PIPE_TEX_FILTER_LINEAR: 82 return aniso ? A6XX_TEX_ANISO : A6XX_TEX_LINEAR; 83 default: 84 DBG("invalid filter: %u", filter); 85 return 0; 86 } 87} 88 89static void * 90fd6_sampler_state_create(struct pipe_context *pctx, 91 const struct pipe_sampler_state *cso) 92{ 93 struct fd6_sampler_stateobj *so = CALLOC_STRUCT(fd6_sampler_stateobj); 94 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8)); 95 bool miplinear = false; 96 97 if (!so) 98 return NULL; 99 100 so->base = *cso; 101 so->seqno = ++fd6_context(fd_context(pctx))->tex_seqno; 102 103 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) 104 miplinear = true; 105 106 so->needs_border = false; 107 so->texsamp0 = 108 COND(miplinear, A6XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) | 109 A6XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 110 A6XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 111 A6XX_TEX_SAMP_0_ANISO(aniso) | 112 A6XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, &so->needs_border)) | 113 A6XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, &so->needs_border)) | 114 A6XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, &so->needs_border)); 115 116 so->texsamp1 = 117 COND(cso->min_mip_filter == PIPE_TEX_MIPFILTER_NONE, 118 A6XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) | 119 COND(!cso->seamless_cube_map, A6XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) | 120 COND(!cso->normalized_coords, A6XX_TEX_SAMP_1_UNNORM_COORDS); 121 122 so->texsamp0 |= A6XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias); 123 so->texsamp1 |= A6XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 124 A6XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 125 126 if (cso->compare_mode) 127 so->texsamp1 |= 128 A6XX_TEX_SAMP_1_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 129 130 return so; 131} 132 133static void 134fd6_sampler_state_delete(struct pipe_context *pctx, void *hwcso) 135{ 136 struct fd_context *ctx = fd_context(pctx); 137 struct fd6_context *fd6_ctx = fd6_context(ctx); 138 struct fd6_sampler_stateobj *samp = hwcso; 139 140 fd_screen_lock(ctx->screen); 141 142 hash_table_foreach (fd6_ctx->tex_cache, entry) { 143 struct fd6_texture_state *state = entry->data; 144 145 for (unsigned i = 0; i < ARRAY_SIZE(state->key.samp); i++) { 146 if (samp->seqno == state->key.samp[i].seqno) { 147 remove_tex_entry(fd6_ctx, entry); 148 break; 149 } 150 } 151 } 152 153 fd_screen_unlock(ctx->screen); 154 155 free(hwcso); 156} 157 158static struct pipe_sampler_view * 159fd6_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 160 const struct pipe_sampler_view *cso) 161{ 162 struct fd6_pipe_sampler_view *so = CALLOC_STRUCT(fd6_pipe_sampler_view); 163 164 if (!so) 165 return NULL; 166 167 so->base = *cso; 168 pipe_reference(NULL, &prsc->reference); 169 so->base.texture = prsc; 170 so->base.reference.count = 1; 171 so->base.context = pctx; 172 so->needs_validate = true; 173 174 return &so->base; 175} 176 177static void 178fd6_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader, 179 unsigned start, unsigned nr, 180 unsigned unbind_num_trailing_slots, 181 bool take_ownership, 182 struct pipe_sampler_view **views) in_dt 183{ 184 struct fd_context *ctx = fd_context(pctx); 185 186 fd_set_sampler_views(pctx, shader, start, nr, unbind_num_trailing_slots, 187 take_ownership, views); 188 189 if (!views) 190 return; 191 192 for (unsigned i = 0; i < nr; i++) { 193 struct fd6_pipe_sampler_view *so = fd6_pipe_sampler_view(views[i]); 194 195 if (!(so && so->needs_validate)) 196 continue; 197 198 struct fd_resource *rsc = fd_resource(so->base.texture); 199 200 fd6_validate_format(ctx, rsc, so->base.format); 201 fd6_sampler_view_update(ctx, so); 202 203 so->needs_validate = false; 204 } 205} 206 207void 208fd6_sampler_view_update(struct fd_context *ctx, 209 struct fd6_pipe_sampler_view *so) 210{ 211 const struct pipe_sampler_view *cso = &so->base; 212 struct pipe_resource *prsc = cso->texture; 213 struct fd_resource *rsc = fd_resource(prsc); 214 enum pipe_format format = cso->format; 215 216 fd6_validate_format(ctx, rsc, cso->format); 217 218 if (format == PIPE_FORMAT_X32_S8X24_UINT) { 219 rsc = rsc->stencil; 220 format = rsc->b.b.format; 221 } 222 223 so->seqno = ++fd6_context(ctx)->tex_seqno; 224 so->ptr1 = rsc; 225 so->rsc_seqno = rsc->seqno; 226 227 if (cso->target == PIPE_BUFFER) { 228 uint8_t swiz[4] = {cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, 229 cso->swizzle_a}; 230 231 /* Using relocs for addresses still */ 232 uint64_t iova = cso->u.buf.offset; 233 234 fdl6_buffer_view_init(so->descriptor, cso->format, swiz, iova, 235 cso->u.buf.size); 236 } else { 237 struct fdl_view_args args = { 238 /* Using relocs for addresses still */ 239 .iova = 0, 240 241 .base_miplevel = fd_sampler_first_level(cso), 242 .level_count = 243 fd_sampler_last_level(cso) - fd_sampler_first_level(cso) + 1, 244 245 .base_array_layer = cso->u.tex.first_layer, 246 .layer_count = cso->u.tex.last_layer - cso->u.tex.first_layer + 1, 247 248 .format = format, 249 .swiz = {cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, 250 cso->swizzle_a}, 251 252 .type = fdl_type_from_pipe_target(cso->target), 253 .chroma_offsets = {FDL_CHROMA_LOCATION_COSITED_EVEN, 254 FDL_CHROMA_LOCATION_COSITED_EVEN}, 255 }; 256 struct fd_resource *plane1 = fd_resource(rsc->b.b.next); 257 struct fd_resource *plane2 = 258 plane1 ? fd_resource(plane1->b.b.next) : NULL; 259 static const struct fdl_layout dummy_layout = {0}; 260 const struct fdl_layout *layouts[3] = { 261 &rsc->layout, 262 plane1 ? &plane1->layout : &dummy_layout, 263 plane2 ? &plane2->layout : &dummy_layout, 264 }; 265 struct fdl6_view view; 266 fdl6_view_init(&view, layouts, &args, 267 ctx->screen->info->a6xx.has_z24uint_s8uint); 268 memcpy(so->descriptor, view.descriptor, sizeof(so->descriptor)); 269 270 if (rsc->b.b.format == PIPE_FORMAT_R8_G8B8_420_UNORM) { 271 /* In case of biplanar R8_G8B8, the UBWC metadata address in 272 * dwords 7 and 8, is instead the pointer to the second plane. 273 */ 274 so->ptr2 = plane1; 275 } else { 276 if (fd_resource_ubwc_enabled(rsc, fd_sampler_first_level(cso))) { 277 so->ptr2 = rsc; 278 } 279 } 280 } 281} 282 283/* NOTE this can be called in either driver thread or frontend thread 284 * depending on where the last unref comes from 285 */ 286static void 287fd6_sampler_view_destroy(struct pipe_context *pctx, 288 struct pipe_sampler_view *_view) 289{ 290 struct fd_context *ctx = fd_context(pctx); 291 struct fd6_context *fd6_ctx = fd6_context(ctx); 292 struct fd6_pipe_sampler_view *view = fd6_pipe_sampler_view(_view); 293 294 fd_screen_lock(ctx->screen); 295 296 hash_table_foreach (fd6_ctx->tex_cache, entry) { 297 struct fd6_texture_state *state = entry->data; 298 299 for (unsigned i = 0; i < ARRAY_SIZE(state->key.view); i++) { 300 if (view->seqno == state->key.view[i].seqno) { 301 remove_tex_entry(fd6_ctx, entry); 302 break; 303 } 304 } 305 } 306 307 fd_screen_unlock(ctx->screen); 308 309 pipe_resource_reference(&view->base.texture, NULL); 310 311 free(view); 312} 313 314static uint32_t 315key_hash(const void *_key) 316{ 317 const struct fd6_texture_key *key = _key; 318 return XXH32(key, sizeof(*key), 0); 319} 320 321static bool 322key_equals(const void *_a, const void *_b) 323{ 324 const struct fd6_texture_key *a = _a; 325 const struct fd6_texture_key *b = _b; 326 return memcmp(a, b, sizeof(struct fd6_texture_key)) == 0; 327} 328 329struct fd6_texture_state * 330fd6_texture_state(struct fd_context *ctx, enum pipe_shader_type type, 331 struct fd_texture_stateobj *tex) 332{ 333 struct fd6_context *fd6_ctx = fd6_context(ctx); 334 struct fd6_texture_state *state = NULL; 335 struct fd6_texture_key key; 336 bool needs_border = false; 337 338 memset(&key, 0, sizeof(key)); 339 340 for (unsigned i = 0; i < tex->num_textures; i++) { 341 if (!tex->textures[i]) 342 continue; 343 344 struct fd6_pipe_sampler_view *view = 345 fd6_pipe_sampler_view(tex->textures[i]); 346 347 /* NOTE that if the backing rsc was uncompressed between the 348 * time that the CSO was originally created and now, the rsc 349 * seqno would have changed, so we don't have to worry about 350 * getting a bogus cache hit. 351 */ 352 key.view[i].rsc_seqno = fd_resource(view->base.texture)->seqno; 353 key.view[i].seqno = view->seqno; 354 } 355 356 for (unsigned i = 0; i < tex->num_samplers; i++) { 357 if (!tex->samplers[i]) 358 continue; 359 360 struct fd6_sampler_stateobj *sampler = 361 fd6_sampler_stateobj(tex->samplers[i]); 362 363 key.samp[i].seqno = sampler->seqno; 364 365 needs_border |= sampler->needs_border; 366 } 367 368 key.type = type; 369 key.bcolor_offset = fd6_border_color_offset(ctx, type, tex); 370 371 uint32_t hash = key_hash(&key); 372 fd_screen_lock(ctx->screen); 373 struct hash_entry *entry = 374 _mesa_hash_table_search_pre_hashed(fd6_ctx->tex_cache, hash, &key); 375 376 if (entry) { 377 fd6_texture_state_reference(&state, entry->data); 378 goto out_unlock; 379 } 380 381 state = CALLOC_STRUCT(fd6_texture_state); 382 383 /* NOTE: one ref for tex_cache, and second ref for returned state: */ 384 pipe_reference_init(&state->reference, 2); 385 state->key = key; 386 state->stateobj = fd_ringbuffer_new_object(ctx->pipe, 32 * 4); 387 state->needs_border = needs_border; 388 389 fd6_emit_textures(ctx, state->stateobj, type, tex, key.bcolor_offset, NULL); 390 391 /* NOTE: uses copy of key in state obj, because pointer passed by caller 392 * is probably on the stack 393 */ 394 _mesa_hash_table_insert_pre_hashed(fd6_ctx->tex_cache, hash, &state->key, 395 state); 396 397out_unlock: 398 fd_screen_unlock(ctx->screen); 399 return state; 400} 401 402void 403__fd6_texture_state_describe(char *buf, const struct fd6_texture_state *tex) 404{ 405 sprintf(buf, "fd6_texture_state<%p>", tex); 406} 407 408void 409__fd6_texture_state_destroy(struct fd6_texture_state *state) 410{ 411 fd_ringbuffer_del(state->stateobj); 412 free(state); 413} 414 415static void 416fd6_rebind_resource(struct fd_context *ctx, struct fd_resource *rsc) assert_dt 417{ 418 fd_screen_assert_locked(ctx->screen); 419 420 if (!(rsc->dirty & FD_DIRTY_TEX)) 421 return; 422 423 struct fd6_context *fd6_ctx = fd6_context(ctx); 424 425 hash_table_foreach (fd6_ctx->tex_cache, entry) { 426 struct fd6_texture_state *state = entry->data; 427 428 for (unsigned i = 0; i < ARRAY_SIZE(state->key.view); i++) { 429 if (rsc->seqno == state->key.view[i].rsc_seqno) { 430 remove_tex_entry(fd6_ctx, entry); 431 break; 432 } 433 } 434 } 435} 436 437void 438fd6_texture_init(struct pipe_context *pctx) disable_thread_safety_analysis 439{ 440 struct fd_context *ctx = fd_context(pctx); 441 struct fd6_context *fd6_ctx = fd6_context(ctx); 442 443 pctx->create_sampler_state = fd6_sampler_state_create; 444 pctx->delete_sampler_state = fd6_sampler_state_delete; 445 pctx->bind_sampler_states = fd_sampler_states_bind; 446 447 pctx->create_sampler_view = fd6_sampler_view_create; 448 pctx->sampler_view_destroy = fd6_sampler_view_destroy; 449 pctx->set_sampler_views = fd6_set_sampler_views; 450 451 ctx->rebind_resource = fd6_rebind_resource; 452 453 fd6_ctx->tex_cache = _mesa_hash_table_create(NULL, key_hash, key_equals); 454} 455 456void 457fd6_texture_fini(struct pipe_context *pctx) 458{ 459 struct fd_context *ctx = fd_context(pctx); 460 struct fd6_context *fd6_ctx = fd6_context(ctx); 461 462 fd_screen_lock(ctx->screen); 463 464 hash_table_foreach (fd6_ctx->tex_cache, entry) { 465 remove_tex_entry(fd6_ctx, entry); 466 } 467 468 fd_screen_unlock(ctx->screen); 469 470 ralloc_free(fd6_ctx->tex_cache); 471} 472