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_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  */
64 bool
st_pbo_addresses_setup(struct st_context * st,struct pipe_resource * buf,intptr_t buf_offset,struct st_pbo_addresses * addr)65 st_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  */
113 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)114 st_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  */
178 void
st_pbo_addresses_invert_y(struct st_pbo_addresses * addr,unsigned viewport_height)179 st_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  */
194 bool
st_pbo_draw(struct st_context * st,const struct st_pbo_addresses * addr,unsigned surface_width,unsigned surface_height)195 st_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 
297 void *
st_pbo_create_vs(struct st_context * st)298 st_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 
344 void *
st_pbo_create_gs(struct st_context * st)345 st_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 
388 static const struct glsl_type *
sampler_type_for_target(enum pipe_texture_target target,enum st_pbo_conversion conv)389 sampler_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 
417 static void *
create_fs(struct st_context * st,bool download,enum pipe_texture_target target,enum st_pbo_conversion conversion,bool need_layer)418 create_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 
586 static enum st_pbo_conversion
get_pbo_conversion(enum pipe_format src_format,enum pipe_format dst_format)587 get_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 
604 void *
st_pbo_get_upload_fs(struct st_context * st,enum pipe_format src_format,enum pipe_format dst_format,bool need_layer)605 st_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 
620 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)621 st_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 
637 void
st_init_pbo_helpers(struct st_context * st)638 st_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 
677 void
st_destroy_pbo_helpers(struct st_context * st)678 st_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