1bf215546Sopenharmony_ci/**********************************************************
2bf215546Sopenharmony_ci * Copyright 2022 VMware, Inc.  All rights reserved.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person
5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation
6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without
7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy,
8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies
9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is
10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be
13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22bf215546Sopenharmony_ci * SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci **********************************************************/
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "pipe/p_defines.h"
27bf215546Sopenharmony_ci#include "util/u_bitmask.h"
28bf215546Sopenharmony_ci#include "util/format/u_format.h"
29bf215546Sopenharmony_ci#include "util/u_inlines.h"
30bf215546Sopenharmony_ci#include "util/u_math.h"
31bf215546Sopenharmony_ci#include "util/u_memory.h"
32bf215546Sopenharmony_ci#include "tgsi/tgsi_parse.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "svga_context.h"
35bf215546Sopenharmony_ci#include "svga_cmd.h"
36bf215546Sopenharmony_ci#include "svga_debug.h"
37bf215546Sopenharmony_ci#include "svga_resource_buffer.h"
38bf215546Sopenharmony_ci#include "svga_resource_texture.h"
39bf215546Sopenharmony_ci#include "svga_surface.h"
40bf215546Sopenharmony_ci#include "svga_sampler_view.h"
41bf215546Sopenharmony_ci#include "svga_format.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/**
45bf215546Sopenharmony_ci * Create a uav object for the specified shader image view
46bf215546Sopenharmony_ci */
47bf215546Sopenharmony_ciSVGA3dUAViewId
48bf215546Sopenharmony_cisvga_create_uav_image(struct svga_context *svga,
49bf215546Sopenharmony_ci                      const struct pipe_image_view *image)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(svga->pipe.screen);
52bf215546Sopenharmony_ci   SVGA3dSurfaceFormat svga_format;
53bf215546Sopenharmony_ci   SVGA3dUAViewDesc desc;
54bf215546Sopenharmony_ci   SVGA3dUAViewId uaViewId;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   assert(image);
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci   /* Make sure the translated svga format supports uav */
59bf215546Sopenharmony_ci   svga_format = svga_translate_format(ss, image->format,
60bf215546Sopenharmony_ci                                       PIPE_BIND_SHADER_IMAGE);
61bf215546Sopenharmony_ci   if (svga_format == SVGA3D_FORMAT_INVALID)
62bf215546Sopenharmony_ci      return SVGA3D_INVALID_ID;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   struct pipe_resource *res = image->resource;
65bf215546Sopenharmony_ci   struct svga_winsys_surface *surf;
66bf215546Sopenharmony_ci   unsigned resourceDim;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   /* resolve target to resource dimension */
69bf215546Sopenharmony_ci   resourceDim = svga_resource_type(res->target);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   memset(&desc, 0, sizeof(desc));
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   if (resourceDim == SVGA3D_RESOURCE_BUFFER) {
74bf215546Sopenharmony_ci      unsigned block_width, block_height, bytes_per_block;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci      svga_format_size(svga_format, &block_width, &block_height,
77bf215546Sopenharmony_ci                       &bytes_per_block);
78bf215546Sopenharmony_ci      surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
79bf215546Sopenharmony_ci      desc.buffer.firstElement = image->u.buf.offset / bytes_per_block;
80bf215546Sopenharmony_ci      desc.buffer.numElements = image->u.buf.size / bytes_per_block;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci      /* mark this buffer as being used in uav */
83bf215546Sopenharmony_ci      struct svga_buffer *sbuf = svga_buffer(res);
84bf215546Sopenharmony_ci      sbuf->uav = TRUE;
85bf215546Sopenharmony_ci   }
86bf215546Sopenharmony_ci   else if (resourceDim == SVGA3D_RESOURCE_TEXTURE1D ||
87bf215546Sopenharmony_ci            resourceDim == SVGA3D_RESOURCE_TEXTURE2D) {
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci      struct svga_texture *tex = svga_texture(res);
90bf215546Sopenharmony_ci      surf = tex->handle;
91bf215546Sopenharmony_ci      desc.tex.mipSlice = image->u.tex.level;
92bf215546Sopenharmony_ci      desc.tex.firstArraySlice = image->u.tex.first_layer;
93bf215546Sopenharmony_ci      desc.tex.arraySize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci   else {
96bf215546Sopenharmony_ci      assert(resourceDim == SVGA3D_RESOURCE_TEXTURE3D);
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci      struct svga_texture *tex = svga_texture(res);
99bf215546Sopenharmony_ci      surf = tex->handle;
100bf215546Sopenharmony_ci      desc.tex3D.mipSlice = image->u.tex.level;
101bf215546Sopenharmony_ci      desc.tex3D.firstW = image->u.tex.first_layer;
102bf215546Sopenharmony_ci      desc.tex3D.wSize = image->u.tex.last_layer - image->u.tex.first_layer + 1;
103bf215546Sopenharmony_ci   }
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci   uaViewId = svga_create_uav(svga, &desc, svga_format, resourceDim, surf);
106bf215546Sopenharmony_ci   if (uaViewId == SVGA3D_INVALID_ID)
107bf215546Sopenharmony_ci      return uaViewId;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   SVGA_DBG(DEBUG_IMAGE, "%s: resource=0x%x dim=%d format=%d uaViewId=%d\n",
110bf215546Sopenharmony_ci            __FUNCTION__, res, resourceDim, svga_format, uaViewId);
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   return uaViewId;
113bf215546Sopenharmony_ci}
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci/**
117bf215546Sopenharmony_ci * Set shader images
118bf215546Sopenharmony_ci */
119bf215546Sopenharmony_cistatic void
120bf215546Sopenharmony_cisvga_set_shader_images(struct pipe_context *pipe,
121bf215546Sopenharmony_ci                       enum pipe_shader_type shader,
122bf215546Sopenharmony_ci                       unsigned start,
123bf215546Sopenharmony_ci                       unsigned num,
124bf215546Sopenharmony_ci                       unsigned unbind_num_trailing_slots,
125bf215546Sopenharmony_ci                       const struct pipe_image_view *images)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   struct svga_context *svga = svga_context(pipe);
128bf215546Sopenharmony_ci   const struct pipe_image_view *img = images;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   assert(svga_have_gl43(svga));
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   assert(start + num <= SVGA_MAX_IMAGES);
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   if (images) {
135bf215546Sopenharmony_ci      for (unsigned i = start; i < start + num; i++, img++) {
136bf215546Sopenharmony_ci         struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci         if (img) {
139bf215546Sopenharmony_ci            cur_image_view->desc = *img;
140bf215546Sopenharmony_ci            if (img->resource == NULL) {
141bf215546Sopenharmony_ci               /* Use a dummy resource if the image view is created with a NULL resource */
142bf215546Sopenharmony_ci               if (svga->dummy_resource == NULL) {
143bf215546Sopenharmony_ci                  struct svga_screen *ss = svga_screen(svga->pipe.screen);
144bf215546Sopenharmony_ci                  struct pipe_resource templ;
145bf215546Sopenharmony_ci                  struct pipe_resource *res;
146bf215546Sopenharmony_ci                  templ.target = PIPE_BUFFER;
147bf215546Sopenharmony_ci                  templ.format = PIPE_FORMAT_R8_UNORM;
148bf215546Sopenharmony_ci                  templ.bind = PIPE_BIND_SHADER_BUFFER;
149bf215546Sopenharmony_ci                  templ.width0 = 64;
150bf215546Sopenharmony_ci                  templ.height0 = 1;
151bf215546Sopenharmony_ci                  templ.depth0 = 1;
152bf215546Sopenharmony_ci                  templ.array_size = 1;
153bf215546Sopenharmony_ci                  res = ss->screen.resource_create(&ss->screen, &templ);
154bf215546Sopenharmony_ci                  pipe_resource_reference(&svga->dummy_resource, res);
155bf215546Sopenharmony_ci               }
156bf215546Sopenharmony_ci               pipe_resource_reference(&cur_image_view->resource,
157bf215546Sopenharmony_ci                                       svga->dummy_resource);
158bf215546Sopenharmony_ci            }
159bf215546Sopenharmony_ci            else {
160bf215546Sopenharmony_ci               pipe_resource_reference(&cur_image_view->resource,
161bf215546Sopenharmony_ci                                       img->resource);
162bf215546Sopenharmony_ci            }
163bf215546Sopenharmony_ci         }
164bf215546Sopenharmony_ci         else {
165bf215546Sopenharmony_ci            pipe_resource_reference(&cur_image_view->resource, NULL);
166bf215546Sopenharmony_ci         }
167bf215546Sopenharmony_ci         cur_image_view->uav_index = -1;
168bf215546Sopenharmony_ci      }
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   /* unbind trailing slots */
172bf215546Sopenharmony_ci   for (unsigned j = 0, i = start + num; j < unbind_num_trailing_slots;
173bf215546Sopenharmony_ci        i++, j++) {
174bf215546Sopenharmony_ci      struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
175bf215546Sopenharmony_ci      cur_image_view->uav_index = -1;
176bf215546Sopenharmony_ci      pipe_resource_reference(&cur_image_view->resource, NULL);
177bf215546Sopenharmony_ci   }
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci   /* number of bound image views */
180bf215546Sopenharmony_ci   svga->curr.num_image_views[shader] = start + num;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci#ifdef DEBUG
183bf215546Sopenharmony_ci   SVGA_DBG(DEBUG_UAV, "%s: num_image_views=%d start=%d num=%d unbind_num_trailing_slots=%d\n",
184bf215546Sopenharmony_ci            __FUNCTION__, svga->curr.num_image_views[shader], start, num,
185bf215546Sopenharmony_ci            unbind_num_trailing_slots);
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   for (unsigned i = start; i < start + num; i++) {
188bf215546Sopenharmony_ci      struct svga_image_view *cur_image_view = &svga->curr.image_views[shader][i];
189bf215546Sopenharmony_ci      struct pipe_image_view *img = &cur_image_view->desc;
190bf215546Sopenharmony_ci      if (img->resource) {
191bf215546Sopenharmony_ci         if (img->resource->target == PIPE_BUFFER) {
192bf215546Sopenharmony_ci            SVGA_DBG(DEBUG_UAV, "   buffer res=0x%x format=%d offset=%d size=%d\n",
193bf215546Sopenharmony_ci                     img->resource, img->format,
194bf215546Sopenharmony_ci                     img->u.buf.offset, img->u.buf.size);
195bf215546Sopenharmony_ci         }
196bf215546Sopenharmony_ci         else {
197bf215546Sopenharmony_ci            SVGA_DBG(DEBUG_UAV,
198bf215546Sopenharmony_ci               "   texture res=0x%x format=%d first_layer=%d last_layer=%d level=%d\n",
199bf215546Sopenharmony_ci                     img->resource, img->format, img->u.tex.first_layer,
200bf215546Sopenharmony_ci                     img->u.tex.last_layer, img->u.tex.level);
201bf215546Sopenharmony_ci         }
202bf215546Sopenharmony_ci      }
203bf215546Sopenharmony_ci      else {
204bf215546Sopenharmony_ci         SVGA_DBG(DEBUG_UAV, "   res=NULL\n");
205bf215546Sopenharmony_ci      }
206bf215546Sopenharmony_ci   }
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   SVGA_DBG(DEBUG_UAV, "\n");
209bf215546Sopenharmony_ci#endif
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   /* purge any unused uav objects */
212bf215546Sopenharmony_ci   svga_destroy_uav(svga);
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   svga->dirty |= SVGA_NEW_IMAGE_VIEW;
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci/**
219bf215546Sopenharmony_ci *  Initialize shader images gallium interface
220bf215546Sopenharmony_ci */
221bf215546Sopenharmony_civoid
222bf215546Sopenharmony_cisvga_init_shader_image_functions(struct svga_context *svga)
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci   if (svga_have_gl43(svga)) {
225bf215546Sopenharmony_ci      svga->pipe.set_shader_images = svga_set_shader_images;
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   /* Initialize shader image views */
229bf215546Sopenharmony_ci   for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; ++shader) {
230bf215546Sopenharmony_ci      struct svga_image_view *hw_image_views =
231bf215546Sopenharmony_ci         &svga->state.hw_draw.image_views[shader][0];
232bf215546Sopenharmony_ci      struct svga_image_view *cur_image_views =
233bf215546Sopenharmony_ci         &svga->curr.image_views[shader][0];
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci      for (unsigned i = 0; i < ARRAY_SIZE(svga->curr.image_views[shader]);
236bf215546Sopenharmony_ci           i++, hw_image_views++, cur_image_views++) {
237bf215546Sopenharmony_ci         hw_image_views->resource = NULL;
238bf215546Sopenharmony_ci         cur_image_views->resource = NULL;
239bf215546Sopenharmony_ci      }
240bf215546Sopenharmony_ci   }
241bf215546Sopenharmony_ci   memset(svga->state.hw_draw.num_image_views, 0,
242bf215546Sopenharmony_ci          sizeof(svga->state.hw_draw.num_image_views));
243bf215546Sopenharmony_ci}
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci/**
247bf215546Sopenharmony_ci * Cleanup shader image state
248bf215546Sopenharmony_ci */
249bf215546Sopenharmony_civoid
250bf215546Sopenharmony_cisvga_cleanup_shader_image_state(struct svga_context *svga)
251bf215546Sopenharmony_ci{
252bf215546Sopenharmony_ci   if (!svga_have_gl43(svga))
253bf215546Sopenharmony_ci      return;
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   svga_destroy_uav(svga);
256bf215546Sopenharmony_ci}
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci/**
260bf215546Sopenharmony_ci * Validate shader image view resources to ensure any pending changes to
261bf215546Sopenharmony_ci * texture buffers are emitted before they are referenced in image views.
262bf215546Sopenharmony_ci * The helper function also rebinds the image view resources if the rebind flag
263bf215546Sopenharmony_ci * is specified.
264bf215546Sopenharmony_ci */
265bf215546Sopenharmony_cienum pipe_error
266bf215546Sopenharmony_cisvga_validate_image_view_resources(struct svga_context *svga,
267bf215546Sopenharmony_ci                                   unsigned count,
268bf215546Sopenharmony_ci                                   struct svga_image_view *images,
269bf215546Sopenharmony_ci                                   bool rebind)
270bf215546Sopenharmony_ci{
271bf215546Sopenharmony_ci   assert(svga_have_gl43(svga));
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   struct svga_winsys_surface *surf;
274bf215546Sopenharmony_ci   enum pipe_error ret;
275bf215546Sopenharmony_ci   unsigned i;
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   for (i = 0; i < count; i++) {
278bf215546Sopenharmony_ci      struct pipe_resource *res = images[i].resource;
279bf215546Sopenharmony_ci      if (res) {
280bf215546Sopenharmony_ci         assert(res == images[i].desc.resource);
281bf215546Sopenharmony_ci         if (res->target == PIPE_BUFFER) {
282bf215546Sopenharmony_ci            struct svga_buffer *sbuf = svga_buffer(res);
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci            surf = svga_buffer_handle(svga, res, PIPE_BIND_SHADER_IMAGE);
285bf215546Sopenharmony_ci            /* Mark buffer surface as RENDERED */
286bf215546Sopenharmony_ci            svga_set_buffer_rendered_to(sbuf->bufsurf);
287bf215546Sopenharmony_ci         } else {
288bf215546Sopenharmony_ci            struct svga_texture *tex = svga_texture(res);
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci            surf = tex->handle;
291bf215546Sopenharmony_ci            /* Mark texture as RENDERED */
292bf215546Sopenharmony_ci            svga_set_texture_rendered_to(tex);
293bf215546Sopenharmony_ci         }
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci         assert(surf);
296bf215546Sopenharmony_ci         if (rebind) {
297bf215546Sopenharmony_ci            ret = svga->swc->resource_rebind(svga->swc, surf, NULL,
298bf215546Sopenharmony_ci                                             SVGA_RELOC_READ|SVGA_RELOC_WRITE);
299bf215546Sopenharmony_ci            if (ret != PIPE_OK)
300bf215546Sopenharmony_ci               return ret;
301bf215546Sopenharmony_ci         }
302bf215546Sopenharmony_ci      }
303bf215546Sopenharmony_ci   }
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   return PIPE_OK;
306bf215546Sopenharmony_ci}
307