/********************************************************** * 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); } 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; }