diff --git a/src/gallium/drivers/svga/meson.build b/src/gallium/drivers/svga/meson.build index d3bdf5c2dee..acdb6c9b6f0 100644 --- a/src/gallium/drivers/svga/meson.build +++ b/src/gallium/drivers/svga/meson.build @@ -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', diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h index 0af095f7ce8..08be8e6d061 100644 --- a/src/gallium/drivers/svga/svga_context.h +++ b/src/gallium/drivers/svga/svga_context.h @@ -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 diff --git a/src/gallium/drivers/svga/svga_debug.h b/src/gallium/drivers/svga/svga_debug.h index cdad858b045..8b43279a9ac 100644 --- a/src/gallium/drivers/svga/svga_debug.h +++ b/src/gallium/drivers/svga/svga_debug.h @@ -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 index 00000000000..4457f6cb385 --- /dev/null +++ b/src/gallium/drivers/svga/svga_image_view.c @@ -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 index 00000000000..6390b933632 --- /dev/null +++ b/src/gallium/drivers/svga/svga_image_view.h @@ -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 index 00000000000..f6f3b4f3572 --- /dev/null +++ b/src/gallium/drivers/svga/svga_pipe_cs.c @@ -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; +} diff --git a/src/gallium/drivers/svga/svga_resource_buffer.h b/src/gallium/drivers/svga/svga_resource_buffer.h index 97649d9724d..f6e3e682747 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.h +++ b/src/gallium/drivers/svga/svga_resource_buffer.h @@ -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 * diff --git a/src/gallium/drivers/svga/svga_shader.h b/src/gallium/drivers/svga/svga_shader.h index 472499c919b..dafcbc021e1 100644 --- a/src/gallium/drivers/svga/svga_shader.h +++ b/src/gallium/drivers/svga/svga_shader.h @@ -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 index 00000000000..b61eff58a5a --- /dev/null +++ b/src/gallium/drivers/svga/svga_shader_buffer.c @@ -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 index 00000000000..7b63b9ee719 --- /dev/null +++ b/src/gallium/drivers/svga/svga_shader_buffer.h @@ -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 index 00000000000..1154d492360 --- /dev/null +++ b/src/gallium/drivers/svga/svga_state_cs.c @@ -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 index 00000000000..a4da2c84229 --- /dev/null +++ b/src/gallium/drivers/svga/svga_state_uav.c @@ -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 +}; diff --git a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c index a9435a09838..dd424fcb55f 100644 --- a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c +++ b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c @@ -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