diff --git a/src/compiler/glsl/ast.h b/src/compiler/glsl/ast.h index 8d1868885ef..99bc01087a8 100644 --- a/src/compiler/glsl/ast.h +++ b/src/compiler/glsl/ast.h @@ -667,6 +667,11 @@ struct ast_type_qualifier { unsigned non_coherent:1; /** \} */ + /** \name Qualifiers for GL_EXT_shader_pixel_local_storage */ + /** \{ */ + unsigned pixel_local_storage:2; + /** \} */ + /** \name Layout qualifiers for NV_compute_shader_derivatives */ /** \{ */ unsigned derivative_group:1; diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp index e93e2481d7c..030b54e46c3 100644 --- a/src/compiler/glsl/ast_to_hir.cpp +++ b/src/compiler/glsl/ast_to_hir.cpp @@ -94,14 +94,24 @@ public: /* We can have memory_write_only set on both images and buffer variables, * but in the former there is a distinction between reads from * the variable itself (write_only) and from the memory they point to - * (memory_write_only), while in the case of buffer variables there is - * no such distinction, that is why this check here is limited to - * buffer variables alone. + * (memory_write_only), while in the case of buffer and pixel local + * storage variables there is no such distinction, that is why this check + * here is limited to buffer and pixel local storage variables. */ - if (!var || var->data.mode != ir_var_shader_storage) + if (!var) return visit_continue; - if (var->data.memory_write_only) { + if (var->data.mode == ir_var_shader_storage && + var->data.memory_write_only) + { + found = var; + return visit_stop; + } + + /* Variables declared with the__pixel_local_outEXT qualifier are + * write-only. + */ + if (var->data.pixel_local_storage == GLSL_PIXEL_LOCAL_STORAGE_OUT) { found = var; return visit_stop; } @@ -994,6 +1004,28 @@ do_assignment(ir_exec_list *instructions, struct _mesa_glsl_parse_state *state, } else if (!lhs->is_lvalue(state)) { _mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment"); error_emitted = true; + } else if (lhs_var != NULL) { + switch(lhs_var->data.mode) { + case ir_var_shader_pixel_local_storage: + state->fs_writes_pixel_local_storage = true; + break; + case ir_var_shader_out: + state->fs_writes_output = true; + break; + } + + /* From the GL_EXT_shader_pixel_local_storage spec: + * + * "It is a compile-time error for a shader to statically write to + * both regular user-defined fragment outputs and to pixel local + * storage variables." + */ + if (state->fs_writes_pixel_local_storage && state->fs_writes_output) { + _mesa_glsl_error(&lhs_loc, state, + "shader writes to both output and pixel local " + "storage"); + error_emitted = true; + } } } @@ -3602,7 +3634,10 @@ validate_image_format_qualifier_for_type(struct _mesa_glsl_parse_state *state, * "Format layout qualifiers can be used on image variable declarations * (those declared with a basic type having “image ” in its keyword)." */ - if (!glsl_type_is_image(type) && qual->flags.q.explicit_image_format) { + if (!glsl_type_is_image(type) && + (qual->flags.q.explicit_image_format && + !qual->flags.q.pixel_local_storage)) + { _mesa_glsl_error(loc, state, "format layout qualifiers may only be " "applied to images"); return false; @@ -5323,6 +5358,17 @@ ast_declarator_list::hir(ir_exec_list *instructions, "interface blocks"); } + /* Similarly, the EXT_shader_pixel_local_storage spec says: + * "Pixel local storage variables may only be declared inside + * interface blocks..." + */ + if (type->qualifier.flags.q.pixel_local_storage && + !glsl_type_is_interface(decl_type)) { + _mesa_glsl_error(&loc, state, + "pixel local storage variables cannot be declared " + "outside interface blocks"); + } + /* An offset-qualified atomic counter declaration sets the default * offset for the next declaration within the same atomic counter * buffer. @@ -7815,8 +7861,13 @@ ast_process_struct_or_iface_block_members(ir_exec_list *instructions, fields[i].explicit_xfb_buffer = explicit_xfb_buffer; fields[i].xfb_buffer = xfb_buffer; fields[i].xfb_stride = xfb_stride; + fields[i].pixel_local_storage = qual->flags.q.pixel_local_storage; - if (qual->flags.q.explicit_location) { + /* for pixel local storage, all locations are effectively "explicit" */ + if (var_mode == ir_var_shader_pixel_local_storage) { + fields[i].location = FRAG_RESULT_DATA0 + expl_location; + expl_location += glsl_count_attribute_slots(fields[i].type, false); + } else if (qual->flags.q.explicit_location) { unsigned qual_location; if (process_qualifier_constant(state, &loc, "location", qual->location, &qual_location)) { @@ -7975,6 +8026,7 @@ ast_process_struct_or_iface_block_members(ir_exec_list *instructions, * the format qualifier is only accepted for images. */ if (var_mode == ir_var_shader_storage || + var_mode == ir_var_shader_pixel_local_storage || glsl_type_is_image(glsl_without_array(field_type))) { /* For readonly and writeonly qualifiers the field definition, * if set, overwrites the layout qualifier. @@ -7999,6 +8051,22 @@ ast_process_struct_or_iface_block_members(ir_exec_list *instructions, fields[i].memory_restrict = qual->flags.q.restrict_flag || (layout && layout->flags.q.restrict_flag); + if (qual->flags.q.pixel_local_storage) { + pipe_format this_image_format = layout->image_format; + glsl_base_type this_image_type = layout->image_base_type; + if (qual->flags.q.explicit_image_format) { + this_image_format = qual->image_format; + this_image_type = qual->image_base_type; + } + if (this_image_type != field_type->base_type || + util_format_get_nr_components(this_image_format) != + field_type->vector_elements) { + _mesa_glsl_error(&loc, state, "format qualifier doesn't " + "match the base data type of the image"); + } + + fields[i].image_format = this_image_format; + } if (glsl_type_is_image(glsl_without_array(field_type))) { if (qual->flags.q.explicit_image_format) { if (qual->image_base_type != @@ -8220,6 +8288,11 @@ ast_interface_block::hir(ir_exec_list *instructions, } else { allowed_blk_qualifiers.flags.q.uniform = 1; } + } else if (this->layout.flags.q.pixel_local_storage) { + allowed_blk_qualifiers.flags.q.pixel_local_storage = 3; + allowed_blk_qualifiers.flags.q.read_only = 1; + allowed_blk_qualifiers.flags.q.write_only = 1; + allowed_blk_qualifiers.flags.q.explicit_image_format = 1; } else { /* Interface block */ assert(this->layout.flags.q.in || this->layout.flags.q.out); @@ -8286,6 +8359,9 @@ ast_interface_block::hir(ir_exec_list *instructions, } else if (this->layout.flags.q.buffer) { var_mode = ir_var_shader_storage; iface_type_name = "buffer"; + } else if (this->layout.flags.q.pixel_local_storage) { + var_mode = ir_var_shader_pixel_local_storage; + iface_type_name = "pixel local storage"; } else { var_mode = ir_var_auto; iface_type_name = "UNKNOWN"; @@ -8628,6 +8704,41 @@ ast_interface_block::hir(ir_exec_list *instructions, } + /* + * Check various features for EXT_shader_pixel_local_storage + */ + if (var_mode == ir_var_shader_pixel_local_storage) { + /* ensure we do not exceed the available space */ + unsigned bytes_used = 4 * num_variables; + if (bytes_used > state->caps->shader_pixel_local_storage_size) { + _mesa_glsl_error(&loc, state, + "bytes needed for pixel local storage (%u) exceeds " + "maximum (%u)", bytes_used, + state->caps->shader_pixel_local_storage_size); + } + /* The GL_EXT_shader_pixel_local_storage spec says: + * + * "A shader may only declare a single input and a single output pixel + * local storage block." + */ + unsigned flags = this->layout.flags.q.pixel_local_storage; + if (flags & GLSL_PIXEL_LOCAL_STORAGE_IN) { + if (state->pixel_local_input_specified) { + _mesa_glsl_error(&loc, state, + "multiple pixel local storage input interfaces " + "specified"); + } + state->pixel_local_input_specified = true; + } + if (flags & GLSL_PIXEL_LOCAL_STORAGE_OUT) { + if (state->pixel_local_output_specified) { + _mesa_glsl_error(&loc, state, + "multiple pixel local storage output interfaces " + "specified"); + } + state->pixel_local_output_specified = true; + } + } /* Page 39 (page 45 of the PDF) of section 4.3.7 in the GLSL ES 3.00 spec * says: * @@ -8794,9 +8905,14 @@ ast_interface_block::hir(ir_exec_list *instructions, if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform) var->data.read_only = true; + else if (var_mode == ir_var_shader_pixel_local_storage) + var->data.read_only = + this->layout.flags.q.pixel_local_storage == + GLSL_PIXEL_LOCAL_STORAGE_IN; var->data.patch = this->layout.flags.q.patch; var->data.per_primitive = this->layout.flags.q.per_primitive; + var->data.pixel_local_storage = this->layout.flags.q.pixel_local_storage; if (state->stage == MESA_SHADER_GEOMETRY && var_mode == ir_var_shader_in) handle_geometry_shader_input_decl(state, loc, var); @@ -8832,6 +8948,9 @@ ast_interface_block::hir(ir_exec_list *instructions, if (layout.flags.q.explicit_location) { var->data.location = expl_location; var->data.explicit_location = true; + } else if (layout.flags.q.pixel_local_storage) { + var->data.location = FRAG_RESULT_DATA0; + var->data.explicit_location = true; } state->symbols->add_variable(var); @@ -8871,6 +8990,14 @@ ast_interface_block::hir(ir_exec_list *instructions, if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform) var->data.read_only = true; + if (var_mode == ir_var_shader_pixel_local_storage) { + var->data.pixel_local_storage = + this->layout.flags.q.pixel_local_storage; + var->data.read_only = + var->data.pixel_local_storage == GLSL_PIXEL_LOCAL_STORAGE_IN; + var->data.image_format = fields[i].image_format; + } + /* Precision qualifiers do not have any meaning in Desktop GLSL */ if (state->es_shader) { var->data.precision = diff --git a/src/compiler/glsl/ast_type.cpp b/src/compiler/glsl/ast_type.cpp index c7f827ab1fa..51fa331bf00 100644 --- a/src/compiler/glsl/ast_type.cpp +++ b/src/compiler/glsl/ast_type.cpp @@ -942,6 +942,7 @@ ast_type_qualifier::validate_flags(YYLTYPE *loc, Q(noperspective); Q(origin_upper_left); Q(pixel_center_integer); + Q(pixel_local_storage); Q2(explicit_align, align); Q2(explicit_component, component); Q2(explicit_location, location); diff --git a/src/compiler/glsl/gl_nir_link_interface_blocks.c b/src/compiler/glsl/gl_nir_link_interface_blocks.c index 68aee470388..4564c18b9ab 100644 --- a/src/compiler/glsl/gl_nir_link_interface_blocks.c +++ b/src/compiler/glsl/gl_nir_link_interface_blocks.c @@ -574,6 +574,13 @@ gl_nir_validate_intrastage_interface_blocks(struct gl_shader_program *prog, case nir_var_mem_ssbo: definitions = buffer_interfaces; break; + case nir_var_mem_pixel_local_in: + case nir_var_mem_pixel_local_out: + case nir_var_mem_pixel_local_inout: + /* These aren't intrastage, they're fragment shader + * only, so they don't need to be checked here. + */ + continue; default: /* Only in, out, and uniform interfaces are legal, so we should * never get here. diff --git a/src/compiler/glsl/gl_nir_lower_named_interface_blocks.c b/src/compiler/glsl/gl_nir_lower_named_interface_blocks.c index 0dd2a5aeb0e..b95bcfe8c31 100644 --- a/src/compiler/glsl/gl_nir_lower_named_interface_blocks.c +++ b/src/compiler/glsl/gl_nir_lower_named_interface_blocks.c @@ -147,7 +147,8 @@ flatten_named_interface_deref(void *mem_ctx, nir_builder *b, struct hash_table *interface_namespace, bool is_src0) { - nir_variable_mode mask = nir_var_shader_in | nir_var_shader_out; + nir_variable_mode mask = nir_var_shader_in | nir_var_shader_out | + nir_var_any_pixel_local; if (!nir_deref_mode_is_one_of(deref, mask)) return false; @@ -252,7 +253,8 @@ lower_named_interface_blocks(struct gl_linked_shader *sh) * hash table so they can be used in the second pass. */ nir_foreach_variable_with_modes_safe(var, sh->Program->nir, - nir_var_shader_in | nir_var_shader_out) { + nir_var_shader_in | nir_var_shader_out | + nir_var_any_pixel_local) { const struct glsl_type * iface_t = glsl_without_array(var->type); if (iface_t != var->interface_type) continue; @@ -283,7 +285,6 @@ lower_named_interface_blocks(struct gl_linked_shader *sh) new_var->data.explicit_location = (new_var->data.location >= 0); new_var->data.offset = field_data->offset; new_var->data.explicit_offset = (field_data->offset >= 0); - new_var->data.xfb.buffer = field_data->xfb_buffer; new_var->data.explicit_xfb_buffer = field_data->explicit_xfb_buffer; new_var->data.interpolation = field_data->interpolation; new_var->data.centroid = field_data->centroid; @@ -294,6 +295,11 @@ lower_named_interface_blocks(struct gl_linked_shader *sh) new_var->data.how_declared = var->data.how_declared; new_var->data.from_named_ifc_block = 1; + if (new_var->data.mode & nir_var_any_pixel_local) + new_var->data.image.format = field_data->image_format; + else + new_var->data.xfb.buffer = field_data->xfb_buffer; + new_var->interface_type = var->type; _mesa_hash_table_insert(interface_namespace, iface_field_name, new_var); @@ -315,7 +321,8 @@ lower_named_interface_blocks(struct gl_linked_shader *sh) * needed now that the default interface block has been lowered away. */ nir_foreach_variable_with_modes(var, sh->Program->nir, - nir_var_shader_in | nir_var_shader_out) { + nir_var_shader_in | nir_var_shader_out | + nir_var_any_pixel_local) { if (var->data.mode == nir_var_shader_in) { if (sh->Program->nir->info.stage == MESA_SHADER_TESS_EVAL && @@ -331,9 +338,7 @@ lower_named_interface_blocks(struct gl_linked_shader *sh) var->data.compact = glsl_type_is_scalar(glsl_without_array(var->type)); } - } else { - assert(var->data.mode == nir_var_shader_out); - + } else if (var->data.mode == nir_var_shader_out) { if (sh->Program->nir->info.stage == MESA_SHADER_TESS_CTRL && (var->data.location == VARYING_SLOT_TESS_LEVEL_INNER || var->data.location == VARYING_SLOT_TESS_LEVEL_OUTER)) { diff --git a/src/compiler/glsl/glsl_lexer.ll b/src/compiler/glsl/glsl_lexer.ll index 309aad2ca82..4bc34f98a7b 100644 --- a/src/compiler/glsl/glsl_lexer.ll +++ b/src/compiler/glsl/glsl_lexer.ll @@ -450,6 +450,9 @@ flat KEYWORD_WITH_ALT(130, 100, 130, 300, yyextra->EXT_gpu_shader4_enable, FLAT smooth KEYWORD(130, 300, 130, 300, SMOOTH); noperspective KEYWORD_WITH_ALT(130, 300, 130, 0, yyextra->EXT_gpu_shader4_enable || yyextra->NV_shader_noperspective_interpolation_enable, NOPERSPECTIVE); patch KEYWORD_WITH_ALT(0, 300, 400, 320, yyextra->has_tessellation_shader(), PATCH); +__pixel_localEXT KEYWORD_WITH_ALT(0, 0, 0, 300, yyextra->EXT_shader_pixel_local_storage_enable, PIXEL_LOCAL); +__pixel_local_inEXT KEYWORD_WITH_ALT(0, 0, 0, 300, yyextra->EXT_shader_pixel_local_storage_enable, PIXEL_LOCAL_IN); +__pixel_local_outEXT KEYWORD_WITH_ALT(0, 0, 0, 300, yyextra->EXT_shader_pixel_local_storage_enable, PIXEL_LOCAL_OUT); sampler1D DEPRECATED_ES_TYPE(&glsl_type_builtin_sampler1D); sampler2D { yylval->type = &glsl_type_builtin_sampler2D; return BASIC_TYPE_TOK; } diff --git a/src/compiler/glsl/glsl_parser.yy b/src/compiler/glsl/glsl_parser.yy index 3a39836e459..edb34bd0f03 100644 --- a/src/compiler/glsl/glsl_parser.yy +++ b/src/compiler/glsl/glsl_parser.yy @@ -144,6 +144,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token BREAK BUFFER CONTINUE DO ELSE FOR IF DEMOTE DISCARD RETURN SWITCH CASE DEFAULT %token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING SAMPLE %token NOPERSPECTIVE FLAT SMOOTH +%token PIXEL_LOCAL PIXEL_LOCAL_IN PIXEL_LOCAL_OUT %token IMAGE1DSHADOW IMAGE2DSHADOW IMAGE1DARRAYSHADOW IMAGE2DARRAYSHADOW %token COHERENT VOLATILE RESTRICT READONLY WRITEONLY %token SHARED @@ -1335,7 +1336,8 @@ layout_qualifier_id: } /* Layout qualifiers for ARB_shader_image_load_store. */ - if (state->has_shader_image_load_store()) { + if (state->has_shader_image_load_store() || + state->EXT_shader_pixel_local_storage_enable) { if (!$$.flags.i) { static const struct { const char *name; @@ -1351,58 +1353,68 @@ layout_qualifier_id: /* NV_image_formats */ bool nv_image_formats; bool ext_qualifiers; + /* for __pixel_localEXT */ + bool pixel_local_qualifiers; } map[] = { - { "rgba32f", PIPE_FORMAT_R32G32B32A32_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false }, - { "rgba16f", PIPE_FORMAT_R16G16B16A16_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false }, - { "rg32f", PIPE_FORMAT_R32G32_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rg16f", PIPE_FORMAT_R16G16_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r11f_g11f_b10f", PIPE_FORMAT_R11G11B10_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r32f", PIPE_FORMAT_R32_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false }, - { "r16f", PIPE_FORMAT_R16_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rgba32ui", PIPE_FORMAT_R32G32B32A32_UINT, GLSL_TYPE_UINT, 130, 310, false, false }, - { "rgba16ui", PIPE_FORMAT_R16G16B16A16_UINT, GLSL_TYPE_UINT, 130, 310, false, false }, - { "rgb10_a2ui", PIPE_FORMAT_R10G10B10A2_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "rgba8ui", PIPE_FORMAT_R8G8B8A8_UINT, GLSL_TYPE_UINT, 130, 310, false, false }, - { "rg32ui", PIPE_FORMAT_R32G32_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "rg16ui", PIPE_FORMAT_R16G16_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "rg8ui", PIPE_FORMAT_R8G8_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "r32ui", PIPE_FORMAT_R32_UINT, GLSL_TYPE_UINT, 130, 310, false, false }, - { "r16ui", PIPE_FORMAT_R16_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "r8ui", PIPE_FORMAT_R8_UINT, GLSL_TYPE_UINT, 130, 0, true, false }, - { "rgba32i", PIPE_FORMAT_R32G32B32A32_SINT, GLSL_TYPE_INT, 130, 310, false, false }, - { "rgba16i", PIPE_FORMAT_R16G16B16A16_SINT, GLSL_TYPE_INT, 130, 310, false, false }, - { "rgba8i", PIPE_FORMAT_R8G8B8A8_SINT, GLSL_TYPE_INT, 130, 310, false, false }, - { "rg32i", PIPE_FORMAT_R32G32_SINT, GLSL_TYPE_INT, 130, 0, true, false }, - { "rg16i", PIPE_FORMAT_R16G16_SINT, GLSL_TYPE_INT, 130, 0, true, false }, - { "rg8i", PIPE_FORMAT_R8G8_SINT, GLSL_TYPE_INT, 130, 0, true, false }, - { "r32i", PIPE_FORMAT_R32_SINT, GLSL_TYPE_INT, 130, 310, false, false }, - { "r16i", PIPE_FORMAT_R16_SINT, GLSL_TYPE_INT, 130, 0, true, false }, - { "r8i", PIPE_FORMAT_R8_SINT, GLSL_TYPE_INT, 130, 0, true, false }, - { "rgba16", PIPE_FORMAT_R16G16B16A16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rgb10_a2", PIPE_FORMAT_R10G10B10A2_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rgba8", PIPE_FORMAT_R8G8B8A8_UNORM, GLSL_TYPE_FLOAT, 130, 310, false, false }, - { "rg16", PIPE_FORMAT_R16G16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rg8", PIPE_FORMAT_R8G8_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r16", PIPE_FORMAT_R16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r8", PIPE_FORMAT_R8_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rgba16_snorm", PIPE_FORMAT_R16G16B16A16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rgba8_snorm", PIPE_FORMAT_R8G8B8A8_SNORM, GLSL_TYPE_FLOAT, 130, 310, false, false }, - { "rg16_snorm", PIPE_FORMAT_R16G16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "rg8_snorm", PIPE_FORMAT_R8G8_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r16_snorm", PIPE_FORMAT_R16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, - { "r8_snorm", PIPE_FORMAT_R8_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false }, + { "rgba32f", PIPE_FORMAT_R32G32B32A32_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false, false }, + { "rgba16f", PIPE_FORMAT_R16G16B16A16_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false, false }, + { "rg32f", PIPE_FORMAT_R32G32_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rg16f", PIPE_FORMAT_R16G16_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false, true }, + { "r11f_g11f_b10f", PIPE_FORMAT_R11G11B10_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false, true }, + { "r32f", PIPE_FORMAT_R32_FLOAT, GLSL_TYPE_FLOAT, 130, 310, false, false, true }, + { "r16f", PIPE_FORMAT_R16_FLOAT, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rgba32ui", PIPE_FORMAT_R32G32B32A32_UINT, GLSL_TYPE_UINT, 130, 310, false, false, false }, + { "rgba16ui", PIPE_FORMAT_R16G16B16A16_UINT, GLSL_TYPE_UINT, 130, 310, false, false, false }, + { "rgb10_a2ui", PIPE_FORMAT_R10G10B10A2_UINT, GLSL_TYPE_UINT, 130, 0, true, false, true }, + { "rgba8ui", PIPE_FORMAT_R8G8B8A8_UINT, GLSL_TYPE_UINT, 130, 310, false, false, true }, + { "rg32ui", PIPE_FORMAT_R32G32_UINT, GLSL_TYPE_UINT, 130, 0, true, false, false }, + { "rg16ui", PIPE_FORMAT_R16G16_UINT, GLSL_TYPE_UINT, 130, 0, true, false, true }, + { "rg8ui", PIPE_FORMAT_R8G8_UINT, GLSL_TYPE_UINT, 130, 0, true, false, false }, + { "r32ui", PIPE_FORMAT_R32_UINT, GLSL_TYPE_UINT, 130, 310, false, false, true }, + { "r16ui", PIPE_FORMAT_R16_UINT, GLSL_TYPE_UINT, 130, 0, true, false, false }, + { "r8ui", PIPE_FORMAT_R8_UINT, GLSL_TYPE_UINT, 130, 0, true, false, false }, + { "rgba32i", PIPE_FORMAT_R32G32B32A32_SINT, GLSL_TYPE_INT, 130, 310, false, false, false }, + { "rgba16i", PIPE_FORMAT_R16G16B16A16_SINT, GLSL_TYPE_INT, 130, 310, false, false, false }, + { "rgba8i", PIPE_FORMAT_R8G8B8A8_SINT, GLSL_TYPE_INT, 130, 310, false, false, true }, + { "rg32i", PIPE_FORMAT_R32G32_SINT, GLSL_TYPE_INT, 130, 0, true, false, false }, + { "rg16i", PIPE_FORMAT_R16G16_SINT, GLSL_TYPE_INT, 130, 0, true, false, true }, + { "rg8i", PIPE_FORMAT_R8G8_SINT, GLSL_TYPE_INT, 130, 0, true, false, false }, + { "r32i", PIPE_FORMAT_R32_SINT, GLSL_TYPE_INT, 130, 310, false, false, true }, + { "r16i", PIPE_FORMAT_R16_SINT, GLSL_TYPE_INT, 130, 0, true, false, false }, + { "r8i", PIPE_FORMAT_R8_SINT, GLSL_TYPE_INT, 130, 0, true, false, false }, + { "rgba16", PIPE_FORMAT_R16G16B16A16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rgb10_a2", PIPE_FORMAT_R10G10B10A2_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, true }, + { "rgba8", PIPE_FORMAT_R8G8B8A8_UNORM, GLSL_TYPE_FLOAT, 130, 310, false, false, true }, + { "rg16", PIPE_FORMAT_R16G16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, true }, + { "rg8", PIPE_FORMAT_R8G8_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "r16", PIPE_FORMAT_R16_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "r8", PIPE_FORMAT_R8_UNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rgba16_snorm", PIPE_FORMAT_R16G16B16A16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rgba8_snorm", PIPE_FORMAT_R8G8B8A8_SNORM, GLSL_TYPE_FLOAT, 130, 310, false, false, false }, + { "rg16_snorm", PIPE_FORMAT_R16G16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "rg8_snorm", PIPE_FORMAT_R8G8_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "r16_snorm", PIPE_FORMAT_R16_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, + { "r8_snorm", PIPE_FORMAT_R8_SNORM, GLSL_TYPE_FLOAT, 130, 0, true, false, false }, /* From GL_EXT_shader_image_load_store: */ /* base_type is incorrect but it'll be patched later when we know * the variable type. See ast_to_hir.cpp */ - { "size1x8", PIPE_FORMAT_R8_SINT, GLSL_TYPE_VOID, 130, 0, false, true }, - { "size1x16", PIPE_FORMAT_R16_SINT, GLSL_TYPE_VOID, 130, 0, false, true }, - { "size1x32", PIPE_FORMAT_R32_SINT, GLSL_TYPE_VOID, 130, 0, false, true }, - { "size2x32", PIPE_FORMAT_R32G32_SINT, GLSL_TYPE_VOID, 130, 0, false, true }, - { "size4x32", PIPE_FORMAT_R32G32B32A32_SINT, GLSL_TYPE_VOID, 130, 0, false, true }, + { "size1x8", PIPE_FORMAT_R8_SINT, GLSL_TYPE_VOID, 130, 0, false, true, false }, + { "size1x16", PIPE_FORMAT_R16_SINT, GLSL_TYPE_VOID, 130, 0, false, true, false }, + { "size1x32", PIPE_FORMAT_R32_SINT, GLSL_TYPE_VOID, 130, 0, false, true, false }, + { "size2x32", PIPE_FORMAT_R32G32_SINT, GLSL_TYPE_VOID, 130, 0, false, true, false }, + { "size4x32", PIPE_FORMAT_R32G32B32A32_SINT, GLSL_TYPE_VOID, 130, 0, false, true, false }, }; for (unsigned i = 0; i < ARRAY_SIZE(map); i++) { + if (state->EXT_shader_pixel_local_storage_enable && + map[i].pixel_local_qualifiers && + match_layout_qualifier($1, map[i].name, state) == 0) { + $$.flags.q.explicit_image_format = 1; + $$.image_format = map[i].format; + $$.image_base_type = map[i].base_type; + break; + } if ((state->is_version(map[i].required_glsl, map[i].required_essl) || (state->NV_image_formats_enable && @@ -2282,6 +2294,21 @@ storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.task_payload = 1; } + | PIXEL_LOCAL + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_INOUT; + } + | PIXEL_LOCAL_IN + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_IN; + } + | PIXEL_LOCAL_OUT + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_OUT; + } ; memory_qualifier: @@ -2962,6 +2989,21 @@ interface_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.buffer = 1; } + | PIXEL_LOCAL + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_INOUT; + } + | PIXEL_LOCAL_IN + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_IN; + } + | PIXEL_LOCAL_OUT + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.pixel_local_storage = GLSL_PIXEL_LOCAL_STORAGE_OUT; + } | auxiliary_storage_qualifier interface_qualifier { if (!$1.flags.q.patch && !$1.flags.q.per_primitive) { diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp index 8b515231008..e56de9aadcb 100644 --- a/src/compiler/glsl/glsl_parser_extras.cpp +++ b/src/compiler/glsl/glsl_parser_extras.cpp @@ -840,6 +840,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { EXT(EXT_shader_implicit_conversions), EXT(EXT_shader_integer_mix), EXT_AEP(EXT_shader_io_blocks), + EXT(EXT_shader_pixel_local_storage), EXT(EXT_shader_realtime_clock), EXT(EXT_shader_samples_identical), EXT(EXT_shadow_samplers), @@ -1175,6 +1176,17 @@ _mesa_ast_process_interface_block(YYLTYPE *locp, "#version 140 / GL_ARB_uniform_buffer_object " "required for defining uniform blocks"); } + } else if (q.flags.q.pixel_local_storage) { + if (!state->EXT_shader_pixel_local_storage_enable) { + _mesa_glsl_error(locp, state, + "GL_EXT_shader_pixel_local_storage " + "required for defining pixel local storage blocks"); + + } else if (state->EXT_shader_pixel_local_storage_warn) { + _mesa_glsl_warning(locp, state, + "GL_EXT_shader_pixel_local_storage " + "required for defining pixel local storage blocks"); + } } else { if (!state->has_shader_io_blocks()) { if (state->es_shader) { @@ -1215,7 +1227,7 @@ _mesa_ast_process_interface_block(YYLTYPE *locp, ast_type_qualifier::bitset_t interface_type_mask; struct ast_type_qualifier temp_type_qualifier; - /* Get a bitmask containing only the in/out/uniform/buffer + /* Get a bitmask containing only the in/out/uniform/buffer/pls * flags, allowing us to ignore other irrelevant flags like * interpolation qualifiers. */ @@ -1226,11 +1238,13 @@ _mesa_ast_process_interface_block(YYLTYPE *locp, temp_type_qualifier.flags.q.buffer = true; temp_type_qualifier.flags.q.patch = true; temp_type_qualifier.flags.q.per_primitive = true; + temp_type_qualifier.flags.q.pixel_local_storage = + GLSL_PIXEL_LOCAL_STORAGE_INOUT; interface_type_mask = temp_type_qualifier.flags.i; /* Get the block's interface qualifier. The interface_qualifier * production rule guarantees that only one bit will be set (and - * it will be in/out/uniform). + * it will be in/out/uniform/pls). */ ast_type_qualifier::bitset_t block_interface_qualifier = q.flags.i; @@ -1274,7 +1288,7 @@ _mesa_ast_process_interface_block(YYLTYPE *locp, * the block." */ _mesa_glsl_error(locp, state, - "uniform/in/out qualifier on " + "optional qualifier on " "interface block member does not match " "the interface block"); } diff --git a/src/compiler/glsl/glsl_parser_extras.h b/src/compiler/glsl/glsl_parser_extras.h index 8a34b16b759..8a1ccc993b7 100644 --- a/src/compiler/glsl/glsl_parser_extras.h +++ b/src/compiler/glsl/glsl_parser_extras.h @@ -493,6 +493,13 @@ struct _mesa_glsl_parse_state { bool ms_output_max_vertices_specified; bool ms_output_max_primitives_specified; + /** + * True if a shader declares input/output pixel local storage interfaces; + * at most one input and one output may be declared. + */ + bool pixel_local_input_specified; + bool pixel_local_output_specified; + /** * Output layout qualifiers from GLSL 1.50 (geometry shader controls), * and GLSL 4.00 (tessellation control shader). @@ -908,6 +915,8 @@ struct _mesa_glsl_parse_state { bool EXT_shader_integer_mix_warn; bool EXT_shader_io_blocks_enable; bool EXT_shader_io_blocks_warn; + bool EXT_shader_pixel_local_storage_enable; + bool EXT_shader_pixel_local_storage_warn; bool EXT_shader_realtime_clock_enable; bool EXT_shader_realtime_clock_warn; bool EXT_shader_samples_identical_enable; @@ -1042,6 +1051,10 @@ struct _mesa_glsl_parse_state { */ unsigned clip_dist_size, cull_dist_size; + /* for EXT_shader_pixel_local_storage */ + bool fs_writes_output; + bool fs_writes_pixel_local_storage; + /* for OVR_multiview */ uint32_t view_mask; }; diff --git a/src/compiler/glsl/glsl_symbol_table.cpp b/src/compiler/glsl/glsl_symbol_table.cpp index b8ddbd2b506..27dca8f9ada 100644 --- a/src/compiler/glsl/glsl_symbol_table.cpp +++ b/src/compiler/glsl/glsl_symbol_table.cpp @@ -46,6 +46,9 @@ public: case ir_var_shader_out: dest = &ibo; break; + case ir_var_shader_pixel_local_storage: + dest = &ipl; + break; default: assert(!"Unsupported interface variable mode!"); return false; @@ -60,19 +63,19 @@ public: } symbol_table_entry(ir_variable *v) : - v(v), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {} + v(v), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), ipl(0), a(0) {} symbol_table_entry(ir_function *f) : - v(0), f(f), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) {} + v(0), f(f), t(0), ibu(0), iss(0), ibi(0), ibo(0), ipl(0), a(0) {} symbol_table_entry(const glsl_type *t) : - v(0), f(0), t(t), ibu(0), iss(0), ibi(0), ibo(0), a(0) {} + v(0), f(0), t(t), ibu(0), iss(0), ibi(0), ibo(0), ipl(0), a(0) {} symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) : - v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(0) + v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), ipl(0), a(0) { assert(glsl_type_is_interface(t)); add_interface(t, mode); } symbol_table_entry(const class ast_type_specifier *a): - v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), a(a) {} + v(0), f(0), t(0), ibu(0), iss(0), ibi(0), ibo(0), ipl(0), a(a) {} ir_variable *v; ir_function *f; @@ -81,6 +84,7 @@ public: const glsl_type *iss; const glsl_type *ibi; const glsl_type *ibo; + const glsl_type *ipl; const class ast_type_specifier *a; }; diff --git a/src/compiler/glsl/glsl_to_nir.cpp b/src/compiler/glsl/glsl_to_nir.cpp index a92dd0be789..f9c709c69b2 100644 --- a/src/compiler/glsl/glsl_to_nir.cpp +++ b/src/compiler/glsl/glsl_to_nir.cpp @@ -531,6 +531,23 @@ nir_visitor::visit(ir_variable *ir) var->data.mode = nir_var_mem_task_payload; break; + case ir_var_shader_pixel_local_storage: + switch (ir->data.pixel_local_storage) { + case GLSL_PIXEL_LOCAL_STORAGE_IN: + var->data.mode = nir_var_mem_pixel_local_in; + break; + case GLSL_PIXEL_LOCAL_STORAGE_OUT: + var->data.mode = nir_var_mem_pixel_local_out; + break; + case GLSL_PIXEL_LOCAL_STORAGE_INOUT: + var->data.mode = nir_var_mem_pixel_local_inout; + break; + default: + UNREACHABLE("bad pixel local storage field"); + break; + } + break; + default: UNREACHABLE("not reached"); } @@ -616,6 +633,8 @@ nir_visitor::visit(ir_variable *ir) } else if (var->data.mode == nir_var_shader_out) { var->data.xfb.buffer = ir->data.xfb_buffer; var->data.xfb.stride = ir->data.xfb_stride; + } else if (var->data.mode & nir_var_any_pixel_local) { + var->data.image.format = ir->data.image_format; } var->data.fb_fetch_output = ir->data.fb_fetch_output; diff --git a/src/compiler/glsl/ir.h b/src/compiler/glsl/ir.h index 605b47f1017..40360100c5c 100644 --- a/src/compiler/glsl/ir.h +++ b/src/compiler/glsl/ir.h @@ -322,6 +322,7 @@ enum ir_variable_mode { ir_var_shader_task_payload, ir_var_shader_in, ir_var_shader_out, + ir_var_shader_pixel_local_storage, /**< Variable declared as pixel local storage */ ir_var_function_in, ir_var_function_out, ir_var_function_inout, @@ -863,6 +864,12 @@ public: */ unsigned per_primitive:1; + /** + * Non-zero if the variable is pixel local storage; in this + * case bit 0 indicates read access, bit 1 write access + */ + unsigned pixel_local_storage:2; + /** * Emit a warning if this variable is accessed. */ diff --git a/src/compiler/glsl/ir_print_visitor.cpp b/src/compiler/glsl/ir_print_visitor.cpp index 4cb08d2f5c8..2c6d0061957 100644 --- a/src/compiler/glsl/ir_print_visitor.cpp +++ b/src/compiler/glsl/ir_print_visitor.cpp @@ -210,6 +210,7 @@ void ir_print_visitor::visit(ir_variable *ir) const char *const memory_restrict = (ir->data.memory_restrict) ? "restrict " : ""; const char *const mode[] = { "", "uniform ", "shader_storage ", "shader_shared ", "task_payload ", "shader_in ", "shader_out ", + "shader_pixel_local ", "in ", "out ", "inout ", "const_in ", "sys ", "temporary " }; const char *const per_primitive = (ir->data.per_primitive) ? "per_primitive " : ""; diff --git a/src/compiler/glsl_types.h b/src/compiler/glsl_types.h index 733c8dbf49c..2d2f643f94c 100644 --- a/src/compiler/glsl_types.h +++ b/src/compiler/glsl_types.h @@ -288,6 +288,13 @@ enum { GLSL_PRECISION_LOW }; +enum { + GLSL_PIXEL_LOCAL_STORAGE_NONE = 0, + GLSL_PIXEL_LOCAL_STORAGE_IN, + GLSL_PIXEL_LOCAL_STORAGE_OUT, + GLSL_PIXEL_LOCAL_STORAGE_INOUT +}; + enum glsl_cmat_use { GLSL_CMAT_USE_NONE = 0, GLSL_CMAT_USE_A, diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index 80ebf2872d2..634e56ec515 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -1125,6 +1125,8 @@ struct pipe_caps { unsigned shader_subgroup_size; unsigned shader_subgroup_supported_stages; unsigned shader_subgroup_supported_features; + unsigned shader_pixel_local_storage_size; + unsigned shader_pixel_local_storage_fast_size; unsigned multiview; unsigned max_label_length; uint64_t max_timeline_semaphore_difference; diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c index 3affa94475b..a6c11300939 100644 --- a/src/mesa/main/buffers.c +++ b/src/mesa/main/buffers.c @@ -465,6 +465,16 @@ draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, GLsizei n, _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid buffers)", caller); return; } + + /* From the GL_EXT_shader_pixel_local_storage spec: + * "INVALID_OPERATION is generated if pixel local storage is enabled and + * the application attempts to [...] change color buffer selection via + * DrawBuffers, [...]" + */ + if (ctx->PixelLocalStorage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(): pixel local storage enabled", caller); + } } supportedMask = supported_buffer_bitmask(ctx, fb); diff --git a/src/mesa/main/consts_exts.h b/src/mesa/main/consts_exts.h index 1563b72b458..d7a83f5ca10 100644 --- a/src/mesa/main/consts_exts.h +++ b/src/mesa/main/consts_exts.h @@ -188,6 +188,7 @@ struct gl_extensions GLboolean EXT_shader_image_load_formatted; GLboolean EXT_shader_image_load_store; GLboolean EXT_shader_integer_mix; + GLboolean EXT_shader_pixel_local_storage; GLboolean EXT_shader_realtime_clock; GLboolean EXT_shader_samples_identical; GLboolean EXT_sRGB; diff --git a/src/mesa/main/draw_validate.c b/src/mesa/main/draw_validate.c index 0fa86be6e3b..bc69fad5c9e 100644 --- a/src/mesa/main/draw_validate.c +++ b/src/mesa/main/draw_validate.c @@ -107,6 +107,19 @@ _mesa_update_valid_to_render_state(struct gl_context *ctx) num_color_buffers - max_dual_source_buffers)) return; + /* From the GL_EXT_shader_pixel_local_storage spec: + * + * "INVALID_OPERATION is generated if pixel local storage is disabled and + * the application attempts to issue a rendering command while a program + * object that accesses pixel local storage is bound." + */ + const struct gl_program *fp = + ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]; + + if (!ctx->PixelLocalStorage && fp && + fp->info.fs.accesses_pixel_local_storage) + return; + if (ctx->Color.BlendEnabled && ctx->Color._AdvancedBlendMode != BLEND_NONE) { /* The KHR_blend_equation_advanced spec says: @@ -138,16 +151,14 @@ _mesa_update_valid_to_render_state(struct gl_context *ctx) * the blend equation or "blend_support_all_equations", the error * INVALID_OPERATION is generated [...]" */ - const struct gl_program *prog = - ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]; - const GLbitfield blend_support = !prog ? 0 : prog->info.fs.advanced_blend_modes; + const GLbitfield blend_support = !fp ? 0 : fp->info.fs.advanced_blend_modes; if ((blend_support & BITFIELD_BIT(ctx->Color._AdvancedBlendMode)) == 0) return; } if (_mesa_is_desktop_gl_compat(ctx)) { - if (!shader->CurrentProgram[MESA_SHADER_FRAGMENT]) { + if (!fp) { if (ctx->FragmentProgram.Enabled && !_mesa_arb_fragment_program_enabled(ctx)) return; diff --git a/src/mesa/main/drawtex.c b/src/mesa/main/drawtex.c index 6e3fc875c0f..d598be15f5f 100644 --- a/src/mesa/main/drawtex.c +++ b/src/mesa/main/drawtex.c @@ -48,8 +48,14 @@ draw_texture(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, if (ctx->NewState) _mesa_update_state(ctx); + if (!ctx->DrawPixValid) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); + goto end; + } + st_DrawTex(ctx, x, y, z, width, height); +end: _mesa_set_vp_override(ctx, GL_FALSE); } diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c index 214684b8f57..28706f82901 100644 --- a/src/mesa/main/enable.c +++ b/src/mesa/main/enable.c @@ -37,6 +37,7 @@ #include "draw_validate.h" #include "enable.h" #include "errors.h" +#include "framebuffer.h" #include "light.h" #include "mtypes.h" #include "enums.h" @@ -363,6 +364,93 @@ _mesa_set_multisample(struct gl_context *ctx, GLboolean state) ctx->Multisample.Enabled = state; } +/** + * Helper function to enable or disable GL_EXT_shader_pixel_local_storage + */ +static GLboolean +_mesa_set_pixel_local_storage(struct gl_context *ctx, GLboolean state) +{ + if (!state) { + /* turning the feature off is always safe */ + ctx->PixelLocalStorage = state; + return state; + } + /* check that turning the feature on is legal */ + struct gl_framebuffer *fb = ctx->DrawBuffer; + const char *func = "glEnable(SHADER_PIXEL_LOCAL_STORAGE)"; + + /* The GL_EXT_shader_pixel_local_storage spec says: + * "INVALID_OPERATION is generated if the application attempts enable + * pixel local storage while the value of SAMPLE_BUFFERS is one." + * + * calling _mesa_GetIntegerv(SAMPLE_BUFFERS,...) has the side effect of + * updating the frame buffer state with any pending attachment changes + */ + GLint sample_buffers = 0; + _mesa_GetIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers); + if (sample_buffers != 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s: SAMPLE_BUFFERS==1", func); + return GL_FALSE; + } + + if (_mesa_is_user_fbo(fb)) { + /* The GL_EXT_shader_pixel_local_storage spec says: + * "INVALID_FRAMEBUFFER_OPERATION is generated if the application + * attempts to enable pixel local storage while the current draw + * framebuffer is incomplete." + */ + if (fb->_Status == 0) + _mesa_test_framebuffer_completeness(ctx, fb); + if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "%s: incomplete framebuffer", func); + return GL_FALSE; + } + + int nz_color_attachments = 0; + for (int i = 0; i < BUFFER_COUNT && nz_color_attachments < 1; i++) { + switch(i) { + case BUFFER_COLOR0: + case BUFFER_DEPTH: + case BUFFER_STENCIL: + case BUFFER_NONE: + break; + default: + if (fb->Attachment[i].Type != GL_NONE) + nz_color_attachments++; + } + } + + /* The GL_EXT_shader_pixel_local_storage spec says: + * "INVALID_OPERATION is generated if the application attempts to + * enable pixel local storage while the current draw framebuffer is + * a user-defined framebuffer object and has an image attached to + * any color attachment other than color attachment zero." + */ + if (nz_color_attachments > 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: too many color attachments", func); + return GL_FALSE; + } + + /* The GL_EXT_shader_pixel_local_storage spec says: + * "INVALID_OPERATION is generated if the application attempts to + * enable pixel local storage while the current draw framebuffer is + * a user-defined framebuffer and the draw buffer for any color + * output other than color output zero is not NONE." + */ + for (int i = 1; i < fb->_NumColorDrawBuffers; i++) { + if (fb->_ColorDrawBufferIndexes[i] != BUFFER_NONE) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: too many draw buffers", func); + return GL_FALSE; + } + } + } + + return state; +} + /** * Helper function to enable or disable GL_FRAMEBUFFER_SRGB, skipping the * check for whether the API supports it (GLES doesn't). @@ -1332,6 +1420,18 @@ _mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) ctx->pipe->set_frontend_noop(ctx->pipe, state); break; + case GL_SHADER_PIXEL_LOCAL_STORAGE_EXT: + if (!_mesa_has_EXT_shader_pixel_local_storage(ctx)) + goto invalid_enum_error; + if (ctx->PixelLocalStorage == state) + return; + FLUSH_VERTICES(ctx, 0, 0); + ST_SET_STATE(ctx->NewDriverState, ST_NEW_FB_STATE); + /* need to validate that pixel local storage is legal */ + ctx->PixelLocalStorage = _mesa_set_pixel_local_storage(ctx, state); + _mesa_update_valid_to_render_state(ctx); + break; + default: goto invalid_enum_error; } @@ -2017,6 +2117,11 @@ _mesa_IsEnabled( GLenum cap ) goto invalid_enum_error; return ctx->IntelBlackholeRender; + case GL_SHADER_PIXEL_LOCAL_STORAGE_EXT: + if (!_mesa_has_EXT_shader_pixel_local_storage(ctx)) + goto invalid_enum_error; + return ctx->PixelLocalStorage; + default: goto invalid_enum_error; } diff --git a/src/mesa/main/extensions_table.h b/src/mesa/main/extensions_table.h index 0290cf3d5e6..ecfc6cde90c 100644 --- a/src/mesa/main/extensions_table.h +++ b/src/mesa/main/extensions_table.h @@ -305,6 +305,7 @@ EXT(EXT_shader_image_load_store , EXT_shader_image_load_store EXT(EXT_shader_implicit_conversions , dummy_true , x , x , x , 31, 2013) EXT(EXT_shader_integer_mix , EXT_shader_integer_mix , GLL, GLC, x , 30, 2013) EXT(EXT_shader_io_blocks , dummy_true , x , x , x , 31, 2014) +EXT(EXT_shader_pixel_local_storage , EXT_shader_pixel_local_storage , x , x , x , 30, 2014) EXT(EXT_shader_realtime_clock , EXT_shader_realtime_clock , GLL, GLC, x , 31, 2018) EXT(EXT_shader_samples_identical , EXT_shader_samples_identical , GLL, GLC, x , 31, 2015) EXT(EXT_shadow_funcs , ARB_shadow , GLL, x , x , x , 2002) diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index d8a37b5b3a6..e89567eb132 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -3362,6 +3362,17 @@ bind_framebuffer(GLenum target, GLuint framebuffer) return; } + /* The GL_EXT_shader_pixel_local_storage spec says: + * + * "INVALID_OPERATION is generated if pixel local storage is enabled and + * the application attempts to bind a new draw framebuffer, [...]" + */ + if (bindDrawBuf && ctx->PixelLocalStorage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindFrameBuffer(draw fb): pixel local storage enabled"); + return; + } + if (framebuffer) { _mesa_HashLockMutex(&ctx->Shared->FrameBuffers); @@ -3478,8 +3489,9 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) GLint i; GET_CURRENT_CONTEXT(ctx); + const char *func = "glDeleteFramebuffers"; if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteFramebuffers(n < 0)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } @@ -3496,6 +3508,19 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) if (fb == ctx->DrawBuffer) { /* bind default */ assert(fb->RefCount >= 2); + + /* The GL_EXT_shader_pixel_local_storage spec says: + * + * "INVALID_OPERATION is generated if pixel local storage is + * enabled and the application attempts to [...] delete the + * currently bound draw framebuffer, [...]" + */ + if (ctx->PixelLocalStorage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(draw fb): pixel local storage enabled", func); + return; + } + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } if (fb == ctx->ReadBuffer) { @@ -4248,6 +4273,18 @@ framebuffer_texture_with_dims(int dims, GLenum target, GLuint framebuffer, struct gl_framebuffer *fb; struct gl_texture_object *texObj; + /* The GL_EXT_shader_pixel_local_storage spec says: + * + * "INVALID_OPERATION is generated if pixel local storage is enabled and + * the application attempts to [...] modify any attachment of the + * currently bound draw framebuffer including their underlying storage." + */ + if (ctx->PixelLocalStorage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(): pixel local storage enabled", caller); + return; + } + /* Get the framebuffer object */ if (dsa) { fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, caller); @@ -4376,6 +4413,18 @@ frame_buffer_texture(GLuint framebuffer, GLenum target, } } + /* The GL_EXT_shader_pixel_local_storage spec says: + * + * "INVALID_OPERATION is generated if pixel local storage is enabled and + * the application attempts to [...] modify any attachment of the + * currently bound draw framebuffer including their underlying storage." + */ + if (!no_error && ctx->PixelLocalStorage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(): pixel local storage enabled", func); + return; + } + /* Get the framebuffer object */ struct gl_framebuffer *fb; if (no_error) { diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 6d2415d8a09..197811ade83 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -602,6 +602,7 @@ EXTRA_EXT(KHR_shader_subgroup); EXTRA_EXT(OVR_multiview); EXTRA_EXT(NV_timeline_semaphore); EXTRA_EXT(EXT_mesh_shader); +EXTRA_EXT(EXT_shader_pixel_local_storage); static const int extra_ARB_gl_spirv_or_es2_compat[] = { EXT(ARB_gl_spirv), diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py index e009038f1c1..884e051c3ef 100644 --- a/src/mesa/main/get_hash_params.py +++ b/src/mesa/main/get_hash_params.py @@ -703,6 +703,10 @@ descriptor=[ [ "VIEWPORT_SWIZZLE_Z_NV", "LOC_CUSTOM, TYPE_ENUM, 0, extra_NV_viewport_swizzle" ], [ "VIEWPORT_SWIZZLE_W_NV", "LOC_CUSTOM, TYPE_ENUM, 0, extra_NV_viewport_swizzle" ], +# GL_EXT_shader_pixel_local_storage + [ "MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT", "CAPS_UINT(shader_pixel_local_storage_size), extra_EXT_shader_pixel_local_storage" ], + [ "MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT", "CAPS_UINT(shader_pixel_local_storage_fast_size), extra_EXT_shader_pixel_local_storage" ], + # GL_KHR_shader_subgroup [ "SUBGROUP_SIZE_KHR", "CONTEXT_INT(Const.ShaderSubgroupSize), extra_KHR_shader_subgroup" ], [ "SUBGROUP_SUPPORTED_STAGES_KHR", "CONTEXT_INT(Const.ShaderSubgroupSupportedStages), extra_KHR_shader_subgroup" ], diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 7dc6f95bfc9..66d890cb89d 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -3593,6 +3593,7 @@ struct gl_context GLboolean RepresentativeFragmentTest; /**< GL_REPRESENTATIVE_FRAGMENT_TEST_NV */ GLboolean IntelBlackholeRender; /**< GL_INTEL_blackhole_render */ + GLboolean PixelLocalStorage; /**< GL_EXT_shader_pixel_local_storage */ /** Does glVertexAttrib(0) alias glVertex()? */ bool _AttribZeroAliasesVertex; diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index f5f360eb80c..f2a59f31307 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -1116,6 +1116,7 @@ void st_init_extensions(struct pipe_screen *screen, #else EXT_CAP(EXT_semaphore_win32, fence_signal); #endif + EXT_CAP(EXT_shader_pixel_local_storage, shader_pixel_local_storage_size); EXT_CAP(EXT_shader_realtime_clock, shader_realtime_clock); EXT_CAP(EXT_shader_samples_identical, shader_samples_identical); EXT_CAP(EXT_texture_array, max_texture_array_layers);