svga: Add support for compute shader, shader buffers and image views
authorNeha Bhende <bhenden@vmware.com>
Thu, 16 Dec 2021 00:36:39 +0000 (16:36 -0800)
committerMarge Bot <emma+marge@anholt.net>
Tue, 18 Jan 2022 23:50:36 +0000 (23:50 +0000)
This commit is squash of commits which handles resource creation and management
for compute shader, shader buffers and image views. It creates uavs for shader
buffers and image views.

Reviewed-by: Charmaine Lee <charmainel@vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14270>

13 files changed:
src/gallium/drivers/svga/meson.build
src/gallium/drivers/svga/svga_context.h
src/gallium/drivers/svga/svga_debug.h
src/gallium/drivers/svga/svga_image_view.c [new file with mode: 0644]
src/gallium/drivers/svga/svga_image_view.h [new file with mode: 0644]
src/gallium/drivers/svga/svga_pipe_cs.c [new file with mode: 0644]
src/gallium/drivers/svga/svga_resource_buffer.h
src/gallium/drivers/svga/svga_shader.h
src/gallium/drivers/svga/svga_shader_buffer.c [new file with mode: 0644]
src/gallium/drivers/svga/svga_shader_buffer.h [new file with mode: 0644]
src/gallium/drivers/svga/svga_state_cs.c [new file with mode: 0644]
src/gallium/drivers/svga/svga_state_uav.c [new file with mode: 0644]
src/gallium/drivers/svga/svga_tgsi_vgpu10.c

index d3bdf5c..acdb6c9 100644 (file)
@@ -26,11 +26,13 @@ files_svga = files(
   'svga_draw.c',
   'svga_draw_elements.c',
   'svga_format.c',
+  'svga_image_view.c',
   'svga_link.c',
   'svga_pipe_blend.c',
   'svga_pipe_blit.c',
   'svga_pipe_clear.c',
   'svga_pipe_constants.c',
+  'svga_pipe_cs.c',
   'svga_pipe_depthstencil.c',
   'svga_pipe_draw.c',
   'svga_pipe_flush.c',
@@ -52,8 +54,10 @@ files_svga = files(
   'svga_screen.c',
   'svga_screen_cache.c',
   'svga_shader.c',
+  'svga_shader_buffer.c',
   'svga_state.c',
   'svga_state_constants.c',
+  'svga_state_cs.c',
   'svga_state_framebuffer.c',
   'svga_state_fs.c',
   'svga_state_gs.c',
@@ -63,6 +67,7 @@ files_svga = files(
   'svga_state_sampler.c',
   'svga_state_tgsi_transform.c',
   'svga_state_tss.c',
+  'svga_state_uav.c',
   'svga_state_vdecl.c',
   'svga_state_vs.c',
   'svga_surface.c',
index 0af095f..08be8e6 100644 (file)
@@ -43,6 +43,8 @@
 #include "svga_winsys.h"
 #include "svga_hw_reg.h"
 #include "svga3d_shaderdefs.h"
+#include "svga_image_view.h"
+#include "svga_shader_buffer.h"
 #include "svga_debug.h"
 
 /** Non-GPU queries for gallium HUD */
@@ -97,6 +99,19 @@ enum svga_hud {
 
 #define CONST0_UPLOAD_ALIGNMENT 256
 
+#define SVGA_MAX_IMAGES         SVGA3D_MAX_UAVIEWS
+#define SVGA_MAX_SHADER_BUFFERS        SVGA3D_MAX_UAVIEWS
+#define SVGA_MAX_ATOMIC_BUFFERS        SVGA3D_MAX_UAVIEWS
+#define SVGA_MAX_UAVIEWS        SVGA3D_DX11_1_MAX_UAVIEWS
+
+enum svga_surface_state
+{
+   SVGA_SURFACE_STATE_CREATED,
+   SVGA_SURFACE_STATE_INVALIDATED,
+   SVGA_SURFACE_STATE_UPDATED,
+   SVGA_SURFACE_STATE_RENDERED,
+};
+
 struct draw_vertex_shader;
 struct draw_fragment_shader;
 struct svga_shader_variant;
@@ -322,12 +337,27 @@ struct svga_state
    unsigned sample_mask;
    unsigned vertices_per_patch;
    float default_tesslevels[6]; /* tessellation (outer[4] + inner[2]) levels */
+
+   /* Image views */
+   unsigned num_image_views[PIPE_SHADER_TYPES];
+   struct svga_image_view image_views[PIPE_SHADER_TYPES][SVGA_MAX_IMAGES];
+
+   /* Shader buffers */
+   unsigned num_shader_buffers[PIPE_SHADER_TYPES];
+   struct svga_shader_buffer shader_buffers[PIPE_SHADER_TYPES][SVGA_MAX_SHADER_BUFFERS];
+
+   /* HW atomic buffers */
+   unsigned num_atomic_buffers;
+   struct svga_shader_buffer atomic_buffers[SVGA_MAX_SHADER_BUFFERS];
+
    struct {
       /* Determine the layout of the grid (in block units) to be used. */
       unsigned size[3];
       /* If DispatchIndirect is used, this will has grid size info*/
       struct pipe_resource *indirect;
    } grid_info;
+
+   unsigned shared_mem_size;
 };
 
 struct svga_prescale {
@@ -441,6 +471,35 @@ struct svga_hw_draw_state
 
    boolean rasterizer_discard; /* set if rasterization is disabled */
    boolean has_backed_views;   /* set if any of the rtv/dsv is a backed surface view */
+
+   /* Image Views */
+   int uavSpliceIndex;
+   unsigned num_image_views[PIPE_SHADER_TYPES];
+   struct svga_image_view image_views[PIPE_SHADER_TYPES][SVGA_MAX_IMAGES];
+
+   /* Shader Buffers */
+   unsigned num_shader_buffers[PIPE_SHADER_TYPES];
+   struct svga_shader_buffer shader_buffers[PIPE_SHADER_TYPES][SVGA_MAX_SHADER_BUFFERS];
+
+   /* HW Atomic Buffers */
+   unsigned num_atomic_buffers;
+   struct svga_shader_buffer atomic_buffers[SVGA_MAX_SHADER_BUFFERS];
+
+   /* UAV state */
+   unsigned num_uavs;
+   SVGA3dUAViewId uaViewIds[SVGA_MAX_UAVIEWS];
+   struct svga_winsys_surface *uaViews[SVGA_MAX_UAVIEWS];
+
+   /* Compute UAV state */
+   unsigned num_cs_uavs;
+   SVGA3dUAViewId csUAViewIds[SVGA_MAX_UAVIEWS];
+   struct svga_winsys_surface *csUAViews[SVGA_MAX_UAVIEWS];
+
+   /* starting uav index for each shader */
+   unsigned uav_start_index[PIPE_SHADER_TYPES];
+
+   /* starting uav index for HW atomic buffers */
+   unsigned uav_atomic_buf_index;
 };
 
 
@@ -468,6 +527,30 @@ struct svga_hw_queue;
 struct svga_query;
 struct svga_qmem_alloc_entry;
 
+enum svga_uav_type
+{
+   SVGA_IMAGE_VIEW = 0,
+   SVGA_SHADER_BUFFER
+};
+
+struct svga_uav
+{
+   enum svga_uav_type type;
+   union {
+      struct svga_image_view image_view;
+      struct svga_shader_buffer shader_buffer;
+   } desc;
+   struct pipe_resource *resource;
+   unsigned next_uaView;
+   SVGA3dUAViewId uaViewId;
+   unsigned timestamp[2];
+};
+struct svga_cache_uav
+{
+   unsigned num_uaViews;
+   unsigned next_uaView;
+   struct svga_uav uaViews[SVGA3D_DX11_1_MAX_UAVIEWS];
+};
 struct svga_context
 {
    struct pipe_context pipe;
@@ -529,6 +612,12 @@ struct svga_context
    /* Bitmask of used query IDs */
    struct util_bitmask *query_id_bm;
 
+   /* Bitmask of used uav IDs */
+   struct util_bitmask *uav_id_bm;
+
+   /* Bitmask of to-free uav IDs */
+   struct util_bitmask *uav_to_free_id_bm;
+
    struct {
       uint64_t dirty[SVGA_STATE_MAX];
 
@@ -536,6 +625,7 @@ struct svga_context
       unsigned dirty_constbufs[PIPE_SHADER_TYPES];
 
       unsigned texture_timestamp;
+      unsigned uav_timestamp[2];
 
       struct svga_sw_state          sw;
       struct svga_hw_draw_state     hw_draw;
@@ -557,6 +647,7 @@ struct svga_context
          unsigned tes:1;
          unsigned cs:1;
          unsigned query:1;
+         unsigned uav:1;
       } flags;
       unsigned val;
    } rebind;
@@ -665,6 +756,8 @@ struct svga_context
       boolean passthrough;
    } tcs;
 
+   struct svga_cache_uav cache_uav;
+   struct pipe_resource *dummy_resource;
 };
 
 /* A flag for each frontend state object:
@@ -707,19 +800,38 @@ struct svga_context
 #define SVGA_NEW_TCS_CONST_BUFFER    ((uint64_t) 0x1000000000)
 #define SVGA_NEW_TES_CONST_BUFFER    ((uint64_t) 0x2000000000)
 #define SVGA_NEW_TCS_PARAM           ((uint64_t) 0x4000000000)
-#define SVGA_NEW_FS_CONSTS           ((uint64_t) 0x8000000000)
-#define SVGA_NEW_VS_CONSTS           ((uint64_t) 0x10000000000)
-#define SVGA_NEW_GS_CONSTS           ((uint64_t) 0x20000000000)
-#define SVGA_NEW_TCS_CONSTS          ((uint64_t) 0x40000000000)
-#define SVGA_NEW_TES_CONSTS          ((uint64_t) 0x800000000000)
+#define SVGA_NEW_IMAGE_VIEW          ((uint64_t) 0x8000000000)
+#define SVGA_NEW_SHADER_BUFFER       ((uint64_t) 0x10000000000)
+#define SVGA_NEW_CS                  ((uint64_t) 0x20000000000)
+#define SVGA_NEW_CS_VARIANT          ((uint64_t) 0x40000000000)
+#define SVGA_NEW_CS_CONST_BUFFER     ((uint64_t) 0x80000000000)
+#define SVGA_NEW_FS_CONSTS           ((uint64_t) 0x100000000000)
+#define SVGA_NEW_VS_CONSTS           ((uint64_t) 0x200000000000)
+#define SVGA_NEW_GS_CONSTS           ((uint64_t) 0x400000000000)
+#define SVGA_NEW_TCS_CONSTS          ((uint64_t) 0x800000000000)
+#define SVGA_NEW_TES_CONSTS          ((uint64_t) 0x1000000000000)
+#define SVGA_NEW_CS_CONSTS           ((uint64_t) 0x2000000000000)
+#define SVGA_NEW_FS_RAW_BUFFER       ((uint64_t) 0x4000000000000)
+#define SVGA_NEW_VS_RAW_BUFFER       ((uint64_t) 0x8000000000000)
+#define SVGA_NEW_GS_RAW_BUFFER       ((uint64_t) 0x10000000000000)
+#define SVGA_NEW_TCS_RAW_BUFFER      ((uint64_t) 0x20000000000000)
+#define SVGA_NEW_TES_RAW_BUFFER      ((uint64_t) 0x40000000000000)
+#define SVGA_NEW_CS_RAW_BUFFER       ((uint64_t) 0x80000000000000)
 #define SVGA_NEW_ALL                 ((uint64_t) 0xFFFFFFFFFFFFFFFF)
 
 #define SVGA_NEW_CONST_BUFFER \
    (SVGA_NEW_FS_CONST_BUFFER | SVGA_NEW_VS_CONST_BUFFER | \
-    SVGA_NEW_GS_CONST_BUFFER | \
+    SVGA_NEW_GS_CONST_BUFFER | SVGA_NEW_CS_CONST_BUFFER | \
     SVGA_NEW_TCS_CONST_BUFFER | SVGA_NEW_TES_CONST_BUFFER)
 
 
+/** Program pipelines */
+enum svga_pipe_type
+{
+   SVGA_PIPE_GRAPHICS = 0,
+   SVGA_PIPE_COMPUTE  = 1
+};
+
 void svga_init_state_functions( struct svga_context *svga );
 void svga_init_flush_functions( struct svga_context *svga );
 void svga_init_string_functions( struct svga_context *svga );
@@ -768,6 +880,28 @@ svga_context_create(struct pipe_screen *screen,
 void svga_toggle_render_condition(struct svga_context *svga,
                                   boolean render_condition_enabled,
                                   boolean on);
+enum pipe_error
+svga_validate_sampler_resources(struct svga_context *svga,
+                                enum svga_pipe_type);
+
+enum pipe_error
+svga_validate_constant_buffers(struct svga_context *svga,
+                               enum svga_pipe_type);
+
+enum pipe_error
+svga_validate_image_views(struct svga_context *svga,
+                          enum svga_pipe_type);
+
+enum pipe_error
+svga_validate_shader_buffers(struct svga_context *svga,
+                             enum svga_pipe_type);
+
+void
+svga_destroy_rawbuf_srv(struct svga_context *svga);
+
+void
+svga_uav_cache_init(struct svga_context *svga);
+
 
 /***********************************************************************
  * Inline conversion functions.  These are better-typed than the
index cdad858..8b43279 100644 (file)
@@ -46,6 +46,8 @@
 #define DEBUG_CACHE        0x8000
 #define DEBUG_STREAMOUT    0x10000
 #define DEBUG_SAMPLERS     0x20000
+#define DEBUG_IMAGE        0x40000
+#define DEBUG_UAV          0x80000
 #define DEBUG_RETRY        0x100000
 
 #ifdef DEBUG
diff --git a/src/gallium/drivers/svga/svga_image_view.c b/src/gallium/drivers/svga/svga_image_view.c
new file mode 100644 (file)
index 0000000..4457f6c
--- /dev/null
@@ -0,0 +1,306 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#include "pipe/p_defines.h"
+#include "util/u_bitmask.h"
+#include "util/format/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_context.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+#include "svga_resource_buffer.h"
+#include "svga_resource_texture.h"
+#include "svga_surface.h"
+#include "svga_sampler_view.h"
+#include "svga_format.h"
+
+
+/**
+ * Create a uav object for the specified shader image view
+ */
+SVGA3dUAViewId
+svga_create_uav_image(struct svga_context *svga,
+                      const struct pipe_image_view *image)
+{
+   struct svga_screen *ss = svga_screen(svga->pipe.screen);
+   SVGA3dSurfaceFormat svga_format;
+   SVGA3dUAViewDesc desc;
+   SVGA3dUAViewId uaViewId;
+
+   assert(image);
+
+   /* Make sure the translated svga format supports uav */
+   svga_format = svga_translate_format(ss, image->format,
+                                       PIPE_BIND_SHADER_IMAGE);
+   if (svga_format == SVGA3D_FORMAT_INVALID)
+      return SVGA3D_INVALID_ID;
+
+   struct pipe_resource *res = image->resource;
+   struct svga_winsys_surface *surf;
+   unsigned resourceDim;
+
+   /* resolve target to resource dimension */
+   resourceDim = svga_resource_type(res->target);
+
+   memset(&desc, 0, sizeof(desc));
+
+   if (resourceDim == SVGA3D_RESOURCE_BUFFER) {
+      unsigned block_width, block_height, bytes_per_block;
+
+      svga_format_size(svga_format, &block_width, &block_height,
+                       &bytes_per_block);
+      surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
+      desc.buffer.firstElement = image->u.buf.offset / bytes_per_block;
+      desc.buffer.numElements = image->u.buf.size / bytes_per_block;
+
+      /* mark this buffer as being used in uav */
+      struct svga_buffer *sbuf = svga_buffer(res);
+      sbuf->uav = TRUE;
+   }
+   else if (resourceDim == SVGA3D_RESOURCE_TEXTURE1D ||
+            resourceDim == SVGA3D_RESOURCE_TEXTURE2D) {
+
+      struct svga_texture *tex = svga_texture(res);
+      surf = tex->handle;
+      desc.tex.mipSlice = image->u.tex.level;
+      desc.tex.firstArraySlice = image->u.tex.first_layer;
+      desc.tex.arraySize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
+   }
+   else {
+      assert(resourceDim == SVGA3D_RESOURCE_TEXTURE3D);
+
+      struct svga_texture *tex = svga_texture(res);
+      surf = tex->handle;
+      desc.tex3D.mipSlice = image->u.tex.level;
+      desc.tex3D.firstW = image->u.tex.first_layer;
+      desc.tex3D.wSize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
+   }
+
+   uaViewId = svga_create_uav(svga, &desc, svga_format, resourceDim, surf);
+   if (uaViewId == SVGA3D_INVALID_ID)
+      return uaViewId;
+
+   SVGA_DBG(DEBUG_IMAGE, "%s: resource=0x%x dim=%d format=%d uaViewId=%d\n",
+            __FUNCTION__, res, resourceDim, svga_format, uaViewId);
+
+   return uaViewId;
+}
+
+
+/**
+ * Set shader images
+ */
+static void
+svga_set_shader_images(struct pipe_context *pipe,
+                       enum pipe_shader_type shader,
+                       unsigned start,
+                       unsigned num,
+                       unsigned unbind_num_trailing_slots,
+                       const struct pipe_image_view *images)
+{
+   struct svga_context *svga = svga_context(pipe);
+   const struct pipe_image_view *img = images;
+
+   assert(svga_have_gl43(svga));
+
+   assert(start + num <= SVGA_MAX_IMAGES);
+
+   if (images) {
+      for (unsigned i = start; i < start + num; i++, img++) {
+         struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
+
+         if (img) {
+            cur_image_view->desc = *img;
+            if (img->resource == NULL) {
+               /* Use a dummy resource if the image view is created with a NULL resource */
+               if (svga->dummy_resource == NULL) {
+                  struct svga_screen *ss = svga_screen(svga->pipe.screen);
+                  struct pipe_resource templ;
+                  struct pipe_resource *res;
+                  templ.target = PIPE_BUFFER;
+                  templ.format = PIPE_FORMAT_R8_UNORM;
+                  templ.bind = PIPE_BIND_SHADER_BUFFER;
+                  templ.width0 = 64;
+                  templ.height0 = 1;
+                  templ.depth0 = 1;
+                  templ.array_size = 1;
+                  res = ss->screen.resource_create(&ss->screen, &templ);
+                  pipe_resource_reference(&svga->dummy_resource, res);
+               }
+               pipe_resource_reference(&cur_image_view->resource,
+                                       svga->dummy_resource);
+            }
+            else {
+               pipe_resource_reference(&cur_image_view->resource,
+                                       img->resource);
+            }
+         }
+         else {
+            pipe_resource_reference(&cur_image_view->resource, NULL);
+         }
+         cur_image_view->uav_index = -1;
+      }
+   }
+
+   /* unbind trailing slots */
+   for (unsigned j = 0, i = start + num; j < unbind_num_trailing_slots;
+        i++, j++) {
+      struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
+      cur_image_view->uav_index = -1;
+      pipe_resource_reference(&cur_image_view->resource, NULL);
+   }
+
+   /* number of bound image views */
+   svga->curr.num_image_views[shader] = start + num;
+
+#ifdef DEBUG
+   SVGA_DBG(DEBUG_UAV, "%s: num_image_views=%d start=%d num=%d unbind_num_trailing_slots=%d\n",
+            __FUNCTION__, svga->curr.num_image_views[shader], start, num,
+            unbind_num_trailing_slots);
+
+   for (unsigned i = start; i < start + num; i++) {
+      struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
+      struct pipe_image_view *img = &cur_image_view->desc;
+      if (img->resource) {
+         if (img->resource->target == PIPE_BUFFER) {
+            SVGA_DBG(DEBUG_UAV, "   buffer res=0x%x format=%d offset=%d size=%d\n",
+                     img->resource, img->format,
+                     img->u.buf.offset, img->u.buf.size);
+         }
+         else {
+            SVGA_DBG(DEBUG_UAV,
+               "   texture res=0x%x format=%d first_layer=%d last_layer=%d level=%d\n",
+                     img->resource, img->format, img->u.tex.first_layer,
+                     img->u.tex.last_layer, img->u.tex.level);
+         }
+      }
+      else {
+         SVGA_DBG(DEBUG_UAV, "   res=NULL\n");
+      }
+   }
+
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   /* purge any unused uav objects */
+   svga_destroy_uav(svga);
+
+   svga->dirty |= SVGA_NEW_IMAGE_VIEW;
+}
+
+
+/**
+ *  Initialize shader images gallium interface
+ */
+void
+svga_init_shader_image_functions(struct svga_context *svga)
+{
+   if (svga_have_gl43(svga)) {
+      svga->pipe.set_shader_images = svga_set_shader_images;
+   }
+
+   /* Initialize shader image views */
+   for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; ++shader) {
+      struct svga_image_view *hw_image_views =
+         &svga->state.hw_draw.image_views[shader][0];
+      struct svga_image_view *cur_image_views =
+         &svga->curr.image_views[shader][0];
+
+      for (unsigned i = 0; i < ARRAY_SIZE(svga->curr.image_views[shader]);
+           i++, hw_image_views++, cur_image_views++) {
+         hw_image_views->resource = NULL;
+         cur_image_views->resource = NULL;
+      }
+   }
+   memset(svga->state.hw_draw.num_image_views, 0,
+          sizeof(svga->state.hw_draw.num_image_views));
+}
+
+
+/**
+ * Cleanup shader image state
+ */
+void
+svga_cleanup_shader_image_state(struct svga_context *svga)
+{
+   if (!svga_have_gl43(svga))
+      return;
+
+   svga_destroy_uav(svga);
+}
+
+
+/**
+ * Validate shader image view resources to ensure any pending changes to
+ * texture buffers are emitted before they are referenced in image views.
+ * The helper function also rebinds the image view resources if the rebind flag
+ * is specified.
+ */
+enum pipe_error
+svga_validate_image_view_resources(struct svga_context *svga,
+                                   unsigned count,
+                                   struct svga_image_view *images,
+                                   bool rebind)
+{
+   assert(svga_have_gl43(svga));
+
+   struct svga_winsys_surface *surf;
+   enum pipe_error ret;
+   unsigned i;
+
+   for (i = 0; i < count; i++) {
+      struct pipe_resource *res = images[i].resource;
+      if (res) {
+         assert(res == images[i].desc.resource);
+         if (res->target == PIPE_BUFFER) {
+            struct svga_buffer *sbuf = svga_buffer(res);
+
+            surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
+            /* Mark buffer surface as RENDERED */
+            svga_set_buffer_rendered_to(sbuf->bufsurf);
+         } else {
+            struct svga_texture *tex = svga_texture(res);
+
+            surf = tex->handle;
+            /* Mark texture as RENDERED */
+            svga_set_texture_rendered_to(tex, 0, 0);
+         }
+
+         assert(surf);
+         if (rebind) {
+            ret = svga->swc->resource_rebind(svga->swc, surf, NULL,
+                                             SVGA_RELOC_READ|SVGA_RELOC_WRITE);
+            if (ret != PIPE_OK)
+               return ret;
+         }
+      }
+   }
+
+   return PIPE_OK;
+}
diff --git a/src/gallium/drivers/svga/svga_image_view.h b/src/gallium/drivers/svga/svga_image_view.h
new file mode 100644 (file)
index 0000000..6390b93
--- /dev/null
@@ -0,0 +1,66 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#ifndef SVGA_IMAGE_VIEW_H
+#define SVGA_IMAGE_VIEW_H
+
+struct svga_image_view {
+   struct pipe_image_view desc;
+   struct pipe_resource *resource;
+   unsigned uav_index;
+};
+
+void
+svga_init_shader_image_functions(struct svga_context *svga);
+
+void
+svga_cleanup_shader_image_state(struct svga_context *svga);
+
+SVGA3dUAViewId
+svga_create_uav(struct svga_context *svga,
+                SVGA3dUAViewDesc *desc,
+                SVGA3dSurfaceFormat svga_format,
+                unsigned resourceDim,
+                struct svga_winsys_surface *surf);
+
+void
+svga_destroy_uav(struct svga_context *svga);
+
+enum pipe_error
+svga_rebind_uav(struct svga_context *svga);
+
+enum pipe_error
+svga_validate_image_view_resources(struct svga_context *svga, unsigned count,
+                                   struct svga_image_view *images,
+                                   bool rebind);
+
+SVGA3dUAViewId
+svga_create_uav_image(struct svga_context *svga,
+                      const struct pipe_image_view *image);
+
+void
+svga_uav_cache_purge_image_views(struct svga_context *svga);
+
+#endif /* SVGA_IMAGE_VIEW_H */
diff --git a/src/gallium/drivers/svga/svga_pipe_cs.c b/src/gallium/drivers/svga/svga_pipe_cs.c
new file mode 100644 (file)
index 0000000..f6f3b4f
--- /dev/null
@@ -0,0 +1,231 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_bitmask.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_text.h"
+
+#include "svga_context.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+#include "svga_shader.h"
+#include "svga_streamout.h"
+#include "svga_resource_buffer.h"
+
+
+/**
+ * Create the compute program.
+ */
+static void *
+svga_create_compute_state(struct pipe_context *pipe,
+                          const struct pipe_compute_state *templ)
+{
+   struct svga_context *svga = svga_context(pipe);
+
+   struct svga_compute_shader *cs = CALLOC_STRUCT(svga_compute_shader);
+
+   if (!cs)
+      return NULL;
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_CREATECS);
+
+   assert(templ->ir_type == PIPE_SHADER_IR_TGSI);
+   cs->base.tokens = tgsi_dup_tokens(templ->prog);
+
+   /* Collect shader basic info */
+   tgsi_scan_shader(cs->base.tokens, &cs->base.info);
+
+   cs->base.id = svga->debug.shader_id++;
+
+   svga->curr.shared_mem_size = templ->req_local_mem;
+
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return cs;
+}
+
+
+/**
+ * Bind the compute program.
+ */
+static void
+svga_bind_compute_state(struct pipe_context *pipe, void *shader)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_compute_shader *cs = (struct svga_compute_shader *)shader;
+
+   svga->curr.cs = cs;
+   svga->dirty |= SVGA_NEW_CS;
+}
+
+
+/**
+ * Delete the compute program.
+ */
+static void
+svga_delete_compute_state(struct pipe_context *pipe, void *shader)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_compute_shader *cs = (struct svga_compute_shader *)shader;
+   struct svga_compute_shader *next_cs;
+   struct svga_shader_variant *variant, *tmp;
+
+   svga_hwtnl_flush_retry(svga);
+
+   /* Free the list of compute shaders */
+   while (cs) {
+      next_cs = (struct svga_compute_shader *)cs->base.next;
+
+      for (variant = cs->base.variants; variant; variant = tmp) {
+         tmp = variant->next;
+
+         /* Check if deleting currently bound shader */
+         if (variant == svga->state.hw_draw.cs) {
+            SVGA_RETRY(svga, svga_set_shader(svga, SVGA3D_SHADERTYPE_CS, NULL));
+            svga->state.hw_draw.cs = NULL;
+         }
+
+         svga_destroy_shader_variant(svga, variant);
+      }
+
+      FREE((void *)cs->base.tokens);
+      FREE(cs);
+      cs = next_cs;
+   }
+}
+
+
+/**
+ * Bind an array of shader resources that will be used by the
+ * compute program.  Any resources that were previously bound to
+ * the specified range will be unbound after this call.
+ */
+static void
+svga_set_compute_resources(struct pipe_context *pipe,
+                           unsigned start, unsigned count,
+                           struct pipe_surface **resources)
+{
+   //TODO
+   return;
+}
+
+
+/**
+ * Bind an array of buffers to be mapped into the address space of
+ * the GLOBAL resource.  Any buffers that were previously bound
+ * between [first, first + count - 1] are unbound after this call.
+ */
+static void
+svga_set_global_binding(struct pipe_context *pipe,
+                        unsigned first, unsigned count,
+                        struct pipe_resource **resources,
+                        uint32_t **handles)
+{
+   //TODO
+   return;
+}
+
+
+/**
+ */
+static void
+svga_validate_compute_resources(struct svga_context *svga)
+{
+   /* validate sampler view resources */
+   SVGA_RETRY(svga,
+              svga_validate_sampler_resources(svga, SVGA_PIPE_COMPUTE));
+
+   /* validate constant buffer resources */
+   SVGA_RETRY(svga,
+              svga_validate_constant_buffers(svga, SVGA_PIPE_COMPUTE));
+
+   /* validate image view resources */
+   SVGA_RETRY(svga,
+              svga_validate_image_views(svga, SVGA_PIPE_COMPUTE));
+
+   /* validate shader buffer resources */
+   SVGA_RETRY(svga,
+              svga_validate_shader_buffers(svga, SVGA_PIPE_COMPUTE));
+}
+
+
+/**
+ * Launch the compute kernel starting from instruction pc of the
+ * currently bound compute program.
+ */
+static void
+svga_launch_grid(struct pipe_context *pipe,
+                 const struct pipe_grid_info *info)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_winsys_context *swc = svga->swc;
+
+   assert(svga_have_gl43(svga));
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_LAUNCHGRID);
+
+   if (info->indirect) {
+      svga->curr.grid_info.indirect= info->indirect;
+   }
+
+   svga_update_compute_state(svga);
+
+   /* validate compute resources */
+   svga_validate_compute_resources(svga);
+
+   if (info->indirect) {
+      struct svga_winsys_surface *indirect_surf;
+      indirect_surf = svga_buffer_handle(svga, info->indirect,
+                                         PIPE_BIND_COMMAND_ARGS_BUFFER);
+      SVGA_RETRY(svga, SVGA3D_sm5_DispatchIndirect(swc, indirect_surf,
+                                                   info->indirect_offset));
+   }
+   else {
+      svga->curr.grid_info.size[0] = info->grid[0];
+      svga->curr.grid_info.size[1] = info->grid[1];
+      svga->curr.grid_info.size[2] = info->grid[2];
+
+      SVGA_RETRY(svga, SVGA3D_sm5_Dispatch(swc, info->grid));
+   }
+
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return;
+}
+
+
+/**
+ * Initialize the compute interface function pointers.
+ */
+void
+svga_init_cs_functions(struct svga_context *svga)
+{
+   svga->pipe.create_compute_state = svga_create_compute_state;
+   svga->pipe.bind_compute_state = svga_bind_compute_state;
+   svga->pipe.delete_compute_state = svga_delete_compute_state;
+   svga->pipe.set_compute_resources = svga_set_compute_resources;
+   svga->pipe.set_global_binding = svga_set_global_binding;
+   svga->pipe.launch_grid = svga_launch_grid;
+}
index 97649d9..f6e3e68 100644 (file)
@@ -65,6 +65,7 @@ struct svga_buffer_surface
    unsigned bind_flags;
    struct svga_host_surface_cache_key key;
    struct svga_winsys_surface *handle;
+   enum svga_surface_state surface_state;
 };
 
 /**
@@ -120,6 +121,9 @@ struct svga_buffer
     */
    struct list_head surfaces;
 
+   /* Current surface structure */
+   struct svga_buffer_surface *bufsurf;
+
    /**
     * Information about ongoing and past map operations.
     */
@@ -212,6 +216,7 @@ struct svga_buffer
    unsigned size;  /**< Approximate size in bytes */
 
    boolean dirty;  /**< Need to do a readback before mapping? */
+   boolean uav;    /* Set if the buffer is bound to a uav */
 
    /** In some cases we try to keep the results of the translate_indices()
     * function from svga_draw_elements.c
@@ -333,6 +338,12 @@ svga_buffer_hw_storage_unmap(struct svga_context *svga,
    } else
       sws->buffer_unmap(sws, sbuf->hwbuf);
 }
+static inline void
+svga_set_buffer_rendered_to(struct svga_buffer_surface *bufsurf)
+{
+   bufsurf->surface_state = SVGA_SURFACE_STATE_RENDERED;
+}
+
 
 
 struct pipe_resource *
index 472499c..dafcbc0 100644 (file)
@@ -115,6 +115,7 @@ struct svga_compile_key
    /* compute shader */
    struct {
       unsigned grid_size[3];
+      unsigned mem_size;
    } cs;
 
    /* any shader type */
diff --git a/src/gallium/drivers/svga/svga_shader_buffer.c b/src/gallium/drivers/svga/svga_shader_buffer.c
new file mode 100644 (file)
index 0000000..b61eff5
--- /dev/null
@@ -0,0 +1,345 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#include "pipe/p_defines.h"
+#include "util/u_bitmask.h"
+#include "util/format/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_context.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+#include "svga_resource_buffer.h"
+#include "svga_resource_texture.h"
+#include "svga_surface.h"
+#include "svga_sampler_view.h"
+#include "svga_format.h"
+
+
+/**
+ * Create a uav object for the specified shader buffer
+ */
+SVGA3dUAViewId
+svga_create_uav_buffer(struct svga_context *svga,
+                       const struct pipe_shader_buffer *buf,
+                       SVGA3dSurfaceFormat format,
+                       SVGA3dUABufferFlags bufFlag)
+{
+   SVGA3dUAViewDesc desc;
+   unsigned uaViewId;
+
+   assert(buf);
+
+   /* If there is not one defined, create one. */
+   memset(&desc, 0, sizeof(desc));
+   desc.buffer.firstElement = buf->buffer_offset / sizeof(uint32);
+   desc.buffer.numElements = buf->buffer_size / sizeof(uint32);
+   desc.buffer.flags = bufFlag;
+
+   uaViewId = svga_create_uav(svga, &desc, format,
+                              SVGA3D_RESOURCE_BUFFER,
+                              svga_buffer_handle(svga, buf->buffer,
+                                                 PIPE_BIND_SHADER_BUFFER));
+   if (uaViewId == SVGA3D_INVALID_ID)
+      return uaViewId;
+
+   SVGA_DBG(DEBUG_UAV, "%s: resource=0x%x uaViewId=%d\n",
+            __FUNCTION__, buf->buffer, uaViewId);
+
+   /* Mark this buffer as a uav bound buffer */
+   struct svga_buffer *sbuf = svga_buffer(buf->buffer);
+   sbuf->uav = TRUE;
+
+   return uaViewId;
+}
+
+
+/**
+ * Set shader buffers.
+ */
+static void
+svga_set_shader_buffers(struct pipe_context *pipe,
+                        enum pipe_shader_type shader,
+                        unsigned start, unsigned num,
+                        const struct pipe_shader_buffer *buffers,
+                        unsigned writeable_bitmask)
+{
+   struct svga_context *svga = svga_context(pipe);
+   const struct pipe_shader_buffer *buf;
+
+   assert(svga_have_gl43(svga));
+
+   assert(start + num <= SVGA_MAX_SHADER_BUFFERS);
+
+#ifdef DEBUG
+   struct pipe_shader_buffer *b = buffers;
+   SVGA_DBG(DEBUG_UAV, "%s: shader=%d start=%d num=%d ",
+            __FUNCTION__, shader, start, num);
+   if (buffers) {
+      for (unsigned i = 0; i < num; i++, b++) {
+         SVGA_DBG(DEBUG_UAV, " 0x%x ", b);
+      }
+   }
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   buf = buffers;
+   if (buffers) {
+      int last_buffer = -1;
+      for (unsigned i = start; i < start + num; i++, buf++) {
+         struct svga_shader_buffer *cbuf = &svga->curr.shader_buffers[shader][i];
+
+         if (buf && buf->buffer) {
+            cbuf->desc = *buf;
+            pipe_resource_reference(&cbuf->resource, buf->buffer);
+
+            /* Mark the last bound shader buffer */
+            last_buffer = i;
+         }
+         else {
+            cbuf->desc.buffer = NULL;
+            pipe_resource_reference(&cbuf->resource, NULL);
+         }
+         cbuf->uav_index = -1;
+      }
+      svga->curr.num_shader_buffers[shader] =
+         MAX2(svga->curr.num_shader_buffers[shader], last_buffer + 1);
+   }
+   else {
+      for (unsigned i = start; i < start + num; i++) {
+         struct svga_shader_buffer *cbuf = &svga->curr.shader_buffers[shader][i];
+         cbuf->desc.buffer = NULL;
+         cbuf->uav_index = -1;
+         pipe_resource_reference(&cbuf->resource, NULL);
+      }
+      if ((start + num) >= svga->curr.num_shader_buffers[shader])
+         svga->curr.num_shader_buffers[shader] = start;
+   }
+
+#ifdef DEBUG
+   SVGA_DBG(DEBUG_UAV,
+            "%s: current num_shader_buffers=%d start=%d num=%d buffers=",
+            __FUNCTION__, svga->curr.num_shader_buffers[shader],
+            start, num);
+
+   for (unsigned i = start; i < start + num; i++) {
+      struct svga_shader_buffer *cbuf = &svga->curr.shader_buffers[shader][i];
+      SVGA_DBG(DEBUG_UAV, " 0x%x ", cbuf->desc.buffer);
+   }
+
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   /* purge any unused uav objects */
+   svga_destroy_uav(svga);
+
+   svga->dirty |= SVGA_NEW_SHADER_BUFFER;
+}
+
+
+/**
+ * Set HW atomic buffers.
+ */
+static void
+svga_set_hw_atomic_buffers(struct pipe_context *pipe,
+                           unsigned start, unsigned num,
+                           const struct pipe_shader_buffer *buffers)
+{
+   struct svga_context *svga = svga_context(pipe);
+   const struct pipe_shader_buffer *buf = buffers;
+
+   assert(svga_have_gl43(svga));
+
+   assert(start + num <= SVGA_MAX_ATOMIC_BUFFERS);
+
+#ifdef DEBUG
+   SVGA_DBG(DEBUG_UAV, "%s: start=%d num=%d \n", __FUNCTION__, start, num);
+#endif
+
+   buf = buffers;
+   if (buffers) {
+      int last_buffer = -1;
+      for (unsigned i = start; i < start + num; i++, buf++) {
+         struct svga_shader_buffer *cbuf = &svga->curr.atomic_buffers[i];
+
+         if (buf && buf->buffer) {
+            cbuf->desc = *buf;
+            pipe_resource_reference(&cbuf->resource, buf->buffer);
+
+            last_buffer = i;
+
+            /* Mark the buffer as uav buffer so that a readback will
+             * be done at each read transfer. We can't rely on the
+             * dirty bit because it is reset after each read, but
+             * the uav buffer can be updated at each draw.
+             */
+            struct svga_buffer *sbuf = svga_buffer(cbuf->desc.buffer);
+            sbuf->uav = TRUE;
+         }
+         else {
+            cbuf->desc.buffer = NULL;
+            pipe_resource_reference(&cbuf->resource, NULL);
+         }
+         cbuf->uav_index = -1;
+      }
+      svga->curr.num_atomic_buffers = MAX2(svga->curr.num_atomic_buffers,
+                                        last_buffer + 1);
+   }
+   else {
+      for (unsigned i = start; i < start + num; i++) {
+         struct svga_shader_buffer *cbuf = &svga->curr.atomic_buffers[i];
+         cbuf->desc.buffer = NULL;
+         cbuf->uav_index = -1;
+         pipe_resource_reference(&cbuf->resource, NULL);
+      }
+      if ((start + num) >= svga->curr.num_atomic_buffers)
+         svga->curr.num_atomic_buffers = start;
+   }
+
+#ifdef DEBUG
+   SVGA_DBG(DEBUG_UAV, "%s: current num_atomic_buffers=%d start=%d num=%d ",
+            __FUNCTION__, svga->curr.num_atomic_buffers,
+            start, num);
+
+   for (unsigned i = start; i < start + num; i++) {
+      struct svga_shader_buffer *cbuf = &svga->curr.atomic_buffers[i];
+      SVGA_DBG(DEBUG_UAV, " 0x%x ", cbuf->desc.buffer);
+   }
+
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   /* purge any unused uav objects */
+   svga_destroy_uav(svga);
+
+   svga->dirty |= SVGA_NEW_SHADER_BUFFER;
+}
+
+
+/**
+ *  Initialize shader images gallium interface
+ */
+void
+svga_init_shader_buffer_functions(struct svga_context *svga)
+{
+   if (!svga_have_gl43(svga))
+      return;
+
+   svga->pipe.set_shader_buffers = svga_set_shader_buffers;
+   svga->pipe.set_hw_atomic_buffers = svga_set_hw_atomic_buffers;
+
+   /* Initialize shader buffers */
+   for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; ++shader) {
+      struct svga_shader_buffer *hw_buf =
+         &svga->state.hw_draw.shader_buffers[shader][0];
+      struct svga_shader_buffer *cur_buf =
+         &svga->curr.shader_buffers[shader][0];
+
+      /* Initialize uaViewId to SVGA3D_INVALID_ID for current shader buffers
+       * and shader buffers in hw state to avoid unintentional unbinding of
+       * shader buffers with uaViewId 0.
+       */
+      for (unsigned i = 0; i < ARRAY_SIZE(svga->curr.shader_buffers[shader]);
+           i++, hw_buf++, cur_buf++) {
+         hw_buf->resource = NULL;
+         hw_buf->uav_index = -1;
+         cur_buf->desc.buffer = NULL;
+         cur_buf->resource = NULL;
+         cur_buf->uav_index = -1;
+      }
+   }
+   memset(svga->state.hw_draw.num_shader_buffers, 0,
+          sizeof(svga->state.hw_draw.num_shader_buffers));
+
+   /* Initialize atomic buffers */
+
+   /* Initialize uaViewId to SVGA3D_INVALID_ID for current atomic buffers
+    * and atomic buffers in hw state to avoid unintentional unbinding of
+    * shader buffer with uaViewId 0.
+    */
+   for (unsigned i = 0; i < ARRAY_SIZE(svga->state.hw_draw.atomic_buffers); i++) {
+      svga->curr.atomic_buffers[i].resource = NULL;
+      svga->curr.atomic_buffers[i].uav_index = -1;
+   }
+   svga->state.hw_draw.num_atomic_buffers = 0;
+}
+
+
+/**
+ * Cleanup shader image state
+ */
+void
+svga_cleanup_shader_buffer_state(struct svga_context *svga)
+{
+   if (!svga_have_gl43(svga))
+      return;
+
+   svga_destroy_uav(svga);
+}
+
+
+/**
+ * Validate shader buffer resources to ensure any pending changes to the
+ * buffers are emitted before they are referenced.
+ * The helper function also rebinds the buffer resources if the rebind flag
+ * is specified.
+ */
+enum pipe_error
+svga_validate_shader_buffer_resources(struct svga_context *svga,
+                                      unsigned count,
+                                      struct svga_shader_buffer *bufs,
+                                      bool rebind)
+{
+   assert(svga_have_gl43(svga));
+
+   struct svga_winsys_surface *surf;
+   enum pipe_error ret;
+   unsigned i;
+
+   for (i = 0; i < count; i++) {
+      if (bufs[i].resource) {
+         assert(bufs[i].resource == bufs[i].desc.buffer);
+
+         struct svga_buffer *sbuf = svga_buffer(bufs[i].resource);
+         surf = svga_buffer_handle(svga, bufs[i].desc.buffer,
+                                   PIPE_BIND_SHADER_BUFFER);
+         assert(surf);
+         if (rebind) {
+            ret = svga->swc->resource_rebind(svga->swc, surf, NULL,
+                                             SVGA_RELOC_READ|SVGA_RELOC_WRITE);
+            if (ret != PIPE_OK)
+               return ret;
+         }
+
+         /* Mark buffer as RENDERED */
+         svga_set_buffer_rendered_to(sbuf->bufsurf);
+      }
+   }
+
+   return PIPE_OK;
+}
diff --git a/src/gallium/drivers/svga/svga_shader_buffer.h b/src/gallium/drivers/svga/svga_shader_buffer.h
new file mode 100644 (file)
index 0000000..7b63b9e
--- /dev/null
@@ -0,0 +1,58 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#ifndef SVGA_SHADER_BUFFER_H
+#define SVGA_SHADER_BUFFER_H
+
+struct svga_shader_buffer {
+   struct pipe_shader_buffer desc;
+   struct pipe_resource *resource;
+   unsigned uav_index;
+   struct svga_winsys_surface *handle;
+};
+
+void
+svga_init_shader_buffer_functions(struct svga_context *svga);
+
+void
+svga_cleanup_shader_buffer_state(struct svga_context *svga);
+
+enum pipe_error
+svga_validate_shader_buffer_resources(struct svga_context *svga,
+                                      unsigned count,
+                                      struct svga_shader_buffer *buffers,
+                                      bool rebind);
+
+SVGA3dUAViewId
+svga_create_uav_buffer(struct svga_context *svga,
+                       const struct pipe_shader_buffer *buf,
+                       SVGA3dSurfaceFormat format,
+                       SVGA3dUABufferFlags bufFlag);
+
+void
+svga_uav_cache_purge_buffers(struct svga_context *svga);
+
+
+#endif /* SVGA_SHADER_BUFFER_H */
diff --git a/src/gallium/drivers/svga/svga_state_cs.c b/src/gallium/drivers/svga/svga_state_cs.c
new file mode 100644 (file)
index 0000000..1154d49
--- /dev/null
@@ -0,0 +1,166 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_bitmask.h"
+#include "translate/translate.h"
+#include "tgsi/tgsi_ureg.h"
+
+#include "svga_context.h"
+#include "svga_cmd.h"
+#include "svga_shader.h"
+#include "svga_tgsi.h"
+
+
+/**
+ * Translate TGSI shader into an svga shader variant.
+ */
+static enum pipe_error
+compile_cs(struct svga_context *svga,
+           struct svga_compute_shader *cs,
+           const struct svga_compile_key *key,
+           struct svga_shader_variant **out_variant)
+{
+   struct svga_shader_variant *variant;
+   enum pipe_error ret = PIPE_ERROR;
+
+   variant = svga_tgsi_vgpu10_translate(svga, &cs->base, key,
+                                        PIPE_SHADER_COMPUTE);
+   if (!variant)
+      return PIPE_ERROR;
+
+   ret = svga_define_shader(svga, variant);
+   if (ret != PIPE_OK) {
+      svga_destroy_shader_variant(svga, variant);
+      return ret;
+   }
+
+   *out_variant = variant;
+
+   return PIPE_OK;
+}
+
+
+/**
+ * Create compute shader compile key.
+ */
+static void
+make_cs_key(struct svga_context *svga,
+            struct svga_compile_key *key)
+{
+   struct svga_compute_shader *cs = svga->curr.cs;
+
+   memset(key, 0, sizeof *key);
+
+   svga_init_shader_key_common(svga, PIPE_SHADER_COMPUTE, &cs->base, key);
+
+   key->cs.grid_size[0] = svga->curr.grid_info.size[0];
+   key->cs.grid_size[1] = svga->curr.grid_info.size[1];
+   key->cs.grid_size[2] = svga->curr.grid_info.size[2];
+   key->cs.mem_size = svga->curr.shared_mem_size;
+
+   if (svga->curr.grid_info.indirect && cs->base.info.uses_grid_size) {
+      struct pipe_transfer *transfer = NULL;
+      const void *map = NULL;
+      map = pipe_buffer_map(&svga->pipe, svga->curr.grid_info.indirect,
+                            PIPE_MAP_READ, &transfer);
+      memcpy(key->cs.grid_size, map, 3 * sizeof(uint));
+      pipe_buffer_unmap(&svga->pipe, transfer);
+   }
+
+}
+
+
+/**
+ * Emit current compute shader to device.
+ */
+static enum pipe_error
+emit_hw_cs(struct svga_context *svga, uint64_t dirty)
+{
+   struct svga_shader_variant *variant;
+   struct svga_compute_shader *cs = svga->curr.cs;
+   enum pipe_error ret = PIPE_OK;
+   struct svga_compile_key key;
+
+   assert(svga_have_sm5(svga));
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_EMITCS);
+
+   if (!cs) {
+      if (svga->state.hw_draw.cs != NULL) {
+
+         /** The previous compute shader is made inactive.
+          *  Needs to unbind the compute shader.
+          */
+         ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_CS, NULL);
+         if (ret != PIPE_OK)
+            goto done;
+         svga->state.hw_draw.cs = NULL;
+      }
+      goto done;
+   }
+
+   make_cs_key(svga, &key);
+
+   /* See if we already have a CS variant that matches the key */
+   variant = svga_search_shader_key(&cs->base, &key);
+
+   if (!variant) {
+      ret = compile_cs(svga, cs, &key, &variant);
+      if (ret != PIPE_OK)
+         goto done;
+
+      /* insert the new variant at head of linked list */
+      assert(variant);
+      variant->next = cs->base.variants;
+      cs->base.variants = variant;
+   }
+
+   if (variant != svga->state.hw_draw.cs) {
+      /* Bind the new variant */
+      ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_CS, variant);
+      if (ret != PIPE_OK)
+         goto done;
+
+      svga->rebind.flags.cs = FALSE;
+      svga->dirty |= SVGA_NEW_CS_VARIANT;
+      svga->state.hw_draw.cs = variant;
+   }
+
+done:
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return ret;
+}
+
+struct svga_tracked_state svga_hw_cs =
+{
+   "compute shader",
+   (SVGA_NEW_CS |
+    SVGA_NEW_TEXTURE_BINDING |
+    SVGA_NEW_SAMPLER |
+    SVGA_NEW_CS_RAW_BUFFER),
+   emit_hw_cs
+};
diff --git a/src/gallium/drivers/svga/svga_state_uav.c b/src/gallium/drivers/svga/svga_state_uav.c
new file mode 100644 (file)
index 0000000..a4da2c8
--- /dev/null
@@ -0,0 +1,909 @@
+/**********************************************************
+ * Copyright 2022 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+#include "pipe/p_defines.h"
+#include "util/u_bitmask.h"
+#include "util/format/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_context.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+#include "svga_resource_buffer.h"
+#include "svga_resource_texture.h"
+#include "svga_surface.h"
+#include "svga_sampler_view.h"
+#include "svga_format.h"
+
+
+/**
+ * Initialize uav cache.
+ */
+void
+svga_uav_cache_init(struct svga_context *svga)
+{
+   struct svga_cache_uav *cache = &svga->cache_uav;
+
+   for (unsigned i = 0; i < ARRAY_SIZE(cache->uaViews); i++) {
+      cache->uaViews[i].uaViewId = SVGA3D_INVALID_ID;
+      cache->uaViews[i].next_uaView = i + 1;
+   }
+   cache->num_uaViews = 0;
+   cache->next_uaView = 0;
+}
+
+
+/**
+ * Helper function to compare two image view descriptions.
+ * Return TRUE if they are identical.
+ */
+static boolean
+image_view_desc_identical(struct pipe_image_view *img1,
+                          struct pipe_image_view *img2)
+{
+   if ((img1->resource != img2->resource) ||
+       (img1->format != img2->format) ||
+       (img1->access != img2->access) ||
+       (img1->shader_access != img2->shader_access))
+      return FALSE;
+
+   if (img1->resource->target == PIPE_BUFFER) {
+      if ((img1->u.buf.offset != img2->u.buf.offset) ||
+          (img1->u.buf.size != img2->u.buf.size))
+         return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+/**
+ * Helper function to compare two shader buffer descriptions.
+ * Return TRUE if they are identical.
+ */
+static boolean
+shader_buffer_desc_identical(struct pipe_shader_buffer *buf1,
+                             struct pipe_shader_buffer *buf2)
+{
+   return memcmp(buf1, buf2, sizeof(*buf1)) == 0;
+}
+
+
+/**
+ * Helper function to compare two uav cache entry descriptions.
+ * Return TRUE if they are identical.
+ */
+static boolean
+uav_desc_identical(enum svga_uav_type uav_type,
+                   void *desc, void *uav_desc)
+{
+   if (uav_type == SVGA_IMAGE_VIEW) {
+      struct svga_image_view *img = (struct svga_image_view *)desc;
+      struct svga_image_view *uav_img = (struct svga_image_view *)uav_desc;
+      if (img->resource != uav_img->resource)
+         return FALSE;
+
+      return image_view_desc_identical(&img->desc, &uav_img->desc);
+   }
+   else {
+      struct svga_shader_buffer *buf = (struct svga_shader_buffer *)desc;
+      struct svga_shader_buffer *uav_buf =
+         (struct svga_shader_buffer *)uav_desc;
+
+      if (buf->resource != uav_buf->resource)
+         return FALSE;
+
+      if (buf->handle != uav_buf->handle)
+         return FALSE;
+
+      return shader_buffer_desc_identical(&buf->desc, &uav_buf->desc);
+   }
+}
+
+
+/**
+ * Find a uav object for the specified image view or shader buffer.
+ * Returns uav entry if there is a match; otherwise returns NULL.
+ */
+static struct svga_uav *
+svga_uav_cache_find_uav(struct svga_context *svga,
+                        enum svga_uav_type uav_type,
+                        void *desc,
+                        unsigned desc_len)
+{
+   struct svga_cache_uav *cache = &svga->cache_uav;
+
+   for (unsigned i = 0; i < cache->num_uaViews; i++) {
+      if ((cache->uaViews[i].type == uav_type) &&
+          (cache->uaViews[i].uaViewId != SVGA3D_INVALID_ID) &&
+          uav_desc_identical(uav_type, desc, &cache->uaViews[i].desc)) {
+         return &cache->uaViews[i];
+      }
+   }
+   return NULL;
+}
+
+
+/**
+ * Add a uav entry to the cache for the specified image view or
+ * shaderr bufferr.
+ */
+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)
+{
+   struct svga_cache_uav *cache = &svga->cache_uav;
+   unsigned i = cache->next_uaView;
+   struct svga_uav *uav;
+
+   if (i > ARRAY_SIZE(cache->uaViews)) {
+      debug_printf("No room to add uav to the cache.\n");
+      return NULL;
+   }
+
+   uav = &cache->uaViews[i];
+
+   /* update the next available uav slot index */
+   cache->next_uaView = uav->next_uaView;
+
+   uav->type = uav_type;
+   memcpy(&uav->desc, desc, desc_len);
+   pipe_resource_reference(&uav->resource, res);
+   uav->uaViewId = uaViewId;
+
+   cache->num_uaViews = MAX2(i+1, cache->num_uaViews);
+
+   return uav;
+}
+
+
+/**
+ * Bump the timestamp of the specified uav for the specified pipeline,
+ * so the uav will not be prematurely purged.
+ */
+static void
+svga_uav_cache_use_uav(struct svga_context *svga,
+                       enum svga_pipe_type pipe_type,
+                       struct svga_uav *uav)
+{
+   assert(uav != NULL);
+   assert(uav->uaViewId != SVGA3D_INVALID_ID);
+
+   uav->timestamp[pipe_type] = svga->state.uav_timestamp[pipe_type];
+}
+
+
+/**
+ * Purge any unused uav from the cache.
+ */
+static void
+svga_uav_cache_purge(struct svga_context *svga, enum svga_pipe_type pipe_type)
+{
+   struct svga_cache_uav *cache = &svga->cache_uav;
+   unsigned timestamp = svga->state.uav_timestamp[pipe_type];
+   unsigned other_pipe_type = !pipe_type;
+   struct svga_uav *uav = &cache->uaViews[0];
+
+   unsigned last_uav = -1;
+   for (unsigned i = 0; i < cache->num_uaViews; i++, uav++) {
+      if (uav->uaViewId != SVGA3D_INVALID_ID) {
+         last_uav = i;
+
+         if (uav->timestamp[pipe_type] < timestamp) {
+
+            /* Reset the timestamp for this uav in the specified
+             * pipeline first.
+             */
+            uav->timestamp[pipe_type] = 0;
+
+            /* Then check if the uav is currently in use in other pipeline.
+             * If yes, then don't delete the uav yet.
+             * If no, then we can mark the uav as to be destroyed.
+             */
+            if (uav->timestamp[other_pipe_type] == 0) {
+
+               /* The unused uav can be destroyed, but will be destroyed
+                * in the next set_image_views or set_shader_buffers,
+                * or at context destroy time, because we do not want to
+                * restart the state update if the Destroy command cannot be
+                * executed in this command buffer.
+                */
+               util_bitmask_set(svga->uav_to_free_id_bm, uav->uaViewId);
+
+               /* Mark this entry as available */
+               uav->next_uaView = cache->next_uaView;
+               uav->uaViewId = SVGA3D_INVALID_ID;
+               cache->next_uaView = i;
+            }
+         }
+      }
+   }
+   cache->num_uaViews = last_uav + 1;
+}
+
+
+/**
+ * A helper function to create an uav.
+ */
+SVGA3dUAViewId
+svga_create_uav(struct svga_context *svga,
+                SVGA3dUAViewDesc *desc,
+                SVGA3dSurfaceFormat svga_format,
+                unsigned resourceDim,
+                struct svga_winsys_surface *surf)
+{
+   SVGA3dUAViewId uaViewId;
+   enum pipe_error ret;
+
+   /* allocate a uav id */
+   uaViewId = util_bitmask_add(svga->uav_id_bm);
+
+   SVGA_DBG(DEBUG_UAV, "%s: uavId=%d surf=0x%x\n", __FUNCTION__, uaViewId, surf);
+
+   ret = SVGA3D_sm5_DefineUAView(svga->swc, uaViewId, surf,
+                                 svga_format, resourceDim, desc);
+
+   if (ret != PIPE_OK) {
+      util_bitmask_clear(svga->uav_id_bm, uaViewId);
+      uaViewId = SVGA3D_INVALID_ID;
+   }
+
+   return uaViewId;
+}
+
+
+/**
+ * Destroy any pending unused uav
+ */
+void
+svga_destroy_uav(struct svga_context *svga)
+{
+   unsigned index = 0;
+
+   SVGA_DBG(DEBUG_UAV, "%s: ", __FUNCTION__);
+
+   while ((index = util_bitmask_get_next_index(svga->uav_to_free_id_bm, index))
+          != UTIL_BITMASK_INVALID_INDEX) {
+      SVGA_DBG(DEBUG_UAV, "%d ", index);
+
+      SVGA_RETRY(svga, SVGA3D_sm5_DestroyUAView(svga->swc, index));
+      util_bitmask_clear(svga->uav_id_bm, index);
+      util_bitmask_clear(svga->uav_to_free_id_bm, index);
+   }
+
+   SVGA_DBG(DEBUG_UAV, "\n");
+}
+
+
+/**
+ * Rebind ua views.
+ * This function is called at the beginning of each new command buffer to make sure
+ * the resources associated with the ua views are properly paged-in.
+ */
+enum pipe_error
+svga_rebind_uav(struct svga_context *svga)
+{
+   struct svga_winsys_context *swc = svga->swc;
+   struct svga_hw_draw_state *hw = &svga->state.hw_draw;
+   enum pipe_error ret;
+
+   assert(svga_have_sm5(svga));
+
+   for (unsigned i = 0; i < hw->num_uavs; i++) {
+      if (hw->uaViews[i]) {
+         ret = swc->resource_rebind(swc, hw->uaViews[i], NULL,
+                                    SVGA_RELOC_READ | SVGA_RELOC_WRITE);
+         if (ret != PIPE_OK)
+            return ret;
+      }
+   }
+   svga->rebind.flags.uav = 0;
+
+   return PIPE_OK;
+}
+
+static int
+svga_find_uav_from_list(struct svga_context *svga, SVGA3dUAViewId uaViewId,
+                        unsigned num_uavs, SVGA3dUAViewId *uaViewsId)
+{
+   for (unsigned i = 0; i < num_uavs; i++) {
+      if (uaViewsId[i] == uaViewId)
+         return i;
+   }
+   return -1;
+}
+
+/**
+ * A helper function to create the uaView lists from the
+ * bound shader images and shader buffers.
+ */
+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)
+{
+   enum pipe_shader_type first_shader, last_shader;
+   struct svga_uav *uav;
+   int uav_index = -1;
+
+   /* Increase uav timestamp */
+   svga->state.uav_timestamp[pipe_type]++;
+
+   if (pipe_type == SVGA_PIPE_GRAPHICS) {
+      first_shader = PIPE_SHADER_VERTEX;
+      last_shader = PIPE_SHADER_TESS_EVAL;
+   } else {
+      first_shader = PIPE_SHADER_COMPUTE;
+      last_shader = PIPE_SHADER_COMPUTE;
+   }
+
+   for (enum pipe_shader_type shader = first_shader;
+        shader <= last_shader; shader++) {
+
+      unsigned num_image_views = svga->curr.num_image_views[shader];
+      unsigned num_shader_buffers = svga->curr.num_shader_buffers[shader];
+
+      SVGA_DBG(DEBUG_UAV,
+            "%s: shader=%d num_image_views=%d num_shader_buffers=%d\n",
+            __FUNCTION__, shader, num_image_views, num_shader_buffers);
+
+      /* add enabled shader images to the uav list */
+      if (num_image_views) {
+         num_image_views = MIN2(num_image_views, num_free_uavs-*num_uavs);
+         for (unsigned i = 0; i < num_image_views; i++) {
+            struct svga_image_view *cur_image_view =
+                &svga->curr.image_views[shader][i];
+            struct pipe_resource *res = cur_image_view->resource;
+            SVGA3dUAViewId uaViewId;
+
+            if (res) {
+
+               /* First check if there is already a uav defined for this
+                * image view.
+                */
+               uav = svga_uav_cache_find_uav(svga, SVGA_IMAGE_VIEW,
+                                             cur_image_view,
+                                             sizeof(*cur_image_view));
+
+               /* If there isn't one, create a uav for this image view. */
+               if (uav == NULL) {
+                  uaViewId = svga_create_uav_image(svga, &cur_image_view->desc);
+                  if (uaViewId == SVGA3D_INVALID_ID)
+                     return PIPE_ERROR_OUT_OF_MEMORY;
+
+                  /* Add the uav to the cache */
+                  uav = svga_uav_cache_add_uav(svga, SVGA_IMAGE_VIEW,
+                                               cur_image_view,
+                                               sizeof(*cur_image_view),
+                                               res,
+                                               uaViewId);
+                  if (uav == NULL)
+                     return PIPE_ERROR_OUT_OF_MEMORY;
+               }
+
+               /* Mark this uav as being used */
+               svga_uav_cache_use_uav(svga, pipe_type, uav);
+
+               /* Check if the uav is already bound in the uav list */
+               uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
+                                                   *num_uavs, uaViewIds);
+
+               /* The uav is not already on the uaView list, add it */
+               if (uav_index == -1) {
+                  uav_index = *num_uavs;
+                  (*num_uavs)++;
+                  if (res->target == PIPE_BUFFER)
+                     uaViews[uav_index] = svga_buffer(res)->handle;
+                  else
+                     uaViews[uav_index] = svga_texture(res)->handle;
+
+                  uaViewIds[uav_index] = uav->uaViewId;
+               }
+
+               /* Save the uav slot index for the image view for later reference
+                * to create the uav mapping in the shader key.
+                */
+               cur_image_view->uav_index = uav_index;
+            }
+         }
+      }
+
+      /* add enabled shader buffers to the uav list */
+      if (num_shader_buffers) {
+         num_shader_buffers = MIN2(num_shader_buffers, num_free_uavs-*num_uavs);
+         for (unsigned i = 0; i < num_shader_buffers; i++) {
+            struct svga_shader_buffer *cur_sbuf =
+                &svga->curr.shader_buffers[shader][i];
+            struct pipe_resource *res = cur_sbuf->resource;
+            SVGA3dUAViewId uaViewId;
+
+            if (res) {
+               /* Get the buffer handle that can be bound as uav. */
+               cur_sbuf->handle = svga_buffer_handle(svga, res,
+                                                    PIPE_BIND_SHADER_BUFFER);
+
+               /* First check if there is already a uav defined for this
+                * shader buffer.
+                */
+               uav = svga_uav_cache_find_uav(svga, SVGA_SHADER_BUFFER,
+                                             cur_sbuf,
+                                             sizeof(*cur_sbuf));
+
+               /* If there isn't one, create a uav for this shader buffer. */
+               if (uav == NULL) {
+                  uaViewId = svga_create_uav_buffer(svga, &cur_sbuf->desc,
+                                                    SVGA3D_R32_TYPELESS,
+                                                    SVGA3D_UABUFFER_RAW);
+
+                  if (uaViewId == SVGA3D_INVALID_ID)
+                     return PIPE_ERROR_OUT_OF_MEMORY;
+
+                  /* Add the uav to the cache */
+                  uav = svga_uav_cache_add_uav(svga, SVGA_SHADER_BUFFER,
+                                               cur_sbuf,
+                                               sizeof(*cur_sbuf),
+                                               res,
+                                               uaViewId);
+                  if (uav == NULL)
+                     return PIPE_ERROR_OUT_OF_MEMORY;
+               }
+
+               /* Mark this uav as being used */
+               svga_uav_cache_use_uav(svga, pipe_type, uav);
+
+               uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
+                                                   *num_uavs, uaViewIds);
+
+               /* The uav is not already on the uaView list, add it */
+               if (uav_index == -1) {
+                  uav_index = *num_uavs;
+                  (*num_uavs)++;
+                  uaViews[uav_index] = svga_buffer(res)->handle;
+                  uaViewIds[uav_index] = uav->uaViewId;
+               }
+
+               /* Save the uav slot index for later reference
+                * to create the uav mapping in the shader key.
+                */
+               cur_sbuf->uav_index = uav_index;
+            }
+         }
+      }
+   }
+
+   /* Since atomic buffers are not specific to a particular shader type,
+    * add any enabled atomic buffers to the uav list when we are done adding
+    * shader specific uavs.
+    */
+
+   unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
+
+   SVGA_DBG(DEBUG_UAV,
+            "%s: num_atomic_buffers=%d\n", __FUNCTION__, num_atomic_buffers);
+
+   if (num_atomic_buffers) {
+      num_atomic_buffers = MIN2(num_atomic_buffers, num_free_uavs-*num_uavs);
+
+      for (unsigned i = 0; i < num_atomic_buffers; i++) {
+         struct svga_shader_buffer *cur_sbuf = &svga->curr.atomic_buffers[i];
+         struct pipe_resource *res = cur_sbuf->resource;
+         SVGA3dUAViewId uaViewId;
+
+         if (res) {
+            /* Get the buffer handle that can be bound as uav. */
+            cur_sbuf->handle = svga_buffer_handle(svga, res,
+                                                  PIPE_BIND_SHADER_BUFFER);
+
+            /* First check if there is already a uav defined for this
+             * shader buffer.
+             */
+            uav = svga_uav_cache_find_uav(svga, SVGA_SHADER_BUFFER,
+                                          cur_sbuf,
+                                          sizeof(*cur_sbuf));
+
+            /* If there isn't one, create a uav for this shader buffer. */
+            if (uav == NULL) {
+               uaViewId = svga_create_uav_buffer(svga, &cur_sbuf->desc,
+                                                 SVGA3D_R32_TYPELESS,
+                                                 SVGA3D_UABUFFER_RAW);
+
+               if (uaViewId == SVGA3D_INVALID_ID)
+                  return PIPE_ERROR_OUT_OF_MEMORY;
+
+               /* Add the uav to the cache */
+               uav = svga_uav_cache_add_uav(svga, SVGA_SHADER_BUFFER,
+                                            cur_sbuf,
+                                            sizeof(*cur_sbuf),
+                                            res,
+                                            uaViewId);
+               if (uav == NULL)
+                  return PIPE_ERROR_OUT_OF_MEMORY;
+            }
+
+            /* Mark this uav as being used */
+            svga_uav_cache_use_uav(svga, pipe_type, uav);
+
+            uav_index = svga_find_uav_from_list(svga, uav->uaViewId,
+                                                *num_uavs, uaViewIds);
+
+            /* The uav is not already on the uaView list, add it */
+            if (uav_index == -1) {
+               uav_index = *num_uavs;
+               (*num_uavs)++;
+               uaViews[uav_index] = svga_buffer(res)->handle;
+               uaViewIds[uav_index] = uav->uaViewId;
+            }
+         }
+
+         /* Save the uav slot index for the atomic buffer for later reference
+          * to create the uav mapping in the shader key.
+          */
+         cur_sbuf->uav_index = uav_index;
+      }
+   }
+
+   /* Reset the rest of the ua views list */
+   for (unsigned u = *num_uavs;
+        u < ARRAY_SIZE(svga->state.hw_draw.uaViewIds); u++) {
+      uaViewIds[u] = SVGA3D_INVALID_ID;
+      uaViews[u] = NULL;
+   }
+
+   return PIPE_OK;
+}
+
+
+/**
+ * A helper function to save the current hw uav state.
+ */
+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)
+{
+   enum pipe_shader_type first_shader, last_shader;
+   unsigned i;
+
+   if (pipe_type == SVGA_PIPE_GRAPHICS) {
+      first_shader = PIPE_SHADER_VERTEX;
+      last_shader = PIPE_SHADER_TESS_EVAL;
+   } else {
+      first_shader = PIPE_SHADER_COMPUTE;
+      last_shader = PIPE_SHADER_COMPUTE;
+   }
+
+   for (enum pipe_shader_type shader = first_shader;
+        shader <= last_shader; shader++) {
+
+      /**
+       * Save the current shader images
+       */
+      for (i = 0; i < ARRAY_SIZE(svga->curr.image_views[0]); i++) {
+         struct svga_image_view *cur_image_view =
+            &svga->curr.image_views[shader][i];
+         struct svga_image_view *hw_image_view =
+            &svga->state.hw_draw.image_views[shader][i];
+
+         /* Save the hw state for image view */
+         *hw_image_view = *cur_image_view;
+      }
+
+      /**
+       * Save the current shader buffers
+       */
+      for (i = 0; i < ARRAY_SIZE(svga->curr.shader_buffers[0]); i++) {
+         struct svga_shader_buffer *cur_shader_buffer =
+            &svga->curr.shader_buffers[shader][i];
+         struct svga_shader_buffer *hw_shader_buffer =
+            &svga->state.hw_draw.shader_buffers[shader][i];
+
+         /* Save the hw state for image view */
+         *hw_shader_buffer = *cur_shader_buffer;
+      }
+
+      svga->state.hw_draw.num_image_views[shader] =
+         svga->curr.num_image_views[shader];
+      svga->state.hw_draw.num_shader_buffers[shader] =
+         svga->curr.num_shader_buffers[shader];
+   }
+
+   /**
+    * Save the current atomic buffers
+    */
+   for (i = 0; i < ARRAY_SIZE(svga->curr.atomic_buffers); i++) {
+      struct svga_shader_buffer *cur_buf = &svga->curr.atomic_buffers[i];
+      struct svga_shader_buffer *hw_buf = &svga->state.hw_draw.atomic_buffers[i];
+
+      /* Save the hw state for atomic buffers */
+      *hw_buf = *cur_buf;
+   }
+
+   svga->state.hw_draw.num_atomic_buffers = svga->curr.num_atomic_buffers;
+
+   /**
+    * Save the hw state for uaviews
+    */
+   if (pipe_type == SVGA_PIPE_COMPUTE) {
+      svga->state.hw_draw.num_cs_uavs = num_uavs;
+      memcpy(svga->state.hw_draw.csUAViewIds, uaViewIds,
+             sizeof svga->state.hw_draw.csUAViewIds);
+      memcpy(svga->state.hw_draw.csUAViews, uaViews,
+             sizeof svga->state.hw_draw.csUAViews);
+   }
+   else {
+      svga->state.hw_draw.num_uavs = num_uavs;
+      memcpy(svga->state.hw_draw.uaViewIds, uaViewIds,
+             sizeof svga->state.hw_draw.uaViewIds);
+      memcpy(svga->state.hw_draw.uaViews, uaViews,
+             sizeof svga->state.hw_draw.uaViews);
+   }
+
+   /* purge the uav cache */
+   svga_uav_cache_purge(svga, pipe_type);
+}
+
+
+/**
+ * A helper function to determine if we need to resend the SetUAViews command.
+ * We need to resend the SetUAViews command when uavSpliceIndex is to
+ * be changed because the existing index overlaps with render target views, or
+ * the image views/shader buffers are changed.
+ */
+static bool
+need_to_set_uav(struct svga_context *svga,
+                int uavSpliceIndex,
+                unsigned num_uavs,
+                SVGA3dUAViewId *uaViewIds,
+                struct svga_winsys_surface **uaViews)
+{
+   /* If number of render target views changed */
+   if (uavSpliceIndex != svga->state.hw_draw.uavSpliceIndex)
+      return true;
+
+   /* If number of render target views + number of ua views exceeds
+    * the max uav count, we will need to trim the ua views.
+    */
+   if ((uavSpliceIndex + num_uavs) > SVGA_MAX_UAVIEWS)
+      return true;
+
+   /* If uavs are different */
+   if (memcmp(svga->state.hw_draw.uaViewIds, uaViewIds,
+              sizeof svga->state.hw_draw.uaViewIds) ||
+       memcmp(svga->state.hw_draw.uaViews, uaViews,
+              sizeof svga->state.hw_draw.uaViews))
+      return true;
+
+   /* If image views are different */
+   for (enum pipe_shader_type shader = PIPE_SHADER_VERTEX;
+        shader < PIPE_SHADER_COMPUTE; shader++) {
+      unsigned num_image_views = svga->curr.num_image_views[shader];
+      if ((num_image_views != svga->state.hw_draw.num_image_views[shader]) ||
+          memcmp(svga->state.hw_draw.image_views[shader],
+                 svga->curr.image_views[shader],
+                 num_image_views * sizeof(struct svga_image_view)))
+         return true;
+
+      /* If shader buffers are different */
+      unsigned num_shader_buffers = svga->curr.num_shader_buffers[shader];
+      if ((num_shader_buffers != svga->state.hw_draw.num_shader_buffers[shader]) ||
+          memcmp(svga->state.hw_draw.shader_buffers[shader],
+                 svga->curr.shader_buffers[shader],
+                 num_shader_buffers * sizeof(struct svga_shader_buffer)))
+         return true;
+   }
+
+   /* If atomic buffers are different */
+   unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
+   if ((num_atomic_buffers != svga->state.hw_draw.num_atomic_buffers) ||
+       memcmp(svga->state.hw_draw.atomic_buffers, svga->curr.atomic_buffers,
+              num_atomic_buffers * sizeof(struct svga_shader_buffer)))
+      return true;
+
+   return false;
+}
+
+
+/**
+ * Update ua views in the HW for the draw pipeline by sending the
+ * SetUAViews command.
+ */
+static enum pipe_error
+update_uav(struct svga_context *svga, uint64_t dirty)
+{
+   enum pipe_error ret = PIPE_OK;
+   unsigned num_uavs = 0;
+   SVGA3dUAViewId uaViewIds[SVGA_MAX_UAVIEWS];
+   struct svga_winsys_surface *uaViews[SVGA_MAX_UAVIEWS];
+
+   /* Determine the uavSpliceIndex since uav and render targets view share the
+    * same bind points.
+    */
+   int uavSpliceIndex = svga->state.hw_clear.num_rendertargets;
+
+   /* Number of free uav entries available for shader images and buffers */
+   unsigned num_free_uavs = SVGA_MAX_UAVIEWS - uavSpliceIndex;
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_UPDATEUAV);
+
+   /* Create the uav list for graphics pipeline */
+   ret = svga_create_uav_list(svga, SVGA_PIPE_GRAPHICS, num_free_uavs,
+                              &num_uavs, uaViewIds, uaViews);
+   if (ret != PIPE_OK)
+      goto done;
+
+   /* check to see if we need to resend the SetUAViews command */
+   if (!need_to_set_uav(svga, uavSpliceIndex, num_uavs, uaViewIds, uaViews))
+      goto done;
+
+   /* Send the SetUAViews command */
+   SVGA_DBG(DEBUG_UAV, "%s: SetUAViews uavSpliceIndex=%d", __FUNCTION__,
+            uavSpliceIndex);
+
+#ifdef DEBUG
+   for (unsigned i = 0; i < ARRAY_SIZE(uaViewIds); i++) {
+      SVGA_DBG(DEBUG_UAV, " %d ", uaViewIds[i]);
+   }
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   ret = SVGA3D_sm5_SetUAViews(svga->swc, uavSpliceIndex, SVGA_MAX_UAVIEWS,
+                               uaViewIds, uaViews);
+   if (ret != PIPE_OK)
+      goto done;
+
+   /* Save the uav hw state */
+   svga_save_uav_state(svga, SVGA_PIPE_GRAPHICS, num_uavs, uaViewIds, uaViews);
+
+   /* Save the uavSpliceIndex as this determines the starting register index
+    * for the first uav used in the shader
+    */
+   svga->state.hw_draw.uavSpliceIndex = uavSpliceIndex;
+
+done:
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return ret;
+}
+
+
+struct svga_tracked_state svga_hw_uav = {
+   "shader image view",
+   (SVGA_NEW_IMAGE_VIEW |
+    SVGA_NEW_SHADER_BUFFER |
+    SVGA_NEW_FRAME_BUFFER),
+   update_uav
+};
+
+
+/**
+ * A helper function to determine if we need to resend the SetCSUAViews command.
+ */
+static bool
+need_to_set_cs_uav(struct svga_context *svga,
+                   unsigned num_uavs,
+                   SVGA3dUAViewId *uaViewIds,
+                   struct svga_winsys_surface **uaViews)
+{
+   enum pipe_shader_type shader = PIPE_SHADER_COMPUTE;
+
+   if (svga->state.hw_draw.num_cs_uavs != num_uavs)
+      return true;
+
+   /* If uavs are different */
+   if (memcmp(svga->state.hw_draw.csUAViewIds, uaViewIds,
+              sizeof svga->state.hw_draw.csUAViewIds) ||
+       memcmp(svga->state.hw_draw.csUAViews, uaViews,
+              sizeof svga->state.hw_draw.csUAViews))
+      return true;
+
+   /* If image views are different */
+   unsigned num_image_views = svga->curr.num_image_views[shader];
+   if ((num_image_views != svga->state.hw_draw.num_image_views[shader]) ||
+       memcmp(svga->state.hw_draw.image_views[shader],
+              svga->curr.image_views[shader],
+              num_image_views * sizeof(struct svga_image_view)))
+      return true;
+
+   /* If atomic buffers are different */
+   unsigned num_atomic_buffers = svga->curr.num_atomic_buffers;
+   if ((num_atomic_buffers != svga->state.hw_draw.num_atomic_buffers) ||
+       memcmp(svga->state.hw_draw.atomic_buffers, svga->curr.atomic_buffers,
+              num_atomic_buffers * sizeof(struct svga_shader_buffer)))
+      return true;
+
+   return false;
+}
+
+
+/**
+ * Update ua views in the HW for the compute pipeline by sending the
+ * SetCSUAViews command.
+ */
+static enum pipe_error
+update_cs_uav(struct svga_context *svga, uint64_t dirty)
+{
+   enum pipe_error ret = PIPE_OK;
+   unsigned num_uavs = 0;
+   SVGA3dUAViewId uaViewIds[SVGA_MAX_UAVIEWS];
+   struct svga_winsys_surface *uaViews[SVGA_MAX_UAVIEWS];
+
+   /* Number of free uav entries available for shader images and buffers */
+   unsigned num_free_uavs = SVGA_MAX_UAVIEWS;
+
+   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_UPDATECSUAV);
+
+   /* Create the uav list */
+   ret = svga_create_uav_list(svga, SVGA_PIPE_COMPUTE, num_free_uavs,
+                              &num_uavs, uaViewIds, uaViews);
+   if (ret != PIPE_OK)
+      goto done;
+
+   /* Check to see if we need to resend the CSSetUAViews command */
+   if (!need_to_set_cs_uav(svga, num_uavs, uaViewIds, uaViews))
+      goto done;
+
+   /* Send the uaviews to compute */
+
+   SVGA_DBG(DEBUG_UAV, "%s: SetCSUAViews", __FUNCTION__);
+
+#ifdef DEBUG
+   for (unsigned i = 0; i < ARRAY_SIZE(uaViewIds); i++) {
+      SVGA_DBG(DEBUG_UAV, " %d ", uaViewIds[i]);
+   }
+   SVGA_DBG(DEBUG_UAV, "\n");
+#endif
+
+   ret = SVGA3D_sm5_SetCSUAViews(svga->swc, SVGA_MAX_UAVIEWS,
+                                 uaViewIds, uaViews);
+   if (ret != PIPE_OK)
+      goto done;
+
+   /* Save the uav hw state */
+   svga_save_uav_state(svga, SVGA_PIPE_COMPUTE, num_uavs, uaViewIds, uaViews);
+
+done:
+   SVGA_STATS_TIME_POP(svga_sws(svga));
+   return ret;
+}
+
+
+struct svga_tracked_state svga_hw_cs_uav = {
+   "shader image view",
+   (SVGA_NEW_IMAGE_VIEW |
+    SVGA_NEW_SHADER_BUFFER |
+    SVGA_NEW_FRAME_BUFFER),
+   update_cs_uav
+};
index a9435a0..dd424fc 100644 (file)
@@ -1,5 +1,5 @@
 /**********************************************************
- * Copyright 1998-2013 VMware, Inc.  All rights reserved.
+ * Copyright 1998-2022 VMware, Inc.  All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation