1 /*
2 * Copyright (c) 2022-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "pipe/p_defines.h"
9 #include "util/u_bitmask.h"
10 #include "util/format/u_format.h"
11 #include "util/u_inlines.h"
12 #include "util/u_math.h"
13 #include "util/u_memory.h"
14
15 #include "svga_context.h"
16 #include "svga_cmd.h"
17 #include "svga_debug.h"
18 #include "svga_resource_buffer.h"
19 #include "svga_resource_texture.h"
20 #include "svga_surface.h"
21 #include "svga_sampler_view.h"
22 #include "svga_format.h"
23
24
25 /**
26 * Create a uav object for the specified shader image view
27 */
28 SVGA3dUAViewId
svga_create_uav_image(struct svga_context * svga,const struct pipe_image_view * image)29 svga_create_uav_image(struct svga_context *svga,
30 const struct pipe_image_view *image)
31 {
32 struct svga_screen *ss = svga_screen(svga->pipe.screen);
33 SVGA3dSurfaceFormat svga_format;
34 SVGA3dUAViewDesc desc;
35 SVGA3dUAViewId uaViewId;
36
37 assert(image);
38
39 /* Make sure the translated svga format supports uav */
40 svga_format = svga_translate_format(ss, image->format,
41 PIPE_BIND_SHADER_IMAGE);
42 if (svga_format == SVGA3D_FORMAT_INVALID)
43 return SVGA3D_INVALID_ID;
44
45 struct pipe_resource *res = image->resource;
46 struct svga_winsys_surface *surf;
47 unsigned resourceDim;
48
49 /* resolve target to resource dimension */
50 resourceDim = svga_resource_type(res->target);
51
52 memset(&desc, 0, sizeof(desc));
53
54 if (resourceDim == SVGA3D_RESOURCE_BUFFER) {
55 unsigned block_width, block_height, bytes_per_block;
56
57 svga_format_size(svga_format, &block_width, &block_height,
58 &bytes_per_block);
59 surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
60 desc.buffer.firstElement = image->u.buf.offset / bytes_per_block;
61 desc.buffer.numElements = image->u.buf.size / bytes_per_block;
62
63 /* mark this buffer as being used in uav */
64 struct svga_buffer *sbuf = svga_buffer(res);
65 sbuf->uav = true;
66 }
67 else if (resourceDim == SVGA3D_RESOURCE_TEXTURE1D ||
68 resourceDim == SVGA3D_RESOURCE_TEXTURE2D) {
69
70 struct svga_texture *tex = svga_texture(res);
71 surf = tex->handle;
72 desc.tex.mipSlice = image->u.tex.level;
73 desc.tex.firstArraySlice = image->u.tex.first_layer;
74 desc.tex.arraySize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
75 }
76 else {
77 assert(resourceDim == SVGA3D_RESOURCE_TEXTURE3D);
78
79 struct svga_texture *tex = svga_texture(res);
80 surf = tex->handle;
81 desc.tex3D.mipSlice = image->u.tex.level;
82 desc.tex3D.firstW = image->u.tex.first_layer;
83 desc.tex3D.wSize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
84 }
85
86 uaViewId = svga_create_uav(svga, &desc, svga_format, resourceDim, surf);
87 if (uaViewId == SVGA3D_INVALID_ID)
88 return uaViewId;
89
90 SVGA_DBG(DEBUG_IMAGE, "%s: resource=0x%x dim=%d format=%d uaViewId=%d\n",
91 __func__, res, resourceDim, svga_format, uaViewId);
92
93 return uaViewId;
94 }
95
96
97 /**
98 * Set shader images
99 */
100 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)101 svga_set_shader_images(struct pipe_context *pipe,
102 enum pipe_shader_type shader,
103 unsigned start,
104 unsigned num,
105 unsigned unbind_num_trailing_slots,
106 const struct pipe_image_view *images)
107 {
108 struct svga_context *svga = svga_context(pipe);
109 const struct pipe_image_view *img = images;
110
111 assert(svga_have_gl43(svga));
112
113 assert(start + num <= SVGA_MAX_IMAGES);
114
115 if (images) {
116 for (unsigned i = start; i < start + num; i++, img++) {
117 struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
118
119 if (img) {
120 cur_image_view->desc = *img;
121 if (img->resource == NULL) {
122 /* Use a dummy resource if the image view is created with a NULL resource */
123 if (svga->dummy_resource == NULL) {
124 struct svga_screen *ss = svga_screen(svga->pipe.screen);
125 struct pipe_resource templ;
126 struct pipe_resource *res;
127 templ.target = PIPE_BUFFER;
128 templ.format = PIPE_FORMAT_R8_UNORM;
129 templ.bind = PIPE_BIND_SHADER_BUFFER;
130 templ.width0 = 64;
131 templ.height0 = 1;
132 templ.depth0 = 1;
133 templ.array_size = 1;
134 res = ss->screen.resource_create(&ss->screen, &templ);
135 pipe_resource_reference(&svga->dummy_resource, res);
136 }
137 pipe_resource_reference(&cur_image_view->resource,
138 svga->dummy_resource);
139 }
140 else {
141 pipe_resource_reference(&cur_image_view->resource,
142 img->resource);
143 }
144 }
145 else {
146 pipe_resource_reference(&cur_image_view->resource, NULL);
147 }
148 cur_image_view->uav_index = -1;
149 }
150 }
151
152 /* unbind trailing slots */
153 for (unsigned j = 0, i = start + num; j < unbind_num_trailing_slots;
154 i++, j++) {
155 struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
156 cur_image_view->uav_index = -1;
157 pipe_resource_reference(&cur_image_view->resource, NULL);
158 }
159
160 /* number of bound image views */
161 svga->curr.num_image_views[shader] = start + num;
162
163 #if MESA_DEBUG
164 SVGA_DBG(DEBUG_UAV, "%s: num_image_views=%d start=%d num=%d unbind_num_trailing_slots=%d\n",
165 __func__, svga->curr.num_image_views[shader], start, num,
166 unbind_num_trailing_slots);
167
168 for (unsigned i = start; i < start + num; i++) {
169 struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
170 struct pipe_image_view *img = &cur_image_view->desc;
171 if (img->resource) {
172 if (img->resource->target == PIPE_BUFFER) {
173 SVGA_DBG(DEBUG_UAV, " buffer res=0x%x format=%d offset=%d size=%d\n",
174 img->resource, img->format,
175 img->u.buf.offset, img->u.buf.size);
176 }
177 else {
178 SVGA_DBG(DEBUG_UAV,
179 " texture res=0x%x format=%d first_layer=%d last_layer=%d level=%d\n",
180 img->resource, img->format, img->u.tex.first_layer,
181 img->u.tex.last_layer, img->u.tex.level);
182 }
183 }
184 else {
185 SVGA_DBG(DEBUG_UAV, " res=NULL\n");
186 }
187 }
188
189 SVGA_DBG(DEBUG_UAV, "\n");
190 #endif
191
192 /* purge any unused uav objects */
193 svga_destroy_uav(svga);
194
195 svga->dirty |= SVGA_NEW_IMAGE_VIEW;
196 }
197
198
199 /**
200 * Initialize shader images gallium interface
201 */
202 void
svga_init_shader_image_functions(struct svga_context * svga)203 svga_init_shader_image_functions(struct svga_context *svga)
204 {
205 if (svga_have_gl43(svga)) {
206 svga->pipe.set_shader_images = svga_set_shader_images;
207 }
208
209 /* Initialize shader image views */
210 for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; ++shader) {
211 struct svga_image_view *hw_image_views =
212 &svga->state.hw_draw.image_views[shader][0];
213 struct svga_image_view *cur_image_views =
214 &svga->curr.image_views[shader][0];
215
216 for (unsigned i = 0; i < ARRAY_SIZE(svga->curr.image_views[shader]);
217 i++, hw_image_views++, cur_image_views++) {
218 hw_image_views->resource = NULL;
219 cur_image_views->resource = NULL;
220 }
221 }
222 memset(svga->state.hw_draw.num_image_views, 0,
223 sizeof(svga->state.hw_draw.num_image_views));
224 }
225
226
227 /**
228 * Cleanup shader image state
229 */
230 void
svga_cleanup_shader_image_state(struct svga_context * svga)231 svga_cleanup_shader_image_state(struct svga_context *svga)
232 {
233 if (!svga_have_gl43(svga))
234 return;
235
236 svga_destroy_uav(svga);
237 }
238
239
240 /**
241 * Validate shader image view resources to ensure any pending changes to
242 * texture buffers are emitted before they are referenced in image views.
243 * The helper function also rebinds the image view resources if the rebind flag
244 * is specified.
245 */
246 enum pipe_error
svga_validate_image_view_resources(struct svga_context * svga,unsigned count,struct svga_image_view * images,bool rebind)247 svga_validate_image_view_resources(struct svga_context *svga,
248 unsigned count,
249 struct svga_image_view *images,
250 bool rebind)
251 {
252 assert(svga_have_gl43(svga));
253
254 struct svga_winsys_surface *surf;
255 enum pipe_error ret;
256 unsigned i;
257
258 for (i = 0; i < count; i++) {
259 struct pipe_resource *res = images[i].resource;
260 if (res) {
261 assert(res == images[i].desc.resource);
262 if (res->target == PIPE_BUFFER) {
263 struct svga_buffer *sbuf = svga_buffer(res);
264
265 surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
266 /* Mark buffer surface as RENDERED */
267 svga_set_buffer_rendered_to(sbuf->bufsurf);
268 } else {
269 struct svga_texture *tex = svga_texture(res);
270
271 surf = tex->handle;
272 /* Mark texture as RENDERED */
273 svga_set_texture_rendered_to(tex);
274 }
275
276 assert(surf);
277 if (rebind) {
278 ret = svga->swc->resource_rebind(svga->swc, surf, NULL,
279 SVGA_RELOC_READ|SVGA_RELOC_WRITE);
280 if (ret != PIPE_OK)
281 return ret;
282 }
283 }
284 }
285
286 return PIPE_OK;
287 }
288