xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_state_uav.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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