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