glsl, mesa: add EXT_shader_pixel_local_storage extension

This commit also checks for and issues errors for the following:

INVALID_OPERATION is generated if the application attempts enable pixel
local storage while the value of SAMPLE_BUFFERS is one.

INVALID_OPERATION is generated if the application attempts to enable pixel
local storage while the current draw framebuffer is a user-defined frame-
buffer object and has an image attached to any color attachment other than
color attachment zero.

INVALID_OPERATION is generated if the application attempts to enable pixel
local storage while the current draw framebuffer is a user-defined frame-
buffer and the draw buffer for any color output other than color
output zero is not NONE.

INVALID_FRAMEBUFFER_OPERATION is generated if the application attempts to
enable pixel local storage while the current draw framebuffer is
incomplete.

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.

INVALID_OPERATION is generated if pixel local storage is enabled and the
application attempts to bind a new draw framebuffer, delete the currently
bound draw framebuffer, change color buffer selection via DrawBuffers, or
modify any attachment of the currently bound draw framebuffer including
their underlying storage.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Eric R. Smith <eric.smith@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37110>
This commit is contained in:
Ryan Mckeever 2025-10-22 22:45:58 -07:00 committed by Marge Bot
parent 04d3da19c6
commit 7f7c4ebbba
26 changed files with 519 additions and 72 deletions

View file

@ -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;

View file

@ -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 =

View file

@ -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);

View file

@ -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.

View file

@ -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)) {

View file

@ -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; }

View file

@ -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) {

View file

@ -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");
}

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;

View file

@ -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.
*/

View file

@ -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 " : "";

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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) {

View file

@ -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),

View file

@ -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" ],

View file

@ -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;

View file

@ -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);