glsl: Implement parser support for atomic counters.
v2: Mark atomic counters as read-only variables. Move offset overlap code to the linker. Use the contains_atomic() convenience method. v3: Use pointer to integer instead of non-const reference. Add comment so we remember to add a spec quotation from the next GLSL release once the issue of atomic counter aggregation within structures is clarified. v4 (idr): Don't use std::map because it's overkill. Add an assertion that ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS. Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Paul Berry <stereotype441@gmail.com> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:

committed by
Ian Romanick

parent
30f61c471d
commit
e63bb29853
@@ -385,6 +385,12 @@ struct ast_type_qualifier {
|
|||||||
*/
|
*/
|
||||||
unsigned explicit_binding:1;
|
unsigned explicit_binding:1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag set if GL_ARB_shader_atomic counter "offset" layout
|
||||||
|
* qualifier is used.
|
||||||
|
*/
|
||||||
|
unsigned explicit_offset:1;
|
||||||
|
|
||||||
/** \name Layout qualifiers for GL_AMD_conservative_depth */
|
/** \name Layout qualifiers for GL_AMD_conservative_depth */
|
||||||
/** \{ */
|
/** \{ */
|
||||||
unsigned depth_any:1;
|
unsigned depth_any:1;
|
||||||
@@ -447,6 +453,15 @@ struct ast_type_qualifier {
|
|||||||
*/
|
*/
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset specified via GL_ARB_shader_atomic_counter's "offset"
|
||||||
|
* keyword.
|
||||||
|
*
|
||||||
|
* \note
|
||||||
|
* This field is only valid if \c explicit_offset is set.
|
||||||
|
*/
|
||||||
|
int offset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if and only if an interpolation qualifier is present.
|
* Return true if and only if an interpolation qualifier is present.
|
||||||
*/
|
*/
|
||||||
|
@@ -1995,12 +1995,22 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
|
|||||||
"exceeds the maximum number of texture image units "
|
"exceeds the maximum number of texture image units "
|
||||||
"(%d)", qual->binding, elements, limit);
|
"(%d)", qual->binding, elements, limit);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (var->type->contains_atomic()) {
|
||||||
|
assert(ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS);
|
||||||
|
if (unsigned(qual->binding) >= ctx->Const.MaxAtomicBufferBindings) {
|
||||||
|
_mesa_glsl_error(loc, state, "layout(binding = %d) exceeds the "
|
||||||
|
" maximum number of atomic counter buffer bindings"
|
||||||
|
"(%d)", qual->binding,
|
||||||
|
ctx->Const.MaxAtomicBufferBindings);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_mesa_glsl_error(loc, state,
|
_mesa_glsl_error(loc, state,
|
||||||
"the \"binding\" qualifier only applies to uniform "
|
"the \"binding\" qualifier only applies to uniform "
|
||||||
"blocks, samplers, or arrays of samplers");
|
"blocks, samplers, atomic counters, or arrays thereof");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2300,6 +2310,29 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
|
|||||||
var->binding = qual->binding;
|
var->binding = qual->binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (var->type->contains_atomic()) {
|
||||||
|
if (var->mode == ir_var_uniform) {
|
||||||
|
if (var->explicit_binding) {
|
||||||
|
unsigned *offset = &state->atomic_counter_offsets[var->binding];
|
||||||
|
|
||||||
|
if (*offset % ATOMIC_COUNTER_SIZE)
|
||||||
|
_mesa_glsl_error(loc, state,
|
||||||
|
"misaligned atomic counter offset");
|
||||||
|
|
||||||
|
var->atomic.offset = *offset;
|
||||||
|
*offset += var->type->atomic_size();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_mesa_glsl_error(loc, state,
|
||||||
|
"atomic counters require explicit binding point");
|
||||||
|
}
|
||||||
|
} else if (var->mode != ir_var_function_in) {
|
||||||
|
_mesa_glsl_error(loc, state, "atomic counters may only be declared as "
|
||||||
|
"function parameters or uniform-qualified "
|
||||||
|
"global variables");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Does the declaration use the deprecated 'attribute' or 'varying'
|
/* Does the declaration use the deprecated 'attribute' or 'varying'
|
||||||
* keywords?
|
* keywords?
|
||||||
*/
|
*/
|
||||||
@@ -2835,6 +2868,18 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||||||
(void) this->type->specifier->hir(instructions, state);
|
(void) this->type->specifier->hir(instructions, state);
|
||||||
|
|
||||||
decl_type = this->type->glsl_type(& type_name, state);
|
decl_type = this->type->glsl_type(& type_name, state);
|
||||||
|
|
||||||
|
/* An offset-qualified atomic counter declaration sets the default
|
||||||
|
* offset for the next declaration within the same atomic counter
|
||||||
|
* buffer.
|
||||||
|
*/
|
||||||
|
if (decl_type && decl_type->contains_atomic()) {
|
||||||
|
if (type->qualifier.flags.q.explicit_binding &&
|
||||||
|
type->qualifier.flags.q.explicit_offset)
|
||||||
|
state->atomic_counter_offsets[type->qualifier.binding] =
|
||||||
|
type->qualifier.offset;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->declarations.is_empty()) {
|
if (this->declarations.is_empty()) {
|
||||||
/* If there is no structure involved in the program text, there are two
|
/* If there is no structure involved in the program text, there are two
|
||||||
* possible scenarios:
|
* possible scenarios:
|
||||||
@@ -2864,6 +2909,11 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||||||
_mesa_glsl_error(&loc, state,
|
_mesa_glsl_error(&loc, state,
|
||||||
"invalid type `%s' in empty declaration",
|
"invalid type `%s' in empty declaration",
|
||||||
type_name);
|
type_name);
|
||||||
|
} else if (decl_type->base_type == GLSL_TYPE_ATOMIC_UINT) {
|
||||||
|
/* Empty atomic counter declarations are allowed and useful
|
||||||
|
* to set the default offset qualifier.
|
||||||
|
*/
|
||||||
|
return NULL;
|
||||||
} else if (this->type->qualifier.precision != ast_precision_none) {
|
} else if (this->type->qualifier.precision != ast_precision_none) {
|
||||||
if (this->type->specifier->structure != NULL) {
|
if (this->type->specifier->structure != NULL) {
|
||||||
_mesa_glsl_error(&loc, state,
|
_mesa_glsl_error(&loc, state,
|
||||||
@@ -4565,6 +4615,17 @@ ast_process_structure_or_interface_block(exec_list *instructions,
|
|||||||
"uniform in non-default uniform block contains sampler");
|
"uniform in non-default uniform block contains sampler");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field_type->contains_atomic()) {
|
||||||
|
/* FINISHME: Add a spec quotation here once updated spec
|
||||||
|
* FINISHME: language is available. See Khronos bug #10903
|
||||||
|
* FINISHME: on whether atomic counters are allowed in
|
||||||
|
* FINISHME: structures.
|
||||||
|
*/
|
||||||
|
YYLTYPE loc = decl_list->get_location();
|
||||||
|
_mesa_glsl_error(&loc, state, "atomic counter in structure or "
|
||||||
|
"uniform block");
|
||||||
|
}
|
||||||
|
|
||||||
const struct ast_type_qualifier *const qual =
|
const struct ast_type_qualifier *const qual =
|
||||||
& decl_list->type->qualifier;
|
& decl_list->type->qualifier;
|
||||||
if (qual->flags.q.std140 ||
|
if (qual->flags.q.std140 ||
|
||||||
|
@@ -72,7 +72,8 @@ ast_type_qualifier::has_layout() const
|
|||||||
|| this->flags.q.packed
|
|| this->flags.q.packed
|
||||||
|| this->flags.q.explicit_location
|
|| this->flags.q.explicit_location
|
||||||
|| this->flags.q.explicit_index
|
|| this->flags.q.explicit_index
|
||||||
|| this->flags.q.explicit_binding;
|
|| this->flags.q.explicit_binding
|
||||||
|
|| this->flags.q.explicit_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -121,13 +122,18 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
|
|||||||
ubo_layout_mask.flags.q.packed = 1;
|
ubo_layout_mask.flags.q.packed = 1;
|
||||||
ubo_layout_mask.flags.q.shared = 1;
|
ubo_layout_mask.flags.q.shared = 1;
|
||||||
|
|
||||||
|
ast_type_qualifier ubo_binding_mask;
|
||||||
|
ubo_binding_mask.flags.q.explicit_binding = 1;
|
||||||
|
ubo_binding_mask.flags.q.explicit_offset = 1;
|
||||||
|
|
||||||
/* Uniform block layout qualifiers get to overwrite each
|
/* Uniform block layout qualifiers get to overwrite each
|
||||||
* other (rightmost having priority), while all other
|
* other (rightmost having priority), while all other
|
||||||
* qualifiers currently don't allow duplicates.
|
* qualifiers currently don't allow duplicates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
|
if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
|
||||||
ubo_layout_mask.flags.i)) != 0) {
|
ubo_layout_mask.flags.i |
|
||||||
|
ubo_binding_mask.flags.i)) != 0) {
|
||||||
_mesa_glsl_error(loc, state,
|
_mesa_glsl_error(loc, state,
|
||||||
"duplicate layout qualifiers used");
|
"duplicate layout qualifiers used");
|
||||||
return false;
|
return false;
|
||||||
@@ -168,6 +174,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
|
|||||||
if (q.flags.q.explicit_binding)
|
if (q.flags.q.explicit_binding)
|
||||||
this->binding = q.binding;
|
this->binding = q.binding;
|
||||||
|
|
||||||
|
if (q.flags.q.explicit_offset)
|
||||||
|
this->offset = q.offset;
|
||||||
|
|
||||||
if (q.precision != ast_precision_none)
|
if (q.precision != ast_precision_none)
|
||||||
this->precision = q.precision;
|
this->precision = q.precision;
|
||||||
|
|
||||||
|
@@ -337,6 +337,7 @@ samplerExternalOES {
|
|||||||
return IDENTIFIER;
|
return IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_uint KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT);
|
||||||
|
|
||||||
struct return STRUCT;
|
struct return STRUCT;
|
||||||
void return VOID_TOK;
|
void return VOID_TOK;
|
||||||
@@ -518,7 +519,6 @@ restrict KEYWORD(0, 300, 0, 0, RESTRICT);
|
|||||||
readonly KEYWORD(0, 300, 0, 0, READONLY);
|
readonly KEYWORD(0, 300, 0, 0, READONLY);
|
||||||
writeonly KEYWORD(0, 300, 0, 0, WRITEONLY);
|
writeonly KEYWORD(0, 300, 0, 0, WRITEONLY);
|
||||||
resource KEYWORD(0, 300, 0, 0, RESOURCE);
|
resource KEYWORD(0, 300, 0, 0, RESOURCE);
|
||||||
atomic_uint KEYWORD(0, 300, 0, 0, ATOMIC_UINT);
|
|
||||||
patch KEYWORD(0, 300, 0, 0, PATCH);
|
patch KEYWORD(0, 300, 0, 0, PATCH);
|
||||||
sample KEYWORD(0, 300, 0, 0, SAMPLE);
|
sample KEYWORD(0, 300, 0, 0, SAMPLE);
|
||||||
subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE);
|
subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE);
|
||||||
|
@@ -144,6 +144,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||||||
%token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
|
%token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
|
||||||
%token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
|
%token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
|
||||||
%token SAMPLEREXTERNALOES
|
%token SAMPLEREXTERNALOES
|
||||||
|
%token ATOMIC_UINT
|
||||||
%token STRUCT VOID_TOK WHILE
|
%token STRUCT VOID_TOK WHILE
|
||||||
%token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
|
%token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
|
||||||
%type <identifier> any_identifier
|
%type <identifier> any_identifier
|
||||||
@@ -173,7 +174,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||||||
%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
|
%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
|
||||||
%token SAMPLER3DRECT
|
%token SAMPLER3DRECT
|
||||||
%token SIZEOF CAST NAMESPACE USING
|
%token SIZEOF CAST NAMESPACE USING
|
||||||
%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT PATCH SAMPLE
|
%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE PATCH SAMPLE
|
||||||
%token SUBROUTINE
|
%token SUBROUTINE
|
||||||
|
|
||||||
%token ERROR_TOK
|
%token ERROR_TOK
|
||||||
@@ -1324,12 +1325,19 @@ layout_qualifier_id:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->ARB_shading_language_420pack_enable &&
|
if ((state->ARB_shading_language_420pack_enable ||
|
||||||
|
state->ARB_shader_atomic_counters_enable) &&
|
||||||
match_layout_qualifier("binding", $1, state) == 0) {
|
match_layout_qualifier("binding", $1, state) == 0) {
|
||||||
$$.flags.q.explicit_binding = 1;
|
$$.flags.q.explicit_binding = 1;
|
||||||
$$.binding = $3;
|
$$.binding = $3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->ARB_shader_atomic_counters_enable &&
|
||||||
|
match_layout_qualifier("offset", $1, state) == 0) {
|
||||||
|
$$.flags.q.explicit_offset = 1;
|
||||||
|
$$.offset = $3;
|
||||||
|
}
|
||||||
|
|
||||||
if (match_layout_qualifier("max_vertices", $1, state) == 0) {
|
if (match_layout_qualifier("max_vertices", $1, state) == 0) {
|
||||||
$$.flags.q.max_vertices = 1;
|
$$.flags.q.max_vertices = 1;
|
||||||
|
|
||||||
@@ -1703,6 +1711,7 @@ basic_type_specifier_nonarray:
|
|||||||
| SAMPLER2DMSARRAY { $$ = "sampler2DMSArray"; }
|
| SAMPLER2DMSARRAY { $$ = "sampler2DMSArray"; }
|
||||||
| ISAMPLER2DMSARRAY { $$ = "isampler2DMSArray"; }
|
| ISAMPLER2DMSARRAY { $$ = "isampler2DMSArray"; }
|
||||||
| USAMPLER2DMSARRAY { $$ = "usampler2DMSArray"; }
|
| USAMPLER2DMSARRAY { $$ = "usampler2DMSArray"; }
|
||||||
|
| ATOMIC_UINT { $$ = "atomic_uint"; }
|
||||||
;
|
;
|
||||||
|
|
||||||
precision_qualifier:
|
precision_qualifier:
|
||||||
|
@@ -373,6 +373,9 @@ struct _mesa_glsl_parse_state {
|
|||||||
* Unused for other shader types.
|
* Unused for other shader types.
|
||||||
*/
|
*/
|
||||||
unsigned gs_input_size;
|
unsigned gs_input_size;
|
||||||
|
|
||||||
|
/** Atomic counter offsets by binding */
|
||||||
|
unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS];
|
||||||
};
|
};
|
||||||
|
|
||||||
# define YYLLOC_DEFAULT(Current, Rhs, N) \
|
# define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||||
|
Reference in New Issue
Block a user