xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_state_sampler.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2013-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 
9 /**
10  * VGPU10 sampler and sampler view functions.
11  */
12 
13 
14 #include "pipe/p_defines.h"
15 #include "util/u_bitmask.h"
16 #include "util/format/u_format.h"
17 #include "util/u_inlines.h"
18 #include "util/u_math.h"
19 #include "util/u_memory.h"
20 
21 #include "svga_cmd.h"
22 #include "svga_context.h"
23 #include "svga_format.h"
24 #include "svga_resource_buffer.h"
25 #include "svga_resource_texture.h"
26 #include "svga_sampler_view.h"
27 #include "svga_shader.h"
28 #include "svga_state.h"
29 #include "svga_surface.h"
30 #include "svga3d_surfacedefs.h"
31 
32 /** Get resource handle for a texture or buffer */
33 static inline struct svga_winsys_surface *
svga_resource_handle(struct pipe_resource * res)34 svga_resource_handle(struct pipe_resource *res)
35 {
36    if (res->target == PIPE_BUFFER) {
37       return svga_buffer(res)->handle;
38    }
39    else {
40       return svga_texture(res)->handle;
41    }
42 }
43 
44 
45 /**
46  * This helper function returns TRUE if the specified resource collides with
47  * any of the resources bound to any of the currently bound sampler views.
48  */
49 bool
svga_check_sampler_view_resource_collision(const struct svga_context * svga,const struct svga_winsys_surface * res,enum pipe_shader_type shader)50 svga_check_sampler_view_resource_collision(const struct svga_context *svga,
51                                            const struct svga_winsys_surface *res,
52                                            enum pipe_shader_type shader)
53 {
54    struct pipe_screen *screen = svga->pipe.screen;
55    unsigned i;
56 
57    if (svga_screen(screen)->debug.no_surface_view) {
58       return false;
59    }
60 
61    if (!svga_curr_shader_use_samplers(svga, shader))
62       return false;
63 
64    for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
65       struct svga_pipe_sampler_view *sv =
66          svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
67 
68       if (sv && res == svga_resource_handle(sv->base.texture)) {
69          return true;
70       }
71    }
72 
73    return false;
74 }
75 
76 
77 /**
78  * Check if there are any resources that are both bound to a render target
79  * and bound as a shader resource for the given type of shader.
80  */
81 bool
svga_check_sampler_framebuffer_resource_collision(struct svga_context * svga,enum pipe_shader_type shader)82 svga_check_sampler_framebuffer_resource_collision(struct svga_context *svga,
83                                                   enum pipe_shader_type shader)
84 {
85    struct svga_surface *surf;
86    unsigned i;
87 
88    for (i = 0; i < svga->curr.framebuffer.nr_cbufs; i++) {
89       surf = svga_surface(svga->curr.framebuffer.cbufs[i]);
90       if (surf &&
91           svga_check_sampler_view_resource_collision(svga, surf->handle,
92                                                      shader)) {
93          return true;
94       }
95    }
96 
97    surf = svga_surface(svga->curr.framebuffer.zsbuf);
98    if (surf &&
99        svga_check_sampler_view_resource_collision(svga, surf->handle, shader)) {
100       return true;
101    }
102 
103    return false;
104 }
105 
106 
107 /**
108  * Create a DX ShaderResourceSamplerView for the given pipe_sampler_view,
109  * if needed.
110  */
111 enum pipe_error
svga_validate_pipe_sampler_view(struct svga_context * svga,struct svga_pipe_sampler_view * sv)112 svga_validate_pipe_sampler_view(struct svga_context *svga,
113                                 struct svga_pipe_sampler_view *sv)
114 {
115    enum pipe_error ret = PIPE_OK;
116 
117    if (sv->id == SVGA3D_INVALID_ID) {
118       struct svga_screen *ss = svga_screen(svga->pipe.screen);
119       struct pipe_resource *texture = sv->base.texture;
120       struct svga_winsys_surface *surface;
121       SVGA3dSurfaceFormat format;
122       SVGA3dResourceType resourceDim;
123       SVGA3dShaderResourceViewDesc viewDesc;
124       enum pipe_format viewFormat = sv->base.format;
125       enum pipe_texture_target target = sv->base.target;
126 
127       /* vgpu10 cannot create a BGRX view for a BGRA resource, so force it to
128        * create a BGRA view (and vice versa).
129        */
130       if (viewFormat == PIPE_FORMAT_B8G8R8X8_UNORM &&
131           svga_texture_device_format_has_alpha(texture)) {
132          viewFormat = PIPE_FORMAT_B8G8R8A8_UNORM;
133       }
134       else if (viewFormat == PIPE_FORMAT_B8G8R8A8_UNORM &&
135                !svga_texture_device_format_has_alpha(texture)) {
136          viewFormat = PIPE_FORMAT_B8G8R8X8_UNORM;
137       }
138 
139       if (target == PIPE_BUFFER) {
140          unsigned pf_flags;
141          assert(texture->target == PIPE_BUFFER);
142          svga_translate_texture_buffer_view_format(viewFormat,
143                                                    &format,
144                                                    &pf_flags);
145          surface = svga_buffer_handle(svga, texture, PIPE_BIND_SAMPLER_VIEW);
146       }
147       else {
148          format = svga_translate_format(ss, viewFormat,
149                                         PIPE_BIND_SAMPLER_VIEW);
150 
151          /* Convert the format to a sampler-friendly format, if needed */
152          format = svga_sampler_format(format);
153 
154          surface = svga_texture(texture)->handle;
155       }
156 
157       assert(format != SVGA3D_FORMAT_INVALID);
158 
159       if (target == PIPE_BUFFER) {
160          unsigned elem_size = util_format_get_blocksize(sv->base.format);
161 
162          viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size;
163          viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size;
164       }
165       else {
166          viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level;
167          viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer;
168          viewDesc.tex.mipLevels = (sv->base.u.tex.last_level -
169                                    sv->base.u.tex.first_level + 1);
170       }
171 
172       /* arraySize in viewDesc specifies the number of array slices in a
173        * texture array. For 3D texture, last_layer in
174        * pipe_sampler_view specifies the last slice of the texture
175        * which is different from the last slice in a texture array,
176        * hence we need to set arraySize to 1 explicitly.
177        */
178       viewDesc.tex.arraySize =
179          (target == PIPE_TEXTURE_3D || target == PIPE_BUFFER) ? 1 :
180             (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1);
181 
182       switch (target) {
183       case PIPE_BUFFER:
184          resourceDim = SVGA3D_RESOURCE_BUFFER;
185          break;
186       case PIPE_TEXTURE_1D:
187       case PIPE_TEXTURE_1D_ARRAY:
188          resourceDim = SVGA3D_RESOURCE_TEXTURE1D;
189          break;
190       case PIPE_TEXTURE_RECT:
191       case PIPE_TEXTURE_2D:
192       case PIPE_TEXTURE_2D_ARRAY:
193          resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
194          break;
195       case PIPE_TEXTURE_3D:
196          resourceDim = SVGA3D_RESOURCE_TEXTURE3D;
197          break;
198       case PIPE_TEXTURE_CUBE:
199       case PIPE_TEXTURE_CUBE_ARRAY:
200          resourceDim = SVGA3D_RESOURCE_TEXTURECUBE;
201          break;
202 
203       default:
204          assert(!"Unexpected texture type");
205          resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
206       }
207 
208       sv->id = util_bitmask_add(svga->sampler_view_id_bm);
209 
210       ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc,
211                                                    sv->id,
212                                                    surface,
213                                                    format,
214                                                    resourceDim,
215                                                    &viewDesc);
216       if (ret != PIPE_OK) {
217          util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
218          sv->id = SVGA3D_INVALID_ID;
219       }
220    }
221 
222    return ret;
223 }
224 
225 
226 static enum pipe_error
update_sampler_resources(struct svga_context * svga,uint64_t dirty)227 update_sampler_resources(struct svga_context *svga, uint64_t dirty)
228 {
229    enum pipe_error ret = PIPE_OK;
230    enum pipe_shader_type shader;
231 
232    assert(svga_have_vgpu10(svga));
233 
234    for (shader = PIPE_SHADER_VERTEX; shader < PIPE_SHADER_COMPUTE; shader++) {
235       SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS];
236       struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];
237       struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
238       unsigned count;
239       unsigned nviews;
240       unsigned i;
241 
242       count = svga->curr.num_sampler_views[shader];
243       for (i = 0; i < count; i++) {
244          struct svga_pipe_sampler_view *sv =
245             svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
246 
247          if (sv) {
248             surfaces[i] = svga_resource_handle(sv->base.texture);
249 
250             ret = svga_validate_pipe_sampler_view(svga, sv);
251             if (ret != PIPE_OK)
252                return ret;
253 
254             assert(sv->id != SVGA3D_INVALID_ID);
255             ids[i] = sv->id;
256             sampler_views[i] = &sv->base;
257          }
258          else {
259             surfaces[i] = NULL;
260             ids[i] = SVGA3D_INVALID_ID;
261             sampler_views[i] = NULL;
262          }
263       }
264 
265       for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
266          ids[i] = SVGA3D_INVALID_ID;
267          surfaces[i] = NULL;
268          sampler_views[i] = NULL;
269       }
270 
271       /* Number of ShaderResources that need to be modified. This includes
272        * the one that need to be unbound.
273        */
274       nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count);
275       if (nviews > 0) {
276          if (count != svga->state.hw_draw.num_sampler_views[shader] ||
277              memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader],
278                     count * sizeof(sampler_views[0])) != 0) {
279             SVGA3dShaderResourceViewId *pIds = ids;
280             struct svga_winsys_surface **pSurf = surfaces;
281             unsigned numSR = 0;
282 
283             /* Loop through the sampler view list to only emit
284              * the sampler views that are not already in the
285              * corresponding entries in the device's
286              * shader resource list.
287              */
288             for (i = 0; i < nviews; i++) {
289                 bool emit;
290 
291                 emit = sampler_views[i] ==
292                        svga->state.hw_draw.sampler_views[shader][i];
293 
294                 if (!emit && i == nviews-1) {
295                    /* Include the last sampler view in the next emit
296                     * if it is different.
297                     */
298                    emit = true;
299                    numSR++;
300                    i++;
301                 }
302 
303                 if (emit) {
304                    /* numSR can only be 0 if the first entry of the list
305                     * is the same as the one in the device list.
306                     * In this case, * there is nothing to send yet.
307                     */
308                    if (numSR) {
309                       ret = SVGA3D_vgpu10_SetShaderResources(
310                                svga->swc,
311                                svga_shader_type(shader),
312                                i - numSR, /* startView */
313                                numSR,
314                                pIds,
315                                pSurf);
316 
317                       if (ret != PIPE_OK)
318                          return ret;
319                    }
320                    pIds += (numSR + 1);
321                    pSurf += (numSR + 1);
322                    numSR = 0;
323                 }
324                 else
325                    numSR++;
326             }
327 
328             /* Save referenced sampler views in the hw draw state.  */
329             svga->state.hw_draw.num_sampler_views[shader] = count;
330             for (i = 0; i < nviews; i++) {
331                pipe_sampler_view_reference(
332                   &svga->state.hw_draw.sampler_views[shader][i],
333                   sampler_views[i]);
334             }
335          }
336       }
337    }
338 
339    /* Handle polygon stipple sampler view */
340    if (svga->curr.rast->templ.poly_stipple_enable) {
341       const unsigned unit =
342          svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit;
343       struct svga_pipe_sampler_view *sv = svga->polygon_stipple.sampler_view;
344       struct svga_winsys_surface *surface;
345 
346       assert(sv);
347       if (!sv) {
348          return PIPE_OK;  /* probably out of memory */
349       }
350 
351       ret = svga_validate_pipe_sampler_view(svga, sv);
352       if (ret != PIPE_OK)
353          return ret;
354 
355       surface = svga_resource_handle(sv->base.texture);
356       ret = SVGA3D_vgpu10_SetShaderResources(
357                svga->swc,
358                svga_shader_type(PIPE_SHADER_FRAGMENT),
359                unit, /* startView */
360                1,
361                &sv->id,
362                &surface);
363    }
364    return ret;
365 }
366 
367 
368 struct svga_tracked_state svga_hw_sampler_bindings = {
369    "shader resources emit",
370    SVGA_NEW_STIPPLE |
371    SVGA_NEW_TEXTURE_BINDING,
372    update_sampler_resources
373 };
374 
375 
376 
377 static enum pipe_error
update_samplers(struct svga_context * svga,uint64_t dirty)378 update_samplers(struct svga_context *svga, uint64_t dirty )
379 {
380    enum pipe_error ret = PIPE_OK;
381    enum pipe_shader_type shader;
382 
383    assert(svga_have_vgpu10(svga));
384 
385    for (shader = PIPE_SHADER_VERTEX; shader < PIPE_SHADER_COMPUTE; shader++) {
386       const unsigned count = svga->curr.num_samplers[shader];
387       SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS*2];
388       unsigned i;
389       unsigned nsamplers = 0;
390       bool sampler_state_mapping =
391          svga_use_sampler_state_mapping(svga, count);
392 
393       for (i = 0; i < count; i++) {
394          bool fs_shadow = false;
395          const struct svga_sampler_state *sampler = svga->curr.sampler[shader][i];
396 
397          /* _NEW_FS */
398          if (shader == PIPE_SHADER_FRAGMENT) {
399             struct svga_fs_variant *fs =
400                svga_fs_variant(svga->state.hw_draw.fs);
401 
402             if (fs && (fs->fs_shadow_compare_units & (1 << i))) {
403 
404                /* Use the alternate sampler state with the compare
405                 * bit disabled when comparison is done in the shader and
406                 * sampler state mapping is not enabled.
407                 */
408                fs_shadow = true;
409             }
410          }
411 
412          if (!sampler_state_mapping) {
413             if (sampler) {
414                SVGA3dSamplerId id = sampler->id[fs_shadow];
415                assert(id != SVGA3D_INVALID_ID);
416                ids[i] = id;
417             }
418             else {
419                ids[i] = SVGA3D_INVALID_ID;
420             }
421             nsamplers++;
422          }
423          else {
424             if (sampler) {
425                SVGA3dSamplerId id = sampler->id[0];
426                assert(id != SVGA3D_INVALID_ID);
427 
428                /* Check if the sampler id is already on the ids list */
429                unsigned k;
430                for (k = 0; k < nsamplers; k++) {
431                    if (ids[k] == id)
432                       break;
433                }
434 
435                /* add the id to the list if it is not already on the list */
436                if (k == nsamplers) {
437                   ids[nsamplers++] = id;
438 
439                   if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
440                      /*
441                       * add the alternate sampler state as well as the shader
442                       * might use this alternate sampler state which has comparison
443                       * disabled when the comparison is done in the shader.
444                       */
445                      ids[nsamplers++] = sampler->id[1];
446                   }
447                }
448             }
449          }
450       }
451 
452       for (i = nsamplers; i < svga->state.hw_draw.num_samplers[shader]; i++) {
453          ids[i] = SVGA3D_INVALID_ID;
454       }
455 
456       unsigned nsamplerIds =
457          MAX2(nsamplers, svga->state.hw_draw.num_samplers[shader]);
458 
459       if (nsamplerIds > 0) {
460 
461          if (nsamplers > SVGA3D_DX_MAX_SAMPLERS) {
462             debug_warn_once("Too many sampler states");
463             nsamplers = SVGA3D_DX_MAX_SAMPLERS;
464          }
465 
466          if (nsamplers != svga->state.hw_draw.num_samplers[shader] ||
467              memcmp(ids, svga->state.hw_draw.samplers[shader],
468                     nsamplerIds * sizeof(ids[0])) != 0) {
469 
470             /* HW state is really changing */
471             ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
472                                             nsamplerIds,
473                                             0,                       /* start */
474                                             svga_shader_type(shader), /* type */
475                                             ids);
476             if (ret != PIPE_OK)
477                return ret;
478             memcpy(svga->state.hw_draw.samplers[shader], ids,
479                    nsamplerIds * sizeof(ids[0]));
480             svga->state.hw_draw.num_samplers[shader] = nsamplers;
481          }
482       }
483    }
484 
485    /* Handle polygon stipple sampler texture */
486    if (svga->curr.rast->templ.poly_stipple_enable) {
487       const unsigned unit =
488          svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_state_index;
489       struct svga_sampler_state *sampler = svga->polygon_stipple.sampler;
490 
491       assert(sampler);
492       if (!sampler) {
493          return PIPE_OK; /* probably out of memory */
494       }
495 
496       if (svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit]
497           != sampler->id[0]) {
498          ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
499                                          1, /* count */
500                                          unit, /* start */
501                                          SVGA3D_SHADERTYPE_PS,
502                                          &sampler->id[0]);
503          if (ret != PIPE_OK)
504             return ret;
505 
506          /* save the polygon stipple sampler in the hw draw state */
507          svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] =
508             sampler->id[0];
509       }
510       svga->state.hw_draw.num_samplers[PIPE_SHADER_FRAGMENT]++;
511    }
512 
513    return ret;
514 }
515 
516 
517 struct svga_tracked_state svga_hw_sampler = {
518    "texture sampler emit",
519    (SVGA_NEW_FS |
520     SVGA_NEW_SAMPLER |
521     SVGA_NEW_STIPPLE),
522    update_samplers
523 };
524 
525 
526 static enum pipe_error
update_cs_sampler_resources(struct svga_context * svga,uint64_t dirty)527 update_cs_sampler_resources(struct svga_context *svga, uint64_t dirty)
528 {
529    enum pipe_error ret = PIPE_OK;
530    enum pipe_shader_type shader = PIPE_SHADER_COMPUTE;
531 
532    assert(svga_have_sm5(svga));
533 
534    SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS];
535    struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];
536    struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
537    unsigned count;
538    unsigned nviews;
539    unsigned i;
540    struct svga_compute_shader *cs = svga->curr.cs;
541 
542    count = svga->curr.num_sampler_views[shader];
543    if (!cs || !cs->base.info.uses_samplers)
544       count = 0;
545 
546    for (i = 0; i < count; i++) {
547       struct svga_pipe_sampler_view *sv =
548          svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
549 
550       if (sv) {
551          surfaces[i] = svga_resource_handle(sv->base.texture);
552 
553          ret = svga_validate_pipe_sampler_view(svga, sv);
554          if (ret != PIPE_OK)
555             return ret;
556 
557          assert(sv->id != SVGA3D_INVALID_ID);
558          ids[i] = sv->id;
559          sampler_views[i] = &sv->base;
560       }
561       else {
562          surfaces[i] = NULL;
563          ids[i] = SVGA3D_INVALID_ID;
564          sampler_views[i] = NULL;
565       }
566    }
567 
568    for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
569       ids[i] = SVGA3D_INVALID_ID;
570       surfaces[i] = NULL;
571       sampler_views[i] = NULL;
572    }
573 
574    /* Number of ShaderResources that need to be modified. This includes
575     * the one that need to be unbound.
576     */
577    nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count);
578    if (nviews > 0) {
579       if (count != svga->state.hw_draw.num_sampler_views[shader] ||
580           memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader],
581                  count * sizeof(sampler_views[0])) != 0) {
582          SVGA3dShaderResourceViewId *pIds = ids;
583          struct svga_winsys_surface **pSurf = surfaces;
584          unsigned numSR = 0;
585 
586          /* Loop through the sampler view list to only emit the sampler views
587           * that are not already in the corresponding entries in the device's
588           * shader resource list.
589           */
590          for (i = 0; i < nviews; i++) {
591             bool emit;
592 
593             emit = sampler_views[i] ==
594                    svga->state.hw_draw.sampler_views[shader][i];
595 
596             if (!emit && i == nviews - 1) {
597                /* Include the last sampler view in the next emit
598                 * if it is different.
599                 */
600                emit = true;
601                numSR++;
602                i++;
603             }
604 
605             if (emit) {
606                /* numSR can only be 0 if the first entry of the list
607                 * is the same as the one in the device list.
608                 * In this case, * there is nothing to send yet.
609                 */
610                if (numSR) {
611                   ret = SVGA3D_vgpu10_SetShaderResources(svga->swc,
612                            svga_shader_type(shader),
613                            i - numSR, /* startView */
614                            numSR,
615                            pIds,
616                            pSurf);
617 
618                   if (ret != PIPE_OK)
619                      return ret;
620                }
621                pIds += (numSR + 1);
622                pSurf += (numSR + 1);
623                numSR = 0;
624             }
625             else
626                numSR++;
627          }
628 
629          /* Save referenced sampler views in the hw draw state.  */
630          svga->state.hw_draw.num_sampler_views[shader] = count;
631          for (i = 0; i < nviews; i++) {
632             pipe_sampler_view_reference(
633                &svga->state.hw_draw.sampler_views[shader][i],
634                sampler_views[i]);
635          }
636       }
637    }
638    return ret;
639 }
640 
641 
642 struct svga_tracked_state svga_hw_cs_sampler_bindings = {
643    "cs shader resources emit",
644    SVGA_NEW_TEXTURE_BINDING,
645    update_cs_sampler_resources
646 };
647 
648 static enum pipe_error
update_cs_samplers(struct svga_context * svga,uint64_t dirty)649 update_cs_samplers(struct svga_context *svga, uint64_t dirty )
650 {
651    enum pipe_error ret = PIPE_OK;
652    enum pipe_shader_type shader = PIPE_SHADER_COMPUTE;
653 
654    assert(svga_have_sm5(svga));
655 
656    const unsigned count = svga->curr.num_samplers[shader];
657    SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS];
658    unsigned i;
659    unsigned nsamplers;
660 
661    for (i = 0; i < count; i++) {
662       if (svga->curr.sampler[shader][i]) {
663          ids[i] = svga->curr.sampler[shader][i]->id[0];
664          assert(ids[i] != SVGA3D_INVALID_ID);
665       }
666       else {
667          ids[i] = SVGA3D_INVALID_ID;
668       }
669    }
670 
671    for (; i < svga->state.hw_draw.num_samplers[shader]; i++) {
672       ids[i] = SVGA3D_INVALID_ID;
673    }
674 
675    nsamplers = MAX2(svga->state.hw_draw.num_samplers[shader], count);
676    if (nsamplers > 0) {
677       if (count != svga->state.hw_draw.num_samplers[shader] ||
678           memcmp(ids, svga->state.hw_draw.samplers[shader],
679                  count * sizeof(ids[0])) != 0) {
680          /* HW state is really changing */
681          ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
682                                          nsamplers,
683                                          0,                        /* start */
684                                          svga_shader_type(shader), /* type */
685                                          ids);
686          if (ret != PIPE_OK)
687             return ret;
688 
689          memcpy(svga->state.hw_draw.samplers[shader], ids,
690                 nsamplers * sizeof(ids[0]));
691          svga->state.hw_draw.num_samplers[shader] = count;
692       }
693    }
694 
695    return ret;
696 }
697 
698 
699 struct svga_tracked_state svga_hw_cs_sampler = {
700    "texture cs sampler emit",
701    (SVGA_NEW_CS |
702     SVGA_NEW_SAMPLER),
703    update_cs_samplers
704 };
705