1 /*
2 * Copyright (c) 2022-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_buffer.h"
19 #include "svga_resource_texture.h"
20 #include "svga_surface.h"
21 #include "svga_sampler_view.h"
22 #include "svga_format.h"
23
24
25 /**
26 * Initialize uav cache.
27 */
28 void
svga_uav_cache_init(struct svga_context * svga)29 svga_uav_cache_init(struct svga_context *svga)
30 {
31 struct svga_cache_uav *cache = &svga->cache_uav;
32
33 for (unsigned i = 0; i < ARRAY_SIZE(cache->uaViews); i++) {
34 cache->uaViews[i].uaViewId = SVGA3D_INVALID_ID;
35 cache->uaViews[i].next_uaView = i + 1;
36 }
37 cache->num_uaViews = 0;
38 cache->next_uaView = 0;
39 }
40
41
42 /**
43 * Helper function to compare two image view descriptions.
44 * Return TRUE if they are identical.
45 */
46 static bool
image_view_desc_identical(struct pipe_image_view * img1,struct pipe_image_view * img2)47 image_view_desc_identical(struct pipe_image_view *img1,
48 struct pipe_image_view *img2)
49 {
50 if ((img1->resource != img2->resource) ||
51 (img1->format != img2->format) ||
52 (img1->access != img2->access) ||
53 (img1->shader_access != img2->shader_access))
54 return false;
55
56 if (img1->resource->target == PIPE_BUFFER) {
57 if ((img1->u.buf.offset != img2->u.buf.offset) ||
58 (img1->u.buf.size != img2->u.buf.size))
59 return false;
60 }
61
62 return true;
63 }
64
65
66 /**
67 * Helper function to compare two shader buffer descriptions.
68 * Return TRUE if they are identical.
69 */
70 static bool
shader_buffer_desc_identical(struct pipe_shader_buffer * buf1,struct pipe_shader_buffer * buf2)71 shader_buffer_desc_identical(struct pipe_shader_buffer *buf1,
72 struct pipe_shader_buffer *buf2)
73 {
74 return memcmp(buf1, buf2, sizeof(*buf1)) == 0;
75 }
76
77
78 /**
79 * Helper function to compare two uav cache entry descriptions.
80 * Return TRUE if they are identical.
81 */
82 static bool
uav_desc_identical(enum svga_uav_type uav_type,void * desc,void * uav_desc)83 uav_desc_identical(enum svga_uav_type uav_type,
84 void *desc, void *uav_desc)
85 {
86 if (uav_type == SVGA_IMAGE_VIEW) {
87 struct svga_image_view *img = (struct svga_image_view *)desc;
88 struct svga_image_view *uav_img = (struct svga_image_view *)uav_desc;
89 if (img->resource != uav_img->resource)
90 return false;
91
92 return image_view_desc_identical(&img->desc, &uav_img->desc);
93 }
94 else {
95 struct svga_shader_buffer *buf = (struct svga_shader_buffer *)desc;
96 struct svga_shader_buffer *uav_buf =
97 (struct svga_shader_buffer *)uav_desc;
98
99 if (buf->resource != uav_buf->resource)
100 return false;
101
102 if (buf->handle != uav_buf->handle)
103 return false;
104
105 return shader_buffer_desc_identical(&buf->desc, &uav_buf->desc);
106 }
107 }
108
109
110 /**
111 * Find a uav object for the specified image view or shader buffer.
112 * Returns uav entry if there is a match; otherwise returns NULL.
113 */
114 static struct svga_uav *
svga_uav_cache_find_uav(struct svga_context * svga,enum svga_uav_type uav_type,void * desc,unsigned desc_len)115 svga_uav_cache_find_uav(struct svga_context *svga,
116 enum svga_uav_type uav_type,
117 void *desc,
118 unsigned desc_len)
119 {
120 struct svga_cache_uav *cache = &svga->cache_uav;
121
122 for (unsigned i = 0; i < cache->num_uaViews; i++) {
123 if ((cache->uaViews[i].type == uav_type) &&
124 (cache->uaViews[i].uaViewId != SVGA3D_INVALID_ID) &&
125 uav_desc_identical(uav_type, desc, &cache->uaViews[i].desc)) {
126 return &cache->uaViews[i];
127 }
128 }
129 return NULL;
130 }
131
132
133 /**
134 * Add a uav entry to the cache for the specified image view or
135 * shaderr bufferr.
136 */
137 static struct svga_uav *
svga_uav_cache_add_uav(struct svga_context * svga,enum svga_uav_type uav_type,void * desc,unsigned desc_len,struct pipe_resource * res,SVGA3dUAViewId uaViewId)138 svga_uav_cache_add_uav(struct svga_context *svga,
139 enum svga_uav_type uav_type,
140 void *desc,
141 unsigned desc_len,
142 struct pipe_resource *res,
143 SVGA3dUAViewId uaViewId)
144 {
145 struct svga_cache_uav *cache = &svga->cache_uav;
146 unsigned i = cache->next_uaView;
147 struct svga_uav *uav;
148
149 if (i > ARRAY_SIZE(cache->uaViews)) {
150 debug_printf("No room to add uav to the cache.\n");
151 return NULL;
152 }
153
154 uav = &cache->uaViews[i];
155
156 /* update the next available uav slot index */
157 cache->next_uaView = uav->next_uaView;
158
159 uav->type = uav_type;
160 memcpy(&uav->desc, desc, desc_len);
161 pipe_resource_reference(&uav->resource, res);
162 uav->uaViewId = uaViewId;
163
164 cache->num_uaViews = MAX2(i+1, cache->num_uaViews);
165
166 return uav;
167 }
168
169
170 /**
171 * Bump the timestamp of the specified uav for the specified pipeline,
172 * so the uav will not be prematurely purged.
173 */
174 static void
svga_uav_cache_use_uav(struct svga_context * svga,enum svga_pipe_type pipe_type,struct svga_uav * uav)175 svga_uav_cache_use_uav(struct svga_context *svga,
176 enum svga_pipe_type pipe_type,
177 struct svga_uav *uav)
178 {
179 assert(uav != NULL);
180 assert(uav->uaViewId != SVGA3D_INVALID_ID);
181
182 uav->timestamp[pipe_type] = svga->state.uav_timestamp[pipe_type];
183 }
184
185
186 /**
187 * Purge any unused uav from the cache.
188 */
189 static void
svga_uav_cache_purge(struct svga_context * svga,enum svga_pipe_type pipe_type)190 svga_uav_cache_purge(struct svga_context *svga, enum svga_pipe_type pipe_type)
191 {
192 struct svga_cache_uav *cache = &svga->cache_uav;
193 unsigned timestamp = svga->state.uav_timestamp[pipe_type];
194 unsigned other_pipe_type = !pipe_type;
195 struct svga_uav *uav = &cache->uaViews[0];
196
197 unsigned last_uav = -1;
198 for (unsigned i = 0; i < cache->num_uaViews; i++, uav++) {
199 if (uav->uaViewId != SVGA3D_INVALID_ID) {
200 last_uav = i;
201
202 if (uav->timestamp[pipe_type] < timestamp) {
203
204 /* Reset the timestamp for this uav in the specified
205 * pipeline first.
206 */
207 uav->timestamp[pipe_type] = 0;
208
209 /* Then check if the uav is currently in use in other pipeline.
210 * If yes, then don't delete the uav yet.
211 * If no, then we can mark the uav as to be destroyed.
212 */
213 if (uav->timestamp[other_pipe_type] == 0) {
214
215 /* The unused uav can be destroyed, but will be destroyed
216 * in the next set_image_views or set_shader_buffers,
217 * or at context destroy time, because we do not want to
218 * restart the state update if the Destroy command cannot be
219 * executed in this command buffer.
220 */
221 util_bitmask_set(svga->uav_to_free_id_bm, uav->uaViewId);
222
223 /* Mark this entry as available */
224 uav->next_uaView = cache->next_uaView;
225 uav->uaViewId = SVGA3D_INVALID_ID;
226 cache->next_uaView = i;
227 }
228 }
229 }
230 }
231 cache->num_uaViews = last_uav + 1;
232 }
233
234
235 /**
236 * A helper function to create an uav.
237 */
238 SVGA3dUAViewId
svga_create_uav(struct svga_context * svga,SVGA3dUAViewDesc * desc,SVGA3dSurfaceFormat svga_format,unsigned resourceDim,struct svga_winsys_surface * surf)239 svga_create_uav(struct svga_context *svga,
240 SVGA3dUAViewDesc *desc,
241 SVGA3dSurfaceFormat svga_format,
242 unsigned resourceDim,
243 struct svga_winsys_surface *surf)
244 {
245 SVGA3dUAViewId uaViewId;
246 enum pipe_error ret;
247
248 /* allocate a uav id */
249 uaViewId = util_bitmask_add(svga->uav_id_bm);
250
251 SVGA_DBG(DEBUG_UAV, "%s: uavId=%d surf=0x%x\n", __func__, uaViewId, surf);
252
253 ret = SVGA3D_sm5_DefineUAView(svga->swc, uaViewId, surf,
254 svga_format, resourceDim, desc);
255
256 if (ret != PIPE_OK) {
257 util_bitmask_clear(svga->uav_id_bm, uaViewId);
258 uaViewId = SVGA3D_INVALID_ID;
259 }
260
261 return uaViewId;
262 }
263
264
265 /**
266 * Destroy any pending unused uav
267 */
268 void
svga_destroy_uav(struct svga_context * svga)269 svga_destroy_uav(struct svga_context *svga)
270 {
271 unsigned index = 0;
272
273 SVGA_DBG(DEBUG_UAV, "%s: ", __func__);
274
275 while ((index = util_bitmask_get_next_index(svga->uav_to_free_id_bm, index))
276 != UTIL_BITMASK_INVALID_INDEX) {
277 SVGA_DBG(DEBUG_UAV, "%d ", index);
278
279 SVGA_RETRY(svga, SVGA3D_sm5_DestroyUAView(svga->swc, index));
280 util_bitmask_clear(svga->uav_id_bm, index);
281 util_bitmask_clear(svga->uav_to_free_id_bm, index);
282 }
283
284 SVGA_DBG(DEBUG_UAV, "\n");
285 }
286
287
288 /**
289 * Rebind ua views.
290 * This function is called at the beginning of each new command buffer to make sure
291 * the resources associated with the ua views are properly paged-in.
292 */
293 enum pipe_error
svga_rebind_uav(struct svga_context * svga)294 svga_rebind_uav(struct svga_context *svga)
295 {
296 struct svga_winsys_context *swc = svga->swc;
297 struct svga_hw_draw_state *hw = &svga->state.hw_draw;
298 enum pipe_error ret;
299
300 assert(svga_have_sm5(svga));
301
302 for (unsigned i = 0; i < hw->num_uavs; i++) {
303 if (hw->uaViews[i]) {
304 ret = swc->resource_rebind(swc, hw->uaViews[i], NULL,
305 SVGA_RELOC_READ | SVGA_RELOC_WRITE);
306 if (ret != PIPE_OK)
307 return ret;
308 }
309 }
310 svga->rebind.flags.uav = 0;
311
312 return PIPE_OK;
313 }
314
315 static int
svga_find_uav_from_list(struct svga_context * svga,SVGA3dUAViewId uaViewId,unsigned num_uavs,SVGA3dUAViewId * uaViewsId)316 svga_find_uav_from_list(struct svga_context *svga, SVGA3dUAViewId uaViewId,
317 unsigned num_uavs, SVGA3dUAViewId *uaViewsId)
318 {
319 for (unsigned i = 0; i < num_uavs; i++) {
320 if (uaViewsId[i] == uaViewId)
321 return i;
322 }
323 return -1;
324 }
325
326 /**
327 * A helper function to create the uaView lists from the
328 * bound shader images and shader buffers.
329 */
330 static enum pipe_error
svga_create_uav_list(struct svga_context * svga,enum svga_pipe_type pipe_type,unsigned num_free_uavs,unsigned * num_uavs,SVGA3dUAViewId * uaViewIds,struct svga_winsys_surface ** uaViews)331 svga_create_uav_list(struct svga_context *svga,
332 enum svga_pipe_type pipe_type,
333 unsigned num_free_uavs,
334 unsigned *num_uavs,
335 SVGA3dUAViewId *uaViewIds,
336 struct svga_winsys_surface **uaViews)
337 {
338 enum pipe_shader_type first_shader, last_shader;
339 struct svga_uav *uav;
340 int uav_index = -1;
341
342 /* Increase uav timestamp */
343 svga->state.uav_timestamp[pipe_type]++;
344
345 if (pipe_type == SVGA_PIPE_GRAPHICS) {
346 first_shader = PIPE_SHADER_VERTEX;
347 last_shader = PIPE_SHADER_COMPUTE;
348 } else {
349 first_shader = PIPE_SHADER_COMPUTE;
350 last_shader = first_shader + 1;
351 }
352
353 for (enum pipe_shader_type shader = first_shader;
354 shader < last_shader; shader++) {
355
356 unsigned num_image_views = svga->curr.num_image_views[shader];
357 unsigned num_shader_buffers = svga->curr.num_shader_buffers[shader];
358
359 SVGA_DBG(DEBUG_UAV,
360 "%s: shader=%d num_image_views=%d num_shader_buffers=%d\n",
361 __func__, shader, num_image_views, num_shader_buffers);
362
363 /* add enabled shader images to the uav list */
364 if (num_image_views) {
365 num_image_views = MIN2(num_image_views, num_free_uavs-*num_uavs);
366 for (unsigned i = 0; i < num_image_views; i++) {
367 struct svga_image_view *cur_image_view =
368 &svga->curr.image_views[shader][i];
369 struct pipe_resource *res = cur_image_view->resource;
370 SVGA3dUAViewId uaViewId;
371
372 if (res) {
373
374 /* First check if there is already a uav defined for this
375 * image view.
376 */
377 uav = svga_uav_cache_find_uav(svga, SVGA_IMAGE_VIEW,
378 cur_image_view,
379 sizeof(*cur_image_view));
380
381 /* If there isn't one, create a uav for this image view. */
382 if (uav == NULL) {
383 uaViewId = svga_create_uav_image(svga, &cur_image_view->desc);
384 if (uaViewId == SVGA3D_INVALID_ID)
385 return PIPE_ERROR_OUT_OF_MEMORY;
386
387 /* Add the uav to the cache */
388 uav = svga_uav_cache_add_uav(svga, SVGA_IMAGE_VIEW,
389 cur_image_view,
390 sizeof(*cur_image_view),
391 res,
392 uaViewId);
393 if (uav == NULL)
394 return PIPE_ERROR_OUT_OF_MEMORY;
395 }
396
397 /* Mark this uav as being used */
398 svga_uav_cache_use_uav(svga, pipe_type, uav);
399
400 /* Check if the uav is already bound in the uav list */
401 uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
402 *num_uavs, uaViewIds);
403
404 /* The uav is not already on the uaView list, add it */
405 if (uav_index == -1) {
406 uav_index = *num_uavs;
407 (*num_uavs)++;
408 if (res->target == PIPE_BUFFER)
409 uaViews[uav_index] = svga_buffer(res)->handle;
410 else
411 uaViews[uav_index] = svga_texture(res)->handle;
412
413 uaViewIds[uav_index] = uav->uaViewId;
414 }
415
416 /* Save the uav slot index for the image view for later reference
417 * to create the uav mapping in the shader key.
418 */
419 cur_image_view->uav_index = uav_index;
420 }
421 }
422 }
423
424 /* add enabled shader buffers to the uav list */
425 if (num_shader_buffers) {
426 num_shader_buffers = MIN2(num_shader_buffers, num_free_uavs-*num_uavs);
427 for (unsigned i = 0; i < num_shader_buffers; i++) {
428 struct svga_shader_buffer *cur_sbuf =
429 &svga->curr.shader_buffers[shader][i];
430 struct pipe_resource *res = cur_sbuf->resource;
431 SVGA3dUAViewId uaViewId;
432 enum pipe_error ret;
433
434 /* Use srv rawbuffer to access readonly shader buffer */
435 if (svga_shader_buffer_can_use_srv(svga, shader, i, cur_sbuf)) {
436 ret = svga_shader_buffer_bind_srv(svga, shader, i, cur_sbuf);
437 if (ret != PIPE_OK)
438 return ret;
439 continue;
440 } else {
441 ret = svga_shader_buffer_unbind_srv(svga, shader, i, cur_sbuf);
442 if (ret != PIPE_OK)
443 return ret;
444 }
445
446 if (res) {
447 /* Get the buffer handle that can be bound as uav. */
448 cur_sbuf->handle = svga_buffer_handle(svga, res,
449 PIPE_BIND_SHADER_BUFFER);
450
451 /* First check if there is already a uav defined for this
452 * shader buffer.
453 */
454 uav = svga_uav_cache_find_uav(svga, SVGA_SHADER_BUFFER,
455 cur_sbuf,
456 sizeof(*cur_sbuf));
457
458 /* If there isn't one, create a uav for this shader buffer. */
459 if (uav == NULL) {
460 uaViewId = svga_create_uav_buffer(svga, &cur_sbuf->desc,
461 SVGA3D_R32_TYPELESS,
462 SVGA3D_UABUFFER_RAW);
463
464 if (uaViewId == SVGA3D_INVALID_ID)
465 return PIPE_ERROR_OUT_OF_MEMORY;
466
467 /* Add the uav to the cache */
468 uav = svga_uav_cache_add_uav(svga, SVGA_SHADER_BUFFER,
469 cur_sbuf,
470 sizeof(*cur_sbuf),
471 res,
472 uaViewId);
473 if (uav == NULL)
474 return PIPE_ERROR_OUT_OF_MEMORY;
475 }
476
477 /* Mark this uav as being used */
478 svga_uav_cache_use_uav(svga, pipe_type, uav);
479
480 uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
481 *num_uavs, uaViewIds);
482
483 /* The uav is not already on the uaView list, add it */
484 if (uav_index == -1) {
485 uav_index = *num_uavs;
486 (*num_uavs)++;
487 uaViews[uav_index] = svga_buffer(res)->handle;
488 uaViewIds[uav_index] = uav->uaViewId;
489 }
490
491 /* Save the uav slot index for later reference
492 * to create the uav mapping in the shader key.
493 */
494 cur_sbuf->uav_index = uav_index;
495 }
496 }
497 }
498 }
499
500 /* Since atomic buffers are not specific to a particular shader type,
501 * add any enabled atomic buffers to the uav list when we are done adding
502 * shader specific uavs.
503 */
504
505 unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
506
507 SVGA_DBG(DEBUG_UAV,
508 "%s: num_atomic_buffers=%d\n", __func__, num_atomic_buffers);
509
510 if (num_atomic_buffers) {
511 num_atomic_buffers = MIN2(num_atomic_buffers, num_free_uavs-*num_uavs);
512
513 for (unsigned i = 0; i < num_atomic_buffers; i++) {
514 struct svga_shader_buffer *cur_sbuf = &svga->curr.atomic_buffers[i];
515 struct pipe_resource *res = cur_sbuf->resource;
516 SVGA3dUAViewId uaViewId;
517
518 if (res) {
519 /* Get the buffer handle that can be bound as uav. */
520 cur_sbuf->handle = svga_buffer_handle(svga, res,
521 PIPE_BIND_SHADER_BUFFER);
522
523 /* First check if there is already a uav defined for this
524 * shader buffer.
525 */
526 uav = svga_uav_cache_find_uav(svga, SVGA_SHADER_BUFFER,
527 cur_sbuf,
528 sizeof(*cur_sbuf));
529
530 /* If there isn't one, create a uav for this shader buffer. */
531 if (uav == NULL) {
532 uaViewId = svga_create_uav_buffer(svga, &cur_sbuf->desc,
533 SVGA3D_R32_TYPELESS,
534 SVGA3D_UABUFFER_RAW);
535
536 if (uaViewId == SVGA3D_INVALID_ID)
537 return PIPE_ERROR_OUT_OF_MEMORY;
538
539 /* Add the uav to the cache */
540 uav = svga_uav_cache_add_uav(svga, SVGA_SHADER_BUFFER,
541 cur_sbuf,
542 sizeof(*cur_sbuf),
543 res,
544 uaViewId);
545 if (uav == NULL)
546 return PIPE_ERROR_OUT_OF_MEMORY;
547 }
548
549 /* Mark this uav as being used */
550 svga_uav_cache_use_uav(svga, pipe_type, uav);
551
552 uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
553 *num_uavs, uaViewIds);
554
555 /* The uav is not already on the uaView list, add it */
556 if (uav_index == -1) {
557 uav_index = *num_uavs;
558 (*num_uavs)++;
559 uaViews[uav_index] = svga_buffer(res)->handle;
560 uaViewIds[uav_index] = uav->uaViewId;
561 }
562 }
563
564 /* Save the uav slot index for the atomic buffer for later reference
565 * to create the uav mapping in the shader key.
566 */
567 cur_sbuf->uav_index = uav_index;
568 }
569 }
570
571 /* Reset the rest of the ua views list */
572 for (unsigned u = *num_uavs;
573 u < ARRAY_SIZE(svga->state.hw_draw.uaViewIds); u++) {
574 uaViewIds[u] = SVGA3D_INVALID_ID;
575 uaViews[u] = NULL;
576 }
577
578 return PIPE_OK;
579 }
580
581
582 /**
583 * A helper function to save the current hw uav state.
584 */
585 static void
svga_save_uav_state(struct svga_context * svga,enum svga_pipe_type pipe_type,unsigned num_uavs,SVGA3dUAViewId * uaViewIds,struct svga_winsys_surface ** uaViews)586 svga_save_uav_state(struct svga_context *svga,
587 enum svga_pipe_type pipe_type,
588 unsigned num_uavs,
589 SVGA3dUAViewId *uaViewIds,
590 struct svga_winsys_surface **uaViews)
591 {
592 enum pipe_shader_type first_shader, last_shader;
593 unsigned i;
594
595 if (pipe_type == SVGA_PIPE_GRAPHICS) {
596 first_shader = PIPE_SHADER_VERTEX;
597 last_shader = PIPE_SHADER_COMPUTE;
598 } else {
599 first_shader = PIPE_SHADER_COMPUTE;
600 last_shader = first_shader + 1;
601 }
602
603 for (enum pipe_shader_type shader = first_shader;
604 shader < last_shader; shader++) {
605
606 /**
607 * Save the current shader images
608 */
609 for (i = 0; i < ARRAY_SIZE(svga->curr.image_views[0]); i++) {
610 struct svga_image_view *cur_image_view =
611 &svga->curr.image_views[shader][i];
612 struct svga_image_view *hw_image_view =
613 &svga->state.hw_draw.image_views[shader][i];
614
615 /* Save the hw state for image view */
616 *hw_image_view = *cur_image_view;
617 }
618
619 /**
620 * Save the current shader buffers
621 */
622 for (i = 0; i < ARRAY_SIZE(svga->curr.shader_buffers[0]); i++) {
623 struct svga_shader_buffer *cur_shader_buffer =
624 &svga->curr.shader_buffers[shader][i];
625 struct svga_shader_buffer *hw_shader_buffer =
626 &svga->state.hw_draw.shader_buffers[shader][i];
627
628 /* Save the hw state for image view */
629 *hw_shader_buffer = *cur_shader_buffer;
630 }
631
632 svga->state.hw_draw.num_image_views[shader] =
633 svga->curr.num_image_views[shader];
634 svga->state.hw_draw.num_shader_buffers[shader] =
635 svga->curr.num_shader_buffers[shader];
636 }
637
638 /**
639 * Save the current atomic buffers
640 */
641 for (i = 0; i < ARRAY_SIZE(svga->curr.atomic_buffers); i++) {
642 struct svga_shader_buffer *cur_buf = &svga->curr.atomic_buffers[i];
643 struct svga_shader_buffer *hw_buf = &svga->state.hw_draw.atomic_buffers[i];
644
645 /* Save the hw state for atomic buffers */
646 *hw_buf = *cur_buf;
647 }
648
649 svga->state.hw_draw.num_atomic_buffers = svga->curr.num_atomic_buffers;
650
651 /**
652 * Save the hw state for uaviews
653 */
654 if (pipe_type == SVGA_PIPE_COMPUTE) {
655 svga->state.hw_draw.num_cs_uavs = num_uavs;
656 memcpy(svga->state.hw_draw.csUAViewIds, uaViewIds,
657 sizeof svga->state.hw_draw.csUAViewIds);
658 memcpy(svga->state.hw_draw.csUAViews, uaViews,
659 sizeof svga->state.hw_draw.csUAViews);
660 }
661 else {
662 svga->state.hw_draw.num_uavs = num_uavs;
663 memcpy(svga->state.hw_draw.uaViewIds, uaViewIds,
664 sizeof svga->state.hw_draw.uaViewIds);
665 memcpy(svga->state.hw_draw.uaViews, uaViews,
666 sizeof svga->state.hw_draw.uaViews);
667 }
668
669 /* purge the uav cache */
670 svga_uav_cache_purge(svga, pipe_type);
671 }
672
673
674 /**
675 * A helper function to determine if we need to resend the SetUAViews command.
676 * We need to resend the SetUAViews command when uavSpliceIndex is to
677 * be changed because the existing index overlaps with render target views, or
678 * the image views/shader buffers are changed.
679 */
680 static bool
need_to_set_uav(struct svga_context * svga,int uavSpliceIndex,unsigned num_uavs,SVGA3dUAViewId * uaViewIds,struct svga_winsys_surface ** uaViews)681 need_to_set_uav(struct svga_context *svga,
682 int uavSpliceIndex,
683 unsigned num_uavs,
684 SVGA3dUAViewId *uaViewIds,
685 struct svga_winsys_surface **uaViews)
686 {
687 /* If number of render target views changed */
688 if (uavSpliceIndex != svga->state.hw_draw.uavSpliceIndex)
689 return true;
690
691 /* If number of render target views + number of ua views exceeds
692 * the max uav count, we will need to trim the ua views.
693 */
694 if ((uavSpliceIndex + num_uavs) > SVGA_MAX_UAVIEWS)
695 return true;
696
697 /* If uavs are different */
698 if (memcmp(svga->state.hw_draw.uaViewIds, uaViewIds,
699 sizeof svga->state.hw_draw.uaViewIds) ||
700 memcmp(svga->state.hw_draw.uaViews, uaViews,
701 sizeof svga->state.hw_draw.uaViews))
702 return true;
703
704 /* If image views are different */
705 for (enum pipe_shader_type shader = PIPE_SHADER_VERTEX;
706 shader < PIPE_SHADER_COMPUTE; shader++) {
707 unsigned num_image_views = svga->curr.num_image_views[shader];
708 if ((num_image_views != svga->state.hw_draw.num_image_views[shader]) ||
709 memcmp(svga->state.hw_draw.image_views[shader],
710 svga->curr.image_views[shader],
711 num_image_views * sizeof(struct svga_image_view)))
712 return true;
713
714 /* If shader buffers are different */
715 unsigned num_shader_buffers = svga->curr.num_shader_buffers[shader];
716 if ((num_shader_buffers != svga->state.hw_draw.num_shader_buffers[shader]) ||
717 memcmp(svga->state.hw_draw.shader_buffers[shader],
718 svga->curr.shader_buffers[shader],
719 num_shader_buffers * sizeof(struct svga_shader_buffer)))
720 return true;
721 }
722
723 /* If atomic buffers are different */
724 unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
725 if ((num_atomic_buffers != svga->state.hw_draw.num_atomic_buffers) ||
726 memcmp(svga->state.hw_draw.atomic_buffers, svga->curr.atomic_buffers,
727 num_atomic_buffers * sizeof(struct svga_shader_buffer)))
728 return true;
729
730 return false;
731 }
732
733
734 /**
735 * Update ua views in the HW for the draw pipeline by sending the
736 * SetUAViews command.
737 */
738 static enum pipe_error
update_uav(struct svga_context * svga,uint64_t dirty)739 update_uav(struct svga_context *svga, uint64_t dirty)
740 {
741 enum pipe_error ret = PIPE_OK;
742 unsigned num_uavs = 0;
743 SVGA3dUAViewId uaViewIds[SVGA_MAX_UAVIEWS];
744 struct svga_winsys_surface *uaViews[SVGA_MAX_UAVIEWS];
745
746 /* Determine the uavSpliceIndex since uav and render targets view share the
747 * same bind points.
748 */
749 int uavSpliceIndex = svga->state.hw_clear.num_rendertargets;
750
751 /* Number of free uav entries available for shader images and buffers */
752 unsigned num_free_uavs = SVGA_MAX_UAVIEWS - uavSpliceIndex;
753
754 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_UPDATEUAV);
755
756 /* Create the uav list for graphics pipeline */
757 ret = svga_create_uav_list(svga, SVGA_PIPE_GRAPHICS, num_free_uavs,
758 &num_uavs, uaViewIds, uaViews);
759 if (ret != PIPE_OK)
760 goto done;
761
762 /* check to see if we need to resend the SetUAViews command */
763 if (!need_to_set_uav(svga, uavSpliceIndex, num_uavs, uaViewIds, uaViews))
764 goto done;
765
766 /* Send the SetUAViews command */
767 SVGA_DBG(DEBUG_UAV, "%s: SetUAViews uavSpliceIndex=%d", __func__,
768 uavSpliceIndex);
769
770 #if MESA_DEBUG
771 for (unsigned i = 0; i < ARRAY_SIZE(uaViewIds); i++) {
772 SVGA_DBG(DEBUG_UAV, " %d ", uaViewIds[i]);
773 }
774 SVGA_DBG(DEBUG_UAV, "\n");
775 #endif
776
777 ret = SVGA3D_sm5_SetUAViews(svga->swc, uavSpliceIndex, SVGA_MAX_UAVIEWS,
778 uaViewIds, uaViews);
779 if (ret != PIPE_OK)
780 goto done;
781
782 /* Save the uav hw state */
783 svga_save_uav_state(svga, SVGA_PIPE_GRAPHICS, num_uavs, uaViewIds, uaViews);
784
785 /* Save the uavSpliceIndex as this determines the starting register index
786 * for the first uav used in the shader
787 */
788 svga->state.hw_draw.uavSpliceIndex = uavSpliceIndex;
789
790 done:
791 SVGA_STATS_TIME_POP(svga_sws(svga));
792 return ret;
793 }
794
795
796 struct svga_tracked_state svga_hw_uav = {
797 "shader image view",
798 (SVGA_NEW_IMAGE_VIEW |
799 SVGA_NEW_SHADER_BUFFER |
800 SVGA_NEW_FRAME_BUFFER),
801 update_uav
802 };
803
804
805 /**
806 * A helper function to determine if we need to resend the SetCSUAViews command.
807 */
808 static bool
need_to_set_cs_uav(struct svga_context * svga,unsigned num_uavs,SVGA3dUAViewId * uaViewIds,struct svga_winsys_surface ** uaViews)809 need_to_set_cs_uav(struct svga_context *svga,
810 unsigned num_uavs,
811 SVGA3dUAViewId *uaViewIds,
812 struct svga_winsys_surface **uaViews)
813 {
814 enum pipe_shader_type shader = PIPE_SHADER_COMPUTE;
815
816 if (svga->state.hw_draw.num_cs_uavs != num_uavs)
817 return true;
818
819 /* If uavs are different */
820 if (memcmp(svga->state.hw_draw.csUAViewIds, uaViewIds,
821 sizeof svga->state.hw_draw.csUAViewIds) ||
822 memcmp(svga->state.hw_draw.csUAViews, uaViews,
823 sizeof svga->state.hw_draw.csUAViews))
824 return true;
825
826 /* If image views are different */
827 unsigned num_image_views = svga->curr.num_image_views[shader];
828 if ((num_image_views != svga->state.hw_draw.num_image_views[shader]) ||
829 memcmp(svga->state.hw_draw.image_views[shader],
830 svga->curr.image_views[shader],
831 num_image_views * sizeof(struct svga_image_view)))
832 return true;
833
834 /* If atomic buffers are different */
835 unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
836 if ((num_atomic_buffers != svga->state.hw_draw.num_atomic_buffers) ||
837 memcmp(svga->state.hw_draw.atomic_buffers, svga->curr.atomic_buffers,
838 num_atomic_buffers * sizeof(struct svga_shader_buffer)))
839 return true;
840
841 return false;
842 }
843
844
845 /**
846 * Update ua views in the HW for the compute pipeline by sending the
847 * SetCSUAViews command.
848 */
849 static enum pipe_error
update_cs_uav(struct svga_context * svga,uint64_t dirty)850 update_cs_uav(struct svga_context *svga, uint64_t dirty)
851 {
852 enum pipe_error ret = PIPE_OK;
853 unsigned num_uavs = 0;
854 SVGA3dUAViewId uaViewIds[SVGA_MAX_UAVIEWS];
855 struct svga_winsys_surface *uaViews[SVGA_MAX_UAVIEWS];
856
857 /* Number of free uav entries available for shader images and buffers */
858 unsigned num_free_uavs = SVGA_MAX_UAVIEWS;
859
860 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_UPDATECSUAV);
861
862 /* Create the uav list */
863 ret = svga_create_uav_list(svga, SVGA_PIPE_COMPUTE, num_free_uavs,
864 &num_uavs, uaViewIds, uaViews);
865 if (ret != PIPE_OK)
866 goto done;
867
868 /* Check to see if we need to resend the CSSetUAViews command */
869 if (!need_to_set_cs_uav(svga, num_uavs, uaViewIds, uaViews))
870 goto done;
871
872 /* Send the uaviews to compute */
873
874 SVGA_DBG(DEBUG_UAV, "%s: SetCSUAViews", __func__);
875
876 #if MESA_DEBUG
877 for (unsigned i = 0; i < ARRAY_SIZE(uaViewIds); i++) {
878 SVGA_DBG(DEBUG_UAV, " %d ", uaViewIds[i]);
879 }
880 SVGA_DBG(DEBUG_UAV, "\n");
881 #endif
882
883 ret = SVGA3D_sm5_SetCSUAViews(svga->swc, SVGA_MAX_UAVIEWS,
884 uaViewIds, uaViews);
885 if (ret != PIPE_OK)
886 goto done;
887
888 /* Save the uav hw state */
889 svga_save_uav_state(svga, SVGA_PIPE_COMPUTE, num_uavs, uaViewIds, uaViews);
890
891 done:
892 SVGA_STATS_TIME_POP(svga_sws(svga));
893 return ret;
894 }
895
896
897 struct svga_tracked_state svga_hw_cs_uav = {
898 "shader image view",
899 (SVGA_NEW_IMAGE_VIEW |
900 SVGA_NEW_SHADER_BUFFER |
901 SVGA_NEW_FRAME_BUFFER),
902 update_cs_uav
903 };
904