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