aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/Makefile.am3
-rw-r--r--mesalib/src/glsl/Makefile.sources5
-rw-r--r--mesalib/src/glsl/ast.h14
-rw-r--r--mesalib/src/glsl/ast_array_index.cpp190
-rw-r--r--mesalib/src/glsl/ast_function.cpp149
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp274
-rw-r--r--mesalib/src/glsl/builtin_variables.cpp33
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y6
-rw-r--r--mesalib/src/glsl/glcpp/pp.c4
-rw-r--r--mesalib/src/glsl/glsl_parser.yy188
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp15
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h4
-rw-r--r--mesalib/src/glsl/glsl_symbol_table.cpp84
-rw-r--r--mesalib/src/glsl/glsl_symbol_table.h4
-rw-r--r--mesalib/src/glsl/glsl_types.cpp4
-rw-r--r--mesalib/src/glsl/glsl_types.h3
-rw-r--r--mesalib/src/glsl/ir.cpp16
-rw-r--r--mesalib/src/glsl/ir.h68
-rw-r--r--mesalib/src/glsl/ir_basic_block.cpp2
-rw-r--r--mesalib/src/glsl/ir_constant_expression.cpp185
-rw-r--r--mesalib/src/glsl/ir_optimization.h7
-rw-r--r--mesalib/src/glsl/ir_print_visitor.cpp5
-rw-r--r--mesalib/src/glsl/ir_reader.cpp10
-rw-r--r--mesalib/src/glsl/ir_uniform.h27
-rw-r--r--mesalib/src/glsl/ir_validate.cpp82
-rw-r--r--mesalib/src/glsl/link_interface_blocks.cpp110
-rw-r--r--mesalib/src/glsl/link_uniform_initializers.cpp25
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp126
-rw-r--r--mesalib/src/glsl/link_varyings.cpp69
-rw-r--r--mesalib/src/glsl/linker.cpp28
-rw-r--r--mesalib/src/glsl/linker.h8
-rw-r--r--mesalib/src/glsl/lower_clip_distance.cpp124
-rw-r--r--mesalib/src/glsl/lower_instructions.cpp39
-rw-r--r--mesalib/src/glsl/lower_named_interface_blocks.cpp238
-rw-r--r--mesalib/src/glsl/lower_packed_varyings.cpp8
-rw-r--r--mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp149
-rw-r--r--mesalib/src/glsl/lower_vec_index_to_swizzle.cpp37
-rw-r--r--mesalib/src/glsl/lower_vector_insert.cpp139
-rw-r--r--mesalib/src/glsl/main.cpp4
-rw-r--r--mesalib/src/glsl/opt_algebraic.cpp6
-rw-r--r--mesalib/src/glsl/opt_flip_matrices.cpp122
-rw-r--r--mesalib/src/glsl/opt_if_simplification.cpp27
-rw-r--r--mesalib/src/glsl/program.h7
-rw-r--r--mesalib/src/glsl/ralloc.c8
-rw-r--r--mesalib/src/glsl/standalone_scaffolding.cpp17
-rw-r--r--mesalib/src/glsl/standalone_scaffolding.h17
-rw-r--r--mesalib/src/glsl/test_optpass.cpp14
47 files changed, 2115 insertions, 589 deletions
diff --git a/mesalib/src/glsl/Makefile.am b/mesalib/src/glsl/Makefile.am
index d0e5cd1d0..2bbad3d65 100644
--- a/mesalib/src/glsl/Makefile.am
+++ b/mesalib/src/glsl/Makefile.am
@@ -27,8 +27,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/src/mesa/ \
-I$(top_srcdir)/src/glsl/glcpp \
-I$(top_srcdir)/src/gtest/include \
- $(DEFINES) \
- $(API_DEFINES)
+ $(DEFINES)
AM_CFLAGS = $(VISIBILITY_CFLAGS)
AM_CXXFLAGS = $(VISIBILITY_CXXFLAGS)
diff --git a/mesalib/src/glsl/Makefile.sources b/mesalib/src/glsl/Makefile.sources
index b5282a604..50bad85ad 100644
--- a/mesalib/src/glsl/Makefile.sources
+++ b/mesalib/src/glsl/Makefile.sources
@@ -16,6 +16,7 @@ LIBGLCPP_GENERATED_FILES = \
# libglsl
LIBGLSL_FILES = \
+ $(GLSL_SRCDIR)/ast_array_index.cpp \
$(GLSL_SRCDIR)/ast_expr.cpp \
$(GLSL_SRCDIR)/ast_function.cpp \
$(GLSL_SRCDIR)/ast_to_hir.cpp \
@@ -45,6 +46,7 @@ LIBGLSL_FILES = \
$(GLSL_SRCDIR)/ir_variable_refcount.cpp \
$(GLSL_SRCDIR)/linker.cpp \
$(GLSL_SRCDIR)/link_functions.cpp \
+ $(GLSL_SRCDIR)/link_interface_blocks.cpp \
$(GLSL_SRCDIR)/link_uniforms.cpp \
$(GLSL_SRCDIR)/link_uniform_initializers.cpp \
$(GLSL_SRCDIR)/link_uniform_block_active_visitor.cpp \
@@ -62,12 +64,14 @@ LIBGLSL_FILES = \
$(GLSL_SRCDIR)/lower_mat_op_to_vec.cpp \
$(GLSL_SRCDIR)/lower_noise.cpp \
$(GLSL_SRCDIR)/lower_packed_varyings.cpp \
+ $(GLSL_SRCDIR)/lower_named_interface_blocks.cpp \
$(GLSL_SRCDIR)/lower_packing_builtins.cpp \
$(GLSL_SRCDIR)/lower_texture_projection.cpp \
$(GLSL_SRCDIR)/lower_variable_index_to_cond_assign.cpp \
$(GLSL_SRCDIR)/lower_vec_index_to_cond_assign.cpp \
$(GLSL_SRCDIR)/lower_vec_index_to_swizzle.cpp \
$(GLSL_SRCDIR)/lower_vector.cpp \
+ $(GLSL_SRCDIR)/lower_vector_insert.cpp \
$(GLSL_SRCDIR)/lower_output_reads.cpp \
$(GLSL_SRCDIR)/lower_ubo_reference.cpp \
$(GLSL_SRCDIR)/opt_algebraic.cpp \
@@ -81,6 +85,7 @@ LIBGLSL_FILES = \
$(GLSL_SRCDIR)/opt_dead_code_local.cpp \
$(GLSL_SRCDIR)/opt_dead_functions.cpp \
$(GLSL_SRCDIR)/opt_flatten_nested_if_blocks.cpp \
+ $(GLSL_SRCDIR)/opt_flip_matrices.cpp \
$(GLSL_SRCDIR)/opt_function_inlining.cpp \
$(GLSL_SRCDIR)/opt_if_simplification.cpp \
$(GLSL_SRCDIR)/opt_noop_swizzle.cpp \
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index fcc6b4566..df2a21f79 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -805,9 +805,9 @@ public:
ast_compound_statement *body;
};
-class ast_uniform_block : public ast_node {
+class ast_interface_block : public ast_node {
public:
- ast_uniform_block(ast_type_qualifier layout,
+ ast_interface_block(ast_type_qualifier layout,
const char *instance_name,
ast_expression *array_size)
: layout(layout), block_name(NULL), instance_name(instance_name),
@@ -854,7 +854,17 @@ _mesa_ast_field_selection_to_hir(const ast_expression *expr,
exec_list *instructions,
struct _mesa_glsl_parse_state *state);
+extern ir_rvalue *
+_mesa_ast_array_index_to_hir(void *mem_ctx,
+ struct _mesa_glsl_parse_state *state,
+ ir_rvalue *array, ir_rvalue *idx,
+ YYLTYPE &loc, YYLTYPE &idx_loc);
+
void
emit_function(_mesa_glsl_parse_state *state, ir_function *f);
+extern void
+check_builtin_array_max_size(const char *name, unsigned size,
+ YYLTYPE loc, struct _mesa_glsl_parse_state *state);
+
#endif /* AST_H */
diff --git a/mesalib/src/glsl/ast_array_index.cpp b/mesalib/src/glsl/ast_array_index.cpp
new file mode 100644
index 000000000..4baeb6f9d
--- /dev/null
+++ b/mesalib/src/glsl/ast_array_index.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ast.h"
+#include "glsl_types.h"
+#include "ir.h"
+
+ir_rvalue *
+_mesa_ast_array_index_to_hir(void *mem_ctx,
+ struct _mesa_glsl_parse_state *state,
+ ir_rvalue *array, ir_rvalue *idx,
+ YYLTYPE &loc, YYLTYPE &idx_loc)
+{
+ if (!array->type->is_error()
+ && !array->type->is_array()
+ && !array->type->is_matrix()
+ && !array->type->is_vector()) {
+ _mesa_glsl_error(& idx_loc, state,
+ "cannot dereference non-array / non-matrix / "
+ "non-vector");
+ }
+
+ if (!idx->type->is_error()) {
+ if (!idx->type->is_integer()) {
+ _mesa_glsl_error(& idx_loc, state, "array index must be integer type");
+ } else if (!idx->type->is_scalar()) {
+ _mesa_glsl_error(& idx_loc, state, "array index must be scalar");
+ }
+ }
+
+ /* If the array index is a constant expression and the array has a
+ * declared size, ensure that the access is in-bounds. If the array
+ * index is not a constant expression, ensure that the array has a
+ * declared size.
+ */
+ ir_constant *const const_index = idx->constant_expression_value();
+ if (const_index != NULL && idx->type->is_integer()) {
+ const int idx = const_index->value.i[0];
+ const char *type_name = "error";
+ unsigned bound = 0;
+
+ /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "It is illegal to declare an array with a size, and then
+ * later (in the same shader) index the same array with an
+ * integral constant expression greater than or equal to the
+ * declared size. It is also illegal to index an array with a
+ * negative constant expression."
+ */
+ if (array->type->is_matrix()) {
+ if (array->type->row_type()->vector_elements <= idx) {
+ type_name = "matrix";
+ bound = array->type->row_type()->vector_elements;
+ }
+ } else if (array->type->is_vector()) {
+ if (array->type->vector_elements <= idx) {
+ type_name = "vector";
+ bound = array->type->vector_elements;
+ }
+ } else {
+ /* glsl_type::array_size() returns 0 for non-array types. This means
+ * that we don't need to verify that the type is an array before
+ * doing the bounds checking.
+ */
+ if ((array->type->array_size() > 0)
+ && (array->type->array_size() <= idx)) {
+ type_name = "array";
+ bound = array->type->array_size();
+ }
+ }
+
+ if (bound > 0) {
+ _mesa_glsl_error(& loc, state, "%s index must be < %u",
+ type_name, bound);
+ } else if (idx < 0) {
+ _mesa_glsl_error(& loc, state, "%s index must be >= 0",
+ type_name);
+ }
+
+ if (array->type->is_array()) {
+ /* If the array is a variable dereference, it dereferences the
+ * whole array, by definition. Use this to get the variable.
+ *
+ * FINISHME: Should some methods for getting / setting / testing
+ * FINISHME: array access limits be added to ir_dereference?
+ */
+ ir_variable *const v = array->whole_variable_referenced();
+ if ((v != NULL) && (unsigned(idx) > v->max_array_access)) {
+ v->max_array_access = idx;
+
+ /* Check whether this access will, as a side effect, implicitly
+ * cause the size of a built-in array to be too large.
+ */
+ check_builtin_array_max_size(v->name, idx+1, loc, state);
+ }
+ }
+ } else if (const_index == NULL && array->type->is_array()) {
+ if (array->type->array_size() == 0) {
+ _mesa_glsl_error(&loc, state, "unsized array index must be constant");
+ } else if (array->type->fields.array->is_interface()) {
+ /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says:
+ *
+ * "All indexes used to index a uniform block array must be
+ * constant integral expressions."
+ */
+ _mesa_glsl_error(&loc, state,
+ "uniform block array index must be constant");
+ } else {
+ /* whole_variable_referenced can return NULL if the array is a
+ * member of a structure. In this case it is safe to not update
+ * the max_array_access field because it is never used for fields
+ * of structures.
+ */
+ ir_variable *v = array->whole_variable_referenced();
+ if (v != NULL)
+ v->max_array_access = array->type->array_size() - 1;
+ }
+
+ /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
+ *
+ * "Samplers aggregated into arrays within a shader (using square
+ * brackets [ ]) can only be indexed with integral constant
+ * expressions [...]."
+ *
+ * This restriction was added in GLSL 1.30. Shaders using earlier
+ * version of the language should not be rejected by the compiler
+ * front-end for using this construct. This allows useful things such
+ * as using a loop counter as the index to an array of samplers. If the
+ * loop in unrolled, the code should compile correctly. Instead, emit a
+ * warning.
+ */
+ if (array->type->element_type()->is_sampler()) {
+ if (!state->is_version(130, 100)) {
+ if (state->es_shader) {
+ _mesa_glsl_warning(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions is optional in %s",
+ state->get_version_string());
+ } else {
+ _mesa_glsl_warning(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions will be forbidden in GLSL 1.30 "
+ "and later");
+ }
+ } else {
+ _mesa_glsl_error(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions is forbidden in GLSL 1.30 and "
+ "later");
+ }
+ }
+ }
+
+ /* After performing all of the error checking, generate the IR for the
+ * expression.
+ */
+ if (array->type->is_array()
+ || array->type->is_matrix()) {
+ return new(mem_ctx) ir_dereference_array(array, idx);
+ } else if (array->type->is_vector()) {
+ return new(mem_ctx) ir_expression(ir_binop_vector_extract, array, idx);
+ } else if (array->type->is_error()) {
+ return array;
+ } else {
+ ir_rvalue *result = new(mem_ctx) ir_dereference_array(array, idx);
+ result->type = glsl_type::error_type;
+
+ return result;
+ }
+}
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 26f72cf8e..00e0c05dd 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -165,10 +165,18 @@ verify_parameter_modes(_mesa_glsl_parse_state *state,
actual->variable_referenced()->name);
return false;
} else if (!actual->is_lvalue()) {
- _mesa_glsl_error(&loc, state,
- "function parameter '%s %s' is not an lvalue",
- mode, formal->name);
- return false;
+ /* Even though ir_binop_vector_extract is not an l-value, let it
+ * slop through. generate_call will handle it correctly.
+ */
+ ir_expression *const expr = ((ir_rvalue *) actual)->as_expression();
+ if (expr == NULL
+ || expr->operation != ir_binop_vector_extract
+ || !expr->operands[0]->is_lvalue()) {
+ _mesa_glsl_error(&loc, state,
+ "function parameter '%s %s' is not an lvalue",
+ mode, formal->name);
+ return false;
+ }
}
}
@@ -178,6 +186,93 @@ verify_parameter_modes(_mesa_glsl_parse_state *state,
return true;
}
+static void
+fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type,
+ exec_list *before_instructions, exec_list *after_instructions,
+ bool parameter_is_inout)
+{
+ ir_expression *const expr = actual->as_expression();
+
+ /* If the types match exactly and the parameter is not a vector-extract,
+ * nothing needs to be done to fix the parameter.
+ */
+ if (formal_type == actual->type
+ && (expr == NULL || expr->operation != ir_binop_vector_extract))
+ return;
+
+ /* To convert an out parameter, we need to create a temporary variable to
+ * hold the value before conversion, and then perform the conversion after
+ * the function call returns.
+ *
+ * This has the effect of transforming code like this:
+ *
+ * void f(out int x);
+ * float value;
+ * f(value);
+ *
+ * Into IR that's equivalent to this:
+ *
+ * void f(out int x);
+ * float value;
+ * int out_parameter_conversion;
+ * f(out_parameter_conversion);
+ * value = float(out_parameter_conversion);
+ *
+ * If the parameter is an ir_expression of ir_binop_vector_extract,
+ * additional conversion is needed in the post-call re-write.
+ */
+ ir_variable *tmp =
+ new(mem_ctx) ir_variable(formal_type, "inout_tmp", ir_var_temporary);
+
+ before_instructions->push_tail(tmp);
+
+ /* If the parameter is an inout parameter, copy the value of the actual
+ * parameter to the new temporary. Note that no type conversion is allowed
+ * here because inout parameters must match types exactly.
+ */
+ if (parameter_is_inout) {
+ /* Inout parameters should never require conversion, since that would
+ * require an implicit conversion to exist both to and from the formal
+ * parameter type, and there are no bidirectional implicit conversions.
+ */
+ assert (actual->type == formal_type);
+
+ ir_dereference_variable *const deref_tmp_1 =
+ new(mem_ctx) ir_dereference_variable(tmp);
+ ir_assignment *const assignment =
+ new(mem_ctx) ir_assignment(deref_tmp_1, actual);
+ before_instructions->push_tail(assignment);
+ }
+
+ /* Replace the parameter in the call with a dereference of the new
+ * temporary.
+ */
+ ir_dereference_variable *const deref_tmp_2 =
+ new(mem_ctx) ir_dereference_variable(tmp);
+ actual->replace_with(deref_tmp_2);
+
+
+ /* Copy the temporary variable to the actual parameter with optional
+ * type conversion applied.
+ */
+ ir_rvalue *rhs = new(mem_ctx) ir_dereference_variable(tmp);
+ if (actual->type != formal_type)
+ rhs = convert_component(rhs, actual->type);
+
+ ir_rvalue *lhs = actual;
+ if (expr != NULL && expr->operation == ir_binop_vector_extract) {
+ rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
+ expr->operands[0]->type,
+ expr->operands[0]->clone(mem_ctx, NULL),
+ rhs,
+ expr->operands[1]->clone(mem_ctx, NULL));
+ lhs = expr->operands[0]->clone(mem_ctx, NULL);
+ }
+
+ ir_assignment *const assignment_2 = new(mem_ctx) ir_assignment(lhs, rhs);
+ after_instructions->push_tail(assignment_2);
+}
+
/**
* If a function call is generated, \c call_ir will point to it on exit.
* Otherwise \c call_ir will be set to \c NULL.
@@ -218,50 +313,10 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
break;
}
case ir_var_function_out:
- if (actual->type != formal->type) {
- /* To convert an out parameter, we need to create a
- * temporary variable to hold the value before conversion,
- * and then perform the conversion after the function call
- * returns.
- *
- * This has the effect of transforming code like this:
- *
- * void f(out int x);
- * float value;
- * f(value);
- *
- * Into IR that's equivalent to this:
- *
- * void f(out int x);
- * float value;
- * int out_parameter_conversion;
- * f(out_parameter_conversion);
- * value = float(out_parameter_conversion);
- */
- ir_variable *tmp =
- new(ctx) ir_variable(formal->type,
- "out_parameter_conversion",
- ir_var_temporary);
- instructions->push_tail(tmp);
- ir_dereference_variable *deref_tmp_1
- = new(ctx) ir_dereference_variable(tmp);
- ir_dereference_variable *deref_tmp_2
- = new(ctx) ir_dereference_variable(tmp);
- ir_rvalue *converted_tmp
- = convert_component(deref_tmp_1, actual->type);
- ir_assignment *assignment
- = new(ctx) ir_assignment(actual, converted_tmp);
- post_call_conversions.push_tail(assignment);
- actual->replace_with(deref_tmp_2);
- }
- break;
case ir_var_function_inout:
- /* Inout parameters should never require conversion, since that
- * would require an implicit conversion to exist both to and
- * from the formal parameter type, and there are no
- * bidirectional implicit conversions.
- */
- assert (actual->type == formal->type);
+ fix_parameter(ctx, actual, formal->type,
+ instructions, &post_call_conversions,
+ formal->mode == ir_var_function_inout);
break;
default:
assert (!"Illegal formal parameter mode");
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 92065f5b7..e918adeef 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -672,6 +672,30 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
void *ctx = state;
bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
+ /* If the assignment LHS comes back as an ir_binop_vector_extract
+ * expression, move it to the RHS as an ir_triop_vector_insert.
+ */
+ if (lhs->ir_type == ir_type_expression) {
+ ir_expression *const expr = lhs->as_expression();
+
+ if (unlikely(expr->operation == ir_binop_vector_extract)) {
+ ir_rvalue *new_rhs =
+ validate_assignment(state, lhs->type, rhs, is_initializer);
+
+ if (new_rhs == NULL) {
+ _mesa_glsl_error(& lhs_loc, state, "type mismatch");
+ return lhs;
+ } else {
+ rhs = new(ctx) ir_expression(ir_triop_vector_insert,
+ expr->operands[0]->type,
+ expr->operands[0],
+ new_rhs,
+ expr->operands[1]);
+ lhs = expr->operands[0]->clone(ctx, NULL);
+ }
+ }
+ }
+
ir_variable *lhs_var = lhs->variable_referenced();
if (lhs_var)
lhs_var->assigned = true;
@@ -904,7 +928,7 @@ get_scalar_boolean_operand(exec_list *instructions,
* If name refers to a builtin array whose maximum allowed size is less than
* size, report an error and return true. Otherwise return false.
*/
-static bool
+void
check_builtin_array_max_size(const char *name, unsigned size,
YYLTYPE loc, struct _mesa_glsl_parse_state *state)
{
@@ -918,7 +942,6 @@ check_builtin_array_max_size(const char *name, unsigned size,
_mesa_glsl_error(&loc, state, "`gl_TexCoord' array size cannot "
"be larger than gl_MaxTextureCoords (%u)\n",
state->Const.MaxTextureCoords);
- return true;
} else if (strcmp("gl_ClipDistance", name) == 0
&& size > state->Const.MaxClipPlanes) {
/* From section 7.1 (Vertex Shader Special Variables) of the
@@ -933,9 +956,7 @@ check_builtin_array_max_size(const char *name, unsigned size,
_mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot "
"be larger than gl_MaxClipDistances (%u)\n",
state->Const.MaxClipPlanes);
- return true;
}
- return false;
}
/**
@@ -1517,172 +1538,11 @@ ast_expression::hir(exec_list *instructions,
op[0] = subexpressions[0]->hir(instructions, state);
op[1] = subexpressions[1]->hir(instructions, state);
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
-
- ir_rvalue *const array = op[0];
-
- result = new(ctx) ir_dereference_array(op[0], op[1]);
-
- /* Do not use op[0] after this point. Use array.
- */
- op[0] = NULL;
-
+ result = _mesa_ast_array_index_to_hir(ctx, state, op[0], op[1],
+ loc, index_loc);
- if (error_emitted)
- break;
-
- if (!array->type->is_array()
- && !array->type->is_matrix()
- && !array->type->is_vector()) {
- _mesa_glsl_error(& index_loc, state,
- "cannot dereference non-array / non-matrix / "
- "non-vector");
+ if (result->type->is_error())
error_emitted = true;
- }
-
- if (!op[1]->type->is_integer()) {
- _mesa_glsl_error(& index_loc, state,
- "array index must be integer type");
- error_emitted = true;
- } else if (!op[1]->type->is_scalar()) {
- _mesa_glsl_error(& index_loc, state,
- "array index must be scalar");
- error_emitted = true;
- }
-
- /* If the array index is a constant expression and the array has a
- * declared size, ensure that the access is in-bounds. If the array
- * index is not a constant expression, ensure that the array has a
- * declared size.
- */
- ir_constant *const const_index = op[1]->constant_expression_value();
- if (const_index != NULL) {
- const int idx = const_index->value.i[0];
- const char *type_name;
- unsigned bound = 0;
-
- if (array->type->is_matrix()) {
- type_name = "matrix";
- } else if (array->type->is_vector()) {
- type_name = "vector";
- } else {
- type_name = "array";
- }
-
- /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
- *
- * "It is illegal to declare an array with a size, and then
- * later (in the same shader) index the same array with an
- * integral constant expression greater than or equal to the
- * declared size. It is also illegal to index an array with a
- * negative constant expression."
- */
- if (array->type->is_matrix()) {
- if (array->type->row_type()->vector_elements <= idx) {
- bound = array->type->row_type()->vector_elements;
- }
- } else if (array->type->is_vector()) {
- if (array->type->vector_elements <= idx) {
- bound = array->type->vector_elements;
- }
- } else {
- if ((array->type->array_size() > 0)
- && (array->type->array_size() <= idx)) {
- bound = array->type->array_size();
- }
- }
-
- if (bound > 0) {
- _mesa_glsl_error(& loc, state, "%s index must be < %u",
- type_name, bound);
- error_emitted = true;
- } else if (idx < 0) {
- _mesa_glsl_error(& loc, state, "%s index must be >= 0",
- type_name);
- error_emitted = true;
- }
-
- if (array->type->is_array()) {
- /* If the array is a variable dereference, it dereferences the
- * whole array, by definition. Use this to get the variable.
- *
- * FINISHME: Should some methods for getting / setting / testing
- * FINISHME: array access limits be added to ir_dereference?
- */
- ir_variable *const v = array->whole_variable_referenced();
- if ((v != NULL) && (unsigned(idx) > v->max_array_access)) {
- v->max_array_access = idx;
-
- /* Check whether this access will, as a side effect, implicitly
- * cause the size of a built-in array to be too large.
- */
- if (check_builtin_array_max_size(v->name, idx+1, loc, state))
- error_emitted = true;
- }
- }
- } else if (array->type->array_size() == 0) {
- _mesa_glsl_error(&loc, state, "unsized array index must be constant");
- } else if (array->type->is_array()
- && array->type->fields.array->is_interface()) {
- /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says:
- *
- * "All indexes used to index a uniform block array must be
- * constant integral expressions."
- */
- _mesa_glsl_error(&loc, state,
- "uniform block array index must be constant");
- } else {
- if (array->type->is_array()) {
- /* whole_variable_referenced can return NULL if the array is a
- * member of a structure. In this case it is safe to not update
- * the max_array_access field because it is never used for fields
- * of structures.
- */
- ir_variable *v = array->whole_variable_referenced();
- if (v != NULL)
- v->max_array_access = array->type->array_size() - 1;
- }
- }
-
- /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
- *
- * "Samplers aggregated into arrays within a shader (using square
- * brackets [ ]) can only be indexed with integral constant
- * expressions [...]."
- *
- * This restriction was added in GLSL 1.30. Shaders using earlier version
- * of the language should not be rejected by the compiler front-end for
- * using this construct. This allows useful things such as using a loop
- * counter as the index to an array of samplers. If the loop in unrolled,
- * the code should compile correctly. Instead, emit a warning.
- */
- if (array->type->is_array() &&
- array->type->element_type()->is_sampler() &&
- const_index == NULL) {
-
- if (!state->is_version(130, 100)) {
- if (state->es_shader) {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is optional in %s",
- state->get_version_string());
- } else {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions will be forbidden in GLSL 1.30 and "
- "later");
- }
- } else {
- _mesa_glsl_error(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is forbidden in GLSL 1.30 and "
- "later");
- error_emitted = true;
- }
- }
-
- if (error_emitted)
- result->type = glsl_type::error_type;
break;
}
@@ -1842,6 +1702,9 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size,
{
unsigned length = 0;
+ if (base == NULL)
+ return glsl_type::error_type;
+
/* From page 19 (page 25) of the GLSL 1.20 spec:
*
* "Only one-dimensional arrays may be declared."
@@ -1894,7 +1757,8 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size,
"allowed in GLSL ES 1.00.");
}
- return glsl_type::get_array_instance(base, length);
+ const glsl_type *array_type = glsl_type::get_array_instance(base, length);
+ return array_type != NULL ? array_type : glsl_type::error_type;
}
@@ -3365,10 +3229,17 @@ ast_function::hir(exec_list *instructions,
"match prototype", name);
}
- if (is_definition && sig->is_defined) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
+ if (sig->is_defined) {
+ if (is_definition) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
+ } else {
+ /* We just encountered a prototype that exactly matches a
+ * function that's already been defined. This is redundant,
+ * and we should ignore it.
+ */
+ return NULL;
+ }
}
}
} else {
@@ -4149,8 +4020,14 @@ ast_process_structure_or_interface_block(exec_list *instructions,
* blocks. All other types, arrays, and structures
* allowed for uniforms are allowed within a uniform
* block."
+ *
+ * It should be impossible for decl_type to be NULL here. Cases that
+ * might naturally lead to decl_type being NULL, especially for the
+ * is_interface case, will have resulted in compilation having
+ * already halted due to a syntax error.
*/
- const struct glsl_type *field_type = decl_type;
+ const struct glsl_type *field_type =
+ decl_type != NULL ? decl_type : glsl_type::error_type;
if (is_interface && field_type->contains_sampler()) {
YYLTYPE loc = decl_list->get_location();
@@ -4173,12 +4050,15 @@ ast_process_structure_or_interface_block(exec_list *instructions,
field_type = process_array_type(&loc, decl_type, decl->array_size,
state);
}
- fields[i].type = (field_type != NULL)
- ? field_type : glsl_type::error_type;
+ fields[i].type = field_type;
fields[i].name = decl->identifier;
if (qual->flags.q.row_major || qual->flags.q.column_major) {
- if (!field_type->is_matrix() && !field_type->is_record()) {
+ if (!qual->flags.q.uniform) {
+ _mesa_glsl_error(&loc, state,
+ "row_major and column_major can only be "
+ "applied to uniform interface blocks.");
+ } else if (!field_type->is_matrix() && !field_type->is_record()) {
_mesa_glsl_error(&loc, state,
"uniform block layout qualifiers row_major and "
"column_major can only be applied to matrix and "
@@ -4187,6 +4067,12 @@ ast_process_structure_or_interface_block(exec_list *instructions,
validate_matrix_layout_for_type(state, &loc, field_type);
}
+ if (qual->flags.q.uniform && qual->has_interpolation()) {
+ _mesa_glsl_error(&loc, state,
+ "interpolation qualifiers cannot be used "
+ "with uniform interface blocks");
+ }
+
if (field_type->is_matrix() ||
(field_type->is_array() && field_type->fields.array->is_matrix())) {
fields[i].row_major = block_row_major;
@@ -4244,12 +4130,12 @@ ast_struct_specifier::hir(exec_list *instructions,
}
ir_rvalue *
-ast_uniform_block::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
+ast_interface_block::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
{
YYLTYPE loc = this->get_location();
- /* The ast_uniform_block has a list of ast_declarator_lists. We
+ /* The ast_interface_block has a list of ast_declarator_lists. We
* need to turn those into ir_variables with an association
* with this uniform block.
*/
@@ -4276,16 +4162,32 @@ ast_uniform_block::hir(exec_list *instructions,
true,
block_row_major);
+ ir_variable_mode var_mode;
+ const char *iface_type_name;
+ if (this->layout.flags.q.in) {
+ var_mode = ir_var_shader_in;
+ iface_type_name = "in";
+ } else if (this->layout.flags.q.out) {
+ var_mode = ir_var_shader_out;
+ iface_type_name = "out";
+ } else if (this->layout.flags.q.uniform) {
+ var_mode = ir_var_uniform;
+ iface_type_name = "uniform";
+ } else {
+ assert(!"interface block layout qualifier not found!");
+ }
+
const glsl_type *block_type =
glsl_type::get_interface_instance(fields,
num_variables,
packing,
this->block_name);
- if (!state->symbols->add_type(block_type->name, block_type)) {
+ if (!state->symbols->add_interface(block_type->name, block_type, var_mode)) {
YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state, "Uniform block name `%s' already taken in "
- "the current scope.\n", this->block_name);
+ _mesa_glsl_error(&loc, state, "Interface block `%s' with type `%s' "
+ "already taken in the current scope.\n",
+ this->block_name, iface_type_name);
}
/* Since interface blocks cannot contain statements, it should be
@@ -4309,11 +4211,11 @@ ast_uniform_block::hir(exec_list *instructions,
var = new(state) ir_variable(block_array_type,
this->instance_name,
- ir_var_uniform);
+ var_mode);
} else {
var = new(state) ir_variable(block_type,
this->instance_name,
- ir_var_uniform);
+ var_mode);
}
var->interface_type = block_type;
@@ -4329,7 +4231,7 @@ ast_uniform_block::hir(exec_list *instructions,
ir_variable *var =
new(state) ir_variable(fields[i].type,
ralloc_strdup(state, fields[i].name),
- ir_var_uniform);
+ var_mode);
var->interface_type = block_type;
state->symbols->add_variable(var);
diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp
index b0c7a2035..4bb361c2e 100644
--- a/mesalib/src/glsl/builtin_variables.cpp
+++ b/mesalib/src/glsl/builtin_variables.cpp
@@ -39,6 +39,12 @@ generate_ARB_draw_instanced_variables(exec_list *,
struct _mesa_glsl_parse_state *,
bool, _mesa_glsl_parser_targets);
+static void
+generate_AMD_vertex_shader_layer_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool warn,
+ _mesa_glsl_parser_targets target);
+
struct builtin_variable {
enum ir_variable_mode mode;
int slot;
@@ -535,7 +541,7 @@ generate_common_ES_uniforms(exec_list *instructions,
add_builtin_constant(instructions, symtab, "gl_MaxTextureImageUnits",
state->Const.MaxTextureImageUnits);
add_builtin_constant(instructions, symtab, "gl_MaxFragmentUniformVectors",
- state->Const.MaxFragmentUniformComponents);
+ state->Const.MaxFragmentUniformComponents / 4);
add_uniform(instructions, symtab, "gl_DepthRange",
state->symbols->get_type("gl_DepthRangeParameters"));
@@ -818,6 +824,8 @@ generate_130_vs_variables(exec_list *instructions,
"gl_ClipDistance", clip_distance_array_type, ir_var_shader_out,
VARYING_SLOT_CLIP_DIST0);
+ generate_AMD_vertex_shader_layer_variables(instructions, state, false,
+ vertex_shader);
}
@@ -1020,6 +1028,29 @@ generate_ARB_draw_instanced_variables(exec_list *instructions,
}
}
+static void
+generate_AMD_vertex_shader_layer_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool warn,
+ _mesa_glsl_parser_targets target)
+{
+ /* gl_Layer is only available in the vertex shader for the
+ * AMD_vertex_shader_layer extension. It will also be available in the
+ * geometry shader when GLSL 1.50 is supported.
+ */
+ if (target != vertex_shader)
+ return;
+
+ if (state->AMD_vertex_shader_layer_enable) {
+ ir_variable *inst =
+ add_variable(instructions, state->symbols,
+ "gl_Layer", glsl_type::int_type,
+ ir_var_shader_out, VARYING_SLOT_LAYER);
+
+ if (warn)
+ inst->warn_extension = "GL_AMD_vertex_shader_layer";
+ }
+}
static void
generate_ARB_shader_stencil_export_variables(exec_list *instructions,
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index 00edbbfbd..81ba04bcc 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -1236,6 +1236,12 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
if (extensions->ARB_texture_query_lod)
add_builtin_define(parser, "GL_ARB_texture_query_lod", 1);
+
+ if (extensions->ARB_gpu_shader5)
+ add_builtin_define(parser, "GL_ARB_gpu_shader5", 1);
+
+ if (extensions->AMD_vertex_shader_layer)
+ add_builtin_define(parser, "GL_AMD_vertex_shader_layer", 1);
}
}
diff --git a/mesalib/src/glsl/glcpp/pp.c b/mesalib/src/glsl/glcpp/pp.c
index 789f7f941..7e1b6c689 100644
--- a/mesalib/src/glsl/glcpp/pp.c
+++ b/mesalib/src/glsl/glcpp/pp.c
@@ -97,8 +97,10 @@ remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
{
ralloc_strncat(&clean, shader,
newline - shader + 1);
- while (collapsed_newlines--)
+ while (collapsed_newlines) {
ralloc_strcat(&clean, "\n");
+ collapsed_newlines--;
+ }
shader = newline + 1;
search_start = shader;
}
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index f52ed9b0a..6e92c2651 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -79,7 +79,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
ast_case_label_list *case_label_list;
ast_case_statement *case_statement;
ast_case_statement_list *case_statement_list;
- ast_uniform_block *uniform_block;
+ ast_interface_block *interface_block;
struct {
ast_node *cond;
@@ -115,7 +115,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%token STRUCT VOID_TOK WHILE
%token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
%type <identifier> any_identifier
-%type <uniform_block> instance_name_opt
+%type <interface_block> instance_name_opt
%token <real> FLOATCONSTANT
%token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
%token <identifier> FIELD_SELECTION
@@ -164,7 +164,8 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%type <type_qualifier> interpolation_qualifier
%type <type_qualifier> layout_qualifier
%type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
-%type <type_qualifier> uniform_block_layout_qualifier
+%type <type_qualifier> interface_block_layout_qualifier
+%type <type_qualifier> interface_qualifier
%type <type_specifier> type_specifier
%type <type_specifier> type_specifier_no_prec
%type <type_specifier> type_specifier_nonarray
@@ -223,8 +224,8 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
%type <node> declaration
%type <node> declaration_statement
%type <node> jump_statement
-%type <node> uniform_block
-%type <uniform_block> basic_uniform_block
+%type <node> interface_block
+%type <interface_block> basic_interface_block
%type <struct_specifier> struct_specifier
%type <declarator_list> struct_declaration_list
%type <declarator_list> struct_declaration
@@ -784,7 +785,7 @@ declaration:
$3->is_precision_statement = true;
$$ = $3;
}
- | uniform_block
+ | interface_block
{
$$ = $1;
}
@@ -1140,7 +1141,7 @@ layout_qualifier_id:
}
}
- /* See also uniform_block_layout_qualifier. */
+ /* See also interface_block_layout_qualifier. */
if (!$$.flags.i && state->ARB_uniform_buffer_object_enable) {
if (strcmp($1, "std140") == 0) {
$$.flags.q.std140 = 1;
@@ -1211,15 +1212,15 @@ layout_qualifier_id:
"identifier `%s' used\n", $1);
}
}
- | uniform_block_layout_qualifier
+ | interface_block_layout_qualifier
{
$$ = $1;
/* Layout qualifiers for ARB_uniform_buffer_object. */
- if (!state->ARB_uniform_buffer_object_enable) {
+ if ($$.flags.q.uniform && !state->ARB_uniform_buffer_object_enable) {
_mesa_glsl_error(& @1, state,
"#version 140 / GL_ARB_uniform_buffer_object "
"layout qualifier `%s' is used\n", $1);
- } else if (state->ARB_uniform_buffer_object_warn) {
+ } else if ($$.flags.q.uniform && state->ARB_uniform_buffer_object_warn) {
_mesa_glsl_warning(& @1, state,
"#version 140 / GL_ARB_uniform_buffer_object "
"layout qualifier `%s' is used\n", $1);
@@ -1232,7 +1233,7 @@ layout_qualifier_id:
* most qualifiers. See the any_identifier path of
* layout_qualifier_id for the others.
*/
-uniform_block_layout_qualifier:
+interface_block_layout_qualifier:
ROW_MAJOR
{
memset(& $$, 0, sizeof($$));
@@ -1893,14 +1894,14 @@ function_definition:
;
/* layout_qualifieropt is packed into this rule */
-uniform_block:
- basic_uniform_block
+interface_block:
+ basic_interface_block
{
$$ = $1;
}
- | layout_qualifier basic_uniform_block
+ | layout_qualifier basic_interface_block
{
- ast_uniform_block *block = $2;
+ ast_interface_block *block = $2;
if (!block->layout.merge_qualifier(& @1, state, $1)) {
YYERROR;
}
@@ -1908,55 +1909,137 @@ uniform_block:
}
;
-basic_uniform_block:
- UNIFORM NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
+basic_interface_block:
+ interface_qualifier NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
{
- ast_uniform_block *const block = $6;
+ ast_interface_block *const block = $6;
block->block_name = $2;
block->declarations.push_degenerate_list_at_head(& $4->link);
- if (!state->ARB_uniform_buffer_object_enable) {
+ if ($1.flags.q.uniform) {
+ if (!state->ARB_uniform_buffer_object_enable) {
+ _mesa_glsl_error(& @1, state,
+ "#version 140 / GL_ARB_uniform_buffer_object "
+ "required for defining uniform blocks\n");
+ } else if (state->ARB_uniform_buffer_object_warn) {
+ _mesa_glsl_warning(& @1, state,
+ "#version 140 / GL_ARB_uniform_buffer_object "
+ "required for defining uniform blocks\n");
+ }
+ } else {
+ if (state->es_shader || state->language_version < 150) {
+ _mesa_glsl_error(& @1, state,
+ "#version 150 required for using "
+ "interface blocks.\n");
+ }
+ }
+
+ /* From the GLSL 1.50.11 spec, section 4.3.7 ("Interface Blocks"):
+ * "It is illegal to have an input block in a vertex shader
+ * or an output block in a fragment shader"
+ */
+ if ((state->target == vertex_shader) && $1.flags.q.in) {
_mesa_glsl_error(& @1, state,
- "#version 140 / GL_ARB_uniform_buffer_object "
- "required for defining uniform blocks\n");
- } else if (state->ARB_uniform_buffer_object_warn) {
- _mesa_glsl_warning(& @1, state,
- "#version 140 / GL_ARB_uniform_buffer_object "
- "required for defining uniform blocks\n");
+ "`in' interface block is not allowed for "
+ "a vertex shader\n");
+ } else if ((state->target == fragment_shader) && $1.flags.q.out) {
+ _mesa_glsl_error(& @1, state,
+ "`out' interface block is not allowed for "
+ "a fragment shader\n");
}
/* Since block arrays require names, and both features are added in
* the same language versions, we don't have to explicitly
* version-check both things.
*/
- if (block->instance_name != NULL
- && !(state->language_version == 300 && state->es_shader)) {
- _mesa_glsl_error(& @1, state,
- "#version 300 es required for using uniform "
- "blocks with an instance name\n");
+ if (block->instance_name != NULL) {
+ state->check_version(150, 300, & @1, "interface blocks with "
+ "an instance name are not allowed");
+ }
+
+ unsigned interface_type_mask;
+ struct ast_type_qualifier temp_type_qualifier;
+
+ /* Get a bitmask containing only the in/out/uniform flags, allowing us
+ * to ignore other irrelevant flags like interpolation qualifiers.
+ */
+ temp_type_qualifier.flags.i = 0;
+ temp_type_qualifier.flags.q.uniform = true;
+ temp_type_qualifier.flags.q.in = true;
+ temp_type_qualifier.flags.q.out = true;
+ 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).
+ */
+ unsigned block_interface_qualifier = $1.flags.i;
+
+ block->layout.flags.i |= block_interface_qualifier;
+
+ foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
+ ast_type_qualifier& qualifier = member->type->qualifier;
+ if ((qualifier.flags.i & interface_type_mask) == 0) {
+ /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+ * "If no optional qualifier is used in a member declaration, the
+ * qualifier of the variable is just in, out, or uniform as declared
+ * by interface-qualifier."
+ */
+ qualifier.flags.i |= block_interface_qualifier;
+ } else if ((qualifier.flags.i & interface_type_mask) !=
+ block_interface_qualifier) {
+ /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+ * "If optional qualifiers are used, they can include interpolation
+ * and storage qualifiers and they must declare an input, output,
+ * or uniform variable consistent with the interface qualifier of
+ * the block."
+ */
+ _mesa_glsl_error(& @1, state,
+ "uniform/in/out qualifier on "
+ "interface block member does not match "
+ "the interface block\n");
+ }
}
$$ = block;
}
;
+interface_qualifier:
+ IN_TOK
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.in = 1;
+ }
+ | OUT_TOK
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.out = 1;
+ }
+ | UNIFORM
+ {
+ memset(& $$, 0, sizeof($$));
+ $$.flags.q.uniform = 1;
+ }
+ ;
+
instance_name_opt:
/* empty */
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
NULL,
NULL);
}
| NEW_IDENTIFIER
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
NULL);
}
| NEW_IDENTIFIER '[' constant_expression ']'
{
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
$3);
}
@@ -1965,7 +2048,7 @@ instance_name_opt:
_mesa_glsl_error(& @1, state,
"instance block arrays must be explicitly sized\n");
- $$ = new(state) ast_uniform_block(*state->default_uniform_qualifier,
+ $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
$1,
NULL);
}
@@ -1984,41 +2067,28 @@ member_list:
}
;
-/* Specifying "uniform" inside of a uniform block is redundant. */
-uniformopt:
- /* nothing */
- | UNIFORM
- ;
-
member_declaration:
- layout_qualifier uniformopt type_specifier struct_declarator_list ';'
+ fully_specified_type struct_declarator_list ';'
{
void *ctx = state;
- ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
+ ast_fully_specified_type *type = $1;
type->set_location(yylloc);
- type->qualifier = $1;
- type->qualifier.flags.q.uniform = true;
- type->specifier = $3;
- $$ = new(ctx) ast_declarator_list(type);
- $$->set_location(yylloc);
- $$->ubo_qualifiers_valid = true;
-
- $$->declarations.push_degenerate_list_at_head(& $4->link);
- }
- | uniformopt type_specifier struct_declarator_list ';'
- {
- void *ctx = state;
- ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
- type->set_location(yylloc);
+ if (type->qualifier.flags.q.attribute) {
+ _mesa_glsl_error(& @1, state,
+ "keyword 'attribute' cannot be used with "
+ "interface block member\n");
+ } else if (type->qualifier.flags.q.varying) {
+ _mesa_glsl_error(& @1, state,
+ "keyword 'varying' cannot be used with "
+ "interface block member\n");
+ }
- type->qualifier.flags.q.uniform = true;
- type->specifier = $2;
$$ = new(ctx) ast_declarator_list(type);
$$->set_location(yylloc);
$$->ubo_qualifiers_valid = true;
- $$->declarations.push_degenerate_list_at_head(& $3->link);
+ $$->declarations.push_degenerate_list_at_head(& $2->link);
}
;
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index 099229410..c0dd71370 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -93,9 +93,9 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs;
this->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents;
this->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4;
- this->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits;
+ this->Const.MaxVertexTextureImageUnits = ctx->Const.VertexProgram.MaxTextureImageUnits;
this->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits;
- this->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+ this->Const.MaxTextureImageUnits = ctx->Const.FragmentProgram.MaxTextureImageUnits;
this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents;
this->Const.MinProgramTexelOffset = ctx->Const.MinProgramTexelOffset;
this->Const.MaxProgramTexelOffset = ctx->Const.MaxProgramTexelOffset;
@@ -468,6 +468,8 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = {
EXT(ARB_shading_language_packing, true, false, true, true, false, ARB_shading_language_packing),
EXT(ARB_texture_multisample, true, false, true, true, false, ARB_texture_multisample),
EXT(ARB_texture_query_lod, false, false, true, true, false, ARB_texture_query_lod),
+ EXT(ARB_gpu_shader5, true, true, true, true, false, ARB_gpu_shader5),
+ EXT(AMD_vertex_shader_layer, true, false, false, true, false, AMD_vertex_shader_layer),
};
#undef EXT
@@ -1202,11 +1204,13 @@ ast_struct_specifier::ast_struct_specifier(const char *identifier,
* \param max_unroll_iterations Maximum number of loop iterations to be
* unrolled. Setting to 0 disables loop
* unrolling.
+ * \param options The driver's preferred shader options.
*/
bool
do_common_optimization(exec_list *ir, bool linked,
bool uniform_locations_assigned,
- unsigned max_unroll_iterations)
+ unsigned max_unroll_iterations,
+ const struct gl_shader_compiler_options *options)
{
GLboolean progress = GL_FALSE;
@@ -1221,6 +1225,10 @@ do_common_optimization(exec_list *ir, bool linked,
progress = opt_flatten_nested_if_blocks(ir) || progress;
progress = do_copy_propagation(ir) || progress;
progress = do_copy_propagation_elements(ir) || progress;
+
+ if (options->PreferDP4 && !linked)
+ progress = opt_flip_matrices(ir) || progress;
+
if (linked)
progress = do_dead_code(ir, uniform_locations_assigned) || progress;
else
@@ -1236,6 +1244,7 @@ do_common_optimization(exec_list *ir, bool linked,
progress = do_algebraic(ir) || progress;
progress = do_lower_jumps(ir) || progress;
progress = do_vec_index_to_swizzle(ir) || progress;
+ progress = lower_vector_insert(ir, false) || progress;
progress = do_swizzle_swizzle(ir) || progress;
progress = do_noop_swizzle(ir) || progress;
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index 95891b595..16e180d3e 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -284,6 +284,10 @@ struct _mesa_glsl_parse_state {
bool ARB_texture_multisample_warn;
bool ARB_texture_query_lod_enable;
bool ARB_texture_query_lod_warn;
+ bool ARB_gpu_shader5_enable;
+ bool ARB_gpu_shader5_warn;
+ bool AMD_vertex_shader_layer_enable;
+ bool AMD_vertex_shader_layer_warn;
/*@}*/
/** Extensions supported by the OpenGL implementation. */
diff --git a/mesalib/src/glsl/glsl_symbol_table.cpp b/mesalib/src/glsl/glsl_symbol_table.cpp
index 8d34547c6..50bf11302 100644
--- a/mesalib/src/glsl/glsl_symbol_table.cpp
+++ b/mesalib/src/glsl/glsl_symbol_table.cpp
@@ -41,13 +41,67 @@ public:
ralloc_free(entry);
}
- symbol_table_entry(ir_variable *v) : v(v), f(0), t(0) {}
- symbol_table_entry(ir_function *f) : v(0), f(f), t(0) {}
- symbol_table_entry(const glsl_type *t) : v(0), f(0), t(t) {}
+ bool add_interface(const glsl_type *i, enum ir_variable_mode mode)
+ {
+ const glsl_type **dest;
+
+ switch (mode) {
+ case ir_var_uniform:
+ dest = &ibu;
+ break;
+ case ir_var_shader_in:
+ dest = &ibi;
+ break;
+ case ir_var_shader_out:
+ dest = &ibo;
+ break;
+ default:
+ assert(!"Unsupported interface variable mode!");
+ return false;
+ }
+
+ if (*dest != NULL) {
+ return false;
+ } else {
+ *dest = i;
+ return true;
+ }
+ }
+
+ const glsl_type *get_interface(enum ir_variable_mode mode)
+ {
+ switch (mode) {
+ case ir_var_uniform:
+ return ibu;
+ case ir_var_shader_in:
+ return ibi;
+ case ir_var_shader_out:
+ return ibo;
+ default:
+ assert(!"Unsupported interface variable mode!");
+ return NULL;
+ }
+ }
+
+ symbol_table_entry(ir_variable *v) :
+ v(v), f(0), t(0), ibu(0), ibi(0), ibo(0) {}
+ symbol_table_entry(ir_function *f) :
+ v(0), f(f), t(0), ibu(0), ibi(0), ibo(0) {}
+ symbol_table_entry(const glsl_type *t) :
+ v(0), f(0), t(t), ibu(0), ibi(0), ibo(0) {}
+ symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) :
+ v(0), f(0), t(0), ibu(0), ibi(0), ibo(0)
+ {
+ assert(t->is_interface());
+ add_interface(t, mode);
+ }
ir_variable *v;
ir_function *f;
const glsl_type *t;
+ const glsl_type *ibu;
+ const glsl_type *ibi;
+ const glsl_type *ibo;
};
glsl_symbol_table::glsl_symbol_table()
@@ -118,6 +172,23 @@ bool glsl_symbol_table::add_type(const char *name, const glsl_type *t)
return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
}
+bool glsl_symbol_table::add_interface(const char *name, const glsl_type *i,
+ enum ir_variable_mode mode)
+{
+ assert(i->is_interface());
+ symbol_table_entry *entry = get_entry(name);
+ if (entry == NULL) {
+ symbol_table_entry *entry =
+ new(mem_ctx) symbol_table_entry(i, mode);
+ bool add_interface_symbol_result =
+ _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
+ assert(add_interface_symbol_result);
+ return add_interface_symbol_result;
+ } else {
+ return entry->add_interface(i, mode);
+ }
+}
+
bool glsl_symbol_table::add_function(ir_function *f)
{
if (this->separate_function_namespace && name_declared_this_scope(f->name)) {
@@ -152,6 +223,13 @@ const glsl_type *glsl_symbol_table::get_type(const char *name)
return entry != NULL ? entry->t : NULL;
}
+const glsl_type *glsl_symbol_table::get_interface(const char *name,
+ enum ir_variable_mode mode)
+{
+ symbol_table_entry *entry = get_entry(name);
+ return entry != NULL ? entry->get_interface(mode) : NULL;
+}
+
ir_function *glsl_symbol_table::get_function(const char *name)
{
symbol_table_entry *entry = get_entry(name);
diff --git a/mesalib/src/glsl/glsl_symbol_table.h b/mesalib/src/glsl/glsl_symbol_table.h
index 9f5602787..2753bdf31 100644
--- a/mesalib/src/glsl/glsl_symbol_table.h
+++ b/mesalib/src/glsl/glsl_symbol_table.h
@@ -99,6 +99,8 @@ public:
bool add_variable(ir_variable *v);
bool add_type(const char *name, const glsl_type *t);
bool add_function(ir_function *f);
+ bool add_interface(const char *name, const glsl_type *i,
+ enum ir_variable_mode mode);
/*@}*/
/**
@@ -113,6 +115,8 @@ public:
ir_variable *get_variable(const char *name);
const glsl_type *get_type(const char *name);
ir_function *get_function(const char *name);
+ const glsl_type *get_interface(const char *name,
+ enum ir_variable_mode mode);
/*@}*/
private:
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 419761a7d..df9c5d36f 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -57,6 +57,7 @@ glsl_type::glsl_type(GLenum gl_type,
length(0)
{
init_ralloc_type_ctx();
+ assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
/* Neither dimension is zero or both dimensions are zero.
*/
@@ -75,6 +76,7 @@ glsl_type::glsl_type(GLenum gl_type,
length(0)
{
init_ralloc_type_ctx();
+ assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
memset(& fields, 0, sizeof(fields));
}
@@ -91,6 +93,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
unsigned int i;
init_ralloc_type_ctx();
+ assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
this->fields.structure = ralloc_array(this->mem_ctx,
glsl_struct_field, length);
@@ -114,6 +117,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
unsigned int i;
init_ralloc_type_ctx();
+ assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
this->fields.structure = ralloc_array(this->mem_ctx,
glsl_struct_field, length);
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 2f3b19f51..31e3dd253 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -132,8 +132,7 @@ struct glsl_type {
/**
* Name of the data type
*
- * This may be \c NULL for anonymous structures, for arrays, or for
- * function types.
+ * Will never be \c NULL.
*/
const char *name;
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index 05b77da2c..dad58deeb 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -399,6 +399,10 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
this->type = op0->type;
break;
+ case ir_binop_vector_extract:
+ this->type = op0->type->get_scalar_type();
+ break;
+
default:
assert(!"not reached: missing automatic type setup for ir_expression");
this->type = glsl_type::float_type;
@@ -419,7 +423,7 @@ ir_expression::get_num_operands(ir_expression_operation op)
if (op <= ir_last_triop)
return 3;
- if (op == ir_quadop_vector)
+ if (op <= ir_last_quadop)
return 4;
assert(false);
@@ -477,6 +481,10 @@ static const char *const operator_strs[] = {
"unpackHalf2x16",
"unpackHalf2x16_split_x",
"unpackHalf2x16_split_y",
+ "bitfield_reverse",
+ "bit_count",
+ "find_msb",
+ "find_lsb",
"noise",
"+",
"-",
@@ -504,8 +512,14 @@ static const char *const operator_strs[] = {
"max",
"pow",
"packHalf2x16_split",
+ "bfm",
"ubo_load",
+ "vector_extract",
"lrp",
+ "bfi",
+ "bitfield_extract",
+ "vector_insert",
+ "bitfield_insert",
"vector",
};
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 0c3e39979..6d4150136 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -131,6 +131,7 @@ public:
virtual class ir_swizzle * as_swizzle() { return NULL; }
virtual class ir_constant * as_constant() { return NULL; }
virtual class ir_discard * as_discard() { return NULL; }
+ virtual class ir_jump * as_jump() { return NULL; }
/*@}*/
protected:
@@ -273,7 +274,8 @@ enum ir_variable_mode {
ir_var_function_inout,
ir_var_const_in, /**< "in" param that must be a constant expression */
ir_var_system_value, /**< Ex: front-face, instance-id, etc. */
- ir_var_temporary /**< Temporary variable generated during compilation. */
+ ir_var_temporary, /**< Temporary variable generated during compilation. */
+ ir_var_mode_count /**< Number of variable modes */
};
/**
@@ -1031,6 +1033,16 @@ enum ir_expression_operation {
ir_unop_unpack_half_2x16_split_y,
/*@}*/
+ /**
+ * \name Bit operations, part of ARB_gpu_shader5.
+ */
+ /*@{*/
+ ir_unop_bitfield_reverse,
+ ir_unop_bit_count,
+ ir_unop_find_msb,
+ ir_unop_find_lsb,
+ /*@}*/
+
ir_unop_noise,
/**
@@ -1107,6 +1119,15 @@ enum ir_expression_operation {
/*@}*/
/**
+ * \name First half of a lowered bitfieldInsert() operation.
+ *
+ * \see lower_instructions::bitfield_insert_to_bfm_bfi
+ */
+ /*@{*/
+ ir_binop_bfm,
+ /*@}*/
+
+ /**
* Load a value the size of a given GLSL type from a uniform block.
*
* operand0 is the ir_constant uniform block index in the linked shader.
@@ -1115,20 +1136,55 @@ enum ir_expression_operation {
ir_binop_ubo_load,
/**
+ * Extract a scalar from a vector
+ *
+ * operand0 is the vector
+ * operand1 is the index of the field to read from operand0
+ */
+ ir_binop_vector_extract,
+
+ /**
* A sentinel marking the last of the binary operations.
*/
- ir_last_binop = ir_binop_ubo_load,
+ ir_last_binop = ir_binop_vector_extract,
ir_triop_lrp,
/**
+ * \name Second half of a lowered bitfieldInsert() operation.
+ *
+ * \see lower_instructions::bitfield_insert_to_bfm_bfi
+ */
+ /*@{*/
+ ir_triop_bfi,
+ /*@}*/
+
+ ir_triop_bitfield_extract,
+
+ /**
+ * Generate a value with one field of a vector changed
+ *
+ * operand0 is the vector
+ * operand1 is the value to write into the vector result
+ * operand2 is the index in operand0 to be modified
+ */
+ ir_triop_vector_insert,
+
+ /**
* A sentinel marking the last of the ternary operations.
*/
- ir_last_triop = ir_triop_lrp,
+ ir_last_triop = ir_triop_vector_insert,
+
+ ir_quadop_bitfield_insert,
ir_quadop_vector,
/**
+ * A sentinel marking the last of the ternary operations.
+ */
+ ir_last_quadop = ir_quadop_vector,
+
+ /**
* A sentinel marking the last of all operations.
*/
ir_last_opcode = ir_quadop_vector
@@ -1297,6 +1353,12 @@ protected:
{
ir_type = ir_type_unset;
}
+
+public:
+ virtual ir_jump *as_jump()
+ {
+ return this;
+ }
};
class ir_return : public ir_jump {
diff --git a/mesalib/src/glsl/ir_basic_block.cpp b/mesalib/src/glsl/ir_basic_block.cpp
index 86e0cf795..2cbc682d4 100644
--- a/mesalib/src/glsl/ir_basic_block.cpp
+++ b/mesalib/src/glsl/ir_basic_block.cpp
@@ -77,7 +77,7 @@ void call_for_basic_blocks(exec_list *instructions,
callback(leader, ir, data);
leader = NULL;
call_for_basic_blocks(&ir_loop->body_instructions, callback, data);
- } else if (ir->as_return() || ir->as_call()) {
+ } else if (ir->as_jump() || ir->as_call()) {
callback(leader, ir, data);
leader = NULL;
} else if ((ir_function = ir->as_function())) {
diff --git a/mesalib/src/glsl/ir_constant_expression.cpp b/mesalib/src/glsl/ir_constant_expression.cpp
index c09e56a3d..0a725b45b 100644
--- a/mesalib/src/glsl/ir_constant_expression.cpp
+++ b/mesalib/src/glsl/ir_constant_expression.cpp
@@ -391,9 +391,17 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
}
if (op[1] != NULL)
- assert(op[0]->type->base_type == op[1]->type->base_type ||
- this->operation == ir_binop_lshift ||
- this->operation == ir_binop_rshift);
+ switch (this->operation) {
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_vector_extract:
+ case ir_triop_bitfield_extract:
+ break;
+
+ default:
+ assert(op[0]->type->base_type == op[1]->type->base_type);
+ break;
+ }
bool op0_scalar = op[0]->type->is_scalar();
bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar();
@@ -1230,6 +1238,29 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
}
break;
+ case ir_binop_vector_extract: {
+ const int c = CLAMP(op[1]->value.i[0], 0,
+ (int) op[0]->type->vector_elements - 1);
+
+ switch (op[0]->type->base_type) {
+ case GLSL_TYPE_UINT:
+ data.u[0] = op[0]->value.u[c];
+ break;
+ case GLSL_TYPE_INT:
+ data.i[0] = op[0]->value.i[c];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[0] = op[0]->value.f[c];
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[0] = op[0]->value.b[c];
+ break;
+ default:
+ assert(0);
+ }
+ break;
+ }
+
case ir_binop_bit_xor:
for (unsigned c = 0, c0 = 0, c1 = 0;
c < components;
@@ -1248,6 +1279,102 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
}
break;
+ case ir_unop_bitfield_reverse:
+ /* http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
+ for (unsigned c = 0; c < components; c++) {
+ unsigned int v = op[0]->value.u[c]; // input bits to be reversed
+ unsigned int r = v; // r will be reversed bits of v; first get LSB of v
+ int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end
+
+ for (v >>= 1; v; v >>= 1) {
+ r <<= 1;
+ r |= v & 1;
+ s--;
+ }
+ r <<= s; // shift when v's highest bits are zero
+
+ data.u[c] = r;
+ }
+ break;
+
+ case ir_unop_bit_count:
+ for (unsigned c = 0; c < components; c++) {
+ unsigned count = 0;
+ unsigned v = op[0]->value.u[c];
+
+ for (; v; count++) {
+ v &= v - 1;
+ }
+ data.u[c] = count;
+ }
+ break;
+
+ case ir_unop_find_msb:
+ for (unsigned c = 0; c < components; c++) {
+ int v = op[0]->value.i[c];
+
+ if (v == 0 || (op[0]->type->base_type == GLSL_TYPE_INT && v == -1))
+ data.i[c] = -1;
+ else {
+ int count = 0;
+ int top_bit = op[0]->type->base_type == GLSL_TYPE_UINT
+ ? 0 : v & (1 << 31);
+
+ while (((v & (1 << 31)) == top_bit) && count != 32) {
+ count++;
+ v <<= 1;
+ }
+
+ data.i[c] = 31 - count;
+ }
+ }
+ break;
+
+ case ir_unop_find_lsb:
+ for (unsigned c = 0; c < components; c++) {
+ if (op[0]->value.i[c] == 0)
+ data.i[c] = -1;
+ else {
+ unsigned pos = 0;
+ unsigned v = op[0]->value.u[c];
+
+ for (; !(v & 1); v >>= 1) {
+ pos++;
+ }
+ data.u[c] = pos;
+ }
+ }
+ break;
+
+ case ir_triop_bitfield_extract: {
+ int offset = op[1]->value.i[0];
+ int bits = op[2]->value.i[0];
+
+ for (unsigned c = 0; c < components; c++) {
+ if (bits == 0)
+ data.u[c] = 0;
+ else if (offset < 0 || bits < 0)
+ data.u[c] = 0; /* Undefined, per spec. */
+ else if (offset + bits > 32)
+ data.u[c] = 0; /* Undefined, per spec. */
+ else {
+ if (op[0]->type->base_type == GLSL_TYPE_INT) {
+ /* int so that the right shift will sign-extend. */
+ int value = op[0]->value.i[c];
+ value <<= 32 - bits - offset;
+ value >>= 32 - bits;
+ data.i[c] = value;
+ } else {
+ unsigned value = op[0]->value.u[c];
+ value <<= 32 - bits - offset;
+ value >>= 32 - bits;
+ data.u[c] = value;
+ }
+ }
+ }
+ break;
+ }
+
case ir_triop_lrp: {
assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
assert(op[1]->type->base_type == GLSL_TYPE_FLOAT);
@@ -1261,6 +1388,58 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
break;
}
+ case ir_triop_vector_insert: {
+ const unsigned idx = op[2]->value.u[0];
+
+ memcpy(&data, &op[0]->value, sizeof(data));
+
+ switch (this->type->base_type) {
+ case GLSL_TYPE_INT:
+ data.i[idx] = op[1]->value.i[0];
+ break;
+ case GLSL_TYPE_UINT:
+ data.u[idx] = op[1]->value.u[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ data.f[idx] = op[1]->value.f[0];
+ break;
+ case GLSL_TYPE_BOOL:
+ data.b[idx] = op[1]->value.b[0];
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+ }
+
+ case ir_quadop_bitfield_insert: {
+ int offset = op[2]->value.i[0];
+ int bits = op[3]->value.i[0];
+
+ for (unsigned c = 0; c < components; c++) {
+ if (bits == 0)
+ data.u[c] = op[0]->value.u[c];
+ else if (offset < 0 || bits < 0)
+ data.u[c] = 0; /* Undefined, per spec. */
+ else if (offset + bits > 32)
+ data.u[c] = 0; /* Undefined, per spec. */
+ else {
+ unsigned insert_mask = ((1 << bits) - 1) << offset;
+
+ unsigned insert = op[1]->value.u[c];
+ insert <<= offset;
+ insert &= insert_mask;
+
+ unsigned base = op[0]->value.u[c];
+ base &= ~insert_mask;
+
+ data.u[c] = base | insert;
+ }
+ }
+ break;
+ }
+
case ir_quadop_vector:
for (unsigned c = 0; c < this->type->vector_elements; c++) {
switch (this->type->base_type) {
diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h
index a8885d722..d38d5e303 100644
--- a/mesalib/src/glsl/ir_optimization.h
+++ b/mesalib/src/glsl/ir_optimization.h
@@ -37,6 +37,7 @@
#define MOD_TO_FRACT 0x20
#define INT_DIV_TO_MUL_RCP 0x40
#define LRP_TO_ARITH 0x80
+#define BITFIELD_INSERT_TO_BFM_BFI 0x100
/**
* \see class lower_packing_builtins_visitor
@@ -65,7 +66,8 @@ enum lower_packing_builtins_op {
bool do_common_optimization(exec_list *ir, bool linked,
bool uniform_locations_assigned,
- unsigned max_unroll_iterations);
+ unsigned max_unroll_iterations,
+ const struct gl_shader_compiler_options *options);
bool do_algebraic(exec_list *instructions);
bool do_constant_folding(exec_list *instructions);
@@ -78,6 +80,7 @@ bool do_dead_code(exec_list *instructions, bool uniform_locations_assigned);
bool do_dead_code_local(exec_list *instructions);
bool do_dead_code_unlinked(exec_list *instructions);
bool do_dead_functions(exec_list *instructions);
+bool opt_flip_matrices(exec_list *instructions);
bool do_function_inlining(exec_list *instructions);
bool do_lower_jumps(exec_list *instructions, bool pull_out_jumps = true, bool lower_sub_return = true, bool lower_main_return = false, bool lower_continue = false, bool lower_break = false);
bool do_lower_texture_projection(exec_list *instructions);
@@ -106,6 +109,8 @@ void lower_ubo_reference(struct gl_shader *shader, exec_list *instructions);
void lower_packed_varyings(void *mem_ctx, unsigned location_base,
unsigned locations_used, ir_variable_mode mode,
gl_shader *shader);
+bool lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index);
+void lower_named_interface_blocks(void *mem_ctx, gl_shader *shader);
bool optimize_redundant_jumps(exec_list *instructions);
bool optimize_split_arrays(exec_list *instructions, bool linked);
diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp
index 597d2813f..f01019c98 100644
--- a/mesalib/src/glsl/ir_print_visitor.cpp
+++ b/mesalib/src/glsl/ir_print_visitor.cpp
@@ -24,6 +24,7 @@
#include "ir_print_visitor.h"
#include "glsl_types.h"
#include "glsl_parser_extras.h"
+#include "main/macros.h"
#include "program/hash_table.h"
static void print_type(const glsl_type *t);
@@ -149,7 +150,9 @@ void ir_print_visitor::visit(ir_variable *ir)
const char *const mode[] = { "", "uniform ", "shader_in ", "shader_out ",
"in ", "out ", "inout ",
"const_in ", "sys ", "temporary " };
- const char *const interp[] = { "", "flat", "noperspective" };
+ STATIC_ASSERT(ARRAY_SIZE(mode) == ir_var_mode_count);
+ const char *const interp[] = { "", "smooth", "flat", "noperspective" };
+ STATIC_ASSERT(ARRAY_SIZE(interp) == INTERP_QUALIFIER_COUNT);
printf("(%s%s%s%s) ",
cent, inv, mode[ir->mode], interp[ir->interpolation]);
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp
index 16fdc41b4..b3667124f 100644
--- a/mesalib/src/glsl/ir_reader.cpp
+++ b/mesalib/src/glsl/ir_reader.cpp
@@ -676,16 +676,18 @@ ir_reader::read_expression(s_expression *expr)
{
s_expression *s_type;
s_symbol *s_op;
- s_expression *s_arg[3];
+ s_expression *s_arg[4] = {NULL};
s_pattern pat[] = { "expression", s_type, s_op, s_arg[0] };
if (!PARTIAL_MATCH(expr, pat)) {
ir_read_error(expr, "expected (expression <type> <operator> "
- "<operand> [<operand>])");
+ "<operand> [<operand>] [<operand>] [<operand>])");
return NULL;
}
s_arg[1] = (s_expression *) s_arg[0]->next; // may be tail sentinel
s_arg[2] = (s_expression *) s_arg[1]->next; // may be tail sentinel or NULL
+ if (s_arg[2])
+ s_arg[3] = (s_expression *) s_arg[2]->next; // may be tail sentinel or NULL
const glsl_type *type = read_type(s_type);
if (type == NULL)
@@ -709,7 +711,7 @@ ir_reader::read_expression(s_expression *expr)
return NULL;
}
- ir_rvalue *arg[3] = {NULL, NULL, NULL};
+ ir_rvalue *arg[4] = {NULL};
for (int i = 0; i < num_operands; i++) {
arg[i] = read_rvalue(s_arg[i]);
if (arg[i] == NULL) {
@@ -718,7 +720,7 @@ ir_reader::read_expression(s_expression *expr)
}
}
- return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2]);
+ return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2], arg[3]);
}
ir_swizzle *
diff --git a/mesalib/src/glsl/ir_uniform.h b/mesalib/src/glsl/ir_uniform.h
index 30e6f260d..8198c4819 100644
--- a/mesalib/src/glsl/ir_uniform.h
+++ b/mesalib/src/glsl/ir_uniform.h
@@ -99,15 +99,24 @@ struct gl_uniform_storage {
*/
bool initialized;
- /**
- * Base sampler index
- *
- * If \c ::base_type is \c GLSL_TYPE_SAMPLER, this represents the index of
- * this sampler. If \c ::array_elements is not zero, the array will use
- * sampler indexes \c ::sampler through \c ::sampler + \c ::array_elements
- * - 1, inclusive.
- */
- uint8_t sampler;
+ struct {
+ /**
+ * Base sampler index
+ *
+ * If \c ::base_type is \c GLSL_TYPE_SAMPLER, this represents the index
+ * of this sampler. If \c ::array_elements is not zero, the array will
+ * use sampler indices \c ::sampler through \c ::sampler +
+ * \c ::array_elements - 1, inclusive.
+ *
+ * Note that the index may be different in each shader stage.
+ */
+ uint8_t index;
+
+ /**
+ * Whether this sampler is used in this shader stage.
+ */
+ bool active;
+ } sampler[MESA_SHADER_TYPES];
/**
* Storage used by the driver for the uniform
diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp
index 699c192cd..ce96f6855 100644
--- a/mesalib/src/glsl/ir_validate.cpp
+++ b/mesalib/src/glsl/ir_validate.cpp
@@ -69,6 +69,8 @@ public:
virtual ir_visitor_status visit_leave(ir_expression *ir);
virtual ir_visitor_status visit_leave(ir_swizzle *ir);
+ virtual ir_visitor_status visit_enter(class ir_dereference_array *);
+
virtual ir_visitor_status visit_enter(ir_assignment *ir);
virtual ir_visitor_status visit_enter(ir_call *ir);
@@ -102,6 +104,33 @@ ir_validate::visit(ir_dereference_variable *ir)
}
ir_visitor_status
+ir_validate::visit_enter(class ir_dereference_array *ir)
+{
+ if (!ir->array->type->is_array() && !ir->array->type->is_matrix()) {
+ printf("ir_dereference_array @ %p does not specify an array or a "
+ "matrix\n",
+ (void *) ir);
+ ir->print();
+ printf("\n");
+ abort();
+ }
+
+ if (!ir->array_index->type->is_scalar()) {
+ printf("ir_dereference_array @ %p does not have scalar index: %s\n",
+ (void *) ir, ir->array_index->type->name);
+ abort();
+ }
+
+ if (!ir->array_index->type->is_integer()) {
+ printf("ir_dereference_array @ %p does not have integer index: %s\n",
+ (void *) ir, ir->array_index->type->name);
+ abort();
+ }
+
+ return visit_continue;
+}
+
+ir_visitor_status
ir_validate::visit_enter(ir_if *ir)
{
if (ir->condition->type != glsl_type::bool_type) {
@@ -361,6 +390,19 @@ ir_validate::visit_leave(ir_expression *ir)
assert(ir->operands[0]->type == glsl_type::uint_type);
break;
+ case ir_unop_bitfield_reverse:
+ assert(ir->operands[0]->type == ir->type);
+ assert(ir->type->is_integer());
+ break;
+
+ case ir_unop_bit_count:
+ case ir_unop_find_msb:
+ case ir_unop_find_lsb:
+ assert(ir->operands[0]->type->vector_elements == ir->type->vector_elements);
+ assert(ir->operands[0]->type->is_integer());
+ assert(ir->type->base_type == GLSL_TYPE_INT);
+ break;
+
case ir_unop_noise:
/* XXX what can we assert here? */
break;
@@ -461,6 +503,12 @@ ir_validate::visit_leave(ir_expression *ir)
assert(ir->operands[1]->type == glsl_type::float_type);
break;
+ case ir_binop_bfm:
+ assert(ir->type->is_integer());
+ assert(ir->operands[0]->type->is_integer());
+ assert(ir->operands[1]->type->is_integer());
+ break;
+
case ir_binop_ubo_load:
assert(ir->operands[0]->as_constant());
assert(ir->operands[0]->type == glsl_type::uint_type);
@@ -468,12 +516,46 @@ ir_validate::visit_leave(ir_expression *ir)
assert(ir->operands[1]->type == glsl_type::uint_type);
break;
+ case ir_binop_vector_extract:
+ assert(ir->operands[0]->type->is_vector());
+ assert(ir->operands[1]->type->is_scalar()
+ && ir->operands[1]->type->is_integer());
+ break;
+
case ir_triop_lrp:
assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
assert(ir->operands[0]->type == ir->operands[1]->type);
assert(ir->operands[2]->type == ir->operands[0]->type || ir->operands[2]->type == glsl_type::float_type);
break;
+ case ir_triop_bfi:
+ assert(ir->operands[0]->type->is_integer());
+ assert(ir->operands[1]->type == ir->operands[2]->type);
+ assert(ir->operands[1]->type == ir->type);
+ break;
+
+ case ir_triop_bitfield_extract:
+ assert(ir->operands[0]->type == ir->type);
+ assert(ir->operands[1]->type == glsl_type::int_type);
+ assert(ir->operands[2]->type == glsl_type::int_type);
+ break;
+
+ case ir_triop_vector_insert:
+ assert(ir->operands[0]->type->is_vector());
+ assert(ir->operands[1]->type->is_scalar());
+ assert(ir->operands[0]->type->base_type == ir->operands[1]->type->base_type);
+ assert(ir->operands[2]->type->is_scalar()
+ && ir->operands[2]->type->is_integer());
+ assert(ir->type == ir->operands[0]->type);
+ break;
+
+ case ir_quadop_bitfield_insert:
+ assert(ir->operands[0]->type == ir->type);
+ assert(ir->operands[1]->type == ir->type);
+ assert(ir->operands[2]->type == glsl_type::int_type);
+ assert(ir->operands[3]->type == glsl_type::int_type);
+ break;
+
case ir_quadop_vector:
/* The vector operator collects some number of scalars and generates a
* vector from them.
diff --git a/mesalib/src/glsl/link_interface_blocks.cpp b/mesalib/src/glsl/link_interface_blocks.cpp
new file mode 100644
index 000000000..b91860d03
--- /dev/null
+++ b/mesalib/src/glsl/link_interface_blocks.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file link_interface_blocks.cpp
+ * Linker support for GLSL's interface blocks.
+ */
+
+#include "ir.h"
+#include "glsl_symbol_table.h"
+#include "linker.h"
+#include "main/macros.h"
+
+bool
+validate_intrastage_interface_blocks(const gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ glsl_symbol_table interfaces;
+
+ for (unsigned int i = 0; i < num_shaders; i++) {
+ if (shader_list[i] == NULL)
+ continue;
+
+ foreach_list(node, shader_list[i]->ir) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (!var)
+ continue;
+
+ const glsl_type *iface_type = var->interface_type;
+
+ if (iface_type == NULL)
+ continue;
+
+ const glsl_type *old_iface_type =
+ interfaces.get_interface(iface_type->name,
+ (enum ir_variable_mode) var->mode);
+
+ if (old_iface_type == NULL) {
+ /* This is the first time we've seen the interface, so save
+ * it into our symbol table.
+ */
+ interfaces.add_interface(iface_type->name, iface_type,
+ (enum ir_variable_mode) var->mode);
+ } else if (old_iface_type != iface_type) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+validate_interstage_interface_blocks(const gl_shader *producer,
+ const gl_shader *consumer)
+{
+ glsl_symbol_table interfaces;
+
+ /* Add non-output interfaces from the consumer to the symbol table. */
+ foreach_list(node, consumer->ir) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (!var || !var->interface_type || var->mode == ir_var_shader_out)
+ continue;
+
+ interfaces.add_interface(var->interface_type->name,
+ var->interface_type,
+ (enum ir_variable_mode) var->mode);
+ }
+
+ /* Verify that the producer's interfaces match. */
+ foreach_list(node, producer->ir) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (!var || !var->interface_type || var->mode == ir_var_shader_in)
+ continue;
+
+ enum ir_variable_mode consumer_mode =
+ var->mode == ir_var_uniform ? ir_var_uniform : ir_var_shader_in;
+ const glsl_type *expected_type =
+ interfaces.get_interface(var->interface_type->name, consumer_mode);
+
+ /* The consumer doesn't use this output block. Ignore it. */
+ if (expected_type == NULL)
+ continue;
+
+ if (var->interface_type != expected_type)
+ return false;
+ }
+
+ return true;
+}
diff --git a/mesalib/src/glsl/link_uniform_initializers.cpp b/mesalib/src/glsl/link_uniform_initializers.cpp
index 836a360fa..54d9bf1f5 100644
--- a/mesalib/src/glsl/link_uniform_initializers.cpp
+++ b/mesalib/src/glsl/link_uniform_initializers.cpp
@@ -138,8 +138,16 @@ set_uniform_initializer(void *mem_ctx, gl_shader_program *prog,
}
if (base_type == GLSL_TYPE_SAMPLER) {
- for (unsigned int i = 0; i < storage->array_elements; i++) {
- prog->SamplerUnits[storage->sampler + i] = storage->storage[i].i;
+ for (int sh = 0; sh < MESA_SHADER_TYPES; sh++) {
+ gl_shader *shader = prog->_LinkedShaders[sh];
+
+ if (shader && storage->sampler[sh].active) {
+ for (unsigned i = 0; i < storage->array_elements; i++) {
+ unsigned index = storage->sampler[sh].index + i;
+
+ shader->SamplerUnits[index] = storage->storage[i].i;
+ }
+ }
}
}
} else {
@@ -148,8 +156,17 @@ set_uniform_initializer(void *mem_ctx, gl_shader_program *prog,
val->type->base_type,
val->type->components());
- if (storage->type->is_sampler())
- prog->SamplerUnits[storage->sampler] = storage->storage[0].i;
+ if (storage->type->is_sampler()) {
+ for (int sh = 0; sh < MESA_SHADER_TYPES; sh++) {
+ gl_shader *shader = prog->_LinkedShaders[sh];
+
+ if (shader && storage->sampler[sh].active) {
+ unsigned index = storage->sampler[sh].index;
+
+ shader->SamplerUnits[index] = storage->storage[0].i;
+ }
+ }
+ }
}
storage->initialized = true;
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index d457e4d0c..ad636681f 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -263,15 +263,19 @@ public:
parcel_out_uniform_storage(struct string_to_uint_map *map,
struct gl_uniform_storage *uniforms,
union gl_constant_value *values)
- : map(map), uniforms(uniforms), next_sampler(0), values(values)
+ : map(map), uniforms(uniforms), values(values)
{
- memset(this->targets, 0, sizeof(this->targets));
}
- void start_shader()
+ void start_shader(gl_shader_type shader_type)
{
+ assert(shader_type < MESA_SHADER_TYPES);
+ this->shader_type = shader_type;
+
this->shader_samplers_used = 0;
this->shader_shadow_samplers = 0;
+ this->next_sampler = 0;
+ memset(this->targets, 0, sizeof(this->targets));
}
void set_and_process(struct gl_shader_program *prog,
@@ -335,8 +339,37 @@ public:
int ubo_block_index;
int ubo_byte_offset;
bool ubo_row_major;
+ gl_shader_type shader_type;
private:
+ void handle_samplers(const glsl_type *base_type,
+ struct gl_uniform_storage *uniform)
+ {
+ if (base_type->is_sampler()) {
+ uniform->sampler[shader_type].index = this->next_sampler;
+ uniform->sampler[shader_type].active = true;
+
+ /* Increment the sampler by 1 for non-arrays and by the number of
+ * array elements for arrays.
+ */
+ this->next_sampler +=
+ MAX2(1, uniform->array_elements);
+
+ const gl_texture_index target = base_type->sampler_index();
+ const unsigned shadow = base_type->sampler_shadow;
+ for (unsigned i = uniform->sampler[shader_type].index;
+ i < MIN2(this->next_sampler, MAX_SAMPLERS);
+ i++) {
+ this->targets[i] = target;
+ this->shader_samplers_used |= 1U << i;
+ this->shader_shadow_samplers |= shadow << i;
+ }
+ } else {
+ uniform->sampler[shader_type].index = ~0;
+ uniform->sampler[shader_type].active = false;
+ }
+ }
+
virtual void visit_field(const glsl_type *type, const char *name,
bool row_major)
{
@@ -354,31 +387,6 @@ private:
if (!found)
return;
- /* If there is already storage associated with this uniform, it means
- * that it was set while processing an earlier shader stage. For
- * example, we may be processing the uniform in the fragment shader, but
- * the uniform was already processed in the vertex shader.
- */
- if (this->uniforms[id].storage != NULL) {
- /* If the uniform already has storage set from another shader stage,
- * mark the samplers used for this shader stage.
- */
- if (type->contains_sampler()) {
- const unsigned count = MAX2(1, this->uniforms[id].array_elements);
- const unsigned shadow = (type->is_array())
- ? type->fields.array->sampler_shadow : type->sampler_shadow;
-
- for (unsigned i = 0; i < count; i++) {
- const unsigned s = this->uniforms[id].sampler + i;
-
- this->shader_samplers_used |= 1U << s;
- this->shader_shadow_samplers |= shadow << s;
- }
- }
-
- return;
- }
-
const glsl_type *base_type;
if (type->is_array()) {
this->uniforms[id].array_elements = type->length;
@@ -388,26 +396,16 @@ private:
base_type = type;
}
- if (base_type->is_sampler()) {
- this->uniforms[id].sampler = this->next_sampler;
+ /* This assigns sampler uniforms to sampler units. */
+ handle_samplers(base_type, &this->uniforms[id]);
- /* Increment the sampler by 1 for non-arrays and by the number of
- * array elements for arrays.
- */
- this->next_sampler += MAX2(1, this->uniforms[id].array_elements);
-
- const gl_texture_index target = base_type->sampler_index();
- const unsigned shadow = base_type->sampler_shadow;
- for (unsigned i = this->uniforms[id].sampler
- ; i < MIN2(this->next_sampler, MAX_SAMPLERS)
- ; i++) {
- this->targets[i] = target;
- this->shader_samplers_used |= 1U << i;
- this->shader_shadow_samplers |= shadow << i;
- }
-
- } else {
- this->uniforms[id].sampler = ~0;
+ /* If there is already storage associated with this uniform, it means
+ * that it was set while processing an earlier shader stage. For
+ * example, we may be processing the uniform in the fragment shader, but
+ * the uniform was already processed in the vertex shader.
+ */
+ if (this->uniforms[id].storage != NULL) {
+ return;
}
this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
@@ -633,17 +631,6 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
prog->UniformHash = new string_to_uint_map;
}
- /* Uniforms that lack an initializer in the shader code have an initial
- * value of zero. This includes sampler uniforms.
- *
- * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
- *
- * "The link time initial value is either the value of the variable's
- * initializer, if present, or 0 if no initializer is present. Sampler
- * types cannot have initializers."
- */
- memset(prog->SamplerUnits, 0, sizeof(prog->SamplerUnits));
-
/* 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.
@@ -656,6 +643,18 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
if (prog->_LinkedShaders[i] == NULL)
continue;
+ /* Uniforms that lack an initializer in the shader code have an initial
+ * value of zero. This includes sampler uniforms.
+ *
+ * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
+ *
+ * "The link time initial value is either the value of the variable's
+ * initializer, if present, or 0 if no initializer is present. Sampler
+ * types cannot have initializers."
+ */
+ memset(prog->_LinkedShaders[i]->SamplerUnits, 0,
+ sizeof(prog->_LinkedShaders[i]->SamplerUnits));
+
link_update_uniform_buffer_variables(prog->_LinkedShaders[i]);
/* Reset various per-shader target counts.
@@ -706,9 +705,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
if (prog->_LinkedShaders[i] == NULL)
continue;
- /* Reset various per-shader target counts.
- */
- parcel.start_shader();
+ parcel.start_shader((gl_shader_type)i);
foreach_list(node, prog->_LinkedShaders[i]->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
@@ -726,10 +723,11 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used;
prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers;
- }
- assert(sizeof(prog->SamplerTargets) == sizeof(parcel.targets));
- memcpy(prog->SamplerTargets, parcel.targets, sizeof(prog->SamplerTargets));
+ STATIC_ASSERT(sizeof(prog->_LinkedShaders[i]->SamplerTargets) == sizeof(parcel.targets));
+ memcpy(prog->_LinkedShaders[i]->SamplerTargets, parcel.targets,
+ sizeof(prog->_LinkedShaders[i]->SamplerTargets));
+ }
#ifndef NDEBUG
for (unsigned i = 0; i < num_user_uniforms; i++) {
diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp
index 04c9fdd7c..34e3440d6 100644
--- a/mesalib/src/glsl/link_varyings.cpp
+++ b/mesalib/src/glsl/link_varyings.cpp
@@ -541,7 +541,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
class varying_matches
{
public:
- varying_matches(bool disable_varying_packing);
+ varying_matches(bool disable_varying_packing, bool consumer_is_fs);
~varying_matches();
void record(ir_variable *producer_var, ir_variable *consumer_var);
unsigned assign_locations();
@@ -621,11 +621,15 @@ private:
* it was allocated.
*/
unsigned matches_capacity;
+
+ const bool consumer_is_fs;
};
-varying_matches::varying_matches(bool disable_varying_packing)
- : disable_varying_packing(disable_varying_packing)
+varying_matches::varying_matches(bool disable_varying_packing,
+ bool consumer_is_fs)
+ : disable_varying_packing(disable_varying_packing),
+ consumer_is_fs(consumer_is_fs)
{
/* Note: this initial capacity is rather arbitrarily chosen to be large
* enough for many cases without wasting an unreasonable amount of space.
@@ -656,6 +660,10 @@ varying_matches::~varying_matches()
* If \c producer_var has already been paired up with a consumer_var, or
* producer_var is part of fixed pipeline functionality (and hence already has
* a location assigned), this function has no effect.
+ *
+ * Note: as a side effect this function may change the interpolation type of
+ * \c producer_var, but only when the change couldn't possibly affect
+ * rendering.
*/
void
varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
@@ -668,6 +676,25 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
return;
}
+ if ((consumer_var == NULL && producer_var->type->contains_integer()) ||
+ !consumer_is_fs) {
+ /* Since this varying is not being consumed by the fragment shader, its
+ * interpolation type varying cannot possibly affect rendering. Also,
+ * this variable is non-flat and is (or contains) an integer.
+ *
+ * lower_packed_varyings requires all integer varyings to flat,
+ * regardless of where they appear. We can trivially satisfy that
+ * requirement by changing the interpolation type to flat here.
+ */
+ producer_var->centroid = false;
+ producer_var->interpolation = INTERP_QUALIFIER_FLAT;
+
+ if (consumer_var) {
+ consumer_var->centroid = false;
+ consumer_var->interpolation = INTERP_QUALIFIER_FLAT;
+ }
+ }
+
if (this->num_matches == this->matches_capacity) {
this->matches_capacity *= 2;
this->matches = (match *)
@@ -960,11 +987,14 @@ assign_varying_locations(struct gl_context *ctx,
{
const unsigned producer_base = VARYING_SLOT_VAR0;
const unsigned consumer_base = VARYING_SLOT_VAR0;
- varying_matches matches(ctx->Const.DisableVaryingPacking);
+ varying_matches matches(ctx->Const.DisableVaryingPacking,
+ consumer && consumer->Type == GL_FRAGMENT_SHADER);
hash_table *tfeedback_candidates
= hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
hash_table *consumer_inputs
= hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
+ hash_table *consumer_interface_inputs
+ = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
/* Operate in a total of three passes.
*
@@ -983,8 +1013,17 @@ assign_varying_locations(struct gl_context *ctx,
((ir_instruction *) node)->as_variable();
if ((input_var != NULL) && (input_var->mode == ir_var_shader_in)) {
- hash_table_insert(consumer_inputs, input_var,
- ralloc_strdup(mem_ctx, input_var->name));
+ if (input_var->interface_type != NULL) {
+ char *const iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s",
+ input_var->interface_type->name,
+ input_var->name);
+ hash_table_insert(consumer_interface_inputs, input_var,
+ iface_field_name);
+ } else {
+ hash_table_insert(consumer_inputs, input_var,
+ ralloc_strdup(mem_ctx, input_var->name));
+ }
}
}
}
@@ -998,8 +1037,19 @@ assign_varying_locations(struct gl_context *ctx,
tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
g.process(output_var);
- ir_variable *input_var =
- (ir_variable *) hash_table_find(consumer_inputs, output_var->name);
+ ir_variable *input_var;
+ if (output_var->interface_type != NULL) {
+ char *const iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s",
+ output_var->interface_type->name,
+ output_var->name);
+ input_var =
+ (ir_variable *) hash_table_find(consumer_interface_inputs,
+ iface_field_name);
+ } else {
+ input_var =
+ (ir_variable *) hash_table_find(consumer_inputs, output_var->name);
+ }
if (input_var && input_var->mode != ir_var_shader_in)
input_var = NULL;
@@ -1019,6 +1069,7 @@ assign_varying_locations(struct gl_context *ctx,
if (matched_candidate == NULL) {
hash_table_dtor(tfeedback_candidates);
hash_table_dtor(consumer_inputs);
+ hash_table_dtor(consumer_interface_inputs);
return false;
}
@@ -1036,12 +1087,14 @@ assign_varying_locations(struct gl_context *ctx,
if (!tfeedback_decls[i].assign_location(ctx, prog)) {
hash_table_dtor(tfeedback_candidates);
hash_table_dtor(consumer_inputs);
+ hash_table_dtor(consumer_interface_inputs);
return false;
}
}
hash_table_dtor(tfeedback_candidates);
hash_table_dtor(consumer_inputs);
+ hash_table_dtor(consumer_interface_inputs);
if (ctx->Const.DisableVaryingPacking) {
/* Transform feedback code assumes varyings are packed, so if the driver
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 2b30d2b65..982fe46bd 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -938,6 +938,12 @@ link_intrastage_shaders(void *mem_ctx,
if (!cross_validate_globals(prog, shader_list, num_shaders, false))
return NULL;
+ /* Check that interface blocks defined in multiple shaders are consistent.
+ */
+ if (!validate_intrastage_interface_blocks((const gl_shader **)shader_list,
+ num_shaders))
+ return NULL;
+
/* Check that uniform blocks between shaders for a stage agree. */
const int num_uniform_blocks =
link_uniform_blocks(mem_ctx, prog, shader_list, num_shaders,
@@ -1512,15 +1518,15 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
};
const unsigned max_samplers[MESA_SHADER_TYPES] = {
- ctx->Const.MaxVertexTextureImageUnits,
- ctx->Const.MaxTextureImageUnits,
- ctx->Const.MaxGeometryTextureImageUnits
+ ctx->Const.VertexProgram.MaxTextureImageUnits,
+ ctx->Const.FragmentProgram.MaxTextureImageUnits,
+ ctx->Const.GeometryProgram.MaxTextureImageUnits
};
const unsigned max_uniform_components[MESA_SHADER_TYPES] = {
ctx->Const.VertexProgram.MaxUniformComponents,
ctx->Const.FragmentProgram.MaxUniformComponents,
- 0 /* FINISHME: Geometry shaders. */
+ ctx->Const.GeometryProgram.MaxUniformComponents
};
const unsigned max_uniform_blocks[MESA_SHADER_TYPES] = {
@@ -1722,6 +1728,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (prog->_LinkedShaders[i] == NULL)
continue;
+ if (!validate_interstage_interface_blocks(prog->_LinkedShaders[prev],
+ prog->_LinkedShaders[i])) {
+ linker_error(prog, "interface block mismatch between shader stages\n");
+ goto done;
+ }
+
if (!cross_validate_outputs_to_inputs(prog,
prog->_LinkedShaders[prev],
prog->_LinkedShaders[i]))
@@ -1733,6 +1745,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->LinkStatus = true;
}
+
+ for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] != NULL)
+ lower_named_interface_blocks(mem_ctx, prog->_LinkedShaders[i]);
+ }
+
/* Implement the GLSL 1.30+ rule for discard vs infinite loops Do
* it before optimization because we want most of the checks to get
* dropped thanks to constant propagation.
@@ -1767,7 +1785,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations;
- while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll))
+ while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll, &ctx->ShaderCompilerOptions[i]))
;
}
diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h
index f1ce50ace..2fe2410c2 100644
--- a/mesalib/src/glsl/linker.h
+++ b/mesalib/src/glsl/linker.h
@@ -60,6 +60,14 @@ link_uniform_blocks(void *mem_ctx,
unsigned num_shaders,
struct gl_uniform_block **blocks_ret);
+bool
+validate_intrastage_interface_blocks(const gl_shader **shader_list,
+ unsigned num_shaders);
+
+bool
+validate_interstage_interface_blocks(const gl_shader *producer,
+ const gl_shader *consumer);
+
/**
* Class for processing all of the leaf fields of a variable that corresponds
* to a program resource.
diff --git a/mesalib/src/glsl/lower_clip_distance.cpp b/mesalib/src/glsl/lower_clip_distance.cpp
index 643807de8..d6cf94438 100644
--- a/mesalib/src/glsl/lower_clip_distance.cpp
+++ b/mesalib/src/glsl/lower_clip_distance.cpp
@@ -46,10 +46,11 @@
*/
#include "glsl_symbol_table.h"
-#include "ir_hierarchical_visitor.h"
+#include "ir_rvalue_visitor.h"
#include "ir.h"
+#include "program/prog_instruction.h" /* For WRITEMASK_* */
-class lower_clip_distance_visitor : public ir_hierarchical_visitor {
+class lower_clip_distance_visitor : public ir_rvalue_visitor {
public:
lower_clip_distance_visitor()
: progress(false), old_clip_distance_var(NULL),
@@ -59,11 +60,14 @@ public:
virtual ir_visitor_status visit(ir_variable *);
void create_indices(ir_rvalue*, ir_rvalue *&, ir_rvalue *&);
- virtual ir_visitor_status visit_leave(ir_dereference_array *);
virtual ir_visitor_status visit_leave(ir_assignment *);
void visit_new_assignment(ir_assignment *ir);
virtual ir_visitor_status visit_leave(ir_call *);
+ virtual void handle_rvalue(ir_rvalue **rvalue);
+
+ void fix_lhs(ir_assignment *);
+
bool progress;
/**
@@ -173,35 +177,70 @@ lower_clip_distance_visitor::create_indices(ir_rvalue *old_index,
}
-/**
- * Replace any expression that indexes into the gl_ClipDistance array with an
- * expression that indexes into one of the vec4's in gl_ClipDistanceMESA and
- * accesses the appropriate component.
- */
-ir_visitor_status
-lower_clip_distance_visitor::visit_leave(ir_dereference_array *ir)
+void
+lower_clip_distance_visitor::handle_rvalue(ir_rvalue **rv)
{
/* If the gl_ClipDistance var hasn't been declared yet, then
* there's no way this deref can refer to it.
*/
- if (!this->old_clip_distance_var)
- return visit_continue;
+ if (!this->old_clip_distance_var || *rv == NULL)
+ return;
+
+ ir_dereference_array *const array_deref = (*rv)->as_dereference_array();
+ if (array_deref == NULL)
+ return;
- ir_dereference_variable *old_var_ref = ir->array->as_dereference_variable();
+ /* Replace any expression that indexes into the gl_ClipDistance array
+ * with an expression that indexes into one of the vec4's in
+ * gl_ClipDistanceMESA and accesses the appropriate component.
+ */
+ ir_dereference_variable *old_var_ref =
+ array_deref->array->as_dereference_variable();
if (old_var_ref && old_var_ref->var == this->old_clip_distance_var) {
this->progress = true;
ir_rvalue *array_index;
ir_rvalue *swizzle_index;
- this->create_indices(ir->array_index, array_index, swizzle_index);
- void *mem_ctx = ralloc_parent(ir);
- ir->array = new(mem_ctx) ir_dereference_array(
- this->new_clip_distance_var, array_index);
- ir->array_index = swizzle_index;
- }
+ this->create_indices(array_deref->array_index, array_index, swizzle_index);
+ void *mem_ctx = ralloc_parent(array_deref);
- return visit_continue;
+ ir_dereference_array *const ClipDistanceMESA_deref =
+ new(mem_ctx) ir_dereference_array(this->new_clip_distance_var,
+ array_index);
+
+ ir_expression *const expr =
+ new(mem_ctx) ir_expression(ir_binop_vector_extract,
+ ClipDistanceMESA_deref,
+ swizzle_index);
+
+ *rv = expr;
+ }
}
+void
+lower_clip_distance_visitor::fix_lhs(ir_assignment *ir)
+{
+ if (ir->lhs->ir_type == ir_type_expression) {
+ void *mem_ctx = ralloc_parent(ir);
+ ir_expression *const expr = (ir_expression *) ir->lhs;
+
+ /* The expression must be of the form:
+ *
+ * (vector_extract gl_ClipDistanceMESA[i], j).
+ */
+ assert(expr->operation == ir_binop_vector_extract);
+ assert(expr->operands[0]->ir_type == ir_type_dereference_array);
+ assert(expr->operands[0]->type == glsl_type::vec4_type);
+
+ ir_dereference *const new_lhs = (ir_dereference *) expr->operands[0];
+ ir->rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
+ glsl_type::vec4_type,
+ new_lhs->clone(mem_ctx, NULL),
+ ir->rhs,
+ expr->operands[1]);
+ ir->set_lhs(new_lhs);
+ ir->write_mask = WRITEMASK_XYZW;
+ }
+}
/**
* Replace any assignment having gl_ClipDistance (undereferenced) as its LHS
@@ -223,29 +262,50 @@ lower_clip_distance_visitor::visit_leave(ir_assignment *ir)
* each of them.
*
* Note: to unroll into element-by-element assignments, we need to make
- * clones of the LHS and RHS. This is only safe if the LHS and RHS are
- * side-effect free. Fortunately, we know that they are, because the
- * only kind of rvalue that can have side effects is an ir_call, and
- * ir_calls only appear (a) as a statement on their own, or (b) as the
- * RHS of an assignment that stores the result of the call in a
- * temporary variable.
+ * clones of the LHS and RHS. This is safe because expressions and
+ * l-values are side-effect free.
*/
void *ctx = ralloc_parent(ir);
int array_size = this->old_clip_distance_var->type->array_size();
for (int i = 0; i < array_size; ++i) {
ir_dereference_array *new_lhs = new(ctx) ir_dereference_array(
ir->lhs->clone(ctx, NULL), new(ctx) ir_constant(i));
- new_lhs->accept(this);
ir_dereference_array *new_rhs = new(ctx) ir_dereference_array(
ir->rhs->clone(ctx, NULL), new(ctx) ir_constant(i));
- new_rhs->accept(this);
- this->base_ir->insert_before(
- new(ctx) ir_assignment(new_lhs, new_rhs));
+ this->handle_rvalue((ir_rvalue **) &new_rhs);
+
+ /* Handle the LHS after creating the new assignment. This must
+ * happen in this order because handle_rvalue may replace the old LHS
+ * with an ir_expression of ir_binop_vector_extract. Since this is
+ * not a valide l-value, this will cause an assertion in the
+ * ir_assignment constructor to fail.
+ *
+ * If this occurs, replace the mangled LHS with a dereference of the
+ * vector, and replace the RHS with an ir_triop_vector_insert.
+ */
+ ir_assignment *const assign = new(ctx) ir_assignment(new_lhs, new_rhs);
+ this->handle_rvalue((ir_rvalue **) &assign->lhs);
+ this->fix_lhs(assign);
+
+ this->base_ir->insert_before(assign);
}
ir->remove();
+
+ return visit_continue;
}
- return visit_continue;
+ /* Handle the LHS as if it were an r-value. Normally
+ * rvalue_visit(ir_assignment *) only visits the RHS, but we need to lower
+ * expressions in the LHS as well.
+ *
+ * This may cause the LHS to get replaced with an ir_expression of
+ * ir_binop_vector_extract. If this occurs, replace it with a dereference
+ * of the vector, and replace the RHS with an ir_triop_vector_insert.
+ */
+ handle_rvalue((ir_rvalue **)&ir->lhs);
+ this->fix_lhs(ir);
+
+ return rvalue_visit(ir);
}
@@ -330,7 +390,7 @@ lower_clip_distance_visitor::visit_leave(ir_call *ir)
}
}
- return visit_continue;
+ return rvalue_visit(ir);
}
diff --git a/mesalib/src/glsl/lower_instructions.cpp b/mesalib/src/glsl/lower_instructions.cpp
index 1ce7b7c9d..d32ec80d6 100644
--- a/mesalib/src/glsl/lower_instructions.cpp
+++ b/mesalib/src/glsl/lower_instructions.cpp
@@ -38,6 +38,7 @@
* - LOG_TO_LOG2
* - MOD_TO_FRACT
* - LRP_TO_ARITH
+ * - BITFIELD_INSERT_TO_BFM_BFI
*
* SUB_TO_ADD_NEG:
* ---------------
@@ -84,6 +85,15 @@
* LRP_TO_ARITH:
* -------------
* Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2).
+ *
+ * BITFIELD_INSERT_TO_BFM_BFI:
+ * ---------------------------
+ * Breaks ir_quadop_bitfield_insert into ir_binop_bfm (bitfield mask) and
+ * ir_triop_bfi (bitfield insert).
+ *
+ * Many GPUs implement the bitfieldInsert() built-in from ARB_gpu_shader_5
+ * with a pair of instructions.
+ *
*/
#include "main/core.h" /* for M_LOG2E */
@@ -114,6 +124,7 @@ private:
void pow_to_exp2(ir_expression *);
void log_to_log2(ir_expression *);
void lrp_to_arith(ir_expression *);
+ void bitfield_insert_to_bfm_bfi(ir_expression *);
};
/**
@@ -298,6 +309,29 @@ lower_instructions_visitor::lrp_to_arith(ir_expression *ir)
this->progress = true;
}
+void
+lower_instructions_visitor::bitfield_insert_to_bfm_bfi(ir_expression *ir)
+{
+ /* Translates
+ * ir_quadop_bitfield_insert base insert offset bits
+ * into
+ * ir_triop_bfi (ir_binop_bfm bits offset) insert base
+ */
+
+ ir_rvalue *base_expr = ir->operands[0];
+
+ ir->operation = ir_triop_bfi;
+ ir->operands[0] = new(ir) ir_expression(ir_binop_bfm,
+ ir->type->get_base_type(),
+ ir->operands[3],
+ ir->operands[2]);
+ /* ir->operands[1] is still the value to insert. */
+ ir->operands[2] = base_expr;
+ ir->operands[3] = NULL;
+
+ this->progress = true;
+}
+
ir_visitor_status
lower_instructions_visitor::visit_leave(ir_expression *ir)
{
@@ -339,6 +373,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
lrp_to_arith(ir);
break;
+ case ir_quadop_bitfield_insert:
+ if (lowering(BITFIELD_INSERT_TO_BFM_BFI))
+ bitfield_insert_to_bfm_bfi(ir);
+ break;
+
default:
return visit_continue;
}
diff --git a/mesalib/src/glsl/lower_named_interface_blocks.cpp b/mesalib/src/glsl/lower_named_interface_blocks.cpp
new file mode 100644
index 000000000..eba667a8b
--- /dev/null
+++ b/mesalib/src/glsl/lower_named_interface_blocks.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file lower_named_interface_blocks.cpp
+ *
+ * This lowering pass converts all interface blocks with instance names
+ * into interface blocks without an instance name.
+ *
+ * For example, the following shader:
+ *
+ * out block {
+ * float block_var;
+ * } inst_name;
+ *
+ * main()
+ * {
+ * inst_name.block_var = 0.0;
+ * }
+ *
+ * Is rewritten to:
+ *
+ * out block {
+ * float block_var;
+ * };
+ *
+ * main()
+ * {
+ * block_var = 0.0;
+ * }
+ *
+ * This takes place after the shader code has already been verified with
+ * the interface name in place.
+ *
+ * The linking phase will use the interface block name rather than the
+ * interface's instance name when linking interfaces.
+ *
+ * This modification to the ir allows our currently existing dead code
+ * elimination to work with interface blocks without changes.
+ */
+
+#include "glsl_symbol_table.h"
+#include "ir.h"
+#include "ir_optimization.h"
+#include "ir_rvalue_visitor.h"
+#include "program/hash_table.h"
+
+class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
+{
+public:
+ void * const mem_ctx;
+ hash_table *interface_namespace;
+
+ flatten_named_interface_blocks_declarations(void *mem_ctx)
+ : mem_ctx(mem_ctx)
+ {
+ }
+
+ void run(exec_list *instructions);
+
+ virtual ir_visitor_status visit_leave(ir_assignment *);
+ virtual void handle_rvalue(ir_rvalue **rvalue);
+};
+
+void
+flatten_named_interface_blocks_declarations::run(exec_list *instructions)
+{
+ interface_namespace = hash_table_ctor(0, hash_table_string_hash,
+ hash_table_string_compare);
+
+ /* First pass: adjust instance block variables with an instance name
+ * to not have an instance name.
+ *
+ * The interface block variables are stored in the interface_namespace
+ * hash table so they can be used in the second pass.
+ */
+ foreach_list_safe(node, instructions) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (!var || !var->is_interface_instance())
+ continue;
+
+ /* It should be possible to handle uniforms during this pass,
+ * but, this will require changes to the other uniform block
+ * support code.
+ */
+ if (var->mode == ir_var_uniform)
+ continue;
+
+ const glsl_type * iface_t = var->type;
+ const glsl_type * array_t = NULL;
+ exec_node *insert_pos = var;
+
+ if (iface_t->is_array()) {
+ array_t = iface_t;
+ iface_t = array_t->fields.array;
+ }
+
+ assert (iface_t->is_interface());
+
+ for (unsigned i = 0; i < iface_t->length; i++) {
+ const char * field_name = iface_t->fields.structure[i].name;
+ char *iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s",
+ iface_t->name, field_name);
+
+ ir_variable *found_var =
+ (ir_variable *) hash_table_find(interface_namespace,
+ iface_field_name);
+ if (!found_var) {
+ ir_variable *new_var;
+ if (array_t == NULL) {
+ char *var_name =
+ ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
+ new_var =
+ new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
+ var_name,
+ (ir_variable_mode) var->mode);
+ } else {
+ const glsl_type *new_array_type =
+ glsl_type::get_array_instance(
+ iface_t->fields.structure[i].type,
+ array_t->length);
+ char *var_name =
+ ralloc_asprintf(mem_ctx, "%s[%d]",
+ iface_t->fields.structure[i].name,
+ array_t->length);
+ new_var =
+ new(mem_ctx) ir_variable(new_array_type,
+ var_name,
+ (ir_variable_mode) var->mode);
+ }
+
+ new_var->interface_type = iface_t;
+ hash_table_insert(interface_namespace, new_var,
+ iface_field_name);
+ insert_pos->insert_after(new_var);
+ insert_pos = new_var;
+ }
+ }
+ var->remove();
+ }
+
+ /* Second pass: visit all ir_dereference_record instances, and if they
+ * reference an interface block, then flatten the refererence out.
+ */
+ visit_list_elements(this, instructions);
+ hash_table_dtor(interface_namespace);
+ interface_namespace = NULL;
+}
+
+ir_visitor_status
+flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
+{
+ ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
+ if (lhs_rec) {
+ ir_rvalue *lhs_rec_tmp = lhs_rec;
+ handle_rvalue(&lhs_rec_tmp);
+ if (lhs_rec_tmp != lhs_rec) {
+ ir->set_lhs(lhs_rec_tmp);
+ }
+ }
+ return rvalue_visit(ir);
+}
+
+void
+flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (*rvalue == NULL)
+ return;
+
+ ir_dereference_record *ir = (*rvalue)->as_dereference_record();
+ if (ir == NULL)
+ return;
+
+ ir_variable *var = ir->variable_referenced();
+
+ if (!var->is_interface_instance())
+ return;
+
+ /* It should be possible to handle uniforms during this pass,
+ * but, this will require changes to the other uniform block
+ * support code.
+ */
+ if (var->mode == ir_var_uniform)
+ return;
+
+ if (var->interface_type != NULL) {
+ char *iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
+ ir->field);
+ /* Find the variable in the set of flattened interface blocks */
+ ir_variable *found_var =
+ (ir_variable *) hash_table_find(interface_namespace,
+ iface_field_name);
+ assert(found_var);
+
+ ir_dereference_variable *deref_var =
+ new(mem_ctx) ir_dereference_variable(found_var);
+
+ ir_dereference_array *deref_array =
+ ir->record->as_dereference_array();
+ if (deref_array != NULL) {
+ *rvalue =
+ new(mem_ctx) ir_dereference_array(deref_var,
+ deref_array->array_index);
+ } else {
+ *rvalue = deref_var;
+ }
+ }
+}
+
+void
+lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
+{
+ flatten_named_interface_blocks_declarations v_decl(mem_ctx);
+ v_decl.run(shader->ir);
+}
+
diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp
index b4cc5cd0d..cdf2289b4 100644
--- a/mesalib/src/glsl/lower_packed_varyings.cpp
+++ b/mesalib/src/glsl/lower_packed_varyings.cpp
@@ -178,6 +178,14 @@ lower_packed_varyings_visitor::run(exec_list *instructions)
!this->needs_lowering(var))
continue;
+ /* This lowering pass is only capable of packing floats and ints
+ * together when their interpolation mode is "flat". Therefore, to be
+ * safe, caller should ensure that integral varyings always use flat
+ * interpolation, even when this is not required by GLSL.
+ */
+ assert(var->interpolation == INTERP_QUALIFIER_FLAT ||
+ !var->type->contains_integer());
+
/* Change the old varying into an ordinary global. */
var->mode = ir_var_auto;
diff --git a/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp b/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
index f85875f49..880859688 100644
--- a/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
+++ b/mesalib/src/glsl/lower_vec_index_to_cond_assign.cpp
@@ -52,7 +52,12 @@ public:
progress = false;
}
- ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
+ ir_rvalue *convert_vec_index_to_cond_assign(void *mem_ctx,
+ ir_rvalue *orig_vector,
+ ir_rvalue *orig_index,
+ const glsl_type *type);
+
+ ir_rvalue *convert_vector_extract_to_cond_assign(ir_rvalue *ir);
virtual ir_visitor_status visit_enter(ir_expression *);
virtual ir_visitor_status visit_enter(ir_swizzle *);
@@ -65,24 +70,16 @@ public:
};
ir_rvalue *
-ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
+ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(void *mem_ctx,
+ ir_rvalue *orig_vector,
+ ir_rvalue *orig_index,
+ const glsl_type *type)
{
- ir_dereference_array *orig_deref = ir->as_dereference_array();
ir_assignment *assign, *value_assign;
ir_variable *index, *var, *value;
ir_dereference *deref, *deref_value;
unsigned i;
- if (!orig_deref)
- return ir;
-
- if (orig_deref->array->type->is_matrix() ||
- orig_deref->array->type->is_array())
- return ir;
-
- void *mem_ctx = ralloc_parent(ir);
-
- assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
exec_list list;
@@ -92,19 +89,19 @@ ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue
ir_var_temporary);
list.push_tail(index);
deref = new(base_ir) ir_dereference_variable(index);
- assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
+ assign = new(base_ir) ir_assignment(deref, orig_index, NULL);
list.push_tail(assign);
/* Store the value inside a temp, thus avoiding matrixes duplication */
- value = new(base_ir) ir_variable(orig_deref->array->type, "vec_value_tmp",
- ir_var_temporary);
+ value = new(base_ir) ir_variable(orig_vector->type, "vec_value_tmp",
+ ir_var_temporary);
list.push_tail(value);
deref_value = new(base_ir) ir_dereference_variable(value);
- value_assign = new(base_ir) ir_assignment(deref_value, orig_deref->array);
+ value_assign = new(base_ir) ir_assignment(deref_value, orig_vector);
list.push_tail(value_assign);
/* Temporary where we store whichever value we swizzle out. */
- var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
+ var = new(base_ir) ir_variable(type, "vec_index_tmp_v",
ir_var_temporary);
list.push_tail(var);
@@ -113,13 +110,14 @@ ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue
*/
ir_rvalue *const cond_deref =
compare_index_block(&list, index, 0,
- orig_deref->array->type->vector_elements,
+ orig_vector->type->vector_elements,
mem_ctx);
/* Generate a conditional move of each vector element to the temp. */
- for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
+ for (i = 0; i < orig_vector->type->vector_elements; i++) {
ir_rvalue *condition_swizzle =
- new(base_ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);
+ new(base_ir) ir_swizzle(cond_deref->clone(mem_ctx, NULL),
+ i, 0, 0, 0, 1);
/* Just clone the rest of the deref chain when trying to get at the
* underlying variable.
@@ -142,13 +140,27 @@ ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue
return new(base_ir) ir_dereference_variable(var);
}
+ir_rvalue *
+ir_vec_index_to_cond_assign_visitor::convert_vector_extract_to_cond_assign(ir_rvalue *ir)
+{
+ ir_expression *const expr = ir->as_expression();
+
+ if (expr == NULL || expr->operation != ir_binop_vector_extract)
+ return ir;
+
+ return convert_vec_index_to_cond_assign(ralloc_parent(ir),
+ expr->operands[0],
+ expr->operands[1],
+ ir->type);
+}
+
ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
{
unsigned int i;
for (i = 0; i < ir->get_num_operands(); i++) {
- ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
+ ir->operands[i] = convert_vector_extract_to_cond_assign(ir->operands[i]);
}
return visit_continue;
@@ -161,7 +173,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
* the result of indexing a vector is. But maybe at some point we'll end up
* using swizzling of scalars for vector construction.
*/
- ir->val = convert_vec_index_to_cond_assign(ir->val);
+ ir->val = convert_vector_extract_to_cond_assign(ir->val);
return visit_continue;
}
@@ -169,91 +181,12 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
{
- ir_variable *index, *var;
- ir_dereference_variable *deref;
- ir_assignment *assign;
- unsigned i;
-
- ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
- if (ir->condition)
- ir->condition = convert_vec_index_to_cond_assign(ir->condition);
-
- /* Last, handle the LHS */
- ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
-
- if (!orig_deref ||
- orig_deref->array->type->is_matrix() ||
- orig_deref->array->type->is_array())
- return visit_continue;
-
- void *mem_ctx = ralloc_parent(ir);
-
- assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
-
- exec_list list;
-
- /* Store the index to a temporary to avoid reusing its tree. */
- index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
- ir_var_temporary);
- list.push_tail(index);
- deref = new(ir) ir_dereference_variable(index);
- assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
- list.push_tail(assign);
-
- /* Store the RHS to a temporary to avoid reusing its tree. */
- var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
- ir_var_temporary);
- list.push_tail(var);
- deref = new(ir) ir_dereference_variable(var);
- assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
- list.push_tail(assign);
-
- /* Generate a single comparison condition "mask" for all of the components
- * in the vector.
- */
- ir_rvalue *const cond_deref =
- compare_index_block(&list, index, 0,
- orig_deref->array->type->vector_elements,
- mem_ctx);
+ ir->rhs = convert_vector_extract_to_cond_assign(ir->rhs);
- /* Generate a conditional move of each vector element to the temp. */
- for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
- ir_rvalue *condition_swizzle =
- new(ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);
-
-
- /* Just clone the rest of the deref chain when trying to get at the
- * underlying variable.
- */
- ir_rvalue *swizzle =
- new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
- i, 0, 0, 0, 1);
-
- deref = new(ir) ir_dereference_variable(var);
- assign = new(ir) ir_assignment(swizzle, deref, condition_swizzle);
- list.push_tail(assign);
+ if (ir->condition) {
+ ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
}
- /* If the original assignment has a condition, respect that original
- * condition! This is acomplished by wrapping the new conditional
- * assignments in an if-statement that uses the original condition.
- */
- if (ir->condition != NULL) {
- /* No need to clone the condition because the IR that it hangs on is
- * going to be removed from the instruction sequence.
- */
- ir_if *if_stmt = new(mem_ctx) ir_if(ir->condition);
-
- list.move_nodes_to(&if_stmt->then_instructions);
- ir->insert_before(if_stmt);
- } else {
- ir->insert_before(&list);
- }
-
- ir->remove();
-
- this->progress = true;
-
return visit_continue;
}
@@ -262,7 +195,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
{
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param = (ir_rvalue *)iter.get();
- ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
+ ir_rvalue *new_param = convert_vector_extract_to_cond_assign(param);
if (new_param != param) {
param->replace_with(new_param);
@@ -276,7 +209,7 @@ ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
{
if (ir->value) {
- ir->value = convert_vec_index_to_cond_assign(ir->value);
+ ir->value = convert_vector_extract_to_cond_assign(ir->value);
}
return visit_continue;
@@ -285,7 +218,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
{
- ir->condition = convert_vec_index_to_cond_assign(ir->condition);
+ ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
return visit_continue;
}
diff --git a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
index 264d6dc07..d5ad692c2 100644
--- a/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
+++ b/mesalib/src/glsl/lower_vec_index_to_swizzle.cpp
@@ -46,7 +46,7 @@ public:
progress = false;
}
- ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
+ ir_rvalue *convert_vector_extract_to_swizzle(ir_rvalue *val);
virtual ir_visitor_status visit_enter(ir_expression *);
virtual ir_visitor_status visit_enter(ir_swizzle *);
@@ -59,20 +59,14 @@ public:
};
ir_rvalue *
-ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
+ir_vec_index_to_swizzle_visitor::convert_vector_extract_to_swizzle(ir_rvalue *ir)
{
- ir_dereference_array *deref = ir->as_dereference_array();
- ir_constant *ir_constant;
-
- if (!deref)
- return ir;
-
- if (deref->array->type->is_matrix() || deref->array->type->is_array())
+ ir_expression *const expr = ir->as_expression();
+ if (expr == NULL || expr->operation != ir_binop_vector_extract)
return ir;
- assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
- ir_constant = deref->array_index->constant_expression_value();
- if (!ir_constant)
+ ir_constant *const idx = expr->operands[1]->constant_expression_value();
+ if (idx == NULL)
return ir;
void *ctx = ralloc_parent(ir);
@@ -92,10 +86,10 @@ ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
* The ir_swizzle constructor gets angry if the index is negative or too
* large. For simplicity sake, just clamp the index to [0, size-1].
*/
- const int i = MIN2(MAX2(ir_constant->value.i[0], 0),
- ((int) deref->array->type->vector_elements - 1));
+ const int i = CLAMP(idx->value.i[0], 0,
+ (int) expr->operands[0]->type->vector_elements - 1);
- return new(ctx) ir_swizzle(deref->array, i, 0, 0, 0, 1);
+ return new(ctx) ir_swizzle(expr->operands[0], i, 0, 0, 0, 1);
}
ir_visitor_status
@@ -104,7 +98,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_expression *ir)
unsigned int i;
for (i = 0; i < ir->get_num_operands(); i++) {
- ir->operands[i] = convert_vec_index_to_swizzle(ir->operands[i]);
+ ir->operands[i] = convert_vector_extract_to_swizzle(ir->operands[i]);
}
return visit_continue;
@@ -117,7 +111,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
* the result of indexing a vector is. But maybe at some point we'll end up
* using swizzling of scalars for vector construction.
*/
- ir->val = convert_vec_index_to_swizzle(ir->val);
+ ir->val = convert_vector_extract_to_swizzle(ir->val);
return visit_continue;
}
@@ -125,8 +119,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
ir_visitor_status
ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
{
- ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
- ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
+ ir->rhs = convert_vector_extract_to_swizzle(ir->rhs);
return visit_continue;
}
@@ -136,7 +129,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_call *ir)
{
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param = (ir_rvalue *)iter.get();
- ir_rvalue *new_param = convert_vec_index_to_swizzle(param);
+ ir_rvalue *new_param = convert_vector_extract_to_swizzle(param);
if (new_param != param) {
param->replace_with(new_param);
@@ -150,7 +143,7 @@ ir_visitor_status
ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
{
if (ir->value) {
- ir->value = convert_vec_index_to_swizzle(ir->value);
+ ir->value = convert_vector_extract_to_swizzle(ir->value);
}
return visit_continue;
@@ -159,7 +152,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
ir_visitor_status
ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
{
- ir->condition = convert_vec_index_to_swizzle(ir->condition);
+ ir->condition = convert_vector_extract_to_swizzle(ir->condition);
return visit_continue;
}
diff --git a/mesalib/src/glsl/lower_vector_insert.cpp b/mesalib/src/glsl/lower_vector_insert.cpp
new file mode 100644
index 000000000..0e640cc32
--- /dev/null
+++ b/mesalib/src/glsl/lower_vector_insert.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "ir.h"
+#include "ir_builder.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+
+using namespace ir_builder;
+
+class vector_insert_visitor : public ir_rvalue_visitor {
+public:
+ vector_insert_visitor(bool lower_nonconstant_index)
+ : progress(false), lower_nonconstant_index(lower_nonconstant_index)
+ {
+ factory.instructions = &factory_instructions;
+ }
+
+ virtual ~vector_insert_visitor()
+ {
+ assert(factory_instructions.is_empty());
+ }
+
+ virtual void handle_rvalue(ir_rvalue **rv);
+
+ ir_factory factory;
+ exec_list factory_instructions;
+ bool progress;
+ bool lower_nonconstant_index;
+};
+
+
+void
+vector_insert_visitor::handle_rvalue(ir_rvalue **rv)
+{
+ if (*rv == NULL || (*rv)->ir_type != ir_type_expression)
+ return;
+
+ ir_expression *const expr = (ir_expression *) *rv;
+
+ if (likely(expr->operation != ir_triop_vector_insert))
+ return;
+
+ factory.mem_ctx = ralloc_parent(expr);
+
+ ir_constant *const idx = expr->operands[2]->constant_expression_value();
+ if (idx != NULL) {
+ /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of
+ * a new temporary. The new temporary gets assigned as
+ *
+ * t = vec
+ * t.mask = scalar
+ *
+ * where mask is the component selected by index.
+ */
+ ir_variable *const temp =
+ factory.make_temp(expr->operands[0]->type, "vec_tmp");
+
+ const int mask = 1 << idx->value.i[0];
+
+ factory.emit(assign(temp, expr->operands[0]));
+ factory.emit(assign(temp, expr->operands[1], mask));
+
+ this->progress = true;
+ *rv = new(factory.mem_ctx) ir_dereference_variable(temp);
+ } else if (this->lower_nonconstant_index) {
+ /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of
+ * a new temporary. The new temporary gets assigned as
+ *
+ * t = vec
+ * if (index == 0)
+ * t.x = scalar
+ * if (index == 1)
+ * t.y = scalar
+ * if (index == 2)
+ * t.z = scalar
+ * if (index == 3)
+ * t.w = scalar
+ */
+ ir_variable *const temp =
+ factory.make_temp(expr->operands[0]->type, "vec_tmp");
+
+ ir_variable *const src_temp =
+ factory.make_temp(expr->operands[1]->type, "src_temp");
+
+ factory.emit(assign(temp, expr->operands[0]));
+ factory.emit(assign(src_temp, expr->operands[1]));
+
+ for (unsigned i = 0; i < expr->type->vector_elements; i++) {
+ ir_constant *const cmp_index =
+ new(factory.mem_ctx) ir_constant(int(i));
+
+ ir_variable *const cmp_result =
+ factory.make_temp(glsl_type::bool_type, "index_condition");
+
+ factory.emit(assign(cmp_result,
+ equal(expr->operands[2]->clone(factory.mem_ctx,
+ NULL),
+ cmp_index)));
+
+ factory.emit(if_tree(cmp_result,
+ assign(temp, src_temp, WRITEMASK_X << i)));
+ }
+
+ this->progress = true;
+ *rv = new(factory.mem_ctx) ir_dereference_variable(temp);
+ }
+
+ base_ir->insert_before(factory.instructions);
+}
+
+bool
+lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index)
+{
+ vector_insert_visitor v(lower_nonconstant_index);
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/main.cpp b/mesalib/src/glsl/main.cpp
index ce084b4d7..d7e35bcb3 100644
--- a/mesalib/src/glsl/main.cpp
+++ b/mesalib/src/glsl/main.cpp
@@ -174,9 +174,11 @@ compile_shader(struct gl_context *ctx, struct gl_shader *shader)
/* Optimization passes */
if (!state->error && !shader->ir->is_empty()) {
+ const struct gl_shader_compiler_options *opts =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)];
bool progress;
do {
- progress = do_common_optimization(shader->ir, false, false, 32);
+ progress = do_common_optimization(shader->ir, false, false, 32, opts);
} while (progress);
validate_ir_tree(shader->ir);
diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp
index 70e016d22..d706a6ad1 100644
--- a/mesalib/src/glsl/opt_algebraic.cpp
+++ b/mesalib/src/glsl/opt_algebraic.cpp
@@ -186,12 +186,12 @@ ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
ir_rvalue *
ir_algebraic_visitor::handle_expression(ir_expression *ir)
{
- ir_constant *op_const[3] = {NULL, NULL, NULL};
- ir_expression *op_expr[3] = {NULL, NULL, NULL};
+ ir_constant *op_const[4] = {NULL, NULL, NULL, NULL};
+ ir_expression *op_expr[4] = {NULL, NULL, NULL, NULL};
ir_expression *temp;
unsigned int i;
- assert(ir->get_num_operands() <= 3);
+ assert(ir->get_num_operands() <= 4);
for (i = 0; i < ir->get_num_operands(); i++) {
if (ir->operands[i]->type->is_matrix())
return ir;
diff --git a/mesalib/src/glsl/opt_flip_matrices.cpp b/mesalib/src/glsl/opt_flip_matrices.cpp
new file mode 100644
index 000000000..497513fe8
--- /dev/null
+++ b/mesalib/src/glsl/opt_flip_matrices.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file opt_flip_matrices.cpp
+ *
+ * Convert (matrix * vector) operations to (vector * matrixTranspose),
+ * which can be done using dot products rather than multiplies and adds.
+ * On some hardware, this is more efficient.
+ *
+ * This currently only does the conversion for built-in matrices which
+ * already have transposed equivalents. Namely, gl_ModelViewProjectionMatrix
+ * and gl_TextureMatrix.
+ */
+#include "ir.h"
+#include "ir_optimization.h"
+#include "main/macros.h"
+
+namespace {
+class matrix_flipper : public ir_hierarchical_visitor {
+public:
+ matrix_flipper(exec_list *instructions)
+ {
+ progress = false;
+ mvp_transpose = NULL;
+ texmat_transpose = NULL;
+
+ foreach_list(n, instructions) {
+ ir_instruction *ir = (ir_instruction *) n;
+ ir_variable *var = ir->as_variable();
+ if (!var)
+ continue;
+ if (strcmp(var->name, "gl_ModelViewProjectionMatrixTranspose") == 0)
+ mvp_transpose = var;
+ if (strcmp(var->name, "gl_TextureMatrixTranspose") == 0)
+ texmat_transpose = var;
+ }
+ }
+
+ ir_visitor_status visit_enter(ir_expression *ir);
+
+ bool progress;
+
+private:
+ ir_variable *mvp_transpose;
+ ir_variable *texmat_transpose;
+};
+}
+
+ir_visitor_status
+matrix_flipper::visit_enter(ir_expression *ir)
+{
+ if (ir->operation != ir_binop_mul ||
+ !ir->operands[0]->type->is_matrix() ||
+ !ir->operands[1]->type->is_vector())
+ return visit_continue;
+
+ ir_variable *mat_var = ir->operands[0]->variable_referenced();
+ if (!mat_var)
+ return visit_continue;
+
+ if (mvp_transpose &&
+ strcmp(mat_var->name, "gl_ModelViewProjectionMatrix") == 0) {
+ ir_dereference_variable *deref = ir->operands[0]->as_dereference_variable();
+ assert(deref && deref->var == mat_var);
+
+ void *mem_ctx = ralloc_parent(ir);
+
+ ir->operands[0] = ir->operands[1];
+ ir->operands[1] = new(mem_ctx) ir_dereference_variable(mvp_transpose);
+
+ progress = true;
+ } else if (texmat_transpose &&
+ strcmp(mat_var->name, "gl_TextureMatrix") == 0) {
+ ir_dereference_array *array_ref = ir->operands[0]->as_dereference_array();
+ assert(array_ref != NULL);
+ ir_dereference_variable *var_ref = array_ref->array->as_dereference_variable();
+ assert(var_ref && var_ref->var == mat_var);
+
+ ir->operands[0] = ir->operands[1];
+ ir->operands[1] = array_ref;
+
+ var_ref->var = texmat_transpose;
+
+ texmat_transpose->max_array_access =
+ MAX2(texmat_transpose->max_array_access, mat_var->max_array_access);
+
+ progress = true;
+ }
+
+ return visit_continue;
+}
+
+bool
+opt_flip_matrices(struct exec_list *instructions)
+{
+ matrix_flipper v(instructions);
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/opt_if_simplification.cpp b/mesalib/src/glsl/opt_if_simplification.cpp
index e1a23d94a..db59b131d 100644
--- a/mesalib/src/glsl/opt_if_simplification.cpp
+++ b/mesalib/src/glsl/opt_if_simplification.cpp
@@ -25,7 +25,8 @@
* \file opt_if_simplification.cpp
*
* Moves constant branches of if statements out to the surrounding
- * instruction stream.
+ * instruction stream, and inverts if conditionals to avoid empty
+ * "then" blocks.
*/
#include "ir.h"
@@ -101,6 +102,30 @@ ir_if_simplification_visitor::visit_leave(ir_if *ir)
}
ir->remove();
this->made_progress = true;
+ return visit_continue;
+ }
+
+ /* Turn:
+ *
+ * if (cond) {
+ * } else {
+ * do_work();
+ * }
+ *
+ * into :
+ *
+ * if (!cond)
+ * do_work();
+ *
+ * which avoids control flow for "else" (which is usually more
+ * expensive than normal operations), and the "not" can usually be
+ * folded into the generation of "cond" anyway.
+ */
+ if (ir->then_instructions.is_empty()) {
+ ir->condition = new(ralloc_parent(ir->condition))
+ ir_expression(ir_unop_logic_not, ir->condition);
+ ir->else_instructions.move_nodes_to(&ir->then_instructions);
+ this->made_progress = true;
}
return visit_continue;
diff --git a/mesalib/src/glsl/program.h b/mesalib/src/glsl/program.h
index 46ce9dccc..6a76d4d54 100644
--- a/mesalib/src/glsl/program.h
+++ b/mesalib/src/glsl/program.h
@@ -16,9 +16,10 @@
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include "main/core.h"
diff --git a/mesalib/src/glsl/ralloc.c b/mesalib/src/glsl/ralloc.c
index 59e71c48b..e79dad764 100644
--- a/mesalib/src/glsl/ralloc.c
+++ b/mesalib/src/glsl/ralloc.c
@@ -107,9 +107,13 @@ void *
ralloc_size(const void *ctx, size_t size)
{
void *block = calloc(1, size + sizeof(ralloc_header));
+ ralloc_header *info;
+ ralloc_header *parent;
- ralloc_header *info = (ralloc_header *) block;
- ralloc_header *parent = ctx != NULL ? get_header(ctx) : NULL;
+ if (unlikely(block == NULL))
+ return NULL;
+ info = (ralloc_header *) block;
+ parent = ctx != NULL ? get_header(ctx) : NULL;
add_child(parent, info);
diff --git a/mesalib/src/glsl/standalone_scaffolding.cpp b/mesalib/src/glsl/standalone_scaffolding.cpp
index 0c1f52f48..11cd6cdc0 100644
--- a/mesalib/src/glsl/standalone_scaffolding.cpp
+++ b/mesalib/src/glsl/standalone_scaffolding.cpp
@@ -104,6 +104,7 @@ void initialize_context_to_defaults(struct gl_context *ctx, gl_api api)
ctx->Extensions.ARB_texture_cube_map_array = true;
ctx->Extensions.ARB_texture_multisample = true;
ctx->Extensions.ARB_texture_query_lod = true;
+ ctx->Extensions.ARB_gpu_shader5 = true;
ctx->Const.GLSLVersion = 120;
@@ -116,10 +117,22 @@ void initialize_context_to_defaults(struct gl_context *ctx, gl_api api)
ctx->Const.VertexProgram.MaxUniformComponents = 512;
ctx->Const.MaxVarying = 8; /* == gl_MaxVaryingFloats / 4 */
- ctx->Const.MaxVertexTextureImageUnits = 0;
+ ctx->Const.VertexProgram.MaxTextureImageUnits = 0;
ctx->Const.MaxCombinedTextureImageUnits = 2;
- ctx->Const.MaxTextureImageUnits = 2;
+ ctx->Const.FragmentProgram.MaxTextureImageUnits = 2;
ctx->Const.FragmentProgram.MaxUniformComponents = 64;
ctx->Const.MaxDrawBuffers = 1;
+
+ /* Set up default shader compiler options. */
+ struct gl_shader_compiler_options options;
+ memset(&options, 0, sizeof(options));
+ options.MaxUnrollIterations = 32;
+ options.MaxIfDepth = UINT_MAX;
+
+ /* Default pragma settings */
+ options.DefaultPragmas.Optimize = true;
+
+ for (int sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+ memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
}
diff --git a/mesalib/src/glsl/standalone_scaffolding.h b/mesalib/src/glsl/standalone_scaffolding.h
index 0a2cde8a3..7afb1c313 100644
--- a/mesalib/src/glsl/standalone_scaffolding.h
+++ b/mesalib/src/glsl/standalone_scaffolding.h
@@ -31,6 +31,7 @@
#ifndef STANDALONE_SCAFFOLDING_H
#define STANDALONE_SCAFFOLDING_H
+#include <assert.h>
#include "main/mtypes.h"
extern "C" void
@@ -47,6 +48,22 @@ extern "C" void
_mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id,
const char *msg, int len);
+static inline gl_shader_type
+_mesa_shader_type_to_index(GLenum v)
+{
+ switch (v) {
+ case GL_VERTEX_SHADER:
+ return MESA_SHADER_VERTEX;
+ case GL_FRAGMENT_SHADER:
+ return MESA_SHADER_FRAGMENT;
+ case GL_GEOMETRY_SHADER:
+ return MESA_SHADER_GEOMETRY;
+ default:
+ assert(!"bad value in _mesa_shader_type_to_index()");
+ return MESA_SHADER_TYPES;
+ }
+}
+
/**
* Initialize the given gl_context structure to a reasonable set of
* defaults representing the minimum capabilities required by the
diff --git a/mesalib/src/glsl/test_optpass.cpp b/mesalib/src/glsl/test_optpass.cpp
index 117b0b006..fc10cbbde 100644
--- a/mesalib/src/glsl/test_optpass.cpp
+++ b/mesalib/src/glsl/test_optpass.cpp
@@ -54,7 +54,8 @@ static string read_stdin_to_eof()
}
static GLboolean
-do_optimization(struct exec_list *ir, const char *optimization)
+do_optimization(struct exec_list *ir, const char *optimization,
+ const struct gl_shader_compiler_options *options)
{
int int_0;
int int_1;
@@ -64,7 +65,7 @@ do_optimization(struct exec_list *ir, const char *optimization)
if (sscanf(optimization, "do_common_optimization ( %d , %d ) ",
&int_0, &int_1) == 2) {
- return do_common_optimization(ir, int_0 != 0, false, int_1);
+ return do_common_optimization(ir, int_0 != 0, false, int_1, options);
} else if (strcmp(optimization, "do_algebraic") == 0) {
return do_algebraic(ir);
} else if (strcmp(optimization, "do_constant_folding") == 0) {
@@ -141,7 +142,8 @@ do_optimization(struct exec_list *ir, const char *optimization)
static GLboolean
do_optimization_passes(struct exec_list *ir, char **optimizations,
- int num_optimizations, bool quiet)
+ int num_optimizations, bool quiet,
+ const struct gl_shader_compiler_options *options)
{
GLboolean overall_progress = false;
@@ -150,7 +152,7 @@ do_optimization_passes(struct exec_list *ir, char **optimizations,
if (!quiet) {
printf("*** Running optimization %s...", optimization);
}
- GLboolean progress = do_optimization(ir, optimization);
+ GLboolean progress = do_optimization(ir, optimization, options);
if (!quiet) {
printf("%s\n", progress ? "progress" : "no progress");
}
@@ -240,9 +242,11 @@ int test_optpass(int argc, char **argv)
/* Optimization passes */
if (!state->error) {
GLboolean progress;
+ const struct gl_shader_compiler_options *options =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader_type)];
do {
progress = do_optimization_passes(shader->ir, &argv[optind],
- argc - optind, quiet != 0);
+ argc - optind, quiet != 0, options);
} while (loop && progress);
}