1b8e80941Smrg/*
2b8e80941Smrg * Copyright 2007 VMware, Inc.
3b8e80941Smrg * Copyright 2016 Advanced Micro Devices, Inc.
4b8e80941Smrg *
5b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
7b8e80941Smrg * to deal in the Software without restriction, including without limitation
8b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
9b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom
10b8e80941Smrg * the Software is furnished to do so, subject to the following conditions:
11b8e80941Smrg *
12b8e80941Smrg * The above copyright notice and this permission notice (including the next
13b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
14b8e80941Smrg * Software.
15b8e80941Smrg *
16b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
23b8e80941Smrg */
24b8e80941Smrg
25b8e80941Smrg/**
26b8e80941Smrg * \file
27b8e80941Smrg *
28b8e80941Smrg * Common helper functions for PBO up- and downloads.
29b8e80941Smrg */
30b8e80941Smrg
31b8e80941Smrg#include "state_tracker/st_context.h"
32b8e80941Smrg#include "state_tracker/st_nir.h"
33b8e80941Smrg#include "state_tracker/st_pbo.h"
34b8e80941Smrg#include "state_tracker/st_cb_bufferobjects.h"
35b8e80941Smrg
36b8e80941Smrg#include "pipe/p_context.h"
37b8e80941Smrg#include "pipe/p_defines.h"
38b8e80941Smrg#include "pipe/p_screen.h"
39b8e80941Smrg#include "cso_cache/cso_context.h"
40b8e80941Smrg#include "tgsi/tgsi_ureg.h"
41b8e80941Smrg#include "util/u_format.h"
42b8e80941Smrg#include "util/u_inlines.h"
43b8e80941Smrg#include "util/u_upload_mgr.h"
44b8e80941Smrg
45b8e80941Smrg#include "compiler/nir/nir_builder.h"
46b8e80941Smrg
47b8e80941Smrg/* Conversion to apply in the fragment shader. */
48b8e80941Smrgenum st_pbo_conversion {
49b8e80941Smrg   ST_PBO_CONVERT_NONE = 0,
50b8e80941Smrg   ST_PBO_CONVERT_UINT_TO_SINT,
51b8e80941Smrg   ST_PBO_CONVERT_SINT_TO_UINT,
52b8e80941Smrg
53b8e80941Smrg   ST_NUM_PBO_CONVERSIONS
54b8e80941Smrg};
55b8e80941Smrg
56b8e80941Smrg/* Final setup of buffer addressing information.
57b8e80941Smrg *
58b8e80941Smrg * buf_offset is in pixels.
59b8e80941Smrg *
60b8e80941Smrg * Returns false if something (e.g. alignment) prevents PBO upload/download.
61b8e80941Smrg */
62b8e80941Smrgbool
63b8e80941Smrgst_pbo_addresses_setup(struct st_context *st,
64b8e80941Smrg                       struct pipe_resource *buf, intptr_t buf_offset,
65b8e80941Smrg                       struct st_pbo_addresses *addr)
66b8e80941Smrg{
67b8e80941Smrg   unsigned skip_pixels;
68b8e80941Smrg
69b8e80941Smrg   /* Check alignment against texture buffer requirements. */
70b8e80941Smrg   {
71b8e80941Smrg      unsigned ofs = (buf_offset * addr->bytes_per_pixel) % st->ctx->Const.TextureBufferOffsetAlignment;
72b8e80941Smrg      if (ofs != 0) {
73b8e80941Smrg         if (ofs % addr->bytes_per_pixel != 0)
74b8e80941Smrg            return false;
75b8e80941Smrg
76b8e80941Smrg         skip_pixels = ofs / addr->bytes_per_pixel;
77b8e80941Smrg         buf_offset -= skip_pixels;
78b8e80941Smrg      } else {
79b8e80941Smrg         skip_pixels = 0;
80b8e80941Smrg      }
81b8e80941Smrg   }
82b8e80941Smrg
83b8e80941Smrg   assert(buf_offset >= 0);
84b8e80941Smrg
85b8e80941Smrg   addr->buffer = buf;
86b8e80941Smrg   addr->first_element = buf_offset;
87b8e80941Smrg   addr->last_element = buf_offset + skip_pixels + addr->width - 1
88b8e80941Smrg         + (addr->height - 1 + (addr->depth - 1) * addr->image_height) * addr->pixels_per_row;
89b8e80941Smrg
90b8e80941Smrg   if (addr->last_element - addr->first_element > st->ctx->Const.MaxTextureBufferSize - 1)
91b8e80941Smrg      return false;
92b8e80941Smrg
93b8e80941Smrg   /* This should be ensured by Mesa before calling our callbacks */
94b8e80941Smrg   assert((addr->last_element + 1) * addr->bytes_per_pixel <= buf->width0);
95b8e80941Smrg
96b8e80941Smrg   addr->constants.xoffset = -addr->xoffset + skip_pixels;
97b8e80941Smrg   addr->constants.yoffset = -addr->yoffset;
98b8e80941Smrg   addr->constants.stride = addr->pixels_per_row;
99b8e80941Smrg   addr->constants.image_size = addr->pixels_per_row * addr->image_height;
100b8e80941Smrg   addr->constants.layer_offset = 0;
101b8e80941Smrg
102b8e80941Smrg   return true;
103b8e80941Smrg}
104b8e80941Smrg
105b8e80941Smrg/* Validate and fill buffer addressing information based on GL pixelstore
106b8e80941Smrg * attributes.
107b8e80941Smrg *
108b8e80941Smrg * Returns false if some aspect of the addressing (e.g. alignment) prevents
109b8e80941Smrg * PBO upload/download.
110b8e80941Smrg */
111b8e80941Smrgbool
112b8e80941Smrgst_pbo_addresses_pixelstore(struct st_context *st,
113b8e80941Smrg                            GLenum gl_target, bool skip_images,
114b8e80941Smrg                            const struct gl_pixelstore_attrib *store,
115b8e80941Smrg                            const void *pixels,
116b8e80941Smrg                            struct st_pbo_addresses *addr)
117b8e80941Smrg{
118b8e80941Smrg   struct pipe_resource *buf = st_buffer_object(store->BufferObj)->buffer;
119b8e80941Smrg   intptr_t buf_offset = (intptr_t) pixels;
120b8e80941Smrg
121b8e80941Smrg   if (buf_offset % addr->bytes_per_pixel)
122b8e80941Smrg      return false;
123b8e80941Smrg
124b8e80941Smrg   /* Convert to texels */
125b8e80941Smrg   buf_offset = buf_offset / addr->bytes_per_pixel;
126b8e80941Smrg
127b8e80941Smrg   /* Determine image height */
128b8e80941Smrg   if (gl_target == GL_TEXTURE_1D_ARRAY) {
129b8e80941Smrg      addr->image_height = 1;
130b8e80941Smrg   } else {
131b8e80941Smrg      addr->image_height = store->ImageHeight > 0 ? store->ImageHeight : addr->height;
132b8e80941Smrg   }
133b8e80941Smrg
134b8e80941Smrg   /* Compute the stride, taking store->Alignment into account */
135b8e80941Smrg   {
136b8e80941Smrg       unsigned pixels_per_row = store->RowLength > 0 ?
137b8e80941Smrg                           store->RowLength : addr->width;
138b8e80941Smrg       unsigned bytes_per_row = pixels_per_row * addr->bytes_per_pixel;
139b8e80941Smrg       unsigned remainder = bytes_per_row % store->Alignment;
140b8e80941Smrg       unsigned offset_rows;
141b8e80941Smrg
142b8e80941Smrg       if (remainder > 0)
143b8e80941Smrg          bytes_per_row += store->Alignment - remainder;
144b8e80941Smrg
145b8e80941Smrg       if (bytes_per_row % addr->bytes_per_pixel)
146b8e80941Smrg          return false;
147b8e80941Smrg
148b8e80941Smrg       addr->pixels_per_row = bytes_per_row / addr->bytes_per_pixel;
149b8e80941Smrg
150b8e80941Smrg       offset_rows = store->SkipRows;
151b8e80941Smrg       if (skip_images)
152b8e80941Smrg          offset_rows += addr->image_height * store->SkipImages;
153b8e80941Smrg
154b8e80941Smrg       buf_offset += store->SkipPixels + addr->pixels_per_row * offset_rows;
155b8e80941Smrg   }
156b8e80941Smrg
157b8e80941Smrg   if (!st_pbo_addresses_setup(st, buf, buf_offset, addr))
158b8e80941Smrg      return false;
159b8e80941Smrg
160b8e80941Smrg   /* Support GL_PACK_INVERT_MESA */
161b8e80941Smrg   if (store->Invert) {
162b8e80941Smrg      addr->constants.xoffset += (addr->height - 1) * addr->constants.stride;
163b8e80941Smrg      addr->constants.stride = -addr->constants.stride;
164b8e80941Smrg   }
165b8e80941Smrg
166b8e80941Smrg   return true;
167b8e80941Smrg}
168b8e80941Smrg
169b8e80941Smrg/* For download from a framebuffer, we may have to invert the Y axis. The
170b8e80941Smrg * setup is as follows:
171b8e80941Smrg * - set viewport to inverted, so that the position sysval is correct for
172b8e80941Smrg *   texel fetches
173b8e80941Smrg * - this function adjusts the fragment shader's constant buffer to compute
174b8e80941Smrg *   the correct destination addresses.
175b8e80941Smrg */
176b8e80941Smrgvoid
177b8e80941Smrgst_pbo_addresses_invert_y(struct st_pbo_addresses *addr,
178b8e80941Smrg                          unsigned viewport_height)
179b8e80941Smrg{
180b8e80941Smrg   addr->constants.xoffset +=
181b8e80941Smrg      (viewport_height - 1 + 2 * addr->constants.yoffset) * addr->constants.stride;
182b8e80941Smrg   addr->constants.stride = -addr->constants.stride;
183b8e80941Smrg}
184b8e80941Smrg
185b8e80941Smrg/* Setup all vertex pipeline state, rasterizer state, and fragment shader
186b8e80941Smrg * constants, and issue the draw call for PBO upload/download.
187b8e80941Smrg *
188b8e80941Smrg * The caller is responsible for saving and restoring state, as well as for
189b8e80941Smrg * setting other fragment shader state (fragment shader, samplers), and
190b8e80941Smrg * framebuffer/viewport/DSA/blend state.
191b8e80941Smrg */
192b8e80941Smrgbool
193b8e80941Smrgst_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr,
194b8e80941Smrg            unsigned surface_width, unsigned surface_height)
195b8e80941Smrg{
196b8e80941Smrg   struct cso_context *cso = st->cso_context;
197b8e80941Smrg
198b8e80941Smrg   /* Setup vertex and geometry shaders */
199b8e80941Smrg   if (!st->pbo.vs) {
200b8e80941Smrg      st->pbo.vs = st_pbo_create_vs(st);
201b8e80941Smrg      if (!st->pbo.vs)
202b8e80941Smrg         return false;
203b8e80941Smrg   }
204b8e80941Smrg
205b8e80941Smrg   if (addr->depth != 1 && st->pbo.use_gs && !st->pbo.gs) {
206b8e80941Smrg      st->pbo.gs = st_pbo_create_gs(st);
207b8e80941Smrg      if (!st->pbo.gs)
208b8e80941Smrg         return false;
209b8e80941Smrg   }
210b8e80941Smrg
211b8e80941Smrg   cso_set_vertex_shader_handle(cso, st->pbo.vs);
212b8e80941Smrg
213b8e80941Smrg   cso_set_geometry_shader_handle(cso, addr->depth != 1 ? st->pbo.gs : NULL);
214b8e80941Smrg
215b8e80941Smrg   cso_set_tessctrl_shader_handle(cso, NULL);
216b8e80941Smrg
217b8e80941Smrg   cso_set_tesseval_shader_handle(cso, NULL);
218b8e80941Smrg
219b8e80941Smrg   /* Upload vertices */
220b8e80941Smrg   {
221b8e80941Smrg      struct pipe_vertex_buffer vbo = {0};
222b8e80941Smrg      struct pipe_vertex_element velem;
223b8e80941Smrg
224b8e80941Smrg      float x0 = (float) addr->xoffset / surface_width * 2.0f - 1.0f;
225b8e80941Smrg      float y0 = (float) addr->yoffset / surface_height * 2.0f - 1.0f;
226b8e80941Smrg      float x1 = (float) (addr->xoffset + addr->width) / surface_width * 2.0f - 1.0f;
227b8e80941Smrg      float y1 = (float) (addr->yoffset + addr->height) / surface_height * 2.0f - 1.0f;
228b8e80941Smrg
229b8e80941Smrg      float *verts = NULL;
230b8e80941Smrg
231b8e80941Smrg      vbo.stride = 2 * sizeof(float);
232b8e80941Smrg
233b8e80941Smrg      u_upload_alloc(st->pipe->stream_uploader, 0, 8 * sizeof(float), 4,
234b8e80941Smrg                     &vbo.buffer_offset, &vbo.buffer.resource, (void **) &verts);
235b8e80941Smrg      if (!verts)
236b8e80941Smrg         return false;
237b8e80941Smrg
238b8e80941Smrg      verts[0] = x0;
239b8e80941Smrg      verts[1] = y0;
240b8e80941Smrg      verts[2] = x0;
241b8e80941Smrg      verts[3] = y1;
242b8e80941Smrg      verts[4] = x1;
243b8e80941Smrg      verts[5] = y0;
244b8e80941Smrg      verts[6] = x1;
245b8e80941Smrg      verts[7] = y1;
246b8e80941Smrg
247b8e80941Smrg      u_upload_unmap(st->pipe->stream_uploader);
248b8e80941Smrg
249b8e80941Smrg      velem.src_offset = 0;
250b8e80941Smrg      velem.instance_divisor = 0;
251b8e80941Smrg      velem.vertex_buffer_index = 0;
252b8e80941Smrg      velem.src_format = PIPE_FORMAT_R32G32_FLOAT;
253b8e80941Smrg
254b8e80941Smrg      cso_set_vertex_elements(cso, 1, &velem);
255b8e80941Smrg
256b8e80941Smrg      cso_set_vertex_buffers(cso, velem.vertex_buffer_index, 1, &vbo);
257b8e80941Smrg
258b8e80941Smrg      pipe_resource_reference(&vbo.buffer.resource, NULL);
259b8e80941Smrg   }
260b8e80941Smrg
261b8e80941Smrg   /* Upload constants */
262b8e80941Smrg   {
263b8e80941Smrg      struct pipe_constant_buffer cb;
264b8e80941Smrg
265b8e80941Smrg      cb.buffer = NULL;
266b8e80941Smrg      cb.user_buffer = &addr->constants;
267b8e80941Smrg      cb.buffer_offset = 0;
268b8e80941Smrg      cb.buffer_size = sizeof(addr->constants);
269b8e80941Smrg
270b8e80941Smrg      cso_set_constant_buffer(cso, PIPE_SHADER_FRAGMENT, 0, &cb);
271b8e80941Smrg
272b8e80941Smrg      pipe_resource_reference(&cb.buffer, NULL);
273b8e80941Smrg   }
274b8e80941Smrg
275b8e80941Smrg   /* Rasterizer state */
276b8e80941Smrg   cso_set_rasterizer(cso, &st->pbo.raster);
277b8e80941Smrg
278b8e80941Smrg   /* Disable stream output */
279b8e80941Smrg   cso_set_stream_outputs(cso, 0, NULL, 0);
280b8e80941Smrg
281b8e80941Smrg   if (addr->depth == 1) {
282b8e80941Smrg      cso_draw_arrays(cso, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
283b8e80941Smrg   } else {
284b8e80941Smrg      cso_draw_arrays_instanced(cso, PIPE_PRIM_TRIANGLE_STRIP,
285b8e80941Smrg                                0, 4, 0, addr->depth);
286b8e80941Smrg   }
287b8e80941Smrg
288b8e80941Smrg   return true;
289b8e80941Smrg}
290b8e80941Smrg
291b8e80941Smrgvoid *
292b8e80941Smrgst_pbo_create_vs(struct st_context *st)
293b8e80941Smrg{
294b8e80941Smrg   struct pipe_screen *pscreen = st->pipe->screen;
295b8e80941Smrg   bool use_nir = PIPE_SHADER_IR_NIR ==
296b8e80941Smrg      pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX,
297b8e80941Smrg                                PIPE_SHADER_CAP_PREFERRED_IR);
298b8e80941Smrg
299b8e80941Smrg   if (use_nir) {
300b8e80941Smrg      unsigned inputs[] =  {  VERT_ATTRIB_POS, SYSTEM_VALUE_INSTANCE_ID, };
301b8e80941Smrg      unsigned outputs[] = { VARYING_SLOT_POS,       VARYING_SLOT_LAYER  };
302b8e80941Smrg
303b8e80941Smrg      return st_nir_make_passthrough_shader(st, "st/pbo VS",
304b8e80941Smrg                                            MESA_SHADER_VERTEX,
305b8e80941Smrg                                            st->pbo.layers ? 2 : 1,
306b8e80941Smrg                                            inputs, outputs, NULL, (1 << 1));
307b8e80941Smrg   }
308b8e80941Smrg
309b8e80941Smrg   struct ureg_program *ureg;
310b8e80941Smrg   struct ureg_src in_pos;
311b8e80941Smrg   struct ureg_src in_instanceid;
312b8e80941Smrg   struct ureg_dst out_pos;
313b8e80941Smrg   struct ureg_dst out_layer;
314b8e80941Smrg
315b8e80941Smrg   ureg = ureg_create(PIPE_SHADER_VERTEX);
316b8e80941Smrg   if (!ureg)
317b8e80941Smrg      return NULL;
318b8e80941Smrg
319b8e80941Smrg   in_pos = ureg_DECL_vs_input(ureg, TGSI_SEMANTIC_POSITION);
320b8e80941Smrg
321b8e80941Smrg   out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
322b8e80941Smrg
323b8e80941Smrg   if (st->pbo.layers) {
324b8e80941Smrg      in_instanceid = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_INSTANCEID, 0);
325b8e80941Smrg
326b8e80941Smrg      if (!st->pbo.use_gs)
327b8e80941Smrg         out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0);
328b8e80941Smrg   }
329b8e80941Smrg
330b8e80941Smrg   /* out_pos = in_pos */
331b8e80941Smrg   ureg_MOV(ureg, out_pos, in_pos);
332b8e80941Smrg
333b8e80941Smrg   if (st->pbo.layers) {
334b8e80941Smrg      if (st->pbo.use_gs) {
335b8e80941Smrg         /* out_pos.z = i2f(gl_InstanceID) */
336b8e80941Smrg         ureg_I2F(ureg, ureg_writemask(out_pos, TGSI_WRITEMASK_Z),
337b8e80941Smrg                        ureg_scalar(in_instanceid, TGSI_SWIZZLE_X));
338b8e80941Smrg      } else {
339b8e80941Smrg         /* out_layer = gl_InstanceID */
340b8e80941Smrg         ureg_MOV(ureg, ureg_writemask(out_layer, TGSI_WRITEMASK_X),
341b8e80941Smrg                        ureg_scalar(in_instanceid, TGSI_SWIZZLE_X));
342b8e80941Smrg      }
343b8e80941Smrg   }
344b8e80941Smrg
345b8e80941Smrg   ureg_END(ureg);
346b8e80941Smrg
347b8e80941Smrg   return ureg_create_shader_and_destroy(ureg, st->pipe);
348b8e80941Smrg}
349b8e80941Smrg
350b8e80941Smrgvoid *
351b8e80941Smrgst_pbo_create_gs(struct st_context *st)
352b8e80941Smrg{
353b8e80941Smrg   static const int zero = 0;
354b8e80941Smrg   struct ureg_program *ureg;
355b8e80941Smrg   struct ureg_dst out_pos;
356b8e80941Smrg   struct ureg_dst out_layer;
357b8e80941Smrg   struct ureg_src in_pos;
358b8e80941Smrg   struct ureg_src imm;
359b8e80941Smrg   unsigned i;
360b8e80941Smrg
361b8e80941Smrg   ureg = ureg_create(PIPE_SHADER_GEOMETRY);
362b8e80941Smrg   if (!ureg)
363b8e80941Smrg      return NULL;
364b8e80941Smrg
365b8e80941Smrg   ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, PIPE_PRIM_TRIANGLES);
366b8e80941Smrg   ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, PIPE_PRIM_TRIANGLE_STRIP);
367b8e80941Smrg   ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, 3);
368b8e80941Smrg
369b8e80941Smrg   out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
370b8e80941Smrg   out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0);
371b8e80941Smrg
372b8e80941Smrg   in_pos = ureg_DECL_input(ureg, TGSI_SEMANTIC_POSITION, 0, 0, 1);
373b8e80941Smrg
374b8e80941Smrg   imm = ureg_DECL_immediate_int(ureg, &zero, 1);
375b8e80941Smrg
376b8e80941Smrg   for (i = 0; i < 3; ++i) {
377b8e80941Smrg      struct ureg_src in_pos_vertex = ureg_src_dimension(in_pos, i);
378b8e80941Smrg
379b8e80941Smrg      /* out_pos = in_pos[i] */
380b8e80941Smrg      ureg_MOV(ureg, out_pos, in_pos_vertex);
381b8e80941Smrg
382b8e80941Smrg      /* out_layer.x = f2i(in_pos[i].z) */
383b8e80941Smrg      ureg_F2I(ureg, ureg_writemask(out_layer, TGSI_WRITEMASK_X),
384b8e80941Smrg                     ureg_scalar(in_pos_vertex, TGSI_SWIZZLE_Z));
385b8e80941Smrg
386b8e80941Smrg      ureg_EMIT(ureg, ureg_scalar(imm, TGSI_SWIZZLE_X));
387b8e80941Smrg   }
388b8e80941Smrg
389b8e80941Smrg   ureg_END(ureg);
390b8e80941Smrg
391b8e80941Smrg   return ureg_create_shader_and_destroy(ureg, st->pipe);
392b8e80941Smrg}
393b8e80941Smrg
394b8e80941Smrgstatic void
395b8e80941Smrgbuild_conversion(struct ureg_program *ureg, const struct ureg_dst *temp,
396b8e80941Smrg                 enum st_pbo_conversion conversion)
397b8e80941Smrg{
398b8e80941Smrg   switch (conversion) {
399b8e80941Smrg   case ST_PBO_CONVERT_SINT_TO_UINT:
400b8e80941Smrg      ureg_IMAX(ureg, *temp, ureg_src(*temp), ureg_imm1i(ureg, 0));
401b8e80941Smrg      break;
402b8e80941Smrg   case ST_PBO_CONVERT_UINT_TO_SINT:
403b8e80941Smrg      ureg_UMIN(ureg, *temp, ureg_src(*temp), ureg_imm1u(ureg, (1u << 31) - 1));
404b8e80941Smrg      break;
405b8e80941Smrg   default:
406b8e80941Smrg      /* no-op */
407b8e80941Smrg      break;
408b8e80941Smrg   }
409b8e80941Smrg}
410b8e80941Smrg
411b8e80941Smrgstatic const struct glsl_type *
412b8e80941Smrgsampler_type_for_target(enum pipe_texture_target target)
413b8e80941Smrg{
414b8e80941Smrg   bool is_array = target >= PIPE_TEXTURE_1D_ARRAY;
415b8e80941Smrg   static const enum glsl_sampler_dim dim[] = {
416b8e80941Smrg      [PIPE_BUFFER]             = GLSL_SAMPLER_DIM_BUF,
417b8e80941Smrg      [PIPE_TEXTURE_1D]         = GLSL_SAMPLER_DIM_1D,
418b8e80941Smrg      [PIPE_TEXTURE_2D]         = GLSL_SAMPLER_DIM_2D,
419b8e80941Smrg      [PIPE_TEXTURE_3D]         = GLSL_SAMPLER_DIM_3D,
420b8e80941Smrg      [PIPE_TEXTURE_CUBE]       = GLSL_SAMPLER_DIM_CUBE,
421b8e80941Smrg      [PIPE_TEXTURE_RECT]       = GLSL_SAMPLER_DIM_RECT,
422b8e80941Smrg      [PIPE_TEXTURE_1D_ARRAY]   = GLSL_SAMPLER_DIM_1D,
423b8e80941Smrg      [PIPE_TEXTURE_2D_ARRAY]   = GLSL_SAMPLER_DIM_2D,
424b8e80941Smrg      [PIPE_TEXTURE_CUBE_ARRAY] = GLSL_SAMPLER_DIM_CUBE,
425b8e80941Smrg   };
426b8e80941Smrg
427b8e80941Smrg   return glsl_sampler_type(dim[target], false, is_array, GLSL_TYPE_FLOAT);
428b8e80941Smrg}
429b8e80941Smrg
430b8e80941Smrgstatic void *
431b8e80941Smrgcreate_fs_nir(struct st_context *st,
432b8e80941Smrg              bool download,
433b8e80941Smrg              enum pipe_texture_target target,
434b8e80941Smrg              enum st_pbo_conversion conversion)
435b8e80941Smrg{
436b8e80941Smrg   struct pipe_screen *screen = st->pipe->screen;
437b8e80941Smrg   struct nir_builder b;
438b8e80941Smrg   const nir_shader_compiler_options *options =
439b8e80941Smrg      st->ctx->Const.ShaderCompilerOptions[MESA_SHADER_FRAGMENT].NirOptions;
440b8e80941Smrg   bool pos_is_sysval =
441b8e80941Smrg      screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL);
442b8e80941Smrg
443b8e80941Smrg   nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options);
444b8e80941Smrg
445b8e80941Smrg   nir_ssa_def *zero = nir_imm_int(&b, 0);
446b8e80941Smrg
447b8e80941Smrg   /* param = [ -xoffset + skip_pixels, -yoffset, stride, image_height ] */
448b8e80941Smrg   nir_variable *param_var =
449b8e80941Smrg      nir_variable_create(b.shader, nir_var_uniform, glsl_vec4_type(), "param");
450b8e80941Smrg   b.shader->num_uniforms += 4;
451b8e80941Smrg   nir_ssa_def *param = nir_load_var(&b, param_var);
452b8e80941Smrg
453b8e80941Smrg   nir_variable *fragcoord =
454b8e80941Smrg      nir_variable_create(b.shader, pos_is_sysval ? nir_var_system_value :
455b8e80941Smrg                          nir_var_shader_in, glsl_vec4_type(), "gl_FragCoord");
456b8e80941Smrg   fragcoord->data.location = pos_is_sysval ? SYSTEM_VALUE_FRAG_COORD
457b8e80941Smrg                                            : VARYING_SLOT_POS;
458b8e80941Smrg   nir_ssa_def *coord = nir_load_var(&b, fragcoord);
459b8e80941Smrg
460b8e80941Smrg   nir_ssa_def *layer = NULL;
461b8e80941Smrg   if (st->pbo.layers && (!download || target == PIPE_TEXTURE_1D_ARRAY ||
462b8e80941Smrg                                       target == PIPE_TEXTURE_2D_ARRAY ||
463b8e80941Smrg                                       target == PIPE_TEXTURE_3D ||
464b8e80941Smrg                                       target == PIPE_TEXTURE_CUBE ||
465b8e80941Smrg                                       target == PIPE_TEXTURE_CUBE_ARRAY)) {
466b8e80941Smrg      nir_variable *var = nir_variable_create(b.shader, nir_var_shader_in,
467b8e80941Smrg                                              glsl_int_type(), "gl_Layer");
468b8e80941Smrg      var->data.location = VARYING_SLOT_LAYER;
469b8e80941Smrg      var->data.interpolation = INTERP_MODE_FLAT;
470b8e80941Smrg      layer = nir_load_var(&b, var);
471b8e80941Smrg   }
472b8e80941Smrg
473b8e80941Smrg   /* offset_pos = param.xy + f2i(coord.xy) */
474b8e80941Smrg   nir_ssa_def *offset_pos =
475b8e80941Smrg      nir_iadd(&b, nir_channels(&b, param, TGSI_WRITEMASK_XY),
476b8e80941Smrg               nir_f2i32(&b, nir_channels(&b, coord, TGSI_WRITEMASK_XY)));
477b8e80941Smrg
478b8e80941Smrg   /* addr = offset_pos.x + offset_pos.y * stride */
479b8e80941Smrg   nir_ssa_def *pbo_addr =
480b8e80941Smrg      nir_iadd(&b, nir_channel(&b, offset_pos, 0),
481b8e80941Smrg               nir_imul(&b, nir_channel(&b, offset_pos, 1),
482b8e80941Smrg                        nir_channel(&b, param, 2)));
483b8e80941Smrg   if (layer) {
484b8e80941Smrg      /* pbo_addr += image_height * layer */
485b8e80941Smrg      pbo_addr = nir_iadd(&b, pbo_addr,
486b8e80941Smrg                          nir_imul(&b, layer, nir_channel(&b, param, 3)));
487b8e80941Smrg   }
488b8e80941Smrg
489b8e80941Smrg   nir_ssa_def *texcoord;
490b8e80941Smrg   if (download) {
491b8e80941Smrg      texcoord = nir_f2i32(&b, nir_channels(&b, coord, TGSI_WRITEMASK_XY));
492b8e80941Smrg
493b8e80941Smrg      if (layer) {
494b8e80941Smrg         nir_ssa_def *src_layer = layer;
495b8e80941Smrg
496b8e80941Smrg         if (target == PIPE_TEXTURE_3D) {
497b8e80941Smrg            nir_variable *layer_offset_var =
498b8e80941Smrg               nir_variable_create(b.shader, nir_var_uniform,
499b8e80941Smrg                                   glsl_int_type(), "layer_offset");
500b8e80941Smrg            b.shader->num_uniforms += 1;
501b8e80941Smrg            layer_offset_var->data.driver_location = 4;
502b8e80941Smrg            nir_ssa_def *layer_offset = nir_load_var(&b, layer_offset_var);
503b8e80941Smrg
504b8e80941Smrg            src_layer = nir_iadd(&b, layer, layer_offset);
505b8e80941Smrg         }
506b8e80941Smrg
507b8e80941Smrg         texcoord = nir_vec3(&b, nir_channel(&b, texcoord, 0),
508b8e80941Smrg                                 nir_channel(&b, texcoord, 1),
509b8e80941Smrg                                 src_layer);
510b8e80941Smrg      }
511b8e80941Smrg   } else {
512b8e80941Smrg      texcoord = pbo_addr;
513b8e80941Smrg   }
514b8e80941Smrg
515b8e80941Smrg   nir_variable *tex_var =
516b8e80941Smrg      nir_variable_create(b.shader, nir_var_uniform,
517b8e80941Smrg                          sampler_type_for_target(target), "tex");
518b8e80941Smrg   tex_var->data.explicit_binding = true;
519b8e80941Smrg   tex_var->data.binding = 0;
520b8e80941Smrg
521b8e80941Smrg   nir_deref_instr *tex_deref = nir_build_deref_var(&b, tex_var);
522b8e80941Smrg
523b8e80941Smrg   nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);
524b8e80941Smrg   tex->op = nir_texop_txf;
525b8e80941Smrg   tex->sampler_dim = glsl_get_sampler_dim(tex_var->type);
526b8e80941Smrg   tex->coord_components =
527b8e80941Smrg      glsl_get_sampler_coordinate_components(tex_var->type);
528b8e80941Smrg   tex->dest_type = nir_type_float;
529b8e80941Smrg   tex->src[0].src_type = nir_tex_src_texture_deref;
530b8e80941Smrg   tex->src[0].src = nir_src_for_ssa(&tex_deref->dest.ssa);
531b8e80941Smrg   tex->src[1].src_type = nir_tex_src_sampler_deref;
532b8e80941Smrg   tex->src[1].src = nir_src_for_ssa(&tex_deref->dest.ssa);
533b8e80941Smrg   tex->src[2].src_type = nir_tex_src_coord;
534b8e80941Smrg   tex->src[2].src = nir_src_for_ssa(texcoord);
535b8e80941Smrg   nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
536b8e80941Smrg   nir_builder_instr_insert(&b, &tex->instr);
537b8e80941Smrg   nir_ssa_def *result = &tex->dest.ssa;
538b8e80941Smrg
539b8e80941Smrg   if (conversion == ST_PBO_CONVERT_SINT_TO_UINT)
540b8e80941Smrg      result = nir_imax(&b, result, zero);
541b8e80941Smrg   else if (conversion == ST_PBO_CONVERT_UINT_TO_SINT)
542b8e80941Smrg      result = nir_umin(&b, result, nir_imm_int(&b, (1u << 31) - 1));
543b8e80941Smrg
544b8e80941Smrg   if (download) {
545b8e80941Smrg      nir_variable *img_var =
546b8e80941Smrg         nir_variable_create(b.shader, nir_var_uniform,
547b8e80941Smrg                             glsl_image_type(GLSL_SAMPLER_DIM_BUF, false,
548b8e80941Smrg                                             GLSL_TYPE_FLOAT), "img");
549b8e80941Smrg      img_var->data.image.access = ACCESS_NON_READABLE;
550b8e80941Smrg      img_var->data.explicit_binding = true;
551b8e80941Smrg      img_var->data.binding = 0;
552b8e80941Smrg      nir_deref_instr *img_deref = nir_build_deref_var(&b, img_var);
553b8e80941Smrg      nir_intrinsic_instr *intrin =
554b8e80941Smrg         nir_intrinsic_instr_create(b.shader, nir_intrinsic_image_deref_store);
555b8e80941Smrg      intrin->src[0] = nir_src_for_ssa(&img_deref->dest.ssa);
556b8e80941Smrg      intrin->src[1] =
557b8e80941Smrg         nir_src_for_ssa(nir_vec4(&b, pbo_addr, zero, zero, zero));
558b8e80941Smrg      intrin->src[2] = nir_src_for_ssa(zero);
559b8e80941Smrg      intrin->src[3] = nir_src_for_ssa(result);
560b8e80941Smrg      intrin->num_components = 4;
561b8e80941Smrg      nir_builder_instr_insert(&b, &intrin->instr);
562b8e80941Smrg   } else {
563b8e80941Smrg      nir_variable *color =
564b8e80941Smrg         nir_variable_create(b.shader, nir_var_shader_out, glsl_vec4_type(),
565b8e80941Smrg                             "gl_FragColor");
566b8e80941Smrg      color->data.location = FRAG_RESULT_COLOR;
567b8e80941Smrg
568b8e80941Smrg      nir_store_var(&b, color, result, TGSI_WRITEMASK_XYZW);
569b8e80941Smrg   }
570b8e80941Smrg
571b8e80941Smrg   return st_nir_finish_builtin_shader(st, b.shader, download ?
572b8e80941Smrg                                       "st/pbo download FS" :
573b8e80941Smrg                                       "st/pbo upload FS");
574b8e80941Smrg}
575b8e80941Smrg
576b8e80941Smrgstatic void *
577b8e80941Smrgcreate_fs_tgsi(struct st_context *st, bool download,
578b8e80941Smrg               enum pipe_texture_target target,
579b8e80941Smrg               enum st_pbo_conversion conversion)
580b8e80941Smrg{
581b8e80941Smrg   struct pipe_context *pipe = st->pipe;
582b8e80941Smrg   struct pipe_screen *screen = pipe->screen;
583b8e80941Smrg   struct ureg_program *ureg;
584b8e80941Smrg   bool have_layer;
585b8e80941Smrg   struct ureg_dst out;
586b8e80941Smrg   struct ureg_src sampler;
587b8e80941Smrg   struct ureg_src pos;
588b8e80941Smrg   struct ureg_src layer;
589b8e80941Smrg   struct ureg_src const0;
590b8e80941Smrg   struct ureg_src const1;
591b8e80941Smrg   struct ureg_dst temp0;
592b8e80941Smrg
593b8e80941Smrg   have_layer =
594b8e80941Smrg      st->pbo.layers &&
595b8e80941Smrg      (!download || target == PIPE_TEXTURE_1D_ARRAY
596b8e80941Smrg                 || target == PIPE_TEXTURE_2D_ARRAY
597b8e80941Smrg                 || target == PIPE_TEXTURE_3D
598b8e80941Smrg                 || target == PIPE_TEXTURE_CUBE
599b8e80941Smrg                 || target == PIPE_TEXTURE_CUBE_ARRAY);
600b8e80941Smrg
601b8e80941Smrg   ureg = ureg_create(PIPE_SHADER_FRAGMENT);
602b8e80941Smrg   if (!ureg)
603b8e80941Smrg      return NULL;
604b8e80941Smrg
605b8e80941Smrg   if (!download) {
606b8e80941Smrg      out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
607b8e80941Smrg   } else {
608b8e80941Smrg      struct ureg_src image;
609b8e80941Smrg
610b8e80941Smrg      /* writeonly images do not require an explicitly given format. */
611b8e80941Smrg      image = ureg_DECL_image(ureg, 0, TGSI_TEXTURE_BUFFER, PIPE_FORMAT_NONE,
612b8e80941Smrg                                    true, false);
613b8e80941Smrg      out = ureg_dst(image);
614b8e80941Smrg   }
615b8e80941Smrg
616b8e80941Smrg   sampler = ureg_DECL_sampler(ureg, 0);
617b8e80941Smrg   if (screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL)) {
618b8e80941Smrg      pos = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0);
619b8e80941Smrg   } else {
620b8e80941Smrg      pos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0,
621b8e80941Smrg                               TGSI_INTERPOLATE_LINEAR);
622b8e80941Smrg   }
623b8e80941Smrg   if (have_layer) {
624b8e80941Smrg      layer = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_LAYER, 0,
625b8e80941Smrg                                       TGSI_INTERPOLATE_CONSTANT);
626b8e80941Smrg   }
627b8e80941Smrg   const0  = ureg_DECL_constant(ureg, 0);
628b8e80941Smrg   const1  = ureg_DECL_constant(ureg, 1);
629b8e80941Smrg   temp0   = ureg_DECL_temporary(ureg);
630b8e80941Smrg
631b8e80941Smrg   /* Note: const0 = [ -xoffset + skip_pixels, -yoffset, stride, image_height ] */
632b8e80941Smrg
633b8e80941Smrg   /* temp0.xy = f2i(temp0.xy) */
634b8e80941Smrg   ureg_F2I(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY),
635b8e80941Smrg                  ureg_swizzle(pos,
636b8e80941Smrg                               TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
637b8e80941Smrg                               TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y));
638b8e80941Smrg
639b8e80941Smrg   /* temp0.xy = temp0.xy + const0.xy */
640b8e80941Smrg   ureg_UADD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY),
641b8e80941Smrg                   ureg_swizzle(ureg_src(temp0),
642b8e80941Smrg                                TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
643b8e80941Smrg                                TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y),
644b8e80941Smrg                   ureg_swizzle(const0,
645b8e80941Smrg                                TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
646b8e80941Smrg                                TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y));
647b8e80941Smrg
648b8e80941Smrg   /* temp0.x = const0.z * temp0.y + temp0.x */
649b8e80941Smrg   ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X),
650b8e80941Smrg                   ureg_scalar(const0, TGSI_SWIZZLE_Z),
651b8e80941Smrg                   ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_Y),
652b8e80941Smrg                   ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X));
653b8e80941Smrg
654b8e80941Smrg   if (have_layer) {
655b8e80941Smrg      /* temp0.x = const0.w * layer + temp0.x */
656b8e80941Smrg      ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X),
657b8e80941Smrg                      ureg_scalar(const0, TGSI_SWIZZLE_W),
658b8e80941Smrg                      ureg_scalar(layer, TGSI_SWIZZLE_X),
659b8e80941Smrg                      ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X));
660b8e80941Smrg   }
661b8e80941Smrg
662b8e80941Smrg   /* temp0.w = 0 */
663b8e80941Smrg   ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_W), ureg_imm1u(ureg, 0));
664b8e80941Smrg
665b8e80941Smrg   if (download) {
666b8e80941Smrg      struct ureg_dst temp1;
667b8e80941Smrg      struct ureg_src op[2];
668b8e80941Smrg
669b8e80941Smrg      temp1 = ureg_DECL_temporary(ureg);
670b8e80941Smrg
671b8e80941Smrg      /* temp1.xy = pos.xy */
672b8e80941Smrg      ureg_F2I(ureg, ureg_writemask(temp1, TGSI_WRITEMASK_XY), pos);
673b8e80941Smrg
674b8e80941Smrg      /* temp1.zw = 0 */
675b8e80941Smrg      ureg_MOV(ureg, ureg_writemask(temp1, TGSI_WRITEMASK_ZW), ureg_imm1u(ureg, 0));
676b8e80941Smrg
677b8e80941Smrg      if (have_layer) {
678b8e80941Smrg         struct ureg_dst temp1_layer =
679b8e80941Smrg            ureg_writemask(temp1, target == PIPE_TEXTURE_1D_ARRAY ? TGSI_WRITEMASK_Y
680b8e80941Smrg                                                                  : TGSI_WRITEMASK_Z);
681b8e80941Smrg
682b8e80941Smrg         /* temp1.y/z = layer */
683b8e80941Smrg         ureg_MOV(ureg, temp1_layer, ureg_scalar(layer, TGSI_SWIZZLE_X));
684b8e80941Smrg
685b8e80941Smrg         if (target == PIPE_TEXTURE_3D) {
686b8e80941Smrg            /* temp1.z += layer_offset */
687b8e80941Smrg            ureg_UADD(ureg, temp1_layer,
688b8e80941Smrg                            ureg_scalar(ureg_src(temp1), TGSI_SWIZZLE_Z),
689b8e80941Smrg                            ureg_scalar(const1, TGSI_SWIZZLE_X));
690b8e80941Smrg         }
691b8e80941Smrg      }
692b8e80941Smrg
693b8e80941Smrg      /* temp1 = txf(sampler, temp1) */
694b8e80941Smrg      ureg_TXF(ureg, temp1, util_pipe_tex_to_tgsi_tex(target, 1),
695b8e80941Smrg                     ureg_src(temp1), sampler);
696b8e80941Smrg
697b8e80941Smrg      build_conversion(ureg, &temp1, conversion);
698b8e80941Smrg
699b8e80941Smrg      /* store(out, temp0, temp1) */
700b8e80941Smrg      op[0] = ureg_src(temp0);
701b8e80941Smrg      op[1] = ureg_src(temp1);
702b8e80941Smrg      ureg_memory_insn(ureg, TGSI_OPCODE_STORE, &out, 1, op, 2, 0,
703b8e80941Smrg                             TGSI_TEXTURE_BUFFER, PIPE_FORMAT_NONE);
704b8e80941Smrg
705b8e80941Smrg      ureg_release_temporary(ureg, temp1);
706b8e80941Smrg   } else {
707b8e80941Smrg      /* out = txf(sampler, temp0.x) */
708b8e80941Smrg      ureg_TXF(ureg, temp0, TGSI_TEXTURE_BUFFER, ureg_src(temp0), sampler);
709b8e80941Smrg
710b8e80941Smrg      build_conversion(ureg, &temp0, conversion);
711b8e80941Smrg
712b8e80941Smrg      ureg_MOV(ureg, out, ureg_src(temp0));
713b8e80941Smrg   }
714b8e80941Smrg
715b8e80941Smrg   ureg_release_temporary(ureg, temp0);
716b8e80941Smrg
717b8e80941Smrg   ureg_END(ureg);
718b8e80941Smrg
719b8e80941Smrg   return ureg_create_shader_and_destroy(ureg, pipe);
720b8e80941Smrg}
721b8e80941Smrg
722b8e80941Smrgstatic void *
723b8e80941Smrgcreate_fs(struct st_context *st, bool download,
724b8e80941Smrg          enum pipe_texture_target target,
725b8e80941Smrg          enum st_pbo_conversion conversion)
726b8e80941Smrg{
727b8e80941Smrg   struct pipe_screen *pscreen = st->pipe->screen;
728b8e80941Smrg   bool use_nir = PIPE_SHADER_IR_NIR ==
729b8e80941Smrg      pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX,
730b8e80941Smrg                                PIPE_SHADER_CAP_PREFERRED_IR);
731b8e80941Smrg
732b8e80941Smrg   if (use_nir)
733b8e80941Smrg      return create_fs_nir(st, download, target, conversion);
734b8e80941Smrg
735b8e80941Smrg   return create_fs_tgsi(st, download, target, conversion);
736b8e80941Smrg}
737b8e80941Smrg
738b8e80941Smrgstatic enum st_pbo_conversion
739b8e80941Smrgget_pbo_conversion(enum pipe_format src_format, enum pipe_format dst_format)
740b8e80941Smrg{
741b8e80941Smrg   if (util_format_is_pure_uint(src_format)) {
742b8e80941Smrg      if (util_format_is_pure_sint(dst_format))
743b8e80941Smrg         return ST_PBO_CONVERT_UINT_TO_SINT;
744b8e80941Smrg   } else if (util_format_is_pure_sint(src_format)) {
745b8e80941Smrg      if (util_format_is_pure_uint(dst_format))
746b8e80941Smrg         return ST_PBO_CONVERT_SINT_TO_UINT;
747b8e80941Smrg   }
748b8e80941Smrg
749b8e80941Smrg   return ST_PBO_CONVERT_NONE;
750b8e80941Smrg}
751b8e80941Smrg
752b8e80941Smrgvoid *
753b8e80941Smrgst_pbo_get_upload_fs(struct st_context *st,
754b8e80941Smrg                     enum pipe_format src_format,
755b8e80941Smrg                     enum pipe_format dst_format)
756b8e80941Smrg{
757b8e80941Smrg   STATIC_ASSERT(ARRAY_SIZE(st->pbo.upload_fs) == ST_NUM_PBO_CONVERSIONS);
758b8e80941Smrg
759b8e80941Smrg   enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
760b8e80941Smrg
761b8e80941Smrg   if (!st->pbo.upload_fs[conversion])
762b8e80941Smrg      st->pbo.upload_fs[conversion] = create_fs(st, false, 0, conversion);
763b8e80941Smrg
764b8e80941Smrg   return st->pbo.upload_fs[conversion];
765b8e80941Smrg}
766b8e80941Smrg
767b8e80941Smrgvoid *
768b8e80941Smrgst_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target,
769b8e80941Smrg                       enum pipe_format src_format,
770b8e80941Smrg                       enum pipe_format dst_format)
771b8e80941Smrg{
772b8e80941Smrg   STATIC_ASSERT(ARRAY_SIZE(st->pbo.download_fs) == ST_NUM_PBO_CONVERSIONS);
773b8e80941Smrg   assert(target < PIPE_MAX_TEXTURE_TYPES);
774b8e80941Smrg
775b8e80941Smrg   enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
776b8e80941Smrg
777b8e80941Smrg   if (!st->pbo.download_fs[conversion][target])
778b8e80941Smrg      st->pbo.download_fs[conversion][target] = create_fs(st, true, target, conversion);
779b8e80941Smrg
780b8e80941Smrg   return st->pbo.download_fs[conversion][target];
781b8e80941Smrg}
782b8e80941Smrg
783b8e80941Smrgvoid
784b8e80941Smrgst_init_pbo_helpers(struct st_context *st)
785b8e80941Smrg{
786b8e80941Smrg   struct pipe_context *pipe = st->pipe;
787b8e80941Smrg   struct pipe_screen *screen = pipe->screen;
788b8e80941Smrg
789b8e80941Smrg   st->pbo.upload_enabled =
790b8e80941Smrg      screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS) &&
791b8e80941Smrg      screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT) >= 1 &&
792b8e80941Smrg      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_INTEGERS);
793b8e80941Smrg   if (!st->pbo.upload_enabled)
794b8e80941Smrg      return;
795b8e80941Smrg
796b8e80941Smrg   st->pbo.download_enabled =
797b8e80941Smrg      st->pbo.upload_enabled &&
798b8e80941Smrg      screen->get_param(screen, PIPE_CAP_SAMPLER_VIEW_TARGET) &&
799b8e80941Smrg      screen->get_param(screen, PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT) &&
800b8e80941Smrg      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
801b8e80941Smrg                                       PIPE_SHADER_CAP_MAX_SHADER_IMAGES) >= 1;
802b8e80941Smrg
803b8e80941Smrg   st->pbo.rgba_only =
804b8e80941Smrg      screen->get_param(screen, PIPE_CAP_BUFFER_SAMPLER_VIEW_RGBA_ONLY);
805b8e80941Smrg
806b8e80941Smrg   if (screen->get_param(screen, PIPE_CAP_TGSI_INSTANCEID)) {
807b8e80941Smrg      if (screen->get_param(screen, PIPE_CAP_TGSI_VS_LAYER_VIEWPORT)) {
808b8e80941Smrg         st->pbo.layers = true;
809b8e80941Smrg      } else if (screen->get_param(screen, PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES) >= 3) {
810b8e80941Smrg         st->pbo.layers = true;
811b8e80941Smrg         st->pbo.use_gs = true;
812b8e80941Smrg      }
813b8e80941Smrg   }
814b8e80941Smrg
815b8e80941Smrg   /* Blend state */
816b8e80941Smrg   memset(&st->pbo.upload_blend, 0, sizeof(struct pipe_blend_state));
817b8e80941Smrg   st->pbo.upload_blend.rt[0].colormask = PIPE_MASK_RGBA;
818b8e80941Smrg
819b8e80941Smrg   /* Rasterizer state */
820b8e80941Smrg   memset(&st->pbo.raster, 0, sizeof(struct pipe_rasterizer_state));
821b8e80941Smrg   st->pbo.raster.half_pixel_center = 1;
822b8e80941Smrg}
823b8e80941Smrg
824b8e80941Smrgvoid
825b8e80941Smrgst_destroy_pbo_helpers(struct st_context *st)
826b8e80941Smrg{
827b8e80941Smrg   unsigned i;
828b8e80941Smrg
829b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(st->pbo.upload_fs); ++i) {
830b8e80941Smrg      if (st->pbo.upload_fs[i]) {
831b8e80941Smrg         cso_delete_fragment_shader(st->cso_context, st->pbo.upload_fs[i]);
832b8e80941Smrg         st->pbo.upload_fs[i] = NULL;
833b8e80941Smrg      }
834b8e80941Smrg   }
835b8e80941Smrg
836b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(st->pbo.download_fs); ++i) {
837b8e80941Smrg      for (unsigned j = 0; j < ARRAY_SIZE(st->pbo.download_fs[0]); ++j) {
838b8e80941Smrg         if (st->pbo.download_fs[i][j]) {
839b8e80941Smrg            cso_delete_fragment_shader(st->cso_context, st->pbo.download_fs[i][j]);
840b8e80941Smrg            st->pbo.download_fs[i][j] = NULL;
841b8e80941Smrg         }
842b8e80941Smrg      }
843b8e80941Smrg   }
844b8e80941Smrg
845b8e80941Smrg   if (st->pbo.gs) {
846b8e80941Smrg      cso_delete_geometry_shader(st->cso_context, st->pbo.gs);
847b8e80941Smrg      st->pbo.gs = NULL;
848b8e80941Smrg   }
849b8e80941Smrg
850b8e80941Smrg   if (st->pbo.vs) {
851b8e80941Smrg      cso_delete_vertex_shader(st->cso_context, st->pbo.vs);
852b8e80941Smrg      st->pbo.vs = NULL;
853b8e80941Smrg   }
854b8e80941Smrg}
855