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:
Brian Paul 2010-02-13 13:57:31 -07:00
parent 26661ac0e1
commit c2c4935cb8
1 changed files with 110 additions and 19 deletions

View File

@ -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 */
#define TYPE_QUALIFIER_NONE 0
#define TYPE_QUALIFIER_CONST 1
@ -907,9 +939,12 @@ static int
parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O,
slang_fully_specified_type * type)
{
if (!parse_layout_qualifiers(C, &type->layout))
RETURN0;
if (!parse_type_variant(C, &type->variant))
RETURN0;
if (!parse_type_centroid(C, &type->centroid))
RETURN0;
@ -2028,6 +2063,30 @@ initialize_global(slang_assemble_ctx * A, slang_variable * var)
#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.
*/
@ -2036,7 +2095,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
const slang_fully_specified_type * type)
{
GET_CURRENT_CONTEXT(ctx); /* a hack */
slang_variable *var;
slang_variable *var = NULL, *prevDecl;
slang_atom a_name;
/* empty init declatator (without name, e.g. "float ;") */
@ -2046,29 +2105,41 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
a_name = parse_identifier(C);
/* check if name is already in this scope */
if (_slang_variable_locate(O->vars, a_name, GL_FALSE)) {
slang_info_log_error(C->L,
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,
"declaration of '%s' conflicts with previous declaration",
(char *) a_name);
RETURN0;
RETURN0;
}
}
/* make room for the new variable and initialize it */
var = slang_variable_scope_grow(O->vars);
if (!var) {
slang_info_log_memory(C->L);
RETURN0;
}
/* make room for a new variable and initialize it */
var = slang_variable_scope_grow(O->vars);
if (!var) {
slang_info_log_memory(C->L);
RETURN0;
}
/* copy the declarator type qualifier/etc info, parse the identifier */
var->type.qualifier = type->qualifier;
var->type.centroid = type->centroid;
var->type.precision = type->precision;
var->type.variant = type->variant;
var->type.array_len = type->array_len;
var->a_name = a_name;
if (var->a_name == SLANG_ATOM_NULL)
RETURN0;
/* copy the declarator type qualifier/etc info, parse the identifier */
var->type.qualifier = type->qualifier;
var->type.centroid = type->centroid;
var->type.precision = type->precision;
var->type.variant = type->variant;
var->type.layout = type->layout;
var->type.array_len = type->array_len;
var->a_name = a_name;
if (var->a_name == SLANG_ATOM_NULL)
RETURN0;
}
switch (*C->I++) {
case VARIABLE_NONE:
@ -2169,6 +2240,21 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
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;
}
@ -2615,6 +2701,11 @@ compile_with_grammar(const char *source,
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 (sl_pp_context_add_predefined(context, "GL_ES", "1") ||
sl_pp_context_add_predefined(context, "GL_FRAGMENT_PRECISION_HIGH", "1")) {