From: Neha Bhende Date: Thu, 16 Dec 2021 00:36:39 +0000 (-0800) Subject: svga: Add support for compute shader, shader buffers and image views X-Git-Tag: upstream/22.3.5~13852 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=247c61f2d0454a94bc8b26601f88ed5f0890cedd;p=platform%2Fupstream%2Fmesa.git svga: Add support for compute shader, shader buffers and image views This commit is squash of commits which handles resource creation and management for compute shader, shader buffers and image views. It creates uavs for shader buffers and image views. Reviewed-by: Charmaine Lee Part-of: --- diff --git a/src/gallium/drivers/svga/meson.build b/src/gallium/drivers/svga/meson.build index d3bdf5c..acdb6c9 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 0af095f..08be8e6 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 cdad858..8b43279 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 0000000..4457f6c --- /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 0000000..6390b93 --- /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 0000000..f6f3b4f --- /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 97649d9..f6e3e68 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 472499c..dafcbc0 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 0000000..b61eff5 --- /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 0000000..7b63b9e --- /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 0000000..1154d49 --- /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 0000000..a4da2c8 --- /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 a9435a0..dd424fc 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