glsl: implement layout qualifiers
For GL_ARB_fragment_coord_conventions. This only applies to gl_FragCoord and controls pixel center origin and pixel center integer. For example: layout (origin_upper_left, pixel_center_integer) varying vec4 gl_FragCoord; This features introduces the idea of re-declaring variables with a changed type. This may also apply to arrays in some cases but that's not implemented at this time.
This commit is contained in:
@@ -636,6 +636,38 @@ parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Layout qualifiers */
|
||||||
|
#define LAYOUT_QUALIFIER_NONE 0
|
||||||
|
#define LAYOUT_QUALIFIER_UPPER_LEFT 1
|
||||||
|
#define LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER 2
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_layout_qualifiers(slang_parse_ctx * C, slang_layout_qualifier *layout)
|
||||||
|
{
|
||||||
|
*layout = 0x0;
|
||||||
|
|
||||||
|
/* the layout qualifiers come as a list of LAYOUT_QUALIFER_x tokens,
|
||||||
|
* terminated by LAYOUT_QUALIFIER_NONE.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
GLuint c = *C->I++;
|
||||||
|
switch (c) {
|
||||||
|
case LAYOUT_QUALIFIER_NONE:
|
||||||
|
/* end of list of qualifiers */
|
||||||
|
return 1;
|
||||||
|
case LAYOUT_QUALIFIER_UPPER_LEFT:
|
||||||
|
*layout |= SLANG_LAYOUT_UPPER_LEFT_BIT;
|
||||||
|
break;
|
||||||
|
case LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER:
|
||||||
|
*layout |= SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "Bad layout qualifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* type qualifier */
|
/* type qualifier */
|
||||||
#define TYPE_QUALIFIER_NONE 0
|
#define TYPE_QUALIFIER_NONE 0
|
||||||
#define TYPE_QUALIFIER_CONST 1
|
#define TYPE_QUALIFIER_CONST 1
|
||||||
@@ -907,6 +939,9 @@ static int
|
|||||||
parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O,
|
parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O,
|
||||||
slang_fully_specified_type * type)
|
slang_fully_specified_type * type)
|
||||||
{
|
{
|
||||||
|
if (!parse_layout_qualifiers(C, &type->layout))
|
||||||
|
RETURN0;
|
||||||
|
|
||||||
if (!parse_type_variant(C, &type->variant))
|
if (!parse_type_variant(C, &type->variant))
|
||||||
RETURN0;
|
RETURN0;
|
||||||
|
|
||||||
@@ -2028,6 +2063,30 @@ initialize_global(slang_assemble_ctx * A, slang_variable * var)
|
|||||||
#define VARIABLE_ARRAY_UNKNOWN 4
|
#define VARIABLE_ARRAY_UNKNOWN 4
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if it's OK to re-declare a variable with the given new type.
|
||||||
|
* This happens when applying layout qualifiers to gl_FragCoord or
|
||||||
|
* (re)setting an array size.
|
||||||
|
* If redeclaration is OK, return a pointer to the incoming variable
|
||||||
|
* updated with new type info. Else return NULL;
|
||||||
|
*/
|
||||||
|
static slang_variable *
|
||||||
|
redeclare_variable(slang_variable *var,
|
||||||
|
const slang_fully_specified_type *type)
|
||||||
|
{
|
||||||
|
if (slang_fully_specified_types_compatible(&var->type, type)) {
|
||||||
|
/* replace orig var layout with new layout */
|
||||||
|
var->type.layout = type->layout;
|
||||||
|
|
||||||
|
/* XXX there may be other type updates in the future here */
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the initializer for a variable declaration.
|
* Parse the initializer for a variable declaration.
|
||||||
*/
|
*/
|
||||||
@@ -2036,7 +2095,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
|
|||||||
const slang_fully_specified_type * type)
|
const slang_fully_specified_type * type)
|
||||||
{
|
{
|
||||||
GET_CURRENT_CONTEXT(ctx); /* a hack */
|
GET_CURRENT_CONTEXT(ctx); /* a hack */
|
||||||
slang_variable *var;
|
slang_variable *var = NULL, *prevDecl;
|
||||||
slang_atom a_name;
|
slang_atom a_name;
|
||||||
|
|
||||||
/* empty init declatator (without name, e.g. "float ;") */
|
/* empty init declatator (without name, e.g. "float ;") */
|
||||||
@@ -2046,14 +2105,24 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
|
|||||||
a_name = parse_identifier(C);
|
a_name = parse_identifier(C);
|
||||||
|
|
||||||
/* check if name is already in this scope */
|
/* check if name is already in this scope */
|
||||||
if (_slang_variable_locate(O->vars, a_name, GL_FALSE)) {
|
prevDecl = _slang_variable_locate(O->vars, a_name, C->global_scope);
|
||||||
|
if (prevDecl) {
|
||||||
|
/* A var with this name has already been declared.
|
||||||
|
* Check if redeclaring the var with a different type/layout is legal.
|
||||||
|
*/
|
||||||
|
if (C->global_scope) {
|
||||||
|
var = redeclare_variable(prevDecl, type);
|
||||||
|
}
|
||||||
|
if (!var) {
|
||||||
slang_info_log_error(C->L,
|
slang_info_log_error(C->L,
|
||||||
"declaration of '%s' conflicts with previous declaration",
|
"declaration of '%s' conflicts with previous declaration",
|
||||||
(char *) a_name);
|
(char *) a_name);
|
||||||
RETURN0;
|
RETURN0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* make room for the new variable and initialize it */
|
if (!var) {
|
||||||
|
/* make room for a new variable and initialize it */
|
||||||
var = slang_variable_scope_grow(O->vars);
|
var = slang_variable_scope_grow(O->vars);
|
||||||
if (!var) {
|
if (!var) {
|
||||||
slang_info_log_memory(C->L);
|
slang_info_log_memory(C->L);
|
||||||
@@ -2065,10 +2134,12 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
|
|||||||
var->type.centroid = type->centroid;
|
var->type.centroid = type->centroid;
|
||||||
var->type.precision = type->precision;
|
var->type.precision = type->precision;
|
||||||
var->type.variant = type->variant;
|
var->type.variant = type->variant;
|
||||||
|
var->type.layout = type->layout;
|
||||||
var->type.array_len = type->array_len;
|
var->type.array_len = type->array_len;
|
||||||
var->a_name = a_name;
|
var->a_name = a_name;
|
||||||
if (var->a_name == SLANG_ATOM_NULL)
|
if (var->a_name == SLANG_ATOM_NULL)
|
||||||
RETURN0;
|
RETURN0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (*C->I++) {
|
switch (*C->I++) {
|
||||||
case VARIABLE_NONE:
|
case VARIABLE_NONE:
|
||||||
@@ -2169,6 +2240,21 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
|
|||||||
RETURN0;
|
RETURN0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT &&
|
||||||
|
var->a_name == slang_atom_pool_atom(C->atoms, "gl_FragCoord")) {
|
||||||
|
/* set the program's PixelCenterInteger, OriginUpperLeft fields */
|
||||||
|
struct gl_fragment_program *fragProg =
|
||||||
|
(struct gl_fragment_program *) O->program;
|
||||||
|
|
||||||
|
if (var->type.layout & SLANG_LAYOUT_UPPER_LEFT_BIT) {
|
||||||
|
fragProg->OriginUpperLeft = GL_TRUE;
|
||||||
|
}
|
||||||
|
if (var->type.layout & SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT) {
|
||||||
|
fragProg->PixelCenterInteger = GL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2615,6 +2701,11 @@ compile_with_grammar(const char *source,
|
|||||||
return GL_FALSE;
|
return GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == SLANG_UNIT_FRAGMENT_SHADER) {
|
||||||
|
sl_pp_context_add_extension(context, "GL_ARB_fragment_coord_conventions");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if FEATURE_es2_glsl
|
#if FEATURE_es2_glsl
|
||||||
if (sl_pp_context_add_predefined(context, "GL_ES", "1") ||
|
if (sl_pp_context_add_predefined(context, "GL_ES", "1") ||
|
||||||
sl_pp_context_add_predefined(context, "GL_FRAGMENT_PRECISION_HIGH", "1")) {
|
sl_pp_context_add_predefined(context, "GL_FRAGMENT_PRECISION_HIGH", "1")) {
|
||||||
|
Reference in New Issue
Block a user