'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',
'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',
'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',
#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 */
#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;
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 {
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;
};
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;
/* 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];
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;
unsigned tes:1;
unsigned cs:1;
unsigned query:1;
+ unsigned uav:1;
} flags;
unsigned val;
} rebind;
boolean passthrough;
} tcs;
+ struct svga_cache_uav cache_uav;
+ struct pipe_resource *dummy_resource;
};
/* A flag for each frontend state object:
#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 );
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
#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
--- /dev/null
+/**********************************************************
+ * 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;
+}
--- /dev/null
+/**********************************************************
+ * 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 */
--- /dev/null
+/**********************************************************
+ * 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;
+}
unsigned bind_flags;
struct svga_host_surface_cache_key key;
struct svga_winsys_surface *handle;
+ enum svga_surface_state surface_state;
};
/**
*/
struct list_head surfaces;
+ /* Current surface structure */
+ struct svga_buffer_surface *bufsurf;
+
/**
* Information about ongoing and past map operations.
*/
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
} 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 *
/* compute shader */
struct {
unsigned grid_size[3];
+ unsigned mem_size;
} cs;
/* any shader type */
--- /dev/null
+/**********************************************************
+ * 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;
+}
--- /dev/null
+/**********************************************************
+ * 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 */
--- /dev/null
+/**********************************************************
+ * 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
+};
--- /dev/null
+/**********************************************************
+ * 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
+};
/**********************************************************
- * 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