st/pbo: select the right swizzle for instance IDs
[mesa.git] / src / mesa / state_tracker / st_pbo.c
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_pbo.h"
33 #include "state_tracker/st_cb_bufferobjects.h"
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_defines.h"
37 #include "pipe/p_screen.h"
38 #include "cso_cache/cso_context.h"
39 #include "tgsi/tgsi_ureg.h"
40 #include "util/u_format.h"
41 #include "util/u_inlines.h"
42 #include "util/u_upload_mgr.h"
43
44 /* Conversion to apply in the fragment shader. */
45 enum st_pbo_conversion {
46 ST_PBO_CONVERT_NONE = 0,
47 ST_PBO_CONVERT_UINT_TO_SINT,
48 ST_PBO_CONVERT_SINT_TO_UINT,
49
50 ST_NUM_PBO_CONVERSIONS
51 };
52
53 /* Final setup of buffer addressing information.
54 *
55 * buf_offset is in pixels.
56 *
57 * Returns false if something (e.g. alignment) prevents PBO upload/download.
58 */
59 bool
60 st_pbo_addresses_setup(struct st_context *st,
61 struct pipe_resource *buf, intptr_t buf_offset,
62 struct st_pbo_addresses *addr)
63 {
64 unsigned skip_pixels;
65
66 /* Check alignment against texture buffer requirements. */
67 {
68 unsigned ofs = (buf_offset * addr->bytes_per_pixel) % st->ctx->Const.TextureBufferOffsetAlignment;
69 if (ofs != 0) {
70 if (ofs % addr->bytes_per_pixel != 0)
71 return false;
72
73 skip_pixels = ofs / addr->bytes_per_pixel;
74 buf_offset -= skip_pixels;
75 } else {
76 skip_pixels = 0;
77 }
78 }
79
80 assert(buf_offset >= 0);
81
82 addr->buffer = buf;
83 addr->first_element = buf_offset;
84 addr->last_element = buf_offset + skip_pixels + addr->width - 1
85 + (addr->height - 1 + (addr->depth - 1) * addr->image_height) * addr->pixels_per_row;
86
87 if (addr->last_element - addr->first_element > st->ctx->Const.MaxTextureBufferSize - 1)
88 return false;
89
90 /* This should be ensured by Mesa before calling our callbacks */
91 assert((addr->last_element + 1) * addr->bytes_per_pixel <= buf->width0);
92
93 addr->constants.xoffset = -addr->xoffset + skip_pixels;
94 addr->constants.yoffset = -addr->yoffset;
95 addr->constants.stride = addr->pixels_per_row;
96 addr->constants.image_size = addr->pixels_per_row * addr->image_height;
97 addr->constants.layer_offset = 0;
98
99 return true;
100 }
101
102 /* Validate and fill buffer addressing information based on GL pixelstore
103 * attributes.
104 *
105 * Returns false if some aspect of the addressing (e.g. alignment) prevents
106 * PBO upload/download.
107 */
108 bool
109 st_pbo_addresses_pixelstore(struct st_context *st,
110 GLenum gl_target, bool skip_images,
111 const struct gl_pixelstore_attrib *store,
112 const void *pixels,
113 struct st_pbo_addresses *addr)
114 {
115 struct pipe_resource *buf = st_buffer_object(store->BufferObj)->buffer;
116 intptr_t buf_offset = (intptr_t) pixels;
117
118 if (buf_offset % addr->bytes_per_pixel)
119 return false;
120
121 /* Convert to texels */
122 buf_offset = buf_offset / addr->bytes_per_pixel;
123
124 /* Determine image height */
125 if (gl_target == GL_TEXTURE_1D_ARRAY) {
126 addr->image_height = 1;
127 } else {
128 addr->image_height = store->ImageHeight > 0 ? store->ImageHeight : addr->height;
129 }
130
131 /* Compute the stride, taking store->Alignment into account */
132 {
133 unsigned pixels_per_row = store->RowLength > 0 ?
134 store->RowLength : addr->width;
135 unsigned bytes_per_row = pixels_per_row * addr->bytes_per_pixel;
136 unsigned remainder = bytes_per_row % store->Alignment;
137 unsigned offset_rows;
138
139 if (remainder > 0)
140 bytes_per_row += store->Alignment - remainder;
141
142 if (bytes_per_row % addr->bytes_per_pixel)
143 return false;
144
145 addr->pixels_per_row = bytes_per_row / addr->bytes_per_pixel;
146
147 offset_rows = store->SkipRows;
148 if (skip_images)
149 offset_rows += addr->image_height * store->SkipImages;
150
151 buf_offset += store->SkipPixels + addr->pixels_per_row * offset_rows;
152 }
153
154 if (!st_pbo_addresses_setup(st, buf, buf_offset, addr))
155 return false;
156
157 /* Support GL_PACK_INVERT_MESA */
158 if (store->Invert) {
159 addr->constants.xoffset += (addr->height - 1) * addr->constants.stride;
160 addr->constants.stride = -addr->constants.stride;
161 }
162
163 return true;
164 }
165
166 /* For download from a framebuffer, we may have to invert the Y axis. The
167 * setup is as follows:
168 * - set viewport to inverted, so that the position sysval is correct for
169 * texel fetches
170 * - this function adjusts the fragment shader's constant buffer to compute
171 * the correct destination addresses.
172 */
173 void
174 st_pbo_addresses_invert_y(struct st_pbo_addresses *addr,
175 unsigned viewport_height)
176 {
177 addr->constants.xoffset +=
178 (viewport_height - 1 + 2 * addr->constants.yoffset) * addr->constants.stride;
179 addr->constants.stride = -addr->constants.stride;
180 }
181
182 /* Setup all vertex pipeline state, rasterizer state, and fragment shader
183 * constants, and issue the draw call for PBO upload/download.
184 *
185 * The caller is responsible for saving and restoring state, as well as for
186 * setting other fragment shader state (fragment shader, samplers), and
187 * framebuffer/viewport/DSA/blend state.
188 */
189 bool
190 st_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr,
191 unsigned surface_width, unsigned surface_height)
192 {
193 struct cso_context *cso = st->cso_context;
194
195 /* Setup vertex and geometry shaders */
196 if (!st->pbo.vs) {
197 st->pbo.vs = st_pbo_create_vs(st);
198 if (!st->pbo.vs)
199 return false;
200 }
201
202 if (addr->depth != 1 && st->pbo.use_gs && !st->pbo.gs) {
203 st->pbo.gs = st_pbo_create_gs(st);
204 if (!st->pbo.gs)
205 return false;
206 }
207
208 cso_set_vertex_shader_handle(cso, st->pbo.vs);
209
210 cso_set_geometry_shader_handle(cso, addr->depth != 1 ? st->pbo.gs : NULL);
211
212 cso_set_tessctrl_shader_handle(cso, NULL);
213
214 cso_set_tesseval_shader_handle(cso, NULL);
215
216 /* Upload vertices */
217 {
218 struct pipe_vertex_buffer vbo;
219 struct pipe_vertex_element velem;
220
221 float x0 = (float) addr->xoffset / surface_width * 2.0f - 1.0f;
222 float y0 = (float) addr->yoffset / surface_height * 2.0f - 1.0f;
223 float x1 = (float) (addr->xoffset + addr->width) / surface_width * 2.0f - 1.0f;
224 float y1 = (float) (addr->yoffset + addr->height) / surface_height * 2.0f - 1.0f;
225
226 float *verts = NULL;
227
228 vbo.user_buffer = NULL;
229 vbo.buffer = NULL;
230 vbo.stride = 2 * sizeof(float);
231
232 u_upload_alloc(st->pipe->stream_uploader, 0, 8 * sizeof(float), 4,
233 &vbo.buffer_offset, &vbo.buffer, (void **) &verts);
234 if (!verts)
235 return false;
236
237 verts[0] = x0;
238 verts[1] = y0;
239 verts[2] = x0;
240 verts[3] = y1;
241 verts[4] = x1;
242 verts[5] = y0;
243 verts[6] = x1;
244 verts[7] = y1;
245
246 u_upload_unmap(st->pipe->stream_uploader);
247
248 velem.src_offset = 0;
249 velem.instance_divisor = 0;
250 velem.vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
251 velem.src_format = PIPE_FORMAT_R32G32_FLOAT;
252
253 cso_set_vertex_elements(cso, 1, &velem);
254
255 cso_set_vertex_buffers(cso, velem.vertex_buffer_index, 1, &vbo);
256
257 pipe_resource_reference(&vbo.buffer, NULL);
258 }
259
260 /* Upload constants */
261 {
262 struct pipe_constant_buffer cb;
263
264 if (!st->has_user_constbuf) {
265 cb.buffer = NULL;
266 cb.user_buffer = NULL;
267 u_upload_data(st->pipe->const_uploader, 0, sizeof(addr->constants),
268 st->ctx->Const.UniformBufferOffsetAlignment,
269 &addr->constants, &cb.buffer_offset, &cb.buffer);
270 if (!cb.buffer)
271 return false;
272
273 u_upload_unmap(st->pipe->const_uploader);
274 } else {
275 cb.buffer = NULL;
276 cb.user_buffer = &addr->constants;
277 cb.buffer_offset = 0;
278 }
279 cb.buffer_size = sizeof(addr->constants);
280
281 cso_set_constant_buffer(cso, PIPE_SHADER_FRAGMENT, 0, &cb);
282
283 pipe_resource_reference(&cb.buffer, NULL);
284 }
285
286 /* Rasterizer state */
287 cso_set_rasterizer(cso, &st->pbo.raster);
288
289 /* Disable stream output */
290 cso_set_stream_outputs(cso, 0, NULL, 0);
291
292 if (addr->depth == 1) {
293 cso_draw_arrays(cso, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
294 } else {
295 cso_draw_arrays_instanced(cso, PIPE_PRIM_TRIANGLE_STRIP,
296 0, 4, 0, addr->depth);
297 }
298
299 return true;
300 }
301
302 void *
303 st_pbo_create_vs(struct st_context *st)
304 {
305 struct ureg_program *ureg;
306 struct ureg_src in_pos;
307 struct ureg_src in_instanceid;
308 struct ureg_dst out_pos;
309 struct ureg_dst out_layer;
310
311 ureg = ureg_create(PIPE_SHADER_VERTEX);
312 if (!ureg)
313 return NULL;
314
315 in_pos = ureg_DECL_vs_input(ureg, TGSI_SEMANTIC_POSITION);
316
317 out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
318
319 if (st->pbo.layers) {
320 in_instanceid = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_INSTANCEID, 0);
321
322 if (!st->pbo.use_gs)
323 out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0);
324 }
325
326 /* out_pos = in_pos */
327 ureg_MOV(ureg, out_pos, in_pos);
328
329 if (st->pbo.layers) {
330 if (st->pbo.use_gs) {
331 /* out_pos.z = i2f(gl_InstanceID) */
332 ureg_I2F(ureg, ureg_writemask(out_pos, TGSI_WRITEMASK_Z),
333 ureg_scalar(in_instanceid, TGSI_SWIZZLE_X));
334 } else {
335 /* out_layer = gl_InstanceID */
336 ureg_MOV(ureg, ureg_writemask(out_layer, TGSI_WRITEMASK_X),
337 ureg_scalar(in_instanceid, TGSI_SWIZZLE_X));
338 }
339 }
340
341 ureg_END(ureg);
342
343 return ureg_create_shader_and_destroy(ureg, st->pipe);
344 }
345
346 void *
347 st_pbo_create_gs(struct st_context *st)
348 {
349 static const int zero = 0;
350 struct ureg_program *ureg;
351 struct ureg_dst out_pos;
352 struct ureg_dst out_layer;
353 struct ureg_src in_pos;
354 struct ureg_src imm;
355 unsigned i;
356
357 ureg = ureg_create(PIPE_SHADER_GEOMETRY);
358 if (!ureg)
359 return NULL;
360
361 ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, PIPE_PRIM_TRIANGLES);
362 ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, PIPE_PRIM_TRIANGLE_STRIP);
363 ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, 3);
364
365 out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
366 out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0);
367
368 in_pos = ureg_DECL_input(ureg, TGSI_SEMANTIC_POSITION, 0, 0, 1);
369
370 imm = ureg_DECL_immediate_int(ureg, &zero, 1);
371
372 for (i = 0; i < 3; ++i) {
373 struct ureg_src in_pos_vertex = ureg_src_dimension(in_pos, i);
374
375 /* out_pos = in_pos[i] */
376 ureg_MOV(ureg, out_pos, in_pos_vertex);
377
378 /* out_layer.x = f2i(in_pos[i].z) */
379 ureg_F2I(ureg, ureg_writemask(out_layer, TGSI_WRITEMASK_X),
380 ureg_scalar(in_pos_vertex, TGSI_SWIZZLE_Z));
381
382 ureg_EMIT(ureg, ureg_scalar(imm, TGSI_SWIZZLE_X));
383 }
384
385 ureg_END(ureg);
386
387 return ureg_create_shader_and_destroy(ureg, st->pipe);
388 }
389
390 static void
391 build_conversion(struct ureg_program *ureg, const struct ureg_dst *temp,
392 enum st_pbo_conversion conversion)
393 {
394 switch (conversion) {
395 case ST_PBO_CONVERT_SINT_TO_UINT:
396 ureg_IMAX(ureg, *temp, ureg_src(*temp), ureg_imm1i(ureg, 0));
397 break;
398 case ST_PBO_CONVERT_UINT_TO_SINT:
399 ureg_UMIN(ureg, *temp, ureg_src(*temp), ureg_imm1u(ureg, (1u << 31) - 1));
400 break;
401 default:
402 /* no-op */
403 break;
404 }
405 }
406
407 static void *
408 create_fs(struct st_context *st, bool download, enum pipe_texture_target target,
409 enum st_pbo_conversion conversion)
410 {
411 struct pipe_context *pipe = st->pipe;
412 struct pipe_screen *screen = pipe->screen;
413 struct ureg_program *ureg;
414 bool have_layer;
415 struct ureg_dst out;
416 struct ureg_src sampler;
417 struct ureg_src pos;
418 struct ureg_src layer;
419 struct ureg_src const0;
420 struct ureg_src const1;
421 struct ureg_dst temp0;
422
423 have_layer =
424 st->pbo.layers &&
425 (!download || target == PIPE_TEXTURE_1D_ARRAY
426 || target == PIPE_TEXTURE_2D_ARRAY
427 || target == PIPE_TEXTURE_3D
428 || target == PIPE_TEXTURE_CUBE
429 || target == PIPE_TEXTURE_CUBE_ARRAY);
430
431 ureg = ureg_create(PIPE_SHADER_FRAGMENT);
432 if (!ureg)
433 return NULL;
434
435 if (!download) {
436 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
437 } else {
438 struct ureg_src image;
439
440 /* writeonly images do not require an explicitly given format. */
441 image = ureg_DECL_image(ureg, 0, TGSI_TEXTURE_BUFFER, PIPE_FORMAT_NONE,
442 true, false);
443 out = ureg_dst(image);
444 }
445
446 sampler = ureg_DECL_sampler(ureg, 0);
447 if (screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL)) {
448 pos = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0);
449 } else {
450 pos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0,
451 TGSI_INTERPOLATE_LINEAR);
452 }
453 if (have_layer) {
454 layer = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_LAYER, 0,
455 TGSI_INTERPOLATE_CONSTANT);
456 }
457 const0 = ureg_DECL_constant(ureg, 0);
458 const1 = ureg_DECL_constant(ureg, 1);
459 temp0 = ureg_DECL_temporary(ureg);
460
461 /* Note: const0 = [ -xoffset + skip_pixels, -yoffset, stride, image_height ] */
462
463 /* temp0.xy = f2i(temp0.xy) */
464 ureg_F2I(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY),
465 ureg_swizzle(pos,
466 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
467 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y));
468
469 /* temp0.xy = temp0.xy + const0.xy */
470 ureg_UADD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY),
471 ureg_swizzle(ureg_src(temp0),
472 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
473 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y),
474 ureg_swizzle(const0,
475 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
476 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y));
477
478 /* temp0.x = const0.z * temp0.y + temp0.x */
479 ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X),
480 ureg_scalar(const0, TGSI_SWIZZLE_Z),
481 ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_Y),
482 ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X));
483
484 if (have_layer) {
485 /* temp0.x = const0.w * layer + temp0.x */
486 ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X),
487 ureg_scalar(const0, TGSI_SWIZZLE_W),
488 ureg_scalar(layer, TGSI_SWIZZLE_X),
489 ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X));
490 }
491
492 /* temp0.w = 0 */
493 ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_W), ureg_imm1u(ureg, 0));
494
495 if (download) {
496 struct ureg_dst temp1;
497 struct ureg_src op[2];
498
499 temp1 = ureg_DECL_temporary(ureg);
500
501 /* temp1.xy = pos.xy */
502 ureg_F2I(ureg, ureg_writemask(temp1, TGSI_WRITEMASK_XY), pos);
503
504 /* temp1.zw = 0 */
505 ureg_MOV(ureg, ureg_writemask(temp1, TGSI_WRITEMASK_ZW), ureg_imm1u(ureg, 0));
506
507 if (have_layer) {
508 struct ureg_dst temp1_layer =
509 ureg_writemask(temp1, target == PIPE_TEXTURE_1D_ARRAY ? TGSI_WRITEMASK_Y
510 : TGSI_WRITEMASK_Z);
511
512 /* temp1.y/z = layer */
513 ureg_MOV(ureg, temp1_layer, ureg_scalar(layer, TGSI_SWIZZLE_X));
514
515 if (target == PIPE_TEXTURE_3D) {
516 /* temp1.z += layer_offset */
517 ureg_UADD(ureg, temp1_layer,
518 ureg_scalar(ureg_src(temp1), TGSI_SWIZZLE_Z),
519 ureg_scalar(const1, TGSI_SWIZZLE_X));
520 }
521 }
522
523 /* temp1 = txf(sampler, temp1) */
524 ureg_TXF(ureg, temp1, util_pipe_tex_to_tgsi_tex(target, 1),
525 ureg_src(temp1), sampler);
526
527 build_conversion(ureg, &temp1, conversion);
528
529 /* store(out, temp0, temp1) */
530 op[0] = ureg_src(temp0);
531 op[1] = ureg_src(temp1);
532 ureg_memory_insn(ureg, TGSI_OPCODE_STORE, &out, 1, op, 2, 0,
533 TGSI_TEXTURE_BUFFER, PIPE_FORMAT_NONE);
534
535 ureg_release_temporary(ureg, temp1);
536 } else {
537 /* out = txf(sampler, temp0.x) */
538 ureg_TXF(ureg, temp0, TGSI_TEXTURE_BUFFER, ureg_src(temp0), sampler);
539
540 build_conversion(ureg, &temp0, conversion);
541
542 ureg_MOV(ureg, out, ureg_src(temp0));
543 }
544
545 ureg_release_temporary(ureg, temp0);
546
547 ureg_END(ureg);
548
549 return ureg_create_shader_and_destroy(ureg, pipe);
550 }
551
552 static enum st_pbo_conversion
553 get_pbo_conversion(enum pipe_format src_format, enum pipe_format dst_format)
554 {
555 if (util_format_is_pure_uint(src_format)) {
556 if (util_format_is_pure_sint(dst_format))
557 return ST_PBO_CONVERT_UINT_TO_SINT;
558 } else if (util_format_is_pure_sint(src_format)) {
559 if (util_format_is_pure_uint(dst_format))
560 return ST_PBO_CONVERT_SINT_TO_UINT;
561 }
562
563 return ST_PBO_CONVERT_NONE;
564 }
565
566 void *
567 st_pbo_get_upload_fs(struct st_context *st,
568 enum pipe_format src_format,
569 enum pipe_format dst_format)
570 {
571 STATIC_ASSERT(ARRAY_SIZE(st->pbo.upload_fs) == ST_NUM_PBO_CONVERSIONS);
572
573 enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
574
575 if (!st->pbo.upload_fs[conversion])
576 st->pbo.upload_fs[conversion] = create_fs(st, false, 0, conversion);
577
578 return st->pbo.upload_fs[conversion];
579 }
580
581 void *
582 st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target,
583 enum pipe_format src_format,
584 enum pipe_format dst_format)
585 {
586 STATIC_ASSERT(ARRAY_SIZE(st->pbo.download_fs) == ST_NUM_PBO_CONVERSIONS);
587 assert(target < PIPE_MAX_TEXTURE_TYPES);
588
589 enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
590
591 if (!st->pbo.download_fs[conversion][target])
592 st->pbo.download_fs[conversion][target] = create_fs(st, true, target, conversion);
593
594 return st->pbo.download_fs[conversion][target];
595 }
596
597 void
598 st_init_pbo_helpers(struct st_context *st)
599 {
600 struct pipe_context *pipe = st->pipe;
601 struct pipe_screen *screen = pipe->screen;
602
603 st->pbo.upload_enabled =
604 screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS) &&
605 screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT) >= 1 &&
606 screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_INTEGERS);
607 if (!st->pbo.upload_enabled)
608 return;
609
610 st->pbo.download_enabled =
611 st->pbo.upload_enabled &&
612 screen->get_param(screen, PIPE_CAP_SAMPLER_VIEW_TARGET) &&
613 screen->get_param(screen, PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT) &&
614 screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
615 PIPE_SHADER_CAP_MAX_SHADER_IMAGES) >= 1;
616
617 st->pbo.rgba_only =
618 screen->get_param(screen, PIPE_CAP_BUFFER_SAMPLER_VIEW_RGBA_ONLY);
619
620 if (screen->get_param(screen, PIPE_CAP_TGSI_INSTANCEID)) {
621 if (screen->get_param(screen, PIPE_CAP_TGSI_VS_LAYER_VIEWPORT)) {
622 st->pbo.layers = true;
623 } else if (screen->get_param(screen, PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES) >= 3) {
624 st->pbo.layers = true;
625 st->pbo.use_gs = true;
626 }
627 }
628
629 /* Blend state */
630 memset(&st->pbo.upload_blend, 0, sizeof(struct pipe_blend_state));
631 st->pbo.upload_blend.rt[0].colormask = PIPE_MASK_RGBA;
632
633 /* Rasterizer state */
634 memset(&st->pbo.raster, 0, sizeof(struct pipe_rasterizer_state));
635 st->pbo.raster.half_pixel_center = 1;
636 }
637
638 void
639 st_destroy_pbo_helpers(struct st_context *st)
640 {
641 unsigned i;
642
643 for (i = 0; i < ARRAY_SIZE(st->pbo.upload_fs); ++i) {
644 if (st->pbo.upload_fs[i]) {
645 cso_delete_fragment_shader(st->cso_context, st->pbo.upload_fs[i]);
646 st->pbo.upload_fs[i] = NULL;
647 }
648 }
649
650 for (i = 0; i < ARRAY_SIZE(st->pbo.download_fs); ++i) {
651 for (unsigned j = 0; j < ARRAY_SIZE(st->pbo.download_fs[0]); ++j) {
652 if (st->pbo.download_fs[i][j]) {
653 cso_delete_fragment_shader(st->cso_context, st->pbo.download_fs[i][j]);
654 st->pbo.download_fs[i][j] = NULL;
655 }
656 }
657 }
658
659 if (st->pbo.gs) {
660 cso_delete_geometry_shader(st->cso_context, st->pbo.gs);
661 st->pbo.gs = NULL;
662 }
663
664 if (st->pbo.vs) {
665 cso_delete_vertex_shader(st->cso_context, st->pbo.vs);
666 st->pbo.vs = NULL;
667 }
668 }