diff options
author | marha <marha@users.sourceforge.net> | 2012-07-31 10:17:14 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2012-07-31 10:17:14 +0200 |
commit | 83da3ad0287bc51cd16ee6911fe73dc98ebe000b (patch) | |
tree | 48d48590a0b0a3770006aeda8ec2b2a45054d1f1 /mesalib/src/glsl | |
parent | 00e30605ffc7ac3cf1a091ff2c1f46cfefb780d7 (diff) | |
parent | bd27b3d008b0abf9ae2edcb127302728808533e4 (diff) | |
download | vcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.tar.gz vcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.tar.bz2 vcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.zip |
Merge remote-tracking branch 'origin/released'
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/ast.h | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 116 | ||||
-rw-r--r-- | mesalib/src/glsl/builtin_types.h | 5 | ||||
-rw-r--r-- | mesalib/src/glsl/glcpp/glcpp-parse.y | 4 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser.yy | 4 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.cpp | 16 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.h | 4 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_types.cpp | 220 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_types.h | 18 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.cpp | 1 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 15 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_clone.cpp | 1 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_set_program_inouts.cpp | 36 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_uniform.h | 34 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniforms.cpp | 177 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 91 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.h | 9 | ||||
-rw-r--r-- | mesalib/src/glsl/lower_vector.cpp | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_dead_code.cpp | 8 | ||||
-rw-r--r-- | mesalib/src/glsl/strtod.c | 2 |
20 files changed, 725 insertions, 44 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 6d81afc99..3c0a2b838 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -517,6 +517,12 @@ public: * is used to note these cases when no type is specified. */ int invariant; + + /** + * Flag indicating that these declarators are in a uniform block, + * allowing UBO type qualifiers. + */ + bool ubo_qualifiers_valid; }; diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index bbe8f0596..1c54991cf 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1917,7 +1917,8 @@ static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, ir_variable *var, struct _mesa_glsl_parse_state *state, - YYLTYPE *loc) + YYLTYPE *loc, + bool ubo_qualifiers_valid) { if (qual->flags.q.invariant) { if (var->used) { @@ -2010,24 +2011,10 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, if (var->interpolation != INTERP_QUALIFIER_NONE && !(state->target == vertex_shader && var->mode == ir_var_out) && !(state->target == fragment_shader && var->mode == ir_var_in)) { - const char *qual_string = NULL; - switch (var->interpolation) { - case INTERP_QUALIFIER_FLAT: - qual_string = "flat"; - break; - case INTERP_QUALIFIER_NOPERSPECTIVE: - qual_string = "noperspective"; - break; - case INTERP_QUALIFIER_SMOOTH: - qual_string = "smooth"; - break; - } - _mesa_glsl_error(loc, state, "interpolation qualifier `%s' can only be applied to " "vertex shader outputs and fragment shader inputs.", - qual_string); - + var->interpolation_string()); } var->pixel_center_integer = qual->flags.q.pixel_center_integer; @@ -2191,6 +2178,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->depth_layout = ir_depth_layout_unchanged; else var->depth_layout = ir_depth_layout_none; + + if (qual->flags.q.std140 || + qual->flags.q.packed || + qual->flags.q.shared) { + _mesa_glsl_error(loc, state, + "uniform block layout qualifiers std140, packed, and " + "shared can only be applied to uniform blocks, not " + "members"); + } + + if (!ubo_qualifiers_valid && + (qual->flags.q.row_major || qual->flags.q.column_major)) { + _mesa_glsl_error(loc, state, + "uniform block layout qualifiers row_major and " + "column_major can only be applied to uniform block " + "members"); + } } /** @@ -2611,7 +2615,7 @@ ast_declarator_list::hir(exec_list *instructions, } apply_type_qualifier_to_variable(& this->type->qualifier, var, state, - & loc); + & loc, this->ubo_qualifiers_valid); if (this->type->qualifier.flags.q.invariant) { if ((state->target == vertex_shader) && !(var->mode == ir_var_out || @@ -3028,7 +3032,8 @@ ast_parameter_declarator::hir(exec_list *instructions, /* Apply any specified qualifiers to the parameter declaration. Note that * for function parameters the default mode is 'in'. */ - apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc); + apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc, + false); /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: * @@ -3989,6 +3994,25 @@ ast_struct_specifier::hir(exec_list *instructions, return NULL; } +static struct gl_uniform_block * +get_next_uniform_block(struct _mesa_glsl_parse_state *state) +{ + if (state->num_uniform_blocks >= state->uniform_block_array_size) { + state->uniform_block_array_size *= 2; + if (state->uniform_block_array_size <= 4) + state->uniform_block_array_size = 4; + + state->uniform_blocks = reralloc(state, + state->uniform_blocks, + struct gl_uniform_block, + state->uniform_block_array_size); + } + + memset(&state->uniform_blocks[state->num_uniform_blocks], + 0, sizeof(*state->uniform_blocks)); + return &state->uniform_blocks[state->num_uniform_blocks++]; +} + ir_rvalue * ast_uniform_block::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -3997,6 +4021,62 @@ ast_uniform_block::hir(exec_list *instructions, * need to turn those into ir_variables with an association * with this uniform block. */ + struct gl_uniform_block *ubo = get_next_uniform_block(state); + ubo->Name = ralloc_strdup(state->uniform_blocks, this->block_name); + + unsigned int num_variables = 0; + foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) { + foreach_list_const(node, &decl_list->declarations) { + num_variables++; + } + } + + bool block_row_major = this->layout.flags.q.row_major; + + ubo->Uniforms = rzalloc_array(state->uniform_blocks, + struct gl_uniform_buffer_variable, + num_variables); + + foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) { + exec_list declared_variables; + + decl_list->hir(&declared_variables, state); + + foreach_list_const(node, &declared_variables) { + struct ir_variable *var = (ir_variable *)node; + + struct gl_uniform_buffer_variable *ubo_var = + &ubo->Uniforms[ubo->NumUniforms++]; + + var->uniform_block = ubo - state->uniform_blocks; + + ubo_var->Name = ralloc_strdup(state->uniform_blocks, var->name); + ubo_var->Type = var->type; + ubo_var->Buffer = ubo - state->uniform_blocks; + ubo_var->Offset = 0; /* Assigned at link time. */ + ubo_var->RowMajor = block_row_major; + if (decl_list->type->qualifier.flags.q.row_major) + ubo_var->RowMajor = true; + else if (decl_list->type->qualifier.flags.q.column_major) + ubo_var->RowMajor = false; + + /* From the GL_ARB_uniform_buffer_object spec: + * + * "Sampler types are not allowed inside of uniform + * blocks. All other types, arrays, and structures + * allowed for uniforms are allowed within a uniform + * block." + */ + if (var->type->contains_sampler()) { + YYLTYPE loc = decl_list->get_location(); + _mesa_glsl_error(&loc, state, + "Uniform in non-default uniform block contains sampler\n"); + } + } + + instructions->append_list(&declared_variables); + } + return NULL; } diff --git a/mesalib/src/glsl/builtin_types.h b/mesalib/src/glsl/builtin_types.h index 8c136e4ab..d75c56261 100644 --- a/mesalib/src/glsl/builtin_types.h +++ b/mesalib/src/glsl/builtin_types.h @@ -63,7 +63,12 @@ const glsl_type glsl_type::builtin_core_types[] = { }; const glsl_type *const glsl_type::bool_type = & builtin_core_types[0]; +const glsl_type *const glsl_type::bvec2_type = & builtin_core_types[1]; +const glsl_type *const glsl_type::bvec3_type = & builtin_core_types[2]; +const glsl_type *const glsl_type::bvec4_type = & builtin_core_types[3]; const glsl_type *const glsl_type::int_type = & builtin_core_types[4]; +const glsl_type *const glsl_type::ivec2_type = & builtin_core_types[5]; +const glsl_type *const glsl_type::ivec3_type = & builtin_core_types[6]; const glsl_type *const glsl_type::ivec4_type = & builtin_core_types[7]; const glsl_type *const glsl_type::float_type = & builtin_core_types[8]; const glsl_type *const glsl_type::vec2_type = & builtin_core_types[9]; diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y index c0c1ca197..bf6f3ad01 100644 --- a/mesalib/src/glsl/glcpp/glcpp-parse.y +++ b/mesalib/src/glsl/glcpp/glcpp-parse.y @@ -213,7 +213,7 @@ expanded_line: parser->new_line_number = $2; ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, - "#line %" PRIiMAX, + "#line %" PRIiMAX "\n", $2); } | LINE_EXPANDED integer_constant integer_constant NEWLINE { @@ -223,7 +223,7 @@ expanded_line: parser->new_source_number = $3; ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, - "#line %" PRIiMAX " %" PRIiMAX, + "#line %" PRIiMAX " %" PRIiMAX "\n", $2, $3); } ; diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index 337337591..f61d6b8dd 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -301,7 +301,7 @@ pragma_statement: | PRAGMA_OPTIMIZE_OFF EOL | PRAGMA_INVARIANT_ALL EOL { - if (state->language_version < 120) { + if (state->language_version < 120 && !state->Const.GLSL_100ES) { _mesa_glsl_warning(& @1, state, "pragma `invariant(all)' not supported in %s", state->version_string); @@ -1967,6 +1967,7 @@ member_declaration: type->specifier = $3; $$ = new(ctx) ast_declarator_list(type); $$->set_location(yylloc); + $$->ubo_qualifiers_valid = true; $$->declarations.push_degenerate_list_at_head(& $4->link); } @@ -1980,6 +1981,7 @@ member_declaration: type->specifier = $2; $$ = new(ctx) ast_declarator_list(type); $$->set_location(yylloc); + $$->ubo_qualifiers_valid = true; $$->declarations.push_degenerate_list_at_head(& $3->link); } diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index d9ee406cf..7a9b22197 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -27,6 +27,7 @@ extern "C" { #include "main/core.h" /* for struct gl_context */ +#include "main/context.h" } #include "ralloc.h" @@ -90,19 +91,17 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, */ this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility; - this->Const.GLSL_110 = (ctx->API == API_OPENGL); - this->Const.GLSL_120 = (ctx->API == API_OPENGL) - && (ctx->Const.GLSLVersion >= 120); - this->Const.GLSL_130 = (ctx->API == API_OPENGL) - && (ctx->Const.GLSLVersion >= 130); - this->Const.GLSL_140 = (ctx->API == API_OPENGL) - && (ctx->Const.GLSLVersion >= 140); + bool is_desktop_gl = _mesa_is_desktop_gl(ctx); + this->Const.GLSL_110 = is_desktop_gl; + this->Const.GLSL_120 = is_desktop_gl && (ctx->Const.GLSLVersion >= 120); + this->Const.GLSL_130 = is_desktop_gl && (ctx->Const.GLSLVersion >= 130); + this->Const.GLSL_140 = is_desktop_gl && (ctx->Const.GLSLVersion >= 140); const unsigned lowest_version = (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility ? 100 : 110; const unsigned highest_version = - (ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100; + is_desktop_gl ? ctx->Const.GLSLVersion : 100; char *supported = ralloc_strdup(this, ""); for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) { @@ -773,6 +772,7 @@ ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type) { this->type = type; this->invariant = false; + this->ubo_qualifiers_valid = false; } void diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 2564e5856..cf6dfbe3b 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -86,6 +86,10 @@ struct _mesa_glsl_parse_state { exec_list translation_unit; glsl_symbol_table *symbols; + unsigned num_uniform_blocks; + unsigned uniform_block_array_size; + struct gl_uniform_block *uniform_blocks; + bool es_shader; unsigned language_version; const char *version_string; diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 8a34b8eb0..3d7866058 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -628,3 +628,223 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired) const && this->is_integer() && this->vector_elements == desired->vector_elements; } + +unsigned +glsl_type::std140_base_alignment(bool row_major) const +{ + /* (1) If the member is a scalar consuming <N> basic machine units, the + * base alignment is <N>. + * + * (2) If the member is a two- or four-component vector with components + * consuming <N> basic machine units, the base alignment is 2<N> or + * 4<N>, respectively. + * + * (3) If the member is a three-component vector with components consuming + * <N> basic machine units, the base alignment is 4<N>. + */ + if (this->is_scalar() || this->is_vector()) { + switch (this->vector_elements) { + case 1: + return 4; + case 2: + return 8; + case 3: + case 4: + return 16; + } + } + + /* (4) If the member is an array of scalars or vectors, the base alignment + * and array stride are set to match the base alignment of a single + * array element, according to rules (1), (2), and (3), and rounded up + * to the base alignment of a vec4. The array may have padding at the + * end; the base offset of the member following the array is rounded up + * to the next multiple of the base alignment. + * + * (6) If the member is an array of <S> column-major matrices with <C> + * columns and <R> rows, the matrix is stored identically to a row of + * <S>*<C> column vectors with <R> components each, according to rule + * (4). + * + * (8) If the member is an array of <S> row-major matrices with <C> columns + * and <R> rows, the matrix is stored identically to a row of <S>*<R> + * row vectors with <C> components each, according to rule (4). + * + * (10) If the member is an array of <S> structures, the <S> elements of + * the array are laid out in order, according to rule (9). + */ + if (this->is_array()) { + if (this->fields.array->is_scalar() || + this->fields.array->is_vector() || + this->fields.array->is_matrix()) { + return MAX2(this->fields.array->std140_base_alignment(row_major), 16); + } else { + assert(this->fields.array->is_record()); + return this->fields.array->std140_base_alignment(row_major); + } + } + + /* (5) If the member is a column-major matrix with <C> columns and + * <R> rows, the matrix is stored identically to an array of + * <C> column vectors with <R> components each, according to + * rule (4). + * + * (7) If the member is a row-major matrix with <C> columns and <R> + * rows, the matrix is stored identically to an array of <R> + * row vectors with <C> components each, according to rule (4). + */ + if (this->is_matrix()) { + const struct glsl_type *vec_type; + if (row_major) { + vec_type = get_instance(GLSL_TYPE_FLOAT, this->vector_elements, 1); + } else { + vec_type = get_instance(GLSL_TYPE_FLOAT, this->matrix_columns, 1); + } + + return vec_type->std140_base_alignment(false); + } + + /* (9) If the member is a structure, the base alignment of the + * structure is <N>, where <N> is the largest base alignment + * value of any of its members, and rounded up to the base + * alignment of a vec4. The individual members of this + * sub-structure are then assigned offsets by applying this set + * of rules recursively, where the base offset of the first + * member of the sub-structure is equal to the aligned offset + * of the structure. The structure may have padding at the end; + * the base offset of the member following the sub-structure is + * rounded up to the next multiple of the base alignment of the + * structure. + */ + if (this->is_record()) { + unsigned base_alignment = 16; + for (unsigned i = 0; i < this->length; i++) { + const struct glsl_type *field_type = this->fields.structure[i].type; + base_alignment = MAX2(base_alignment, + field_type->std140_base_alignment(row_major)); + } + return base_alignment; + } + + assert(!"not reached"); + return -1; +} + +static unsigned +align(unsigned val, unsigned align) +{ + return (val + align - 1) / align * align; +} + +unsigned +glsl_type::std140_size(bool row_major) const +{ + /* (1) If the member is a scalar consuming <N> basic machine units, the + * base alignment is <N>. + * + * (2) If the member is a two- or four-component vector with components + * consuming <N> basic machine units, the base alignment is 2<N> or + * 4<N>, respectively. + * + * (3) If the member is a three-component vector with components consuming + * <N> basic machine units, the base alignment is 4<N>. + */ + if (this->is_scalar() || this->is_vector()) { + return this->vector_elements * 4; + } + + /* (5) If the member is a column-major matrix with <C> columns and + * <R> rows, the matrix is stored identically to an array of + * <C> column vectors with <R> components each, according to + * rule (4). + * + * (6) If the member is an array of <S> column-major matrices with <C> + * columns and <R> rows, the matrix is stored identically to a row of + * <S>*<C> column vectors with <R> components each, according to rule + * (4). + * + * (7) If the member is a row-major matrix with <C> columns and <R> + * rows, the matrix is stored identically to an array of <R> + * row vectors with <C> components each, according to rule (4). + * + * (8) If the member is an array of <S> row-major matrices with <C> columns + * and <R> rows, the matrix is stored identically to a row of <S>*<R> + * row vectors with <C> components each, according to rule (4). + */ + if (this->is_matrix() || (this->is_array() && + this->fields.array->is_matrix())) { + const struct glsl_type *element_type; + const struct glsl_type *vec_type; + unsigned int array_len; + + if (this->is_array()) { + element_type = this->fields.array; + array_len = this->length; + } else { + element_type = this; + array_len = 1; + } + + if (row_major) { + vec_type = get_instance(GLSL_TYPE_FLOAT, + element_type->matrix_columns, 1); + array_len *= element_type->vector_elements; + } else { + vec_type = get_instance(GLSL_TYPE_FLOAT, + element_type->vector_elements, 1); + array_len *= element_type->matrix_columns; + } + const glsl_type *array_type = glsl_type::get_array_instance(vec_type, + array_len); + + return array_type->std140_size(false); + } + + /* (4) If the member is an array of scalars or vectors, the base alignment + * and array stride are set to match the base alignment of a single + * array element, according to rules (1), (2), and (3), and rounded up + * to the base alignment of a vec4. The array may have padding at the + * end; the base offset of the member following the array is rounded up + * to the next multiple of the base alignment. + * + * (10) If the member is an array of <S> structures, the <S> elements of + * the array are laid out in order, according to rule (9). + */ + if (this->is_array()) { + if (this->fields.array->is_record()) { + return this->length * this->fields.array->std140_size(row_major); + } else { + unsigned element_base_align = + this->fields.array->std140_base_alignment(row_major); + return this->length * MAX2(element_base_align, 16); + } + } + + /* (9) If the member is a structure, the base alignment of the + * structure is <N>, where <N> is the largest base alignment + * value of any of its members, and rounded up to the base + * alignment of a vec4. The individual members of this + * sub-structure are then assigned offsets by applying this set + * of rules recursively, where the base offset of the first + * member of the sub-structure is equal to the aligned offset + * of the structure. The structure may have padding at the end; + * the base offset of the member following the sub-structure is + * rounded up to the next multiple of the base alignment of the + * structure. + */ + if (this->is_record()) { + unsigned size = 0; + for (unsigned i = 0; i < this->length; i++) { + const struct glsl_type *field_type = this->fields.structure[i].type; + unsigned align = field_type->std140_base_alignment(row_major); + size = (size + align - 1) / align * align; + size += field_type->std140_size(row_major); + } + size = align(size, + this->fields.structure[0].type->std140_base_alignment(row_major)); + return size; + } + + assert(!"not reached"); + return -1; +} diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index 48d41d7f8..915d1a22b 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -152,6 +152,8 @@ struct glsl_type { static const glsl_type *const error_type; static const glsl_type *const void_type; static const glsl_type *const int_type; + static const glsl_type *const ivec2_type; + static const glsl_type *const ivec3_type; static const glsl_type *const ivec4_type; static const glsl_type *const uint_type; static const glsl_type *const uvec2_type; @@ -162,6 +164,9 @@ struct glsl_type { static const glsl_type *const vec3_type; static const glsl_type *const vec4_type; static const glsl_type *const bool_type; + static const glsl_type *const bvec2_type; + static const glsl_type *const bvec3_type; + static const glsl_type *const bvec4_type; static const glsl_type *const mat2_type; static const glsl_type *const mat2x3_type; static const glsl_type *const mat2x4_type; @@ -243,6 +248,19 @@ struct glsl_type { unsigned component_slots() const; /** + * Alignment in bytes of the start of this type in a std140 uniform + * block. + */ + unsigned std140_base_alignment(bool row_major) const; + + /** Size in bytes of this type in a std140 uniform block. + * + * Note that this is not GL_UNIFORM_SIZE (which is the number of + * elements in the array) + */ + unsigned std140_size(bool row_major) const; + + /** * \brief Can this type be implicitly converted to another? * * \return True if the types are identical or if this type can be converted diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 1c9eec6e2..b0e38d820 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1491,6 +1491,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name, this->explicit_location = false; this->has_initializer = false; this->location = -1; + this->uniform_block = -1; this->warn_extension = NULL; this->constant_value = NULL; this->constant_initializer = NULL; diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 9bbf3b7ef..f019837d5 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -453,7 +453,8 @@ public: * - Vertex shader output: one of the values from \c gl_vert_result. * - Fragment shader input: one of the values from \c gl_frag_attrib. * - Fragment shader output: one of the values from \c gl_frag_result. - * - Uniforms: Per-stage uniform slot number. + * - Uniforms: Per-stage uniform slot number for default uniform block. + * - Uniforms: Index within the uniform block definition for UBO members. * - Other: This field is not currently used. * * If the variable is a uniform, shader input, or shader output, and the @@ -462,6 +463,16 @@ public: int location; /** + * Uniform block number for uniforms. + * + * This index is into the shader's list of uniform blocks, not the + * linked program's merged list. + * + * If the variable is not in a uniform block, the value will be -1. + */ + int uniform_block; + + /** * output index for dual source blending. */ int index; @@ -1016,7 +1027,7 @@ enum ir_expression_operation { /** * A sentinel marking the last of all operations. */ - ir_last_opcode = ir_last_binop + ir_last_opcode = ir_quadop_vector }; class ir_expression : public ir_rvalue { diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index 591fe7b77..4314efa76 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -54,6 +54,7 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->interpolation = this->interpolation; var->location = this->location; var->index = this->index; + var->uniform_block = this->uniform_block; var->warn_extension = this->warn_extension; var->origin_upper_left = this->origin_upper_left; var->pixel_center_integer = this->pixel_center_integer; diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp index a7415c7e3..e5de07e01 100644 --- a/mesalib/src/glsl/ir_set_program_inouts.cpp +++ b/mesalib/src/glsl/ir_set_program_inouts.cpp @@ -26,8 +26,8 @@ * * Sets the InputsRead and OutputsWritten of Mesa programs. * - * Additionally, for fragment shaders, sets the InterpQualifier array and - * IsCentroid bitfield. + * Additionally, for fragment shaders, sets the InterpQualifier array, the + * IsCentroid bitfield, and the UsesDFdy flag. * * Mesa programs (gl_program, not gl_shader_program) have a set of * flags indicating which varyings are read and written. Computing @@ -61,6 +61,8 @@ public: virtual ir_visitor_status visit_enter(ir_dereference_array *); virtual ir_visitor_status visit_enter(ir_function_signature *); + virtual ir_visitor_status visit_enter(ir_expression *); + virtual ir_visitor_status visit_enter(ir_discard *); virtual ir_visitor_status visit(ir_dereference_variable *); virtual ir_visitor_status visit(ir_variable *); @@ -169,6 +171,28 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir) return visit_continue_with_parent; } +ir_visitor_status +ir_set_program_inouts_visitor::visit_enter(ir_expression *ir) +{ + if (is_fragment_shader && ir->operation == ir_unop_dFdy) { + gl_fragment_program *fprog = (gl_fragment_program *) prog; + fprog->UsesDFdy = true; + } + return visit_continue; +} + +ir_visitor_status +ir_set_program_inouts_visitor::visit_enter(ir_discard *) +{ + /* discards are only allowed in fragment shaders. */ + assert(is_fragment_shader); + + gl_fragment_program *fprog = (gl_fragment_program *) prog; + fprog->UsesKill = true; + + return visit_continue; +} + void do_set_program_inouts(exec_list *instructions, struct gl_program *prog, bool is_fragment_shader) @@ -179,9 +203,11 @@ do_set_program_inouts(exec_list *instructions, struct gl_program *prog, prog->OutputsWritten = 0; prog->SystemValuesRead = 0; if (is_fragment_shader) { - memset(((gl_fragment_program *) prog)->InterpQualifier, 0, - sizeof(((gl_fragment_program *) prog)->InterpQualifier)); - ((gl_fragment_program *) prog)->IsCentroid = 0; + gl_fragment_program *fprog = (gl_fragment_program *) prog; + memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier)); + fprog->IsCentroid = 0; + fprog->UsesDFdy = false; + fprog->UsesKill = false; } visit_list_elements(&v, instructions); } diff --git a/mesalib/src/glsl/ir_uniform.h b/mesalib/src/glsl/ir_uniform.h index 225da3fc5..913c53773 100644 --- a/mesalib/src/glsl/ir_uniform.h +++ b/mesalib/src/glsl/ir_uniform.h @@ -119,6 +119,40 @@ struct gl_uniform_storage { * uniform if the \c ::driver_storage interface is not used. */ union gl_constant_value *storage; + + /** Fields for GL_ARB_uniform_buffer_object + * @{ + */ + + /** + * GL_UNIFORM_BLOCK_INDEX: index of the uniform block containing + * the uniform, or -1 for the default uniform block. Note that the + * index is into the linked program's UniformBlocks[] array, not + * the linked shader's. + */ + int block_index; + + /** GL_UNIFORM_OFFSET: byte offset within the uniform block, or -1. */ + int offset; + + /** + * GL_UNIFORM_MATRIX_STRIDE: byte stride between columns or rows of + * a matrix. Set to 0 for non-matrices in UBOs, or -1 for uniforms + * in the default uniform block. + */ + int matrix_stride; + + /** + * GL_UNIFORM_ARRAY_STRIDE: byte stride between elements of the + * array. Set to zero for non-arrays in UBOs, or -1 for uniforms + * in the default uniform block. + */ + int array_stride; + + /** GL_UNIFORM_ROW_MAJOR: true iff it's a row-major matrix in a UBO */ + bool row_major; + + /** @} */ }; #ifdef __cplusplus diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index 3cbc50510..307f5de09 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -27,6 +27,13 @@ #include "ir_uniform.h" #include "glsl_symbol_table.h" #include "program/hash_table.h" +#include "program.h" + +static inline unsigned int +align(unsigned int a, unsigned int align) +{ + return (a + align - 1) / align * align; +} /** * \file link_uniforms.cpp @@ -216,6 +223,28 @@ public: this->shader_shadow_samplers = 0; } + void set_and_process(struct gl_shader_program *prog, + ir_variable *var) + { + ubo_var = NULL; + if (var->uniform_block != -1) { + struct gl_uniform_block *block = + &prog->UniformBlocks[var->uniform_block]; + + ubo_block_index = var->uniform_block; + ubo_var_index = var->location; + ubo_var = &block->Uniforms[var->location]; + ubo_byte_offset = ubo_var->Offset; + } + + process(var); + } + + struct gl_uniform_buffer_variable *ubo_var; + int ubo_block_index; + int ubo_var_index; + int ubo_byte_offset; + private: virtual void visit_field(const glsl_type *type, const char *name) { @@ -291,6 +320,25 @@ private: this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].storage = this->values; + if (this->ubo_var) { + this->uniforms[id].block_index = this->ubo_block_index; + + unsigned alignment = type->std140_base_alignment(ubo_var->RowMajor); + this->ubo_byte_offset = align(this->ubo_byte_offset, alignment); + this->uniforms[id].offset = this->ubo_byte_offset; + this->ubo_byte_offset += type->std140_size(ubo_var->RowMajor); + + this->uniforms[id].array_stride = 0; + this->uniforms[id].matrix_stride = 0; + this->uniforms[id].row_major = base_type->is_matrix() && + ubo_var->RowMajor; + } else { + this->uniforms[id].block_index = -1; + this->uniforms[id].offset = -1; + this->uniforms[id].array_stride = -1; + this->uniforms[id].matrix_stride = -1; + this->uniforms[id].row_major = false; + } this->values += values_for_type(type); } @@ -316,6 +364,125 @@ public: unsigned shader_shadow_samplers; }; +/** + * Merges a uniform block into an array of uniform blocks that may or + * may not already contain a copy of it. + * + * Returns the index of the new block in the array. + */ +int +link_cross_validate_uniform_block(void *mem_ctx, + struct gl_uniform_block **linked_blocks, + unsigned int *num_linked_blocks, + struct gl_uniform_block *new_block) +{ + for (unsigned int i = 0; i < *num_linked_blocks; i++) { + struct gl_uniform_block *old_block = &(*linked_blocks)[i]; + if (strcmp(old_block->Name, new_block->Name) == 0) { + if (old_block->NumUniforms != new_block->NumUniforms) { + return -1; + } + + for (unsigned j = 0; j < old_block->NumUniforms; j++) { + if (strcmp(old_block->Uniforms[j].Name, + new_block->Uniforms[j].Name) != 0) + return -1; + + if (old_block->Uniforms[j].Offset != + new_block->Uniforms[j].Offset) + return -1; + + if (old_block->Uniforms[j].RowMajor != + new_block->Uniforms[j].RowMajor) + return -1; + } + return i; + } + } + + *linked_blocks = reralloc(mem_ctx, *linked_blocks, + struct gl_uniform_block, + *num_linked_blocks + 1); + int linked_block_index = (*num_linked_blocks)++; + struct gl_uniform_block *linked_block = &(*linked_blocks)[linked_block_index]; + + memcpy(linked_block, new_block, sizeof(*new_block)); + linked_block->Uniforms = ralloc_array(*linked_blocks, + struct gl_uniform_buffer_variable, + linked_block->NumUniforms); + + memcpy(linked_block->Uniforms, + new_block->Uniforms, + sizeof(*linked_block->Uniforms) * linked_block->NumUniforms); + + for (unsigned int i = 0; i < linked_block->NumUniforms; i++) { + struct gl_uniform_buffer_variable *ubo_var = + &linked_block->Uniforms[i]; + + ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name); + } + + return linked_block_index; +} + +/** + * Walks the IR and update the references to uniform blocks in the + * ir_variables to point at linked shader's list (previously, they + * would point at the uniform block list in one of the pre-linked + * shaders). + */ +static bool +link_update_uniform_buffer_variables(struct gl_shader *shader) +{ + foreach_list(node, shader->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->uniform_block == -1)) + continue; + + assert(var->mode == ir_var_uniform); + + bool found = false; + for (unsigned i = 0; i < shader->NumUniformBlocks; i++) { + for (unsigned j = 0; j < shader->UniformBlocks[i].NumUniforms; j++) { + if (!strcmp(var->name, shader->UniformBlocks[i].Uniforms[j].Name)) { + found = true; + var->uniform_block = i; + var->location = j; + break; + } + } + if (found) + break; + } + assert(found); + } + + return true; +} + +void +link_assign_uniform_block_offsets(struct gl_shader *shader) +{ + for (unsigned b = 0; b < shader->NumUniformBlocks; b++) { + struct gl_uniform_block *block = &shader->UniformBlocks[b]; + + unsigned offset = 0; + for (unsigned int i = 0; i < block->NumUniforms; i++) { + struct gl_uniform_buffer_variable *ubo_var = &block->Uniforms[i]; + const struct glsl_type *type = ubo_var->Type; + + unsigned alignment = type->std140_base_alignment(ubo_var->RowMajor); + unsigned size = type->std140_size(ubo_var->RowMajor); + + offset = align(offset, alignment); + ubo_var->Offset = offset; + offset += size; + } + block->UniformBufferSize = offset; + } +} + void link_assign_uniform_locations(struct gl_shader_program *prog) { @@ -340,6 +507,14 @@ link_assign_uniform_locations(struct gl_shader_program *prog) */ memset(prog->SamplerUnits, 0, sizeof(prog->SamplerUnits)); + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + if (!link_update_uniform_buffer_variables(prog->_LinkedShaders[i])) + return; + } + /* First pass: Count the uniform resources used by the user-defined * uniforms. While this happens, each active uniform will have an index * assigned to it. @@ -412,7 +587,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog) if (strncmp("gl_", var->name, 3) == 0) continue; - parcel.process(var); + parcel.set_and_process(prog, var); } prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used; diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index f06298cf6..bfdde4023 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -581,6 +581,48 @@ cross_validate_uniforms(struct gl_shader_program *prog) MESA_SHADER_TYPES, true); } +/** + * Accumulates the array of prog->UniformBlocks and checks that all + * definitons of blocks agree on their contents. + */ +static bool +interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog) +{ + unsigned max_num_uniform_blocks = 0; + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + if (prog->_LinkedShaders[i]) + max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks; + } + + for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + + prog->UniformBlockStageIndex[i] = ralloc_array(prog, int, + max_num_uniform_blocks); + for (unsigned int j = 0; j < max_num_uniform_blocks; j++) + prog->UniformBlockStageIndex[i][j] = -1; + + if (sh == NULL) + continue; + + for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) { + int index = link_cross_validate_uniform_block(prog, + &prog->UniformBlocks, + &prog->NumUniformBlocks, + &sh->UniformBlocks[j]); + + if (index == -1) { + linker_error(prog, "uniform block `%s' has mismatching definitions", + sh->UniformBlocks[j].Name); + return false; + } + + prog->UniformBlockStageIndex[i][index] = j; + } + } + + return true; +} /** * Validate that outputs from one stage match inputs of another @@ -910,7 +952,6 @@ public: } }; - /** * Combine a group of shaders for a single stage to generate a linked shader * @@ -925,11 +966,33 @@ link_intrastage_shaders(void *mem_ctx, struct gl_shader **shader_list, unsigned num_shaders) { + struct gl_uniform_block *uniform_blocks = NULL; + unsigned num_uniform_blocks = 0; + /* Check that global variables defined in multiple shaders are consistent. */ if (!cross_validate_globals(prog, shader_list, num_shaders, false)) return NULL; + /* Check that uniform blocks between shaders for a stage agree. */ + for (unsigned i = 0; i < num_shaders; i++) { + struct gl_shader *sh = shader_list[i]; + + for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) { + link_assign_uniform_block_offsets(shader_list[i]); + + int index = link_cross_validate_uniform_block(mem_ctx, + &uniform_blocks, + &num_uniform_blocks, + &sh->UniformBlocks[j]); + if (index == -1) { + linker_error(prog, "uniform block `%s' has mismatching definitions", + sh->UniformBlocks[j].Name); + return NULL; + } + } + } + /* Check that there is only a single definition of each function signature * across all shaders. */ @@ -997,6 +1060,10 @@ link_intrastage_shaders(void *mem_ctx, linked->ir = new(linked) exec_list; clone_ir_list(mem_ctx, linked->ir, main->ir); + linked->UniformBlocks = uniform_blocks; + linked->NumUniformBlocks = num_uniform_blocks; + ralloc_steal(linked, linked->UniformBlocks); + populate_symbol_table(linked); /* The a pointer to the main function in the final linked shader (i.e., the @@ -1100,6 +1167,13 @@ update_array_sizes(struct gl_shader_program *prog) !var->type->is_array()) continue; + /* GL_ARB_uniform_buffer_object says that std140 uniforms + * will not be eliminated. Since we always do std140, just + * don't resize arrays in UBOs. + */ + if (var->uniform_block != -1) + continue; + unsigned int size = var->max_array_access; for (unsigned j = 0; j < MESA_SHADER_TYPES; j++) { if (prog->_LinkedShaders[j] == NULL) @@ -2289,11 +2363,17 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) prog->Validated = false; prog->_Used = false; - if (prog->InfoLog != NULL) - ralloc_free(prog->InfoLog); - + ralloc_free(prog->InfoLog); prog->InfoLog = ralloc_strdup(NULL, ""); + ralloc_free(prog->UniformBlocks); + prog->UniformBlocks = NULL; + prog->NumUniformBlocks = 0; + for (int i = 0; i < MESA_SHADER_TYPES; i++) { + ralloc_free(prog->UniformBlockStageIndex[i]); + prog->UniformBlockStageIndex[i] = NULL; + } + /* Separate the shaders into groups based on their type. */ struct gl_shader **vert_shader_list; @@ -2422,6 +2502,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } + if (!interstage_cross_validate_uniform_blocks(prog)) + goto done; + /* Do common optimization before assigning storage for attributes, * uniforms, and varyings. Later optimization could possibly make * some of that unused. diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h index d0aaf3e1e..7d2e98a15 100644 --- a/mesalib/src/glsl/linker.h +++ b/mesalib/src/glsl/linker.h @@ -40,6 +40,15 @@ link_assign_uniform_locations(struct gl_shader_program *prog); extern void link_set_uniform_initializers(struct gl_shader_program *prog); +extern int +link_cross_validate_uniform_block(void *mem_ctx, + struct gl_uniform_block **linked_blocks, + unsigned int *num_linked_blocks, + struct gl_uniform_block *new_block); + +void +link_assign_uniform_block_offsets(struct gl_shader *shader); + /** * Class for processing all of the leaf fields of an uniform * diff --git a/mesalib/src/glsl/lower_vector.cpp b/mesalib/src/glsl/lower_vector.cpp index 57963a121..0cd6909db 100644 --- a/mesalib/src/glsl/lower_vector.cpp +++ b/mesalib/src/glsl/lower_vector.cpp @@ -183,7 +183,7 @@ lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue) if (assigned > 0) { ir_constant *const c = new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type, - assigned, 0), + assigned, 1), &d); ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp); ir_assignment *const assign = diff --git a/mesalib/src/glsl/opt_dead_code.cpp b/mesalib/src/glsl/opt_dead_code.cpp index 0578f1737..de8475f95 100644 --- a/mesalib/src/glsl/opt_dead_code.cpp +++ b/mesalib/src/glsl/opt_dead_code.cpp @@ -95,9 +95,15 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned) /* uniform initializers are precious, and could get used by another * stage. Also, once uniform locations have been assigned, the * declaration cannot be deleted. + * + * Also, GL_ARB_uniform_buffer_object says that std140 + * uniforms will not be eliminated. Since we always do + * std140, just don't eliminate uniforms in UBOs. */ if (entry->var->mode == ir_var_uniform && - (uniform_locations_assigned || entry->var->constant_value)) + (uniform_locations_assigned || + entry->var->constant_value || + entry->var->uniform_block != -1)) continue; entry->var->remove(); diff --git a/mesalib/src/glsl/strtod.c b/mesalib/src/glsl/strtod.c index a876e138b..47c1f0ed6 100644 --- a/mesalib/src/glsl/strtod.c +++ b/mesalib/src/glsl/strtod.c @@ -45,7 +45,7 @@ double glsl_strtod(const char *s, char **end) { #if defined(_GNU_SOURCE) && !defined(__CYGWIN__) && !defined(__FreeBSD__) && \ - !defined(__HAIKU__) + !defined(__HAIKU__) && !defined(__UCLIBC__) static locale_t loc = NULL; if (!loc) { loc = newlocale(LC_CTYPE_MASK, "C", NULL); |