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