xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_pipe_sampler.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
3  * The term “Broadcom” refers to Broadcom Inc.
4  * and/or its subsidiaries.
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #include "pipe/p_defines.h"
9 #include "util/u_bitmask.h"
10 #include "util/format/u_format.h"
11 #include "util/u_inlines.h"
12 #include "util/u_math.h"
13 #include "util/u_memory.h"
14 
15 #include "svga_context.h"
16 #include "svga_cmd.h"
17 #include "svga_debug.h"
18 #include "svga_resource_texture.h"
19 #include "svga_surface.h"
20 #include "svga_sampler_view.h"
21 
22 
23 static inline unsigned
translate_wrap_mode(unsigned wrap)24 translate_wrap_mode(unsigned wrap)
25 {
26    switch (wrap) {
27    case PIPE_TEX_WRAP_REPEAT:
28       return SVGA3D_TEX_ADDRESS_WRAP;
29    case PIPE_TEX_WRAP_CLAMP:
30       return SVGA3D_TEX_ADDRESS_CLAMP;
31    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
32       /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by
33        * hardware.
34        */
35       return SVGA3D_TEX_ADDRESS_CLAMP;
36    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
37       return SVGA3D_TEX_ADDRESS_BORDER;
38    case PIPE_TEX_WRAP_MIRROR_REPEAT:
39       return SVGA3D_TEX_ADDRESS_MIRROR;
40    case PIPE_TEX_WRAP_MIRROR_CLAMP:
41    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
42    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
43       return SVGA3D_TEX_ADDRESS_MIRRORONCE;
44    default:
45       assert(0);
46       return SVGA3D_TEX_ADDRESS_WRAP;
47    }
48 }
49 
50 
51 static inline unsigned
translate_img_filter(unsigned filter)52 translate_img_filter(unsigned filter)
53 {
54    switch (filter) {
55    case PIPE_TEX_FILTER_NEAREST:
56       return SVGA3D_TEX_FILTER_NEAREST;
57    case PIPE_TEX_FILTER_LINEAR:
58       return SVGA3D_TEX_FILTER_LINEAR;
59    default:
60       assert(0);
61       return SVGA3D_TEX_FILTER_NEAREST;
62    }
63 }
64 
65 
66 static inline unsigned
translate_mip_filter(unsigned filter)67 translate_mip_filter(unsigned filter)
68 {
69    switch (filter) {
70    case PIPE_TEX_MIPFILTER_NONE:
71       return SVGA3D_TEX_FILTER_NONE;
72    case PIPE_TEX_MIPFILTER_NEAREST:
73       return SVGA3D_TEX_FILTER_NEAREST;
74    case PIPE_TEX_MIPFILTER_LINEAR:
75       return SVGA3D_TEX_FILTER_LINEAR;
76    default:
77       assert(0);
78       return SVGA3D_TEX_FILTER_NONE;
79    }
80 }
81 
82 
83 static uint8
translate_comparison_func(unsigned func)84 translate_comparison_func(unsigned func)
85 {
86    switch (func) {
87    case PIPE_FUNC_NEVER:
88       return SVGA3D_COMPARISON_NEVER;
89    case PIPE_FUNC_LESS:
90       return SVGA3D_COMPARISON_LESS;
91    case PIPE_FUNC_EQUAL:
92       return SVGA3D_COMPARISON_EQUAL;
93    case PIPE_FUNC_LEQUAL:
94       return SVGA3D_COMPARISON_LESS_EQUAL;
95    case PIPE_FUNC_GREATER:
96       return SVGA3D_COMPARISON_GREATER;
97    case PIPE_FUNC_NOTEQUAL:
98       return SVGA3D_COMPARISON_NOT_EQUAL;
99    case PIPE_FUNC_GEQUAL:
100       return SVGA3D_COMPARISON_GREATER_EQUAL;
101    case PIPE_FUNC_ALWAYS:
102       return SVGA3D_COMPARISON_ALWAYS;
103    default:
104       assert(!"Invalid comparison function");
105       return SVGA3D_COMPARISON_ALWAYS;
106    }
107 }
108 
109 
110 /**
111  * Translate filtering state to vgpu10 format.
112  */
113 static SVGA3dFilter
translate_filter_mode(unsigned img_filter,unsigned min_filter,unsigned mag_filter,bool anisotropic,bool compare)114 translate_filter_mode(unsigned img_filter,
115                       unsigned min_filter,
116                       unsigned mag_filter,
117                       bool anisotropic,
118                       bool compare)
119 {
120    SVGA3dFilter mode = 0;
121 
122    if (img_filter == PIPE_TEX_FILTER_LINEAR)
123       mode |= SVGA3D_FILTER_MIP_LINEAR;
124    if (min_filter == PIPE_TEX_FILTER_LINEAR)
125       mode |= SVGA3D_FILTER_MIN_LINEAR;
126    if (mag_filter == PIPE_TEX_FILTER_LINEAR)
127       mode |= SVGA3D_FILTER_MAG_LINEAR;
128    if (anisotropic)
129       mode |= SVGA3D_FILTER_ANISOTROPIC;
130    if (compare)
131       mode |= SVGA3D_FILTER_COMPARE;
132 
133    return mode;
134 }
135 
136 
137 /**
138  * Define a vgpu10 sampler state.
139  */
140 static void
define_sampler_state_object(struct svga_context * svga,struct svga_sampler_state * ss,const struct pipe_sampler_state * ps)141 define_sampler_state_object(struct svga_context *svga,
142                             struct svga_sampler_state *ss,
143                             const struct pipe_sampler_state *ps)
144 {
145    uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */
146    bool anisotropic;
147    uint8 compare_func;
148    SVGA3dFilter filter;
149    SVGA3dRGBAFloat bcolor;
150    float min_lod, max_lod;
151 
152    assert(svga_have_vgpu10(svga));
153 
154    anisotropic = ss->aniso_level > 1.0f;
155 
156    filter = translate_filter_mode(ps->min_mip_filter,
157                                   ps->min_img_filter,
158                                   ps->mag_img_filter,
159                                   anisotropic,
160                                   ss->compare_mode);
161 
162    compare_func = translate_comparison_func(ss->compare_func);
163 
164    COPY_4V(bcolor.value, ps->border_color.f);
165 
166    assert(ps->min_lod <= ps->max_lod);
167 
168    if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
169       /* just use the base level image */
170       min_lod = max_lod = 0.0f;
171    }
172    else {
173       min_lod = ps->min_lod;
174       max_lod = ps->max_lod;
175    }
176 
177    /* If shadow comparisons are enabled, create two sampler states: one
178     * with the given shadow compare mode, another with shadow comparison off.
179     * We need the later because in some cases, we have to do the shadow
180     * compare in the shader.  So, we don't want to do it twice.
181     */
182    STATIC_ASSERT(PIPE_TEX_COMPARE_NONE == 0);
183    STATIC_ASSERT(PIPE_TEX_COMPARE_R_TO_TEXTURE == 1);
184    ss->id[1] = SVGA3D_INVALID_ID;
185 
186    unsigned i;
187    for (i = 0; i <= ss->compare_mode; i++) {
188       ss->id[i] = util_bitmask_add(svga->sampler_object_id_bm);
189 
190       SVGA_RETRY(svga, SVGA3D_vgpu10_DefineSamplerState
191                  (svga->swc,
192                   ss->id[i],
193                   filter,
194                   ss->addressu,
195                   ss->addressv,
196                   ss->addressw,
197                   ss->lod_bias, /* float */
198                   max_aniso,
199                   compare_func,
200                   bcolor,
201                   min_lod,       /* float */
202                   max_lod));      /* float */
203 
204       /* turn off the shadow compare option for second iteration */
205       filter &= ~SVGA3D_FILTER_COMPARE;
206    }
207 }
208 
209 
210 static void *
svga_create_sampler_state(struct pipe_context * pipe,const struct pipe_sampler_state * sampler)211 svga_create_sampler_state(struct pipe_context *pipe,
212                           const struct pipe_sampler_state *sampler)
213 {
214    struct svga_context *svga = svga_context(pipe);
215    struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state );
216 
217    if (!cso)
218       return NULL;
219 
220    cso->mipfilter = translate_mip_filter(sampler->min_mip_filter);
221    cso->magfilter = translate_img_filter( sampler->mag_img_filter );
222    cso->minfilter = translate_img_filter( sampler->min_img_filter );
223    cso->aniso_level = MAX2( sampler->max_anisotropy, 1 );
224    if (sampler->max_anisotropy)
225       cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC;
226    cso->lod_bias = sampler->lod_bias;
227    cso->addressu = translate_wrap_mode(sampler->wrap_s);
228    cso->addressv = translate_wrap_mode(sampler->wrap_t);
229    cso->addressw = translate_wrap_mode(sampler->wrap_r);
230    cso->normalized_coords = !sampler->unnormalized_coords;
231    cso->compare_mode = sampler->compare_mode;
232    cso->compare_func = sampler->compare_func;
233 
234    {
235       uint32 r = float_to_ubyte(sampler->border_color.f[0]);
236       uint32 g = float_to_ubyte(sampler->border_color.f[1]);
237       uint32 b = float_to_ubyte(sampler->border_color.f[2]);
238       uint32 a = float_to_ubyte(sampler->border_color.f[3]);
239 
240       cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b;
241    }
242 
243    /* No SVGA3D support for:
244     *    - min/max LOD clamping
245     */
246    cso->min_lod = 0;
247    cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0);
248    cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0);
249 
250    /* Use min_mipmap */
251    if (svga->debug.use_min_mipmap) {
252       if (cso->view_min_lod == cso->view_max_lod) {
253          cso->min_lod = cso->view_min_lod;
254          cso->view_min_lod = 0;
255          cso->view_max_lod = 1000; /* Just a high number */
256          cso->mipfilter = SVGA3D_TEX_FILTER_NONE;
257       }
258    }
259 
260    if (svga_have_vgpu10(svga)) {
261       define_sampler_state_object(svga, cso, sampler);
262    }
263 
264    SVGA_DBG(DEBUG_SAMPLERS,
265             "New sampler: min %u, view(min %u, max %u) lod, mipfilter %s\n",
266             cso->min_lod, cso->view_min_lod, cso->view_max_lod,
267             cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING");
268 
269    svga->hud.num_sampler_objects++;
270    SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
271                         SVGA_STATS_COUNT_SAMPLER);
272 
273    return cso;
274 }
275 
276 
277 static void
svga_bind_sampler_states(struct pipe_context * pipe,enum pipe_shader_type shader,unsigned start,unsigned num,void ** samplers)278 svga_bind_sampler_states(struct pipe_context *pipe,
279                          enum pipe_shader_type shader,
280                          unsigned start,
281                          unsigned num,
282                          void **samplers)
283 {
284    struct svga_context *svga = svga_context(pipe);
285    unsigned i;
286    bool any_change = false;
287 
288    assert(shader < PIPE_SHADER_TYPES);
289    assert(start + num <= PIPE_MAX_SAMPLERS);
290 
291    /* Pre-VGPU10 only supports FS textures */
292    if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
293       return;
294 
295    for (i = 0; i < num; i++) {
296       if (svga->curr.sampler[shader][start + i] != samplers[i])
297          any_change = true;
298       svga->curr.sampler[shader][start + i] = samplers[i];
299    }
300 
301    if (!any_change) {
302       return;
303    }
304 
305    /* find highest non-null sampler[] entry */
306    {
307       unsigned j = MAX2(svga->curr.num_samplers[shader], start + num);
308       while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL)
309          j--;
310       svga->curr.num_samplers[shader] = j;
311    }
312 
313    svga->dirty |= SVGA_NEW_SAMPLER;
314 }
315 
316 
317 static void
svga_delete_sampler_state(struct pipe_context * pipe,void * sampler)318 svga_delete_sampler_state(struct pipe_context *pipe, void *sampler)
319 {
320    struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler;
321    struct svga_context *svga = svga_context(pipe);
322 
323    if (svga_have_vgpu10(svga)) {
324       unsigned i;
325       for (i = 0; i < ARRAY_SIZE(ss->id); i++) {
326          if (ss->id[i] != SVGA3D_INVALID_ID) {
327             svga_hwtnl_flush_retry(svga);
328 
329             SVGA_RETRY(svga, SVGA3D_vgpu10_DestroySamplerState(svga->swc,
330                                                                ss->id[i]));
331             util_bitmask_clear(svga->sampler_object_id_bm, ss->id[i]);
332          }
333       }
334    }
335 
336    FREE(sampler);
337    svga->hud.num_sampler_objects--;
338 }
339 
340 
341 static struct pipe_sampler_view *
svga_create_sampler_view(struct pipe_context * pipe,struct pipe_resource * texture,const struct pipe_sampler_view * templ)342 svga_create_sampler_view(struct pipe_context *pipe,
343                          struct pipe_resource *texture,
344                          const struct pipe_sampler_view *templ)
345 {
346    struct svga_context *svga = svga_context(pipe);
347    struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view);
348 
349    if (!sv) {
350       return NULL;
351    }
352 
353    sv->base = *templ;
354    sv->base.reference.count = 1;
355    sv->base.texture = NULL;
356    pipe_resource_reference(&sv->base.texture, texture);
357 
358    sv->base.context = pipe;
359    sv->id = SVGA3D_INVALID_ID;
360 
361    svga->hud.num_samplerview_objects++;
362    SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
363                         SVGA_STATS_COUNT_SAMPLERVIEW);
364 
365    return &sv->base;
366 }
367 
368 
369 static void
svga_sampler_view_destroy(struct pipe_context * pipe,struct pipe_sampler_view * view)370 svga_sampler_view_destroy(struct pipe_context *pipe,
371                           struct pipe_sampler_view *view)
372 {
373    struct svga_context *svga = svga_context(pipe);
374    struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view);
375 
376    if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) {
377       assert(view->context == pipe);
378 
379       svga_hwtnl_flush_retry(svga);
380 
381       SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc,
382                                                                sv->id));
383       util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
384    }
385 
386    pipe_resource_reference(&sv->base.texture, NULL);
387 
388    FREE(sv);
389    svga->hud.num_samplerview_objects--;
390 }
391 
392 
393 static void
svga_set_sampler_views(struct pipe_context * pipe,enum pipe_shader_type shader,unsigned start,unsigned num,unsigned unbind_num_trailing_slots,bool take_ownership,struct pipe_sampler_view ** views)394 svga_set_sampler_views(struct pipe_context *pipe,
395                        enum pipe_shader_type shader,
396                        unsigned start,
397                        unsigned num,
398                        unsigned unbind_num_trailing_slots,
399                        bool take_ownership,
400                        struct pipe_sampler_view **views)
401 {
402    struct svga_context *svga = svga_context(pipe);
403    unsigned flag_1d = 0;
404    unsigned flag_srgb = 0;
405    uint i;
406    bool any_change = false;
407 
408    assert(shader < PIPE_SHADER_TYPES);
409    assert(start + num <= ARRAY_SIZE(svga->curr.sampler_views[shader]));
410 
411    /* Pre-VGPU10 only supports FS textures */
412    if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) {
413       for (unsigned i = 0; i < num; i++) {
414          struct pipe_sampler_view *view = views[i];
415          pipe_sampler_view_reference(&view, NULL);
416       }
417       return;
418    }
419 
420    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_SETSAMPLERVIEWS);
421 
422    /* This bit of code works around a quirk in the CSO module.
423     * If start=num=0 it means all sampler views should be released.
424     * Note that the CSO module treats sampler views for fragment shaders
425     * differently than other shader types.
426     */
427    if (start == 0 && num == 0 && svga->curr.num_sampler_views[shader] > 0) {
428       for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
429          pipe_sampler_view_reference(&svga->curr.sampler_views[shader][i],
430                                      NULL);
431       }
432       any_change = true;
433    }
434 
435    for (i = 0; i < num; i++) {
436       enum pipe_texture_target target;
437 
438       any_change |= svga->curr.sampler_views[shader][start + i] != views[i];
439 
440       if (take_ownership) {
441          pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
442                NULL);
443          svga->curr.sampler_views[shader][start + i] = views[i];
444       } else if (svga->curr.sampler_views[shader][start + i] != views[i]) {
445          pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
446                                      views[i]);
447       }
448 
449       if (!views[i])
450          continue;
451 
452       if (util_format_is_srgb(views[i]->format))
453          flag_srgb |= 1 << (start + i);
454 
455       target = views[i]->target;
456       if (target == PIPE_TEXTURE_1D) {
457          flag_1d |= 1 << (start + i);
458       } else if (target == PIPE_TEXTURE_RECT) {
459          /* If the size of the bound texture changes, we need to emit new
460           * const buffer values.
461           */
462          svga->dirty |= SVGA_NEW_TEXTURE_CONSTS;
463       } else if (target == PIPE_BUFFER) {
464          /* If the size of the bound buffer changes, we need to emit new
465           * const buffer values.
466           */
467          svga->dirty |= SVGA_NEW_TEXTURE_CONSTS;
468       }
469    }
470 
471    for (; i < num + unbind_num_trailing_slots; i++) {
472       if (svga->curr.sampler_views[shader][start + i]) {
473          pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
474                                      NULL);
475          any_change = true;
476       }
477    }
478 
479    if (!any_change) {
480       goto done;
481    }
482 
483    /* find highest non-null sampler_views[] entry */
484    {
485       unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num);
486       while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL)
487          j--;
488       svga->curr.num_sampler_views[shader] = j;
489    }
490 
491    svga->dirty |= SVGA_NEW_TEXTURE_BINDING;
492 
493    if (flag_srgb != svga->curr.tex_flags.flag_srgb ||
494        flag_1d != svga->curr.tex_flags.flag_1d) {
495       svga->dirty |= SVGA_NEW_TEXTURE_FLAGS;
496       svga->curr.tex_flags.flag_1d = flag_1d;
497       svga->curr.tex_flags.flag_srgb = flag_srgb;
498    }
499 
500    /* Check if any of the sampler view resources collide with the framebuffer
501     * color buffers or depth stencil resource. If so, set the NEW_FRAME_BUFFER
502     * dirty bit so that emit_framebuffer can be invoked to create backed view
503     * for the conflicted surface view.
504     */
505    if (svga_check_sampler_framebuffer_resource_collision(svga, shader)) {
506       svga->dirty |= SVGA_NEW_FRAME_BUFFER;
507    }
508 
509 done:
510    SVGA_STATS_TIME_POP(svga_sws(svga));
511 }
512 
513 /**
514  * Clean up sampler, sampler view state at context destruction time
515  */
516 void
svga_cleanup_sampler_state(struct svga_context * svga)517 svga_cleanup_sampler_state(struct svga_context *svga)
518 {
519    enum pipe_shader_type shader;
520 
521    for (shader = 0; shader <= PIPE_SHADER_COMPUTE; shader++) {
522       unsigned i;
523 
524       for (i = 0; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
525          pipe_sampler_view_reference(&svga->state.hw_draw.sampler_views[shader][i],
526                                      NULL);
527       }
528    }
529 
530    /* free polygon stipple state */
531    if (svga->polygon_stipple.sampler) {
532       svga->pipe.delete_sampler_state(&svga->pipe, svga->polygon_stipple.sampler);
533    }
534 
535    if (svga->polygon_stipple.sampler_view) {
536       svga->pipe.sampler_view_destroy(&svga->pipe,
537                                       &svga->polygon_stipple.sampler_view->base);
538    }
539    pipe_resource_reference(&svga->polygon_stipple.texture, NULL);
540 }
541 
542 void
svga_init_sampler_functions(struct svga_context * svga)543 svga_init_sampler_functions( struct svga_context *svga )
544 {
545    svga->pipe.create_sampler_state = svga_create_sampler_state;
546    svga->pipe.bind_sampler_states = svga_bind_sampler_states;
547    svga->pipe.delete_sampler_state = svga_delete_sampler_state;
548    svga->pipe.set_sampler_views = svga_set_sampler_views;
549    svga->pipe.create_sampler_view = svga_create_sampler_view;
550    svga->pipe.sampler_view_destroy = svga_sampler_view_destroy;
551 }
552