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