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