• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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