1 /*
2 * Copyright © 2016 Rob Clark <robclark@freedesktop.org>
3 * Copyright © 2018 Google, Inc.
4 * SPDX-License-Identifier: MIT
5 *
6 * Authors:
7 * Rob Clark <robclark@freedesktop.org>
8 */
9
10 #define FD_BO_NO_HARDPIN 1
11
12 #include "pipe/p_state.h"
13 #include "util/format/u_format.h"
14 #include "util/hash_table.h"
15 #include "util/u_inlines.h"
16 #include "util/u_memory.h"
17 #include "util/u_string.h"
18
19 #include "freedreno_dev_info.h"
20 #include "fd6_emit.h"
21 #include "fd6_resource.h"
22 #include "fd6_screen.h"
23 #include "fd6_texture.h"
24
25 static void fd6_texture_state_destroy(struct fd6_texture_state *state);
26
27 static void
remove_tex_entry(struct fd6_context * fd6_ctx,struct hash_entry * entry)28 remove_tex_entry(struct fd6_context *fd6_ctx, struct hash_entry *entry)
29 {
30 struct fd6_texture_state *tex = (struct fd6_texture_state *)entry->data;
31 _mesa_hash_table_remove(fd6_ctx->tex_cache, entry);
32 fd6_texture_state_destroy(tex);
33 }
34
35 static enum a6xx_tex_clamp
tex_clamp(unsigned wrap,bool * needs_border)36 tex_clamp(unsigned wrap, bool *needs_border)
37 {
38 switch (wrap) {
39 case PIPE_TEX_WRAP_REPEAT:
40 return A6XX_TEX_REPEAT;
41 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
42 return A6XX_TEX_CLAMP_TO_EDGE;
43 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
44 *needs_border = true;
45 return A6XX_TEX_CLAMP_TO_BORDER;
46 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
47 /* only works for PoT.. need to emulate otherwise! */
48 return A6XX_TEX_MIRROR_CLAMP;
49 case PIPE_TEX_WRAP_MIRROR_REPEAT:
50 return A6XX_TEX_MIRROR_REPEAT;
51 case PIPE_TEX_WRAP_MIRROR_CLAMP:
52 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
53 /* these two we could perhaps emulate, but we currently
54 * just don't advertise pipe_caps.texture_mirror_clamp
55 */
56 default:
57 DBG("invalid wrap: %u", wrap);
58 return (enum a6xx_tex_clamp)0;
59 }
60 }
61
62 static enum a6xx_tex_filter
tex_filter(unsigned filter,bool aniso)63 tex_filter(unsigned filter, bool aniso)
64 {
65 switch (filter) {
66 case PIPE_TEX_FILTER_NEAREST:
67 return A6XX_TEX_NEAREST;
68 case PIPE_TEX_FILTER_LINEAR:
69 return aniso ? A6XX_TEX_ANISO : A6XX_TEX_LINEAR;
70 default:
71 DBG("invalid filter: %u", filter);
72 return (enum a6xx_tex_filter)0;
73 }
74 }
75
76 static enum a6xx_reduction_mode
reduction_mode(unsigned reduction_mode)77 reduction_mode(unsigned reduction_mode)
78 {
79 switch (reduction_mode) {
80 default:
81 case PIPE_TEX_REDUCTION_WEIGHTED_AVERAGE:
82 return A6XX_REDUCTION_MODE_AVERAGE;
83 case PIPE_TEX_REDUCTION_MIN:
84 return A6XX_REDUCTION_MODE_MIN;
85 case PIPE_TEX_REDUCTION_MAX:
86 return A6XX_REDUCTION_MODE_MAX;
87 }
88 }
89
90 static void
setup_border_color(struct fd_screen * screen,const struct pipe_sampler_state * sampler,struct fd6_bcolor_entry * e)91 setup_border_color(struct fd_screen *screen,
92 const struct pipe_sampler_state *sampler,
93 struct fd6_bcolor_entry *e)
94 {
95 STATIC_ASSERT(sizeof(struct fd6_bcolor_entry) == FD6_BORDER_COLOR_SIZE);
96 const bool has_z24uint_s8uint = screen->info->a6xx.has_z24uint_s8uint;
97 const union pipe_color_union *bc = &sampler->border_color;
98
99 enum pipe_format format = sampler->border_color_format;
100 const struct util_format_description *desc =
101 util_format_description(format);
102
103 e->rgb565 = 0;
104 e->rgb5a1 = 0;
105 e->rgba4 = 0;
106 e->rgb10a2 = 0;
107 e->z24 = 0;
108
109 unsigned char swiz[4];
110
111 fdl6_format_swiz(format, false, swiz);
112
113 for (unsigned j = 0; j < 4; j++) {
114 int c = swiz[j];
115 int cd = c;
116
117 /*
118 * HACK: for PIPE_FORMAT_X24S8_UINT we end up w/ the
119 * stencil border color value in bc->ui[0] but according
120 * to desc->swizzle and desc->channel, the .x/.w component
121 * is NONE and the stencil value is in the y component.
122 * Meanwhile the hardware wants this in the .x component
123 * for x24s8 and x32_s8x24, or the .y component for x24s8 with the
124 * special Z24UINT_S8UINT format.
125 */
126 if ((format == PIPE_FORMAT_X24S8_UINT) ||
127 (format == PIPE_FORMAT_X32_S8X24_UINT)) {
128 if (j == 0) {
129 c = 1;
130 cd = (format == PIPE_FORMAT_X24S8_UINT && has_z24uint_s8uint) ? 1 : 0;
131 } else {
132 continue;
133 }
134 }
135
136 if (c >= 4)
137 continue;
138
139 if (desc->channel[c].pure_integer) {
140 uint16_t clamped;
141 switch (desc->channel[c].size) {
142 case 2:
143 assert(desc->channel[c].type == UTIL_FORMAT_TYPE_UNSIGNED);
144 clamped = CLAMP(bc->ui[j], 0, 0x3);
145 break;
146 case 8:
147 if (desc->channel[c].type == UTIL_FORMAT_TYPE_SIGNED)
148 clamped = CLAMP(bc->i[j], -128, 127);
149 else
150 clamped = CLAMP(bc->ui[j], 0, 255);
151 break;
152 case 10:
153 assert(desc->channel[c].type == UTIL_FORMAT_TYPE_UNSIGNED);
154 clamped = CLAMP(bc->ui[j], 0, 0x3ff);
155 break;
156 case 16:
157 if (desc->channel[c].type == UTIL_FORMAT_TYPE_SIGNED)
158 clamped = CLAMP(bc->i[j], -32768, 32767);
159 else
160 clamped = CLAMP(bc->ui[j], 0, 65535);
161 break;
162 default:
163 unreachable("Unexpected bit size");
164 case 32:
165 clamped = 0;
166 break;
167 }
168 e->fp32[cd] = bc->ui[j];
169 e->fp16[cd] = clamped;
170 } else {
171 float f = bc->f[j];
172 float f_u = CLAMP(f, 0, 1);
173 float f_s = CLAMP(f, -1, 1);
174
175 e->fp32[c] = fui(f);
176 e->fp16[c] = _mesa_float_to_half(f);
177 e->srgb[c] = _mesa_float_to_half(f_u);
178 e->ui16[c] = f_u * 0xffff;
179 e->si16[c] = f_s * 0x7fff;
180 e->ui8[c] = f_u * 0xff;
181 e->si8[c] = f_s * 0x7f;
182
183 if (c == 1)
184 e->rgb565 |= (int)(f_u * 0x3f) << 5;
185 else if (c < 3)
186 e->rgb565 |= (int)(f_u * 0x1f) << (c ? 11 : 0);
187 if (c == 3)
188 e->rgb5a1 |= (f_u > 0.5f) ? 0x8000 : 0;
189 else
190 e->rgb5a1 |= (int)(f_u * 0x1f) << (c * 5);
191 if (c == 3)
192 e->rgb10a2 |= (int)(f_u * 0x3) << 30;
193 else
194 e->rgb10a2 |= (int)(f_u * 0x3ff) << (c * 10);
195 e->rgba4 |= (int)(f_u * 0xf) << (c * 4);
196 if (c == 0)
197 e->z24 = f_u * 0xffffff;
198 }
199 }
200 }
201
202 static uint32_t
bcolor_key_hash(const void * _key)203 bcolor_key_hash(const void *_key)
204 {
205 const struct fd6_bcolor_entry *key = (const struct fd6_bcolor_entry *)_key;
206 return XXH32(key, sizeof(*key), 0);
207 }
208
209 static bool
bcolor_key_equals(const void * _a,const void * _b)210 bcolor_key_equals(const void *_a, const void *_b)
211 {
212 const struct fd6_bcolor_entry *a = (const struct fd6_bcolor_entry *)_a;
213 const struct fd6_bcolor_entry *b = (const struct fd6_bcolor_entry *)_b;
214 return memcmp(a, b, sizeof(struct fd6_bcolor_entry)) == 0;
215 }
216
217 static unsigned
get_bcolor_offset(struct fd_context * ctx,const struct pipe_sampler_state * sampler)218 get_bcolor_offset(struct fd_context *ctx, const struct pipe_sampler_state *sampler)
219 {
220 struct fd6_context *fd6_ctx = fd6_context(ctx);
221 struct fd6_bcolor_entry *entries =
222 (struct fd6_bcolor_entry *)fd_bo_map(fd6_ctx->bcolor_mem);
223 struct fd6_bcolor_entry key = {};
224
225 setup_border_color(ctx->screen, sampler, &key);
226
227 uint32_t hash = bcolor_key_hash(&key);
228
229 struct hash_entry *entry =
230 _mesa_hash_table_search_pre_hashed(fd6_ctx->bcolor_cache, hash, &key);
231
232 if (entry) {
233 return (unsigned)(uintptr_t)entry->data;
234 }
235
236 unsigned idx = fd6_ctx->bcolor_cache->entries;
237 if (idx >= FD6_MAX_BORDER_COLORS) {
238 mesa_loge("too many border colors");
239 return 0;
240 }
241
242 entries[idx] = key;
243
244 _mesa_hash_table_insert_pre_hashed(fd6_ctx->bcolor_cache, hash,
245 &entries[idx], (void *)(uintptr_t)idx);
246
247 return idx;
248 }
249
250 static void *
fd6_sampler_state_create(struct pipe_context * pctx,const struct pipe_sampler_state * cso)251 fd6_sampler_state_create(struct pipe_context *pctx,
252 const struct pipe_sampler_state *cso)
253 {
254 struct fd6_sampler_stateobj *so = CALLOC_STRUCT(fd6_sampler_stateobj);
255 struct fd_context *ctx = fd_context(pctx);
256 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8));
257 bool miplinear = false;
258
259 if (!so)
260 return NULL;
261
262 so->base = *cso;
263 so->seqno = util_idalloc_alloc(&fd6_context(ctx)->tex_ids);
264
265 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR)
266 miplinear = true;
267
268 bool needs_border = false;
269 so->texsamp0 =
270 COND(miplinear, A6XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) |
271 A6XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) |
272 A6XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) |
273 A6XX_TEX_SAMP_0_ANISO((enum a6xx_tex_aniso)aniso) |
274 A6XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, &needs_border)) |
275 A6XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, &needs_border)) |
276 A6XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, &needs_border));
277
278 so->texsamp1 =
279 COND(cso->min_mip_filter == PIPE_TEX_MIPFILTER_NONE,
280 A6XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) |
281 COND(!cso->seamless_cube_map, A6XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) |
282 COND(cso->unnormalized_coords, A6XX_TEX_SAMP_1_UNNORM_COORDS);
283
284 so->texsamp0 |= A6XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias);
285 so->texsamp1 |= A6XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) |
286 A6XX_TEX_SAMP_1_MAX_LOD(cso->max_lod);
287
288 if (cso->compare_mode)
289 so->texsamp1 |=
290 A6XX_TEX_SAMP_1_COMPARE_FUNC((enum adreno_compare_func)cso->compare_func); /* maps 1:1 */
291
292 if (needs_border)
293 so->texsamp2 = A6XX_TEX_SAMP_2_BCOLOR(get_bcolor_offset(ctx, cso));
294
295 /* We don't know if the format is going to be YUV. Setting CHROMA_LINEAR
296 * unconditionally seems fine.
297 */
298 if (cso->mag_img_filter == PIPE_TEX_FILTER_LINEAR &&
299 cso->min_img_filter == PIPE_TEX_FILTER_LINEAR)
300 so->texsamp2 |= A6XX_TEX_SAMP_2_CHROMA_LINEAR;
301
302 so->texsamp2 |=
303 A6XX_TEX_SAMP_2_REDUCTION_MODE(reduction_mode(cso->reduction_mode));
304
305 return so;
306 }
307
308 static void
fd6_sampler_state_delete(struct pipe_context * pctx,void * hwcso)309 fd6_sampler_state_delete(struct pipe_context *pctx, void *hwcso)
310 {
311 struct fd_context *ctx = fd_context(pctx);
312 struct fd6_context *fd6_ctx = fd6_context(ctx);
313 struct fd6_sampler_stateobj *samp = (struct fd6_sampler_stateobj *)hwcso;
314
315 fd_screen_lock(ctx->screen);
316
317 hash_table_foreach (fd6_ctx->tex_cache, entry) {
318 struct fd6_texture_state *state = (struct fd6_texture_state *)entry->data;
319
320 for (unsigned i = 0; i < ARRAY_SIZE(state->key.samp_seqno); i++) {
321 if (samp->seqno == state->key.samp_seqno[i]) {
322 remove_tex_entry(fd6_ctx, entry);
323 break;
324 }
325 }
326 }
327
328 fd_screen_unlock(ctx->screen);
329
330 util_idalloc_free(&fd6_ctx->tex_ids, samp->seqno);
331
332 free(hwcso);
333 }
334
335 static struct pipe_sampler_view *
fd6_sampler_view_create(struct pipe_context * pctx,struct pipe_resource * prsc,const struct pipe_sampler_view * cso)336 fd6_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc,
337 const struct pipe_sampler_view *cso)
338 {
339 struct fd6_context *fd6_ctx = fd6_context(fd_context(pctx));
340 struct fd6_pipe_sampler_view *so = CALLOC_STRUCT(fd6_pipe_sampler_view);
341
342 if (!so)
343 return NULL;
344
345 so->base = *cso;
346 so->seqno = util_idalloc_alloc(&fd6_ctx->tex_ids);
347 pipe_reference(NULL, &prsc->reference);
348 so->base.texture = prsc;
349 so->base.reference.count = 1;
350 so->base.context = pctx;
351
352 return &so->base;
353 }
354
355 /**
356 * Remove any texture state entries that reference the specified sampler
357 * view.
358 */
359 static void
fd6_sampler_view_invalidate(struct fd_context * ctx,struct fd6_pipe_sampler_view * view)360 fd6_sampler_view_invalidate(struct fd_context *ctx,
361 struct fd6_pipe_sampler_view *view)
362 {
363 struct fd6_context *fd6_ctx = fd6_context(ctx);
364
365 fd_screen_lock(ctx->screen);
366
367 hash_table_foreach (fd6_ctx->tex_cache, entry) {
368 struct fd6_texture_state *state = (struct fd6_texture_state *)entry->data;
369
370 for (unsigned i = 0; i < ARRAY_SIZE(state->key.view_seqno); i++) {
371 if (view->seqno == state->key.view_seqno[i]) {
372 remove_tex_entry(fd6_ctx, entry);
373 break;
374 }
375 }
376 }
377
378 fd_screen_unlock(ctx->screen);
379 }
380
381 static void
fd6_sampler_view_update(struct fd_context * ctx,struct fd6_pipe_sampler_view * so)382 fd6_sampler_view_update(struct fd_context *ctx,
383 struct fd6_pipe_sampler_view *so)
384 assert_dt
385 {
386 const struct pipe_sampler_view *cso = &so->base;
387 struct pipe_resource *prsc = cso->texture;
388 struct fd_resource *rsc = fd_resource(prsc);
389 enum pipe_format format = cso->format;
390
391 fd6_assert_valid_format(rsc, cso->format);
392
393 /* If texture has not had a layout change, then no update needed: */
394 if (so->rsc_seqno == rsc->seqno)
395 return;
396
397 fd6_sampler_view_invalidate(ctx, so);
398
399 so->rsc_seqno = rsc->seqno;
400
401 if (format == PIPE_FORMAT_X32_S8X24_UINT) {
402 rsc = rsc->stencil;
403 format = rsc->b.b.format;
404 }
405
406 so->ptr1 = rsc;
407
408 if (cso->target == PIPE_BUFFER) {
409 uint8_t swiz[4] = {cso->swizzle_r, cso->swizzle_g, cso->swizzle_b,
410 cso->swizzle_a};
411
412 /* Using relocs for addresses still */
413 uint64_t iova = cso->u.buf.offset;
414
415 uint32_t size = fd_clamp_buffer_size(cso->format, cso->u.buf.size,
416 A4XX_MAX_TEXEL_BUFFER_ELEMENTS_UINT);
417
418 fdl6_buffer_view_init(so->descriptor, cso->format, swiz, iova, size);
419 } else {
420 struct fdl_view_args args = {
421 .chip = ctx->screen->gen,
422
423 /* Using relocs for addresses still */
424 .iova = 0,
425
426 .base_miplevel = fd_sampler_first_level(cso),
427 .level_count =
428 fd_sampler_last_level(cso) - fd_sampler_first_level(cso) + 1,
429
430 .base_array_layer = cso->u.tex.first_layer,
431 .layer_count = cso->u.tex.last_layer - cso->u.tex.first_layer + 1,
432
433 .swiz = {cso->swizzle_r, cso->swizzle_g, cso->swizzle_b,
434 cso->swizzle_a},
435 .format = format,
436
437 .type = fdl_type_from_pipe_target(cso->target),
438 .chroma_offsets = {FDL_CHROMA_LOCATION_COSITED_EVEN,
439 FDL_CHROMA_LOCATION_COSITED_EVEN},
440 };
441
442 if (rsc->b.b.format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
443 args.chroma_offsets[0] = FDL_CHROMA_LOCATION_MIDPOINT;
444 args.chroma_offsets[1] = FDL_CHROMA_LOCATION_MIDPOINT;
445 }
446
447 struct fd_resource *plane1 = fd_resource(rsc->b.b.next);
448 struct fd_resource *plane2 =
449 plane1 ? fd_resource(plane1->b.b.next) : NULL;
450 static const struct fdl_layout dummy_layout = {};
451 const struct fdl_layout *layouts[3] = {
452 &rsc->layout,
453 plane1 ? &plane1->layout : &dummy_layout,
454 plane2 ? &plane2->layout : &dummy_layout,
455 };
456 struct fdl6_view view;
457 fdl6_view_init(&view, layouts, &args,
458 ctx->screen->info->a6xx.has_z24uint_s8uint);
459 memcpy(so->descriptor, view.descriptor, sizeof(so->descriptor));
460
461 if (rsc->b.b.format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
462 /* In case of biplanar R8_G8B8, the UBWC metadata address in
463 * dwords 7 and 8, is instead the pointer to the second plane.
464 */
465 so->ptr2 = plane1;
466 } else {
467 if (fd_resource_ubwc_enabled(rsc, fd_sampler_first_level(cso))) {
468 so->ptr2 = rsc;
469 }
470 }
471 }
472 }
473
474 static void
fd6_set_sampler_views(struct pipe_context * pctx,enum pipe_shader_type shader,unsigned start,unsigned nr,unsigned unbind_num_trailing_slots,bool take_ownership,struct pipe_sampler_view ** views)475 fd6_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader,
476 unsigned start, unsigned nr,
477 unsigned unbind_num_trailing_slots,
478 bool take_ownership,
479 struct pipe_sampler_view **views)
480 in_dt
481 {
482 struct fd_context *ctx = fd_context(pctx);
483
484 fd_set_sampler_views(pctx, shader, start, nr, unbind_num_trailing_slots,
485 take_ownership, views);
486
487 if (!views)
488 return;
489
490 for (unsigned i = 0; i < nr; i++) {
491 struct fd6_pipe_sampler_view *so = fd6_pipe_sampler_view(views[i + start]);
492
493 if (!so)
494 continue;
495
496 struct fd_resource *rsc = fd_resource(so->base.texture);
497
498 fd6_validate_format(ctx, rsc, so->base.format);
499 fd6_sampler_view_update(ctx, so);
500 }
501 }
502
503 /* NOTE this can be called in either driver thread or frontend thread
504 * depending on where the last unref comes from
505 */
506 static void
fd6_sampler_view_destroy(struct pipe_context * pctx,struct pipe_sampler_view * _view)507 fd6_sampler_view_destroy(struct pipe_context *pctx,
508 struct pipe_sampler_view *_view)
509 {
510 struct fd_context *ctx = fd_context(pctx);
511 struct fd6_pipe_sampler_view *view = fd6_pipe_sampler_view(_view);
512
513 fd6_sampler_view_invalidate(ctx, view);
514
515 pipe_resource_reference(&view->base.texture, NULL);
516
517 util_idalloc_free(&fd6_context(ctx)->tex_ids, view->seqno);
518
519 free(view);
520 }
521
522 static uint32_t
tex_key_hash(const void * _key)523 tex_key_hash(const void *_key)
524 {
525 const struct fd6_texture_key *key = (const struct fd6_texture_key *)_key;
526 return XXH32(key, sizeof(*key), 0);
527 }
528
529 static bool
tex_key_equals(const void * _a,const void * _b)530 tex_key_equals(const void *_a, const void *_b)
531 {
532 const struct fd6_texture_key *a = (const struct fd6_texture_key *)_a;
533 const struct fd6_texture_key *b = (const struct fd6_texture_key *)_b;
534 return memcmp(a, b, sizeof(struct fd6_texture_key)) == 0;
535 }
536
537 static struct fd_ringbuffer *
build_texture_state(struct fd_context * ctx,enum pipe_shader_type type,struct fd_texture_stateobj * tex)538 build_texture_state(struct fd_context *ctx, enum pipe_shader_type type,
539 struct fd_texture_stateobj *tex)
540 assert_dt
541 {
542 struct fd_ringbuffer *ring = fd_ringbuffer_new_object(ctx->pipe, 32 * 4);
543 unsigned opcode, tex_samp_reg, tex_const_reg, tex_count_reg;
544 enum a6xx_state_block sb;
545
546 switch (type) {
547 case PIPE_SHADER_VERTEX:
548 sb = SB6_VS_TEX;
549 opcode = CP_LOAD_STATE6_GEOM;
550 tex_samp_reg = REG_A6XX_SP_VS_TEX_SAMP;
551 tex_const_reg = REG_A6XX_SP_VS_TEX_CONST;
552 tex_count_reg = REG_A6XX_SP_VS_TEX_COUNT;
553 break;
554 case PIPE_SHADER_TESS_CTRL:
555 sb = SB6_HS_TEX;
556 opcode = CP_LOAD_STATE6_GEOM;
557 tex_samp_reg = REG_A6XX_SP_HS_TEX_SAMP;
558 tex_const_reg = REG_A6XX_SP_HS_TEX_CONST;
559 tex_count_reg = REG_A6XX_SP_HS_TEX_COUNT;
560 break;
561 case PIPE_SHADER_TESS_EVAL:
562 sb = SB6_DS_TEX;
563 opcode = CP_LOAD_STATE6_GEOM;
564 tex_samp_reg = REG_A6XX_SP_DS_TEX_SAMP;
565 tex_const_reg = REG_A6XX_SP_DS_TEX_CONST;
566 tex_count_reg = REG_A6XX_SP_DS_TEX_COUNT;
567 break;
568 case PIPE_SHADER_GEOMETRY:
569 sb = SB6_GS_TEX;
570 opcode = CP_LOAD_STATE6_GEOM;
571 tex_samp_reg = REG_A6XX_SP_GS_TEX_SAMP;
572 tex_const_reg = REG_A6XX_SP_GS_TEX_CONST;
573 tex_count_reg = REG_A6XX_SP_GS_TEX_COUNT;
574 break;
575 case PIPE_SHADER_FRAGMENT:
576 sb = SB6_FS_TEX;
577 opcode = CP_LOAD_STATE6_FRAG;
578 tex_samp_reg = REG_A6XX_SP_FS_TEX_SAMP;
579 tex_const_reg = REG_A6XX_SP_FS_TEX_CONST;
580 tex_count_reg = REG_A6XX_SP_FS_TEX_COUNT;
581 break;
582 case PIPE_SHADER_COMPUTE:
583 sb = SB6_CS_TEX;
584 opcode = CP_LOAD_STATE6_FRAG;
585 tex_samp_reg = REG_A6XX_SP_CS_TEX_SAMP;
586 tex_const_reg = REG_A6XX_SP_CS_TEX_CONST;
587 tex_count_reg = REG_A6XX_SP_CS_TEX_COUNT;
588 break;
589 default:
590 unreachable("bad state block");
591 }
592
593 if (tex->num_samplers > 0) {
594 struct fd_ringbuffer *state =
595 fd_ringbuffer_new_object(ctx->pipe, tex->num_samplers * 4 * 4);
596 for (unsigned i = 0; i < tex->num_samplers; i++) {
597 static const struct fd6_sampler_stateobj dummy_sampler = {};
598 const struct fd6_sampler_stateobj *sampler =
599 tex->samplers[i] ? fd6_sampler_stateobj(tex->samplers[i])
600 : &dummy_sampler;
601 OUT_RING(state, sampler->texsamp0);
602 OUT_RING(state, sampler->texsamp1);
603 OUT_RING(state, sampler->texsamp2);
604 OUT_RING(state, sampler->texsamp3);
605 }
606
607 /* output sampler state: */
608 OUT_PKT7(ring, opcode, 3);
609 OUT_RING(ring, CP_LOAD_STATE6_0_DST_OFF(0) |
610 CP_LOAD_STATE6_0_STATE_TYPE(ST6_SHADER) |
611 CP_LOAD_STATE6_0_STATE_SRC(SS6_INDIRECT) |
612 CP_LOAD_STATE6_0_STATE_BLOCK(sb) |
613 CP_LOAD_STATE6_0_NUM_UNIT(tex->num_samplers));
614 OUT_RB(ring, state); /* SRC_ADDR_LO/HI */
615
616 OUT_PKT4(ring, tex_samp_reg, 2);
617 OUT_RB(ring, state); /* SRC_ADDR_LO/HI */
618
619 fd_ringbuffer_del(state);
620 }
621
622 unsigned num_textures = tex->num_textures;
623
624 if (num_textures > 0) {
625 struct fd_ringbuffer *state =
626 fd_ringbuffer_new_object(ctx->pipe, num_textures * 16 * 4);
627 for (unsigned i = 0; i < num_textures; i++) {
628 const struct fd6_pipe_sampler_view *view;
629
630 if (tex->textures[i]) {
631 view = fd6_pipe_sampler_view(tex->textures[i]);
632 struct fd_resource *rsc = fd_resource(view->base.texture);
633 fd6_assert_valid_format(rsc, view->base.format);
634 assert(view->rsc_seqno == rsc->seqno);
635 } else {
636 static const struct fd6_pipe_sampler_view dummy_view = {};
637 view = &dummy_view;
638 }
639
640 OUT_RING(state, view->descriptor[0]);
641 OUT_RING(state, view->descriptor[1]);
642 OUT_RING(state, view->descriptor[2]);
643 OUT_RING(state, view->descriptor[3]);
644
645 if (view->ptr1) {
646 OUT_RELOC(state, view->ptr1->bo, view->descriptor[4],
647 (uint64_t)view->descriptor[5] << 32, 0);
648 } else {
649 OUT_RING(state, view->descriptor[4]);
650 OUT_RING(state, view->descriptor[5]);
651 }
652
653 OUT_RING(state, view->descriptor[6]);
654
655 if (view->ptr2) {
656 OUT_RELOC(state, view->ptr2->bo, view->descriptor[7], 0, 0);
657 } else {
658 OUT_RING(state, view->descriptor[7]);
659 OUT_RING(state, view->descriptor[8]);
660 }
661
662 OUT_RING(state, view->descriptor[9]);
663 OUT_RING(state, view->descriptor[10]);
664 OUT_RING(state, view->descriptor[11]);
665 OUT_RING(state, view->descriptor[12]);
666 OUT_RING(state, view->descriptor[13]);
667 OUT_RING(state, view->descriptor[14]);
668 OUT_RING(state, view->descriptor[15]);
669 }
670
671 /* emit texture state: */
672 OUT_PKT7(ring, opcode, 3);
673 OUT_RING(ring, CP_LOAD_STATE6_0_DST_OFF(0) |
674 CP_LOAD_STATE6_0_STATE_TYPE(ST6_CONSTANTS) |
675 CP_LOAD_STATE6_0_STATE_SRC(SS6_INDIRECT) |
676 CP_LOAD_STATE6_0_STATE_BLOCK(sb) |
677 CP_LOAD_STATE6_0_NUM_UNIT(num_textures));
678 OUT_RB(ring, state); /* SRC_ADDR_LO/HI */
679
680 OUT_PKT4(ring, tex_const_reg, 2);
681 OUT_RB(ring, state); /* SRC_ADDR_LO/HI */
682
683 fd_ringbuffer_del(state);
684 }
685
686 OUT_PKT4(ring, tex_count_reg, 1);
687 OUT_RING(ring, num_textures);
688
689 return ring;
690 }
691
692 /**
693 * Handle invalidates potentially coming from other contexts. By
694 * flagging the invalidate rather than handling it immediately, we
695 * avoid needing to refcnt (with it's associated atomics) the tex
696 * state. And furthermore, this avoids cross-ctx (thread) sharing
697 * of fd_ringbuffer's, avoiding their need for atomic refcnts.
698 */
699 static void
handle_invalidates(struct fd_context * ctx)700 handle_invalidates(struct fd_context *ctx)
701 assert_dt
702 {
703 struct fd6_context *fd6_ctx = fd6_context(ctx);
704
705 fd_screen_lock(ctx->screen);
706
707 hash_table_foreach (fd6_ctx->tex_cache, entry) {
708 struct fd6_texture_state *state = (struct fd6_texture_state *)entry->data;
709
710 if (state->invalidate)
711 remove_tex_entry(fd6_ctx, entry);
712 }
713
714 fd_screen_unlock(ctx->screen);
715
716 for (unsigned type = 0; type < ARRAY_SIZE(ctx->tex); type++) {
717 struct fd_texture_stateobj *tex = &ctx->tex[type];
718
719 for (unsigned i = 0; i < tex->num_textures; i++) {
720 struct fd6_pipe_sampler_view *so =
721 fd6_pipe_sampler_view(tex->textures[i]);
722
723 if (!so)
724 continue;
725
726 fd6_sampler_view_update(ctx, so);
727 }
728 }
729
730 fd6_ctx->tex_cache_needs_invalidate = false;
731 }
732
733 struct fd6_texture_state *
fd6_texture_state(struct fd_context * ctx,enum pipe_shader_type type)734 fd6_texture_state(struct fd_context *ctx, enum pipe_shader_type type)
735 {
736 struct fd_texture_stateobj *tex = &ctx->tex[type];
737 struct fd6_context *fd6_ctx = fd6_context(ctx);
738 struct fd6_texture_state *state = NULL;
739 struct fd6_texture_key key;
740
741 if (unlikely(fd6_ctx->tex_cache_needs_invalidate))
742 handle_invalidates(ctx);
743
744 memset(&key, 0, sizeof(key));
745
746 for (unsigned i = 0; i < tex->num_textures; i++) {
747 if (!tex->textures[i])
748 continue;
749
750 struct fd6_pipe_sampler_view *view =
751 fd6_pipe_sampler_view(tex->textures[i]);
752
753 key.view_seqno[i] = view->seqno;
754 }
755
756 for (unsigned i = 0; i < tex->num_samplers; i++) {
757 if (!tex->samplers[i])
758 continue;
759
760 struct fd6_sampler_stateobj *sampler =
761 fd6_sampler_stateobj(tex->samplers[i]);
762
763 key.samp_seqno[i] = sampler->seqno;
764 }
765
766 key.type = type;
767
768 uint32_t hash = tex_key_hash(&key);
769 fd_screen_lock(ctx->screen);
770
771 struct hash_entry *entry =
772 _mesa_hash_table_search_pre_hashed(fd6_ctx->tex_cache, hash, &key);
773
774 if (entry) {
775 state = (struct fd6_texture_state *)entry->data;
776 for (unsigned i = 0; i < tex->num_textures; i++) {
777 uint16_t seqno = tex->textures[i] ?
778 fd_resource(tex->textures[i]->texture)->seqno : 0;
779
780 assert(state->view_rsc_seqno[i] == seqno);
781 }
782 goto out_unlock;
783 }
784
785 state = CALLOC_STRUCT(fd6_texture_state);
786
787 for (unsigned i = 0; i < tex->num_textures; i++) {
788 if (!tex->textures[i])
789 continue;
790
791 struct fd_resource *rsc = fd_resource(tex->textures[i]->texture);
792
793 assert(rsc->dirty & FD_DIRTY_TEX);
794
795 state->view_rsc_seqno[i] = rsc->seqno;
796 }
797
798 state->key = key;
799 state->stateobj = build_texture_state(ctx, type, tex);
800
801 /* NOTE: uses copy of key in state obj, because pointer passed by caller
802 * is probably on the stack
803 */
804 _mesa_hash_table_insert_pre_hashed(fd6_ctx->tex_cache, hash, &state->key,
805 state);
806
807 out_unlock:
808 fd_screen_unlock(ctx->screen);
809 return state;
810 }
811
812 static void
fd6_texture_state_destroy(struct fd6_texture_state * state)813 fd6_texture_state_destroy(struct fd6_texture_state *state)
814 {
815 fd_ringbuffer_del(state->stateobj);
816 free(state);
817 }
818
819 static void
fd6_rebind_resource(struct fd_context * ctx,struct fd_resource * rsc)820 fd6_rebind_resource(struct fd_context *ctx, struct fd_resource *rsc) assert_dt
821 {
822 fd_screen_assert_locked(ctx->screen);
823
824 if (!(rsc->dirty & FD_DIRTY_TEX))
825 return;
826
827 struct fd6_context *fd6_ctx = fd6_context(ctx);
828
829 hash_table_foreach (fd6_ctx->tex_cache, entry) {
830 struct fd6_texture_state *state = (struct fd6_texture_state *)entry->data;
831
832 STATIC_ASSERT(ARRAY_SIZE(state->view_rsc_seqno) == ARRAY_SIZE(state->key.view_seqno));
833
834 for (unsigned i = 0; i < ARRAY_SIZE(state->view_rsc_seqno); i++) {
835 if (rsc->seqno == state->view_rsc_seqno[i]) {
836 struct fd6_texture_state *tex =
837 (struct fd6_texture_state *)entry->data;
838 tex->invalidate = true;
839 fd6_ctx->tex_cache_needs_invalidate = true;
840 }
841 }
842 }
843 }
844
845 void
fd6_texture_init(struct pipe_context * pctx)846 fd6_texture_init(struct pipe_context *pctx) disable_thread_safety_analysis
847 {
848 struct fd_context *ctx = fd_context(pctx);
849 struct fd6_context *fd6_ctx = fd6_context(ctx);
850
851 pctx->create_sampler_state = fd6_sampler_state_create;
852 pctx->delete_sampler_state = fd6_sampler_state_delete;
853 pctx->bind_sampler_states = fd_sampler_states_bind;
854
855 pctx->create_sampler_view = fd6_sampler_view_create;
856 pctx->sampler_view_destroy = fd6_sampler_view_destroy;
857 pctx->set_sampler_views = fd6_set_sampler_views;
858
859 ctx->rebind_resource = fd6_rebind_resource;
860
861 fd6_ctx->bcolor_cache =
862 _mesa_hash_table_create(NULL, bcolor_key_hash, bcolor_key_equals);
863 fd6_ctx->bcolor_mem = fd_bo_new(ctx->screen->dev,
864 FD6_MAX_BORDER_COLORS * FD6_BORDER_COLOR_SIZE,
865 0, "bcolor");
866
867 fd_context_add_private_bo(ctx, fd6_ctx->bcolor_mem);
868
869 fd6_ctx->tex_cache = _mesa_hash_table_create(NULL, tex_key_hash, tex_key_equals);
870 util_idalloc_init(&fd6_ctx->tex_ids, 256);
871 }
872
873 void
fd6_texture_fini(struct pipe_context * pctx)874 fd6_texture_fini(struct pipe_context *pctx)
875 {
876 struct fd_context *ctx = fd_context(pctx);
877 struct fd6_context *fd6_ctx = fd6_context(ctx);
878
879 fd_screen_lock(ctx->screen);
880
881 hash_table_foreach (fd6_ctx->tex_cache, entry) {
882 remove_tex_entry(fd6_ctx, entry);
883 }
884
885 fd_screen_unlock(ctx->screen);
886
887 util_idalloc_fini(&fd6_ctx->tex_ids);
888 ralloc_free(fd6_ctx->tex_cache);
889 fd_bo_del(fd6_ctx->bcolor_mem);
890 ralloc_free(fd6_ctx->bcolor_cache);
891 }
892