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