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