aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast_array_index.cpp4
-rw-r--r--mesalib/src/glsl/ast_function.cpp14
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp222
-rw-r--r--mesalib/src/glsl/builtin_functions.cpp229
-rw-r--r--mesalib/src/glsl/builtin_type_macros.h2
-rw-r--r--mesalib/src/glsl/builtin_types.cpp6
-rw-r--r--mesalib/src/glsl/builtin_variables.cpp15
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y3
-rw-r--r--mesalib/src/glsl/glsl_parser.yy42
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp7
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h32
-rw-r--r--mesalib/src/glsl/glsl_types.cpp20
-rw-r--r--mesalib/src/glsl/glsl_types.h38
-rw-r--r--mesalib/src/glsl/hir_field_selection.cpp2
-rw-r--r--mesalib/src/glsl/ir.cpp49
-rw-r--r--mesalib/src/glsl/ir.h17
-rw-r--r--mesalib/src/glsl/ir_clone.cpp3
-rw-r--r--mesalib/src/glsl/ir_uniform.h7
-rw-r--r--mesalib/src/glsl/link_functions.cpp16
-rw-r--r--mesalib/src/glsl/link_uniform_initializers.cpp1
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp1
-rw-r--r--mesalib/src/glsl/linker.cpp27
-rw-r--r--mesalib/src/glsl/opt_algebraic.cpp166
-rw-r--r--mesalib/src/glsl/opt_array_splitting.cpp2
-rw-r--r--mesalib/src/glsl/opt_dead_builtin_varyings.cpp167
-rw-r--r--mesalib/src/glsl/opt_function_inlining.cpp66
-rw-r--r--mesalib/src/glsl/ralloc.h14
27 files changed, 814 insertions, 358 deletions
diff --git a/mesalib/src/glsl/ast_array_index.cpp b/mesalib/src/glsl/ast_array_index.cpp
index b457ec899..f7b5e8350 100644
--- a/mesalib/src/glsl/ast_array_index.cpp
+++ b/mesalib/src/glsl/ast_array_index.cpp
@@ -143,7 +143,7 @@ _mesa_ast_array_index_to_hir(void *mem_ctx,
bound = array->type->vector_elements;
}
} else {
- /* glsl_type::array_size() returns 0 for non-array types. This means
+ /* glsl_type::array_size() returns -1 for non-array types. This means
* that we don't need to verify that the type is an array before
* doing the bounds checking.
*/
@@ -165,7 +165,7 @@ _mesa_ast_array_index_to_hir(void *mem_ctx,
if (array->type->is_array())
update_max_array_access(array, idx, &loc, state);
} else if (const_index == NULL && array->type->is_array()) {
- if (array->type->array_size() == 0) {
+ if (array->type->is_unsized_array()) {
_mesa_glsl_error(&loc, state, "unsized array index must be constant");
} else if (array->type->fields.array->is_interface()
&& array->variable_referenced()->mode == ir_var_uniform) {
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 02aad4f8f..2707522ef 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -732,21 +732,21 @@ process_array_constructor(exec_list *instructions,
exec_list actual_parameters;
const unsigned parameter_count =
process_parameters(instructions, &actual_parameters, parameters, state);
+ bool is_unsized_array = constructor_type->is_unsized_array();
- if ((parameter_count == 0)
- || ((constructor_type->length != 0)
- && (constructor_type->length != parameter_count))) {
- const unsigned min_param = (constructor_type->length == 0)
- ? 1 : constructor_type->length;
+ if ((parameter_count == 0) ||
+ (!is_unsized_array && (constructor_type->length != parameter_count))) {
+ const unsigned min_param = is_unsized_array
+ ? 1 : constructor_type->length;
_mesa_glsl_error(loc, state, "array constructor must have %s %u "
"parameter%s",
- (constructor_type->length == 0) ? "at least" : "exactly",
+ is_unsized_array ? "at least" : "exactly",
min_param, (min_param <= 1) ? "" : "s");
return ir_rvalue::error_value(ctx);
}
- if (constructor_type->length == 0) {
+ if (is_unsized_array) {
constructor_type =
glsl_type::get_array_instance(constructor_type->element_type(),
parameter_count);
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 3551a5956..f75e68ce1 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -675,8 +675,8 @@ shift_result_type(const struct glsl_type *type_a,
*/
ir_rvalue *
validate_assignment(struct _mesa_glsl_parse_state *state,
- const glsl_type *lhs_type, ir_rvalue *rhs,
- bool is_initializer)
+ YYLTYPE loc, const glsl_type *lhs_type,
+ ir_rvalue *rhs, bool is_initializer)
{
/* If there is already some error in the RHS, just return it. Anything
* else will lead to an avalanche of error message back to the user.
@@ -689,16 +689,15 @@ validate_assignment(struct _mesa_glsl_parse_state *state,
if (rhs->type == lhs_type)
return rhs;
- /* If the array element types are the same and the size of the LHS is zero,
+ /* If the array element types are the same and the LHS is unsized,
* the assignment is okay for initializers embedded in variable
* declarations.
*
* Note: Whole-array assignments are not permitted in GLSL 1.10, but this
* is handled by ir_dereference::is_lvalue.
*/
- if (is_initializer && lhs_type->is_array() && rhs->type->is_array()
- && (lhs_type->element_type() == rhs->type->element_type())
- && (lhs_type->array_size() == 0)) {
+ if (is_initializer && lhs_type->is_unsized_array() && rhs->type->is_array()
+ && (lhs_type->element_type() == rhs->type->element_type())) {
return rhs;
}
@@ -708,6 +707,12 @@ validate_assignment(struct _mesa_glsl_parse_state *state,
return rhs;
}
+ _mesa_glsl_error(&loc, state,
+ "%s of type %s cannot be assigned to "
+ "variable of type %s",
+ is_initializer ? "initializer" : "value",
+ rhs->type->name, lhs_type->name);
+
return NULL;
}
@@ -738,10 +743,10 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
if (unlikely(expr->operation == ir_binop_vector_extract)) {
ir_rvalue *new_rhs =
- validate_assignment(state, lhs->type, rhs, is_initializer);
+ validate_assignment(state, lhs_loc, 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,
@@ -790,10 +795,8 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
}
ir_rvalue *new_rhs =
- validate_assignment(state, lhs->type, rhs, is_initializer);
- if (new_rhs == NULL) {
- _mesa_glsl_error(& lhs_loc, state, "type mismatch");
- } else {
+ validate_assignment(state, lhs_loc, lhs->type, rhs, is_initializer);
+ if (new_rhs != NULL) {
rhs = new_rhs;
/* If the LHS array was not declared with a size, it takes it size from
@@ -801,7 +804,7 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
* dereference of a variable. Any other case would require that the LHS
* is either not an l-value or not a whole array.
*/
- if (lhs->type->array_size() == 0) {
+ if (lhs->type->is_unsized_array()) {
ir_dereference *const d = lhs->as_dereference();
assert(d != NULL);
@@ -940,6 +943,7 @@ do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
case GLSL_TYPE_VOID:
case GLSL_TYPE_SAMPLER:
case GLSL_TYPE_INTERFACE:
+ case GLSL_TYPE_ATOMIC_UINT:
/* I assume a comparison of a struct containing a sampler just
* ignores the sampler present in the type.
*/
@@ -1234,6 +1238,10 @@ ast_expression::hir(exec_list *instructions,
!state->check_version(120, 300, &loc,
"array comparisons forbidden")) {
error_emitted = true;
+ } else if ((op[0]->type->contains_opaque() ||
+ op[1]->type->contains_opaque())) {
+ _mesa_glsl_error(&loc, state, "opaque type comparisons forbidden");
+ error_emitted = true;
}
if (error_emitted) {
@@ -2039,6 +2047,96 @@ interpret_interpolation_qualifier(const struct ast_type_qualifier *qual,
static void
+validate_explicit_location(const struct ast_type_qualifier *qual,
+ ir_variable *var,
+ struct _mesa_glsl_parse_state *state,
+ YYLTYPE *loc)
+{
+ bool fail = false;
+
+ /* In the vertex shader only shader inputs can be given explicit
+ * locations.
+ *
+ * In the fragment shader only shader outputs can be given explicit
+ * locations.
+ */
+ switch (state->target) {
+ case vertex_shader:
+ if (var->mode == ir_var_shader_in) {
+ if (!state->check_explicit_attrib_location_allowed(loc, var))
+ return;
+
+ break;
+ }
+
+ fail = true;
+ break;
+
+ case geometry_shader:
+ _mesa_glsl_error(loc, state,
+ "geometry shader variables cannot be given "
+ "explicit locations");
+ return;
+
+ case fragment_shader:
+ if (var->mode == ir_var_shader_out) {
+ if (!state->check_explicit_attrib_location_allowed(loc, var))
+ return;
+
+ break;
+ }
+
+ fail = true;
+ break;
+ };
+
+ if (fail) {
+ _mesa_glsl_error(loc, state,
+ "%s cannot be given an explicit location in %s shader",
+ mode_string(var),
+ _mesa_glsl_shader_target_name(state->target));
+ } else {
+ var->explicit_location = true;
+
+ /* This bit of silliness is needed because invalid explicit locations
+ * are supposed to be flagged during linking. Small negative values
+ * biased by VERT_ATTRIB_GENERIC0 or FRAG_RESULT_DATA0 could alias
+ * built-in values (e.g., -16+VERT_ATTRIB_GENERIC0 = VERT_ATTRIB_POS).
+ * The linker needs to be able to differentiate these cases. This
+ * ensures that negative values stay negative.
+ */
+ if (qual->location >= 0) {
+ var->location = (state->target == vertex_shader)
+ ? (qual->location + VERT_ATTRIB_GENERIC0)
+ : (qual->location + FRAG_RESULT_DATA0);
+ } else {
+ var->location = qual->location;
+ }
+
+ if (qual->flags.q.explicit_index) {
+ /* From the GLSL 4.30 specification, section 4.4.2 (Output
+ * Layout Qualifiers):
+ *
+ * "It is also a compile-time error if a fragment shader
+ * sets a layout index to less than 0 or greater than 1."
+ *
+ * Older specifications don't mandate a behavior; we take
+ * this as a clarification and always generate the error.
+ */
+ if (qual->index < 0 || qual->index > 1) {
+ _mesa_glsl_error(loc, state,
+ "explicit index may only be 0 or 1");
+ } else {
+ var->explicit_index = true;
+ var->index = qual->index;
+ }
+ }
+ }
+
+ return;
+}
+
+static void
apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
ir_variable *var,
struct _mesa_glsl_parse_state *state,
@@ -2190,81 +2288,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
}
if (qual->flags.q.explicit_location) {
- const bool global_scope = (state->current_function == NULL);
- bool fail = false;
- const char *string = "";
-
- /* In the vertex shader only shader inputs can be given explicit
- * locations.
- *
- * In the fragment shader only shader outputs can be given explicit
- * locations.
- */
- switch (state->target) {
- case vertex_shader:
- if (!global_scope || (var->mode != ir_var_shader_in)) {
- fail = true;
- string = "input";
- }
- break;
-
- case geometry_shader:
- _mesa_glsl_error(loc, state,
- "geometry shader variables cannot be given "
- "explicit locations");
- break;
-
- case fragment_shader:
- if (!global_scope || (var->mode != ir_var_shader_out)) {
- fail = true;
- string = "output";
- }
- break;
- };
-
- if (fail) {
- _mesa_glsl_error(loc, state,
- "only %s shader %s variables can be given an "
- "explicit location",
- _mesa_glsl_shader_target_name(state->target),
- string);
- } else {
- var->explicit_location = true;
-
- /* This bit of silliness is needed because invalid explicit locations
- * are supposed to be flagged during linking. Small negative values
- * biased by VERT_ATTRIB_GENERIC0 or FRAG_RESULT_DATA0 could alias
- * built-in values (e.g., -16+VERT_ATTRIB_GENERIC0 = VERT_ATTRIB_POS).
- * The linker needs to be able to differentiate these cases. This
- * ensures that negative values stay negative.
- */
- if (qual->location >= 0) {
- var->location = (state->target == vertex_shader)
- ? (qual->location + VERT_ATTRIB_GENERIC0)
- : (qual->location + FRAG_RESULT_DATA0);
- } else {
- var->location = qual->location;
- }
-
- if (qual->flags.q.explicit_index) {
- /* From the GLSL 4.30 specification, section 4.4.2 (Output
- * Layout Qualifiers):
- *
- * "It is also a compile-time error if a fragment shader
- * sets a layout index to less than 0 or greater than 1."
- *
- * Older specifications don't mandate a behavior; we take
- * this as a clarification and always generate the error.
- */
- if (qual->index < 0 || qual->index > 1) {
- _mesa_glsl_error(loc, state,
- "explicit index may only be 0 or 1");
- } else {
- var->explicit_index = true;
- var->index = qual->index;
- }
- }
- }
+ validate_explicit_location(qual, var, state, loc);
} else if (qual->flags.q.explicit_index) {
_mesa_glsl_error(loc, state,
"explicit index requires explicit location");
@@ -2403,8 +2427,7 @@ get_variable_being_redeclared(ir_variable *var, YYLTYPE loc,
* later re-declare the same name as an array of the same
* type and specify a size."
*/
- if ((earlier->type->array_size() == 0)
- && var->type->is_array()
+ if (earlier->type->is_unsized_array() && var->type->is_array()
&& (var->type->element_type() == earlier->type->element_type())) {
/* FINISHME: This doesn't match the qualifiers on the two
* FINISHME: declarations. It's not 100% clear whether this is
@@ -2547,7 +2570,8 @@ process_initializer(ir_variable *var, ast_declaration *decl,
*/
if (type->qualifier.flags.q.constant
|| type->qualifier.flags.q.uniform) {
- ir_rvalue *new_rhs = validate_assignment(state, var->type, rhs, true);
+ ir_rvalue *new_rhs = validate_assignment(state, initializer_loc,
+ var->type, rhs, true);
if (new_rhs != NULL) {
rhs = new_rhs;
@@ -2576,10 +2600,6 @@ process_initializer(ir_variable *var, ast_declaration *decl,
var->constant_value = constant_value;
}
} else {
- _mesa_glsl_error(&initializer_loc, state,
- "initializer of type %s cannot be assigned to "
- "variable of type %s",
- rhs->type->name, var->type->name);
if (var->type->is_numeric()) {
/* Reduce cascading errors. */
var->constant_value = ir_constant::zero(state, var->type);
@@ -2659,7 +2679,7 @@ handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
return;
}
- if (var->type->length == 0) {
+ if (var->type->is_unsized_array()) {
/* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec says:
*
* All geometry shader input unsized array declarations will be
@@ -3308,7 +3328,7 @@ ast_declarator_list::hir(exec_list *instructions,
const glsl_type *const t = (earlier == NULL)
? var->type : earlier->type;
- if (t->is_array() && t->length == 0)
+ if (t->is_unsized_array())
/* Section 10.17 of the GLSL ES 1.00 specification states that
* unsized array declarations have been removed from the language.
* Arrays that are sized using an initializer are still explicitly
@@ -3441,7 +3461,7 @@ ast_parameter_declarator::hir(exec_list *instructions,
type = process_array_type(&loc, type, this->array_size, state);
}
- if (!type->is_error() && type->array_size() == 0) {
+ if (!type->is_error() && type->is_unsized_array()) {
_mesa_glsl_error(&loc, state, "arrays passed as parameters must have "
"a declared size");
type = glsl_type::error_type;
@@ -3613,7 +3633,7 @@ ast_function::hir(exec_list *instructions,
* "Arrays are allowed as arguments and as the return type. In both
* cases, the array must be explicitly sized."
*/
- if (return_type->is_array() && return_type->length == 0) {
+ if (return_type->is_unsized_array()) {
YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state,
"function `%s' return type array must be explicitly "
@@ -5099,10 +5119,8 @@ ast_gs_input_layout::hir(exec_list *instructions,
/* Note: gl_PrimitiveIDIn has mode ir_var_shader_in, but it's not an
* array; skip it.
*/
- if (!var->type->is_array())
- continue;
- if (var->type->length == 0) {
+ if (var->type->is_unsized_array()) {
if (var->max_array_access >= num_vertices) {
_mesa_glsl_error(&loc, state,
"this geometry shader input layout implies %u"
diff --git a/mesalib/src/glsl/builtin_functions.cpp b/mesalib/src/glsl/builtin_functions.cpp
index d40888d38..3fa0cb5ad 100644
--- a/mesalib/src/glsl/builtin_functions.cpp
+++ b/mesalib/src/glsl/builtin_functions.cpp
@@ -277,6 +277,17 @@ texture_gather(const _mesa_glsl_parse_state *state)
state->ARB_gpu_shader5_enable;
}
+/* Only ARB_texture_gather but not GLSL 4.0 or ARB_gpu_shader5.
+ * used for relaxation of const offset requirements.
+ */
+static bool
+texture_gather_only(const _mesa_glsl_parse_state *state)
+{
+ return !state->is_version(400, 0) &&
+ !state->ARB_gpu_shader5_enable &&
+ state->ARB_texture_gather_enable;
+}
+
/* Desktop GL or OES_standard_derivatives + fragment shader only */
static bool
fs_oes_derivatives(const _mesa_glsl_parse_state *state)
@@ -315,6 +326,13 @@ tex3d_lod(const _mesa_glsl_parse_state *state)
{
return tex3d(state) && lod_exists_in_stage(state);
}
+
+static bool
+shader_atomic_counters(const _mesa_glsl_parse_state *state)
+{
+ return state->ARB_shader_atomic_counters_enable;
+}
+
/** @} */
/******************************************************************************/
@@ -354,6 +372,7 @@ private:
ir_variable *gl_Vertex;
void create_shader();
+ void create_intrinsics();
void create_builtins();
/**
@@ -375,6 +394,14 @@ private:
ir_expression *asin_expr(ir_variable *x);
+ /**
+ * Call function \param f with parameters specified as the linked
+ * list \param params of \c ir_variable objects. \param ret should
+ * point to the ir_variable that will hold the function return
+ * value, or be \c NULL if the function has void return type.
+ */
+ ir_call *call(ir_function *f, ir_variable *ret, exec_list params);
+
/** Create a new function and add the given signatures. */
void add_function(const char *name, ...);
@@ -495,6 +522,8 @@ private:
#define TEX_PROJECT 1
#define TEX_OFFSET 2
#define TEX_COMPONENT 4
+#define TEX_OFFSET_NONCONST 8
+#define TEX_OFFSET_ARRAY 16
ir_function_signature *_texture(ir_texture_opcode opcode,
builtin_available_predicate avail,
@@ -534,6 +563,11 @@ private:
B1(uaddCarry)
B1(usubBorrow)
B1(mulExtended)
+
+ ir_function_signature *_atomic_intrinsic(builtin_available_predicate avail);
+ ir_function_signature *_atomic_op(const char *intrinsic,
+ builtin_available_predicate avail);
+
#undef B0
#undef B1
#undef B2
@@ -596,6 +630,7 @@ builtin_builder::initialize()
mem_ctx = ralloc_context(NULL);
create_shader();
+ create_intrinsics();
create_builtins();
}
@@ -633,6 +668,24 @@ builtin_builder::create_shader()
/** @} */
/**
+ * Create ir_function and ir_function_signature objects for each
+ * intrinsic.
+ */
+void
+builtin_builder::create_intrinsics()
+{
+ add_function("__intrinsic_atomic_read",
+ _atomic_intrinsic(shader_atomic_counters),
+ NULL);
+ add_function("__intrinsic_atomic_increment",
+ _atomic_intrinsic(shader_atomic_counters),
+ NULL);
+ add_function("__intrinsic_atomic_predecrement",
+ _atomic_intrinsic(shader_atomic_counters),
+ NULL);
+}
+
+/**
* Create ir_function and ir_function_signature objects for each built-in.
*
* Contains a list of every available built-in.
@@ -1909,16 +1962,80 @@ builtin_builder::create_builtins()
_texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT),
_texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isamplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT),
_texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usamplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeShadow_type, glsl_type::vec3_type),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeArrayShadow_type, glsl_type::vec4_type),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRectShadow_type, glsl_type::vec2_type),
NULL);
add_function("textureGatherOffset",
- _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
- _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
- _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
+ _texture(ir_tg4, texture_gather_only, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
+ _texture(ir_tg4, texture_gather_only, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
+ _texture(ir_tg4, texture_gather_only, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET),
+
+ _texture(ir_tg4, texture_gather_only, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
+ _texture(ir_tg4, texture_gather_only, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
+ _texture(ir_tg4, texture_gather_only, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRectShadow_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST),
+ NULL);
+
+ add_function("textureGatherOffsets",
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY),
- _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
- _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
- _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+ _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY | TEX_COMPONENT),
+
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type, TEX_OFFSET_ARRAY),
+ _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRectShadow_type, glsl_type::vec2_type, TEX_OFFSET_ARRAY),
NULL);
F(dFdx)
@@ -1974,6 +2091,20 @@ builtin_builder::create_builtins()
_mulExtended(glsl_type::uvec3_type),
_mulExtended(glsl_type::uvec4_type),
NULL);
+
+ add_function("atomicCounter",
+ _atomic_op("__intrinsic_atomic_read",
+ shader_atomic_counters),
+ NULL);
+ add_function("atomicCounterIncrement",
+ _atomic_op("__intrinsic_atomic_increment",
+ shader_atomic_counters),
+ NULL);
+ add_function("atomicCounterDecrement",
+ _atomic_op("__intrinsic_atomic_predecrement",
+ shader_atomic_counters),
+ NULL);
+
#undef F
#undef FI
#undef FIU
@@ -1994,8 +2125,6 @@ builtin_builder::add_function(const char *name, ...)
if (sig == NULL)
break;
- sig->is_defined = true;
-
if (false) {
exec_list stuff;
stuff.push_tail(sig);
@@ -2093,7 +2222,13 @@ builtin_builder::new_sig(const glsl_type *return_type,
#define MAKE_SIG(return_type, avail, ...) \
ir_function_signature *sig = \
new_sig(return_type, avail, __VA_ARGS__); \
- ir_factory body(&sig->body, mem_ctx);
+ ir_factory body(&sig->body, mem_ctx); \
+ sig->is_defined = true;
+
+#define MAKE_INTRINSIC(return_type, avail, ...) \
+ ir_function_signature *sig = \
+ new_sig(return_type, avail, __VA_ARGS__); \
+ sig->is_intrinsic = true;
ir_function_signature *
builtin_builder::unop(builtin_available_predicate avail,
@@ -2185,6 +2320,26 @@ builtin_builder::asin_expr(ir_variable *x)
mul(abs(x), imm(-0.03102955f))))))))));
}
+ir_call *
+builtin_builder::call(ir_function *f, ir_variable *ret, exec_list params)
+{
+ exec_list actual_params;
+
+ foreach_iter(exec_list_iterator, it, params) {
+ ir_variable *var = ((ir_instruction *)it.get())->as_variable();
+ actual_params.push_tail(var_ref(var));
+ }
+
+ ir_function_signature *sig =
+ f->exact_matching_signature(NULL, &actual_params);
+ if (!sig)
+ return NULL;
+
+ ir_dereference_variable *deref =
+ (sig->return_type->is_void() ? NULL : var_ref(ret));
+
+ return new(mem_ctx) ir_call(sig, deref, &actual_params);
+}
ir_function_signature *
builtin_builder::_asin(const glsl_type *type)
@@ -3347,11 +3502,21 @@ builtin_builder::_texture(ir_texture_opcode opcode,
if (flags & TEX_PROJECT)
tex->projector = swizzle(P, coord_type->vector_elements - 1, 1);
- /* The shadow comparitor is normally in the Z component, but a few types
- * have sufficiently large coordinates that it's in W.
- */
- if (sampler_type->sampler_shadow)
- tex->shadow_comparitor = swizzle(P, MAX2(coord_size, SWIZZLE_Z), 1);
+ if (sampler_type->sampler_shadow) {
+ if (opcode == ir_tg4) {
+ /* gather has refz as a separate parameter, immediately after the
+ * coordinate
+ */
+ ir_variable *refz = in_var(glsl_type::float_type, "refz");
+ sig->parameters.push_tail(refz);
+ tex->shadow_comparitor = var_ref(refz);
+ } else {
+ /* The shadow comparitor is normally in the Z component, but a few types
+ * have sufficiently large coordinates that it's in W.
+ */
+ tex->shadow_comparitor = swizzle(P, MAX2(coord_size, SWIZZLE_Z), 1);
+ }
+ }
if (opcode == ir_txl) {
ir_variable *lod = in_var(glsl_type::float_type, "lod");
@@ -3367,14 +3532,23 @@ builtin_builder::_texture(ir_texture_opcode opcode,
tex->lod_info.grad.dPdy = var_ref(dPdy);
}
- if (flags & TEX_OFFSET) {
+ if (flags & (TEX_OFFSET | TEX_OFFSET_NONCONST)) {
int offset_size = coord_size - (sampler_type->sampler_array ? 1 : 0);
ir_variable *offset =
- new(mem_ctx) ir_variable(glsl_type::ivec(offset_size), "offset", ir_var_const_in);
+ new(mem_ctx) ir_variable(glsl_type::ivec(offset_size), "offset",
+ (flags & TEX_OFFSET) ? ir_var_const_in : ir_var_function_in);
sig->parameters.push_tail(offset);
tex->offset = var_ref(offset);
}
+ if (flags & TEX_OFFSET_ARRAY) {
+ ir_variable *offsets =
+ new(mem_ctx) ir_variable(glsl_type::get_array_instance(glsl_type::ivec2_type, 4),
+ "offsets", ir_var_const_in);
+ sig->parameters.push_tail(offsets);
+ tex->offset = var_ref(offsets);
+ }
+
if (opcode == ir_tg4) {
if (flags & TEX_COMPONENT) {
ir_variable *component =
@@ -3793,6 +3967,29 @@ builtin_builder::_mulExtended(const glsl_type *type)
return sig;
}
+
+ir_function_signature *
+builtin_builder::_atomic_intrinsic(builtin_available_predicate avail)
+{
+ ir_variable *counter = in_var(glsl_type::atomic_uint_type, "counter");
+ MAKE_INTRINSIC(glsl_type::uint_type, avail, 1, counter);
+ return sig;
+}
+
+ir_function_signature *
+builtin_builder::_atomic_op(const char *intrinsic,
+ builtin_available_predicate avail)
+{
+ ir_variable *counter = in_var(glsl_type::atomic_uint_type, "atomic_counter");
+ MAKE_SIG(glsl_type::uint_type, avail, 1, counter);
+
+ ir_variable *retval = body.make_temp(glsl_type::uint_type, "atomic_retval");
+ body.emit(call(shader->symbols->get_function(intrinsic), retval,
+ sig->parameters));
+ body.emit(ret(retval));
+ return sig;
+}
+
/** @} */
/******************************************************************************/
diff --git a/mesalib/src/glsl/builtin_type_macros.h b/mesalib/src/glsl/builtin_type_macros.h
index fec38da12..263fd83ff 100644
--- a/mesalib/src/glsl/builtin_type_macros.h
+++ b/mesalib/src/glsl/builtin_type_macros.h
@@ -110,6 +110,8 @@ DECL_TYPE(sampler2DRectShadow, GL_SAMPLER_2D_RECT_SHADOW, GLSL_SAMPLER
DECL_TYPE(samplerExternalOES, GL_SAMPLER_EXTERNAL_OES, GLSL_SAMPLER_DIM_EXTERNAL, 0, 0, GLSL_TYPE_FLOAT)
+DECL_TYPE(atomic_uint, GL_UNSIGNED_INT_ATOMIC_COUNTER, GLSL_TYPE_ATOMIC_UINT, 1, 1)
+
STRUCT_TYPE(gl_DepthRangeParameters)
STRUCT_TYPE(gl_PointParameters)
STRUCT_TYPE(gl_MaterialParameters)
diff --git a/mesalib/src/glsl/builtin_types.cpp b/mesalib/src/glsl/builtin_types.cpp
index 1a5e5a190..92e386057 100644
--- a/mesalib/src/glsl/builtin_types.cpp
+++ b/mesalib/src/glsl/builtin_types.cpp
@@ -203,6 +203,8 @@ const static struct builtin_type_versions {
T(sampler2DRectShadow, 140, 999)
T(struct_gl_DepthRangeParameters, 110, 100)
+
+ T(atomic_uint, 420, 999)
};
const glsl_type *const deprecated_types[] = {
@@ -284,5 +286,9 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
if (state->OES_texture_3D_enable) {
add_type(symbols, glsl_type::sampler3D_type);
}
+
+ if (state->ARB_shader_atomic_counters_enable) {
+ add_type(symbols, glsl_type::atomic_uint_type);
+ }
}
/** @} */
diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp
index 018daf67f..7a3505ace 100644
--- a/mesalib/src/glsl/builtin_variables.cpp
+++ b/mesalib/src/glsl/builtin_variables.cpp
@@ -638,6 +638,21 @@ builtin_variable_generator::generate_constants()
*/
add_const("gl_MaxTextureCoords", state->Const.MaxTextureCoords);
}
+
+ if (state->ARB_shader_atomic_counters_enable) {
+ add_const("gl_MaxVertexAtomicCounters",
+ state->Const.MaxVertexAtomicCounters);
+ add_const("gl_MaxGeometryAtomicCounters",
+ state->Const.MaxGeometryAtomicCounters);
+ add_const("gl_MaxFragmentAtomicCounters",
+ state->Const.MaxFragmentAtomicCounters);
+ add_const("gl_MaxCombinedAtomicCounters",
+ state->Const.MaxCombinedAtomicCounters);
+ add_const("gl_MaxAtomicCounterBindings",
+ state->Const.MaxAtomicBufferBindings);
+ add_const("gl_MaxTessControlAtomicCounters", 0);
+ add_const("gl_MaxTessEvaluationAtomicCounters", 0);
+ }
}
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index 02100ab0c..86f3cd5aa 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -1254,6 +1254,9 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
if (extensions->ARB_texture_gather)
add_builtin_define(parser, "GL_ARB_texture_gather", 1);
+
+ if (extensions->ARB_shader_atomic_counters)
+ add_builtin_define(parser, "GL_ARB_shader_atomic_counters", 1);
}
}
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index 0a0708e95..14420f8a3 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -66,14 +66,8 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
*/
if (state->es_shader)
return strcmp(s1, s2);
- else {
-#if defined(_MSC_VER)
- /* MSVC doesn't have a strcasecmp() function; instead it has _stricmp. */
- return _stricmp(s1, s2);
-#else
+ else
return strcasecmp(s1, s2);
-#endif
- }
}
%}
@@ -1308,29 +1302,25 @@ layout_qualifier_id:
{
memset(& $$, 0, sizeof($$));
- if (state->has_explicit_attrib_location()) {
- if (match_layout_qualifier("location", $1, state) == 0) {
- $$.flags.q.explicit_location = 1;
+ if (match_layout_qualifier("location", $1, state) == 0) {
+ $$.flags.q.explicit_location = 1;
- if ($3 >= 0) {
- $$.location = $3;
- } else {
- _mesa_glsl_error(& @3, state,
- "invalid location %d specified", $3);
- YYERROR;
- }
+ if ($3 >= 0) {
+ $$.location = $3;
+ } else {
+ _mesa_glsl_error(& @3, state, "invalid location %d specified", $3);
+ YYERROR;
}
+ }
- if (match_layout_qualifier("index", $1, state) == 0) {
- $$.flags.q.explicit_index = 1;
+ if (match_layout_qualifier("index", $1, state) == 0) {
+ $$.flags.q.explicit_index = 1;
- if ($3 >= 0) {
- $$.index = $3;
- } else {
- _mesa_glsl_error(& @3, state,
- "invalid index %d specified", $3);
- YYERROR;
- }
+ if ($3 >= 0) {
+ $$.index = $3;
+ } else {
+ _mesa_glsl_error(& @3, state, "invalid index %d specified", $3);
+ YYERROR;
}
}
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index be17109e1..77e8816c4 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -118,6 +118,12 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->Const.MaxGeometryTotalOutputComponents = ctx->Const.MaxGeometryTotalOutputComponents;
this->Const.MaxGeometryUniformComponents = ctx->Const.GeometryProgram.MaxUniformComponents;
+ this->Const.MaxVertexAtomicCounters = ctx->Const.VertexProgram.MaxAtomicCounters;
+ this->Const.MaxGeometryAtomicCounters = ctx->Const.GeometryProgram.MaxAtomicCounters;
+ this->Const.MaxFragmentAtomicCounters = ctx->Const.FragmentProgram.MaxAtomicCounters;
+ this->Const.MaxCombinedAtomicCounters = ctx->Const.MaxCombinedAtomicCounters;
+ this->Const.MaxAtomicBufferBindings = ctx->Const.MaxAtomicBufferBindings;
+
this->current_function = NULL;
this->toplevel_ir = NULL;
this->found_return = false;
@@ -533,6 +539,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = {
EXT(AMD_vertex_shader_layer, true, false, AMD_vertex_shader_layer),
EXT(EXT_shader_integer_mix, true, true, EXT_shader_integer_mix),
EXT(ARB_texture_gather, true, false, ARB_texture_gather),
+ EXT(ARB_shader_atomic_counters, true, false, ARB_shader_atomic_counters),
};
#undef EXT
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index a67438412..f22dac355 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -69,6 +69,10 @@ typedef struct YYLTYPE {
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
+extern void _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
+ const char *fmt, ...);
+
+
struct _mesa_glsl_parse_state {
_mesa_glsl_parse_state(struct gl_context *_ctx, GLenum target,
void *mem_ctx);
@@ -121,6 +125,22 @@ struct _mesa_glsl_parse_state {
return check_version(130, 300, locp, "bit-wise operations are forbidden");
}
+ bool check_explicit_attrib_location_allowed(YYLTYPE *locp,
+ const ir_variable *var)
+ {
+ if (!this->has_explicit_attrib_location()) {
+ const char *const requirement = this->es_shader
+ ? "GLSL ES 300"
+ : "GL_ARB_explicit_attrib_location extension or GLSL 330";
+
+ _mesa_glsl_error(locp, this, "%s explicit location requires %s",
+ mode_string(var), requirement);
+ return false;
+ }
+
+ return true;
+ }
+
bool has_explicit_attrib_location() const
{
return ARB_explicit_attrib_location_enable || is_version(330, 300);
@@ -229,6 +249,13 @@ struct _mesa_glsl_parse_state {
unsigned MaxGeometryOutputVertices;
unsigned MaxGeometryTotalOutputComponents;
unsigned MaxGeometryUniformComponents;
+
+ /* ARB_shader_atomic_counters */
+ unsigned MaxVertexAtomicCounters;
+ unsigned MaxGeometryAtomicCounters;
+ unsigned MaxFragmentAtomicCounters;
+ unsigned MaxCombinedAtomicCounters;
+ unsigned MaxAtomicBufferBindings;
} Const;
/**
@@ -325,6 +352,8 @@ struct _mesa_glsl_parse_state {
bool ARB_shading_language_420pack_warn;
bool EXT_shader_integer_mix_enable;
bool EXT_shader_integer_mix_warn;
+ bool ARB_shader_atomic_counters_enable;
+ bool ARB_shader_atomic_counters_warn;
/*@}*/
/** Extensions supported by the OpenGL implementation. */
@@ -363,9 +392,6 @@ do { \
(Current).source = 0; \
} while (0)
-extern void _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
- const char *fmt, ...);
-
/**
* Emit a warning to the shader log
*
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index bc8d87f5f..f74013096 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -168,6 +168,24 @@ glsl_type::contains_integer() const
}
}
+bool
+glsl_type::contains_opaque() const {
+ switch (base_type) {
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_ATOMIC_UINT:
+ return true;
+ case GLSL_TYPE_ARRAY:
+ return element_type()->contains_opaque();
+ case GLSL_TYPE_STRUCT:
+ for (unsigned int i = 0; i < length; i++) {
+ if (fields.structure[i].type->contains_opaque())
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
gl_texture_index
glsl_type::sampler_index() const
@@ -601,6 +619,7 @@ glsl_type::component_slots() const
return this->length * this->fields.array->component_slots();
case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_ATOMIC_UINT:
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
break;
@@ -889,6 +908,7 @@ glsl_type::count_attribute_slots() const
return this->length * this->fields.array->count_attribute_slots();
case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_ATOMIC_UINT:
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
break;
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 4b5b6efb3..fdb1f3a6e 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -53,6 +53,7 @@ enum glsl_base_type {
GLSL_TYPE_FLOAT,
GLSL_TYPE_BOOL,
GLSL_TYPE_SAMPLER,
+ GLSL_TYPE_ATOMIC_UINT,
GLSL_TYPE_STRUCT,
GLSL_TYPE_INTERFACE,
GLSL_TYPE_ARRAY,
@@ -441,6 +442,32 @@ struct glsl_type {
}
/**
+ * Return the amount of atomic counter storage required for a type.
+ */
+ unsigned atomic_size() const
+ {
+ if (base_type == GLSL_TYPE_ATOMIC_UINT)
+ return ATOMIC_COUNTER_SIZE;
+ else if (is_array())
+ return length * element_type()->atomic_size();
+ else
+ return 0;
+ }
+
+ /**
+ * Return whether a type contains any atomic counters.
+ */
+ bool contains_atomic() const
+ {
+ return atomic_size();
+ }
+
+ /**
+ * Return whether a type contains any opaque types.
+ */
+ bool contains_opaque() const;
+
+ /**
* Query the full type of a matrix row
*
* \return
@@ -468,7 +495,6 @@ struct glsl_type {
: error_type;
}
-
/**
* Get the type of a structure field
*
@@ -478,13 +504,11 @@ struct glsl_type {
*/
const glsl_type *field_type(const char *name) const;
-
/**
* Get the location of a filed within a record type
*/
int field_index(const char *name) const;
-
/**
* Query the number of elements in an array type
*
@@ -499,6 +523,14 @@ struct glsl_type {
}
/**
+ * Query whether the array size for all dimensions has been declared.
+ */
+ bool is_unsized_array() const
+ {
+ return is_array() && length == 0;
+ }
+
+ /**
* Return the number of coordinate components needed for this sampler type.
*
* This is based purely on the sampler's dimensionality. For example, this
diff --git a/mesalib/src/glsl/hir_field_selection.cpp b/mesalib/src/glsl/hir_field_selection.cpp
index 08be74365..1e92c89ae 100644
--- a/mesalib/src/glsl/hir_field_selection.cpp
+++ b/mesalib/src/glsl/hir_field_selection.cpp
@@ -72,7 +72,7 @@ _mesa_ast_field_selection_to_hir(const ast_expression *expr,
_mesa_glsl_error(&loc, state, "length method takes no arguments");
if (op->type->is_array()) {
- if (op->type->array_size() == 0)
+ if (op->type->is_unsized_array())
_mesa_glsl_error(&loc, state, "length called on unsized array");
result = new(ctx) ir_constant(op->type->array_size());
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index c682e3ed5..1b4973612 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1586,7 +1586,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
ir_variable_mode mode)
: max_array_access(0), max_ifc_array_access(NULL),
read_only(false), centroid(false), invariant(false),
- mode(mode), interpolation(INTERP_QUALIFIER_NONE)
+ mode(mode), interpolation(INTERP_QUALIFIER_NONE), atomic()
{
this->ir_type = ir_type_variable;
this->type = type;
@@ -1647,8 +1647,8 @@ ir_variable::determine_interpolation_mode(bool flat_shade)
ir_function_signature::ir_function_signature(const glsl_type *return_type,
builtin_available_predicate b)
- : return_type(return_type), is_defined(false), builtin_avail(b),
- _function(NULL)
+ : return_type(return_type), is_defined(false), is_intrinsic(false),
+ builtin_avail(b), _function(NULL)
{
this->ir_type = ir_type_function_signature;
this->origin = NULL;
@@ -1891,3 +1891,46 @@ vertices_per_prim(GLenum prim)
return 3;
}
}
+
+/**
+ * Generate a string describing the mode of a variable
+ */
+const char *
+mode_string(const ir_variable *var)
+{
+ switch (var->mode) {
+ case ir_var_auto:
+ return (var->read_only) ? "global constant" : "global variable";
+
+ case ir_var_uniform:
+ return "uniform";
+
+ case ir_var_shader_in:
+ return "shader input";
+
+ case ir_var_shader_out:
+ return "shader output";
+
+ case ir_var_function_in:
+ case ir_var_const_in:
+ return "function input";
+
+ case ir_var_function_out:
+ return "function output";
+
+ case ir_var_function_inout:
+ return "function inout";
+
+ case ir_var_system_value:
+ return "shader input";
+
+ case ir_var_temporary:
+ return "compiler temporary";
+
+ case ir_var_mode_count:
+ break;
+ }
+
+ assert(!"Should not get here.");
+ return "invalid variable";
+}
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 8d5bec9c1..5b30fe59b 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -639,6 +639,14 @@ public:
int binding;
/**
+ * Location an atomic counter is stored at.
+ */
+ struct {
+ unsigned buffer_index;
+ unsigned offset;
+ } atomic;
+
+ /**
* Built-in state that backs this uniform
*
* Once set at variable creation, \c state_slots must remain invariant.
@@ -779,6 +787,12 @@ public:
/** Whether or not this function signature is a built-in. */
bool is_builtin() const;
+ /**
+ * Whether or not this function is an intrinsic to be implemented
+ * by the driver.
+ */
+ bool is_intrinsic;
+
/** Whether or not a built-in is available for this shader. */
bool is_builtin_available(const _mesa_glsl_parse_state *state) const;
@@ -2292,6 +2306,9 @@ extern char *
prototype_string(const glsl_type *return_type, const char *name,
exec_list *parameters);
+const char *
+mode_string(const ir_variable *var);
+
extern "C" {
#endif /* __cplusplus */
diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp
index 105f9063a..b0f173a62 100644
--- a/mesalib/src/glsl/ir_clone.cpp
+++ b/mesalib/src/glsl/ir_clone.cpp
@@ -57,6 +57,8 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const
var->location = this->location;
var->index = this->index;
var->binding = this->binding;
+ var->atomic.buffer_index = this->atomic.buffer_index;
+ var->atomic.offset = this->atomic.offset;
var->warn_extension = this->warn_extension;
var->origin_upper_left = this->origin_upper_left;
var->pixel_center_integer = this->pixel_center_integer;
@@ -395,6 +397,7 @@ ir_constant::clone(void *mem_ctx, struct hash_table *ht) const
}
case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_ATOMIC_UINT:
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
case GLSL_TYPE_INTERFACE:
diff --git a/mesalib/src/glsl/ir_uniform.h b/mesalib/src/glsl/ir_uniform.h
index 8198c4819..13faab7c0 100644
--- a/mesalib/src/glsl/ir_uniform.h
+++ b/mesalib/src/glsl/ir_uniform.h
@@ -166,6 +166,13 @@ struct gl_uniform_storage {
bool row_major;
/** @} */
+
+ /**
+ * Index within gl_shader_program::AtomicBuffers[] of the atomic
+ * counter buffer this uniform is stored in, or -1 if this is not
+ * an atomic counter.
+ */
+ int atomic_buffer_index;
};
#ifdef __cplusplus
diff --git a/mesalib/src/glsl/link_functions.cpp b/mesalib/src/glsl/link_functions.cpp
index fd8009998..68aa62032 100644
--- a/mesalib/src/glsl/link_functions.cpp
+++ b/mesalib/src/glsl/link_functions.cpp
@@ -155,14 +155,17 @@ public:
linked_sig->replace_parameters(&formal_parameters);
- foreach_list_const(node, &sig->body) {
- const ir_instruction *const original = (ir_instruction *) node;
+ if (sig->is_defined) {
+ foreach_list_const(node, &sig->body) {
+ const ir_instruction *const original = (ir_instruction *) node;
- ir_instruction *copy = original->clone(linked, ht);
- linked_sig->body.push_tail(copy);
+ ir_instruction *copy = original->clone(linked, ht);
+ linked_sig->body.push_tail(copy);
+ }
+
+ linked_sig->is_defined = true;
}
- linked_sig->is_defined = true;
hash_table_dtor(ht);
/* Patch references inside the function to things outside the function
@@ -307,7 +310,8 @@ find_matching_signature(const char *name, const exec_list *actual_parameters,
ir_function_signature *sig =
f->matching_signature(NULL, actual_parameters);
- if ((sig == NULL) || !sig->is_defined)
+ if ((sig == NULL) ||
+ (!sig->is_defined && !sig->is_intrinsic))
continue;
/* If this function expects to bind to a built-in function and the
diff --git a/mesalib/src/glsl/link_uniform_initializers.cpp b/mesalib/src/glsl/link_uniform_initializers.cpp
index 3f6671047..786aaf0b4 100644
--- a/mesalib/src/glsl/link_uniform_initializers.cpp
+++ b/mesalib/src/glsl/link_uniform_initializers.cpp
@@ -69,6 +69,7 @@ copy_constant_to_storage(union gl_constant_value *storage,
break;
case GLSL_TYPE_ARRAY:
case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_ATOMIC_UINT:
case GLSL_TYPE_INTERFACE:
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index ea71b3063..0a15739c2 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -513,6 +513,7 @@ private:
this->uniforms[id].num_driver_storage = 0;
this->uniforms[id].driver_storage = NULL;
this->uniforms[id].storage = this->values;
+ this->uniforms[id].atomic_buffer_index = -1;
if (this->ubo_block_index != -1) {
this->uniforms[id].block_index = this->ubo_block_index;
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index d8f655c39..49bb142a8 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -558,29 +558,6 @@ validate_geometry_shader_executable(struct gl_shader_program *prog,
/**
- * Generate a string describing the mode of a variable
- */
-static const char *
-mode_string(const ir_variable *var)
-{
- switch (var->mode) {
- case ir_var_auto:
- return (var->read_only) ? "global constant" : "global variable";
-
- case ir_var_uniform: return "uniform";
- case ir_var_shader_in: return "shader input";
- case ir_var_shader_out: return "shader output";
-
- case ir_var_const_in:
- case ir_var_temporary:
- default:
- assert(!"Should not get here.");
- return "invalid variable";
- }
-}
-
-
-/**
* Perform validation of global variables used across multiple shaders
*/
void
@@ -1108,7 +1085,7 @@ private:
*/
static void fixup_type(const glsl_type **type, unsigned max_array_access)
{
- if ((*type)->is_array() && (*type)->length == 0) {
+ if ((*type)->is_unsized_array()) {
*type = glsl_type::get_array_instance((*type)->fields.array,
max_array_access + 1);
assert(*type != NULL);
@@ -1123,7 +1100,7 @@ private:
{
for (unsigned i = 0; i < type->length; i++) {
const glsl_type *elem_type = type->fields.structure[i].type;
- if (elem_type->is_array() && elem_type->length == 0)
+ if (elem_type->is_unsized_array())
return true;
}
return false;
diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp
index 37b2f02c6..a07e153ae 100644
--- a/mesalib/src/glsl/opt_algebraic.cpp
+++ b/mesalib/src/glsl/opt_algebraic.cpp
@@ -32,8 +32,11 @@
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "ir_optimization.h"
+#include "ir_builder.h"
#include "glsl_types.h"
+using namespace ir_builder;
+
namespace {
/**
@@ -194,7 +197,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
{
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() <= 4);
@@ -217,12 +219,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
switch (op_expr[0]->operation) {
case ir_unop_abs:
case ir_unop_neg:
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_abs,
- ir->type,
- op_expr[0]->operands[0],
- NULL);
- return swizzle_if_required(ir, temp);
+ return abs(op_expr[0]->operands[0]);
default:
break;
}
@@ -233,8 +230,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
break;
if (op_expr[0]->operation == ir_unop_neg) {
- this->progress = true;
- return swizzle_if_required(ir, op_expr[0]->operands[0]);
+ return op_expr[0]->operands[0];
}
break;
@@ -261,7 +257,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
}
if (new_op != ir_unop_logic_not) {
- this->progress = true;
return new(mem_ctx) ir_expression(new_op,
ir->type,
op_expr[0]->operands[0],
@@ -272,14 +267,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
}
case ir_binop_add:
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[1]);
- }
- if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
+ if (is_vec_zero(op_const[0]))
+ return ir->operands[1];
+ if (is_vec_zero(op_const[1]))
+ return ir->operands[0];
/* Reassociate addition of constants so that we can do constant
* folding.
@@ -291,50 +282,25 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
break;
case ir_binop_sub:
- if (is_vec_zero(op_const[0])) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_neg,
- ir->operands[1]->type,
- ir->operands[1],
- NULL);
- return swizzle_if_required(ir, temp);
- }
- if (is_vec_zero(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
+ if (is_vec_zero(op_const[0]))
+ return neg(ir->operands[1]);
+ if (is_vec_zero(op_const[1]))
+ return ir->operands[0];
break;
case ir_binop_mul:
- if (is_vec_one(op_const[0])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[1]);
- }
- if (is_vec_one(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
- }
+ if (is_vec_one(op_const[0]))
+ return ir->operands[1];
+ if (is_vec_one(op_const[1]))
+ return ir->operands[0];
- if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
- this->progress = true;
+ if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1]))
return ir_constant::zero(ir, ir->type);
- }
- if (is_vec_negative_one(op_const[0])) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_neg,
- ir->operands[1]->type,
- ir->operands[1],
- NULL);
- return swizzle_if_required(ir, temp);
- }
- if (is_vec_negative_one(op_const[1])) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_neg,
- ir->operands[0]->type,
- ir->operands[0],
- NULL);
- return swizzle_if_required(ir, temp);
- }
+
+ if (is_vec_negative_one(op_const[0]))
+ return neg(ir->operands[1]);
+ if (is_vec_negative_one(op_const[1]))
+ return neg(ir->operands[0]);
/* Reassociate multiplication of constants so that we can do
@@ -349,26 +315,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
case ir_binop_div:
if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_rcp,
+ return new(mem_ctx) ir_expression(ir_unop_rcp,
ir->operands[1]->type,
ir->operands[1],
NULL);
- return swizzle_if_required(ir, temp);
- }
- if (is_vec_one(op_const[1])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
}
+ if (is_vec_one(op_const[1]))
+ return ir->operands[0];
break;
case ir_binop_dot:
- if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
- this->progress = true;
+ if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1]))
return ir_constant::zero(mem_ctx, ir->type);
- }
+
if (is_vec_basis(op_const[0])) {
- this->progress = true;
unsigned component = 0;
for (unsigned c = 0; c < op_const[0]->type->vector_elements; c++) {
if (op_const[0]->value.f[c] == 1.0)
@@ -377,7 +337,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
return new(mem_ctx) ir_swizzle(ir->operands[1], component, 0, 0, 0, 1);
}
if (is_vec_basis(op_const[1])) {
- this->progress = true;
unsigned component = 0;
for (unsigned c = 0; c < op_const[1]->type->vector_elements; c++) {
if (op_const[1]->value.f[c] == 1.0)
@@ -387,46 +346,52 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
}
break;
+ case ir_binop_rshift:
+ case ir_binop_lshift:
+ /* 0 >> x == 0 */
+ if (is_vec_zero(op_const[0]))
+ return ir->operands[0];
+ /* x >> 0 == x */
+ if (is_vec_zero(op_const[1]))
+ return ir->operands[0];
+ break;
+
case ir_binop_logic_and:
/* FINISHME: Also simplify (a && a) to (a). */
if (is_vec_one(op_const[0])) {
- this->progress = true;
return ir->operands[1];
} else if (is_vec_one(op_const[1])) {
- this->progress = true;
return ir->operands[0];
} else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
- this->progress = true;
return ir_constant::zero(mem_ctx, ir->type);
+ } else if (op_expr[0] && op_expr[0]->operation == ir_unop_logic_not &&
+ op_expr[1] && op_expr[1]->operation == ir_unop_logic_not) {
+ /* De Morgan's Law:
+ * (not A) and (not B) === not (A or B)
+ */
+ return logic_not(logic_or(op_expr[0]->operands[0],
+ op_expr[1]->operands[0]));
}
break;
case ir_binop_logic_xor:
/* FINISHME: Also simplify (a ^^ a) to (false). */
if (is_vec_zero(op_const[0])) {
- this->progress = true;
return ir->operands[1];
} else if (is_vec_zero(op_const[1])) {
- this->progress = true;
return ir->operands[0];
} else if (is_vec_one(op_const[0])) {
- this->progress = true;
- return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
- ir->operands[1], NULL);
+ return logic_not(ir->operands[1]);
} else if (is_vec_one(op_const[1])) {
- this->progress = true;
- return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
- ir->operands[0], NULL);
+ return logic_not(ir->operands[0]);
}
break;
case ir_binop_logic_or:
/* FINISHME: Also simplify (a || a) to (a). */
if (is_vec_zero(op_const[0])) {
- this->progress = true;
return ir->operands[1];
} else if (is_vec_zero(op_const[1])) {
- this->progress = true;
return ir->operands[0];
} else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
ir_constant_data data;
@@ -434,16 +399,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
for (unsigned i = 0; i < 16; i++)
data.b[i] = true;
- this->progress = true;
return new(mem_ctx) ir_constant(ir->type, &data);
+ } else if (op_expr[0] && op_expr[0]->operation == ir_unop_logic_not &&
+ op_expr[1] && op_expr[1]->operation == ir_unop_logic_not) {
+ /* De Morgan's Law:
+ * (not A) or (not B) === not (A and B)
+ */
+ return logic_not(logic_and(op_expr[0]->operands[0],
+ op_expr[1]->operands[0]));
}
break;
case ir_unop_rcp:
- if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
- this->progress = true;
+ if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp)
return op_expr[0]->operands[0];
- }
/* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
* backends, except that some backends will have done sqrt ->
@@ -452,12 +421,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
/* As far as we know, all backends are OK with rsq. */
if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
- this->progress = true;
- temp = new(mem_ctx) ir_expression(ir_unop_rsq,
- op_expr[0]->operands[0]->type,
- op_expr[0]->operands[0],
- NULL);
- return swizzle_if_required(ir, temp);
+ return rsq(op_expr[0]->operands[0]);
}
break;
@@ -465,11 +429,9 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
case ir_triop_lrp:
/* Operands are (x, y, a). */
if (is_vec_zero(op_const[2])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[0]);
+ return ir->operands[0];
} else if (is_vec_one(op_const[2])) {
- this->progress = true;
- return swizzle_if_required(ir, ir->operands[1]);
+ return ir->operands[1];
}
break;
@@ -490,7 +452,17 @@ ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
if (!expr || expr->operation == ir_quadop_vector)
return;
- *rvalue = handle_expression(expr);
+ ir_rvalue *new_rvalue = handle_expression(expr);
+ if (new_rvalue == *rvalue)
+ return;
+
+ /* If the expr used to be some vec OP scalar returning a vector, and the
+ * optimization gave us back a scalar, we still need to turn it into a
+ * vector.
+ */
+ *rvalue = swizzle_if_required(expr, new_rvalue);
+
+ this->progress = true;
}
bool
diff --git a/mesalib/src/glsl/opt_array_splitting.cpp b/mesalib/src/glsl/opt_array_splitting.cpp
index 34ac836ae..c7c5f6712 100644
--- a/mesalib/src/glsl/opt_array_splitting.cpp
+++ b/mesalib/src/glsl/opt_array_splitting.cpp
@@ -132,7 +132,7 @@ ir_array_reference_visitor::get_variable_entry(ir_variable *var)
/* If the array hasn't been sized yet, we can't split it. After
* linking, this should be resolved.
*/
- if (var->type->is_array() && var->type->length == 0)
+ if (var->type->is_unsized_array())
return NULL;
foreach_iter(exec_list_iterator, iter, this->variable_list) {
diff --git a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
index 7e8cd4372..b336bc0a8 100644
--- a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
+++ b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
@@ -42,9 +42,11 @@
* If any texture coordinate slots can be eliminated, the gl_TexCoord array is
* broken down into separate vec4 variables with locations equal to
* VARYING_SLOT_TEX0 + i.
+ *
+ * The same is done for the gl_FragData fragment shader output.
*/
-#include "main/imports.h" /* for snprintf */
+#include "main/core.h" /* for snprintf and ARRAY_SIZE */
#include "ir.h"
#include "ir_rvalue_visitor.h"
#include "ir_optimization.h"
@@ -60,10 +62,14 @@ namespace {
class varying_info_visitor : public ir_hierarchical_visitor {
public:
/* "mode" can be either ir_var_shader_in or ir_var_shader_out */
- varying_info_visitor(ir_variable_mode mode)
+ varying_info_visitor(ir_variable_mode mode, bool find_frag_outputs = false)
: lower_texcoord_array(true),
texcoord_array(NULL),
texcoord_usage(0),
+ find_frag_outputs(find_frag_outputs),
+ lower_fragdata_array(true),
+ fragdata_array(NULL),
+ fragdata_usage(0),
color_usage(0),
tfeedback_color_usage(0),
fog(NULL),
@@ -79,8 +85,27 @@ public:
{
ir_variable *var = ir->variable_referenced();
- if (var && var->mode == this->mode &&
- var->location == VARYING_SLOT_TEX0) {
+ if (!var || var->mode != this->mode)
+ return visit_continue;
+
+ if (this->find_frag_outputs && var->location == FRAG_RESULT_DATA0) {
+ this->fragdata_array = var;
+
+ ir_constant *index = ir->array_index->as_constant();
+ if (index == NULL) {
+ /* This is variable indexing. */
+ this->fragdata_usage |= (1 << var->type->array_size()) - 1;
+ this->lower_fragdata_array = false;
+ }
+ else {
+ this->fragdata_usage |= 1 << index->get_uint_component(0);
+ }
+
+ /* Don't visit the leaves of ir_dereference_array. */
+ return visit_continue_with_parent;
+ }
+
+ if (!this->find_frag_outputs && var->location == VARYING_SLOT_TEX0) {
this->texcoord_array = var;
ir_constant *index = ir->array_index->as_constant();
@@ -105,8 +130,17 @@ public:
{
ir_variable *var = ir->variable_referenced();
- if (var->mode == this->mode && var->type->is_array() &&
- var->location == VARYING_SLOT_TEX0) {
+ if (var->mode != this->mode || !var->type->is_array())
+ return visit_continue;
+
+ if (this->find_frag_outputs && var->location == FRAG_RESULT_DATA0) {
+ /* This is a whole array dereference. */
+ this->fragdata_usage |= (1 << var->type->array_size()) - 1;
+ this->lower_fragdata_array = false;
+ return visit_continue;
+ }
+
+ if (!this->find_frag_outputs && var->location == VARYING_SLOT_TEX0) {
/* This is a whole array dereference like "gl_TexCoord = x;",
* there's probably no point in lowering that.
*/
@@ -121,6 +155,10 @@ public:
if (var->mode != this->mode)
return visit_continue;
+ /* Nothing to do here for fragment outputs. */
+ if (this->find_frag_outputs)
+ return visit_continue;
+
/* Handle colors and fog. */
switch (var->location) {
case VARYING_SLOT_COL0:
@@ -185,12 +223,20 @@ public:
if (!this->texcoord_array) {
this->lower_texcoord_array = false;
}
+ if (!this->fragdata_array) {
+ this->lower_fragdata_array = false;
+ }
}
bool lower_texcoord_array;
ir_variable *texcoord_array;
unsigned texcoord_usage; /* bitmask */
+ bool find_frag_outputs; /* false if it's looking for varyings */
+ bool lower_fragdata_array;
+ ir_variable *fragdata_array;
+ unsigned fragdata_usage; /* bitmask */
+
ir_variable *color[2];
ir_variable *backcolor[2];
unsigned color_usage; /* bitmask */
@@ -222,6 +268,7 @@ public:
{
void *const ctx = ir;
+ memset(this->new_fragdata, 0, sizeof(this->new_fragdata));
memset(this->new_texcoord, 0, sizeof(this->new_texcoord));
memset(this->new_color, 0, sizeof(this->new_color));
memset(this->new_backcolor, 0, sizeof(this->new_backcolor));
@@ -236,31 +283,16 @@ public:
* occurences of gl_TexCoord will be replaced with.
*/
if (info->lower_texcoord_array) {
- for (int i = MAX_TEXTURE_COORD_UNITS-1; i >= 0; i--) {
- if (info->texcoord_usage & (1 << i)) {
- char name[32];
-
- if (!(external_texcoord_usage & (1 << i))) {
- /* This varying is unused in the next stage. Declare
- * a temporary instead of an output. */
- snprintf(name, 32, "gl_%s_TexCoord%i_dummy", mode_str, i);
- this->new_texcoord[i] =
- new (ctx) ir_variable(glsl_type::vec4_type, name,
- ir_var_temporary);
- }
- else {
- snprintf(name, 32, "gl_%s_TexCoord%i", mode_str, i);
- this->new_texcoord[i] =
- new(ctx) ir_variable(glsl_type::vec4_type, name,
- info->mode);
- this->new_texcoord[i]->location = VARYING_SLOT_TEX0 + i;
- this->new_texcoord[i]->explicit_location = true;
- this->new_texcoord[i]->explicit_index = 0;
- }
-
- ir->head->insert_before(new_texcoord[i]);
- }
- }
+ prepare_array(ir, this->new_texcoord, ARRAY_SIZE(this->new_texcoord),
+ VARYING_SLOT_TEX0, "TexCoord", mode_str,
+ info->texcoord_usage, external_texcoord_usage);
+ }
+
+ /* Handle gl_FragData in the same way like gl_TexCoord. */
+ if (info->lower_fragdata_array) {
+ prepare_array(ir, this->new_fragdata, ARRAY_SIZE(this->new_fragdata),
+ FRAG_RESULT_DATA0, "FragData", mode_str,
+ info->fragdata_usage, (1 << MAX_DRAW_BUFFERS) - 1);
}
/* Create dummy variables which will replace set-but-unused color and
@@ -301,6 +333,41 @@ public:
visit_list_elements(this, ir);
}
+ void prepare_array(exec_list *ir,
+ struct ir_variable **new_var,
+ int max_elements, unsigned start_location,
+ const char *var_name, const char *mode_str,
+ unsigned usage, unsigned external_usage)
+ {
+ void *const ctx = ir;
+
+ for (int i = max_elements-1; i >= 0; i--) {
+ if (usage & (1 << i)) {
+ char name[32];
+
+ if (!(external_usage & (1 << i))) {
+ /* This varying is unused in the next stage. Declare
+ * a temporary instead of an output. */
+ snprintf(name, 32, "gl_%s_%s%i_dummy", mode_str, var_name, i);
+ new_var[i] =
+ new (ctx) ir_variable(glsl_type::vec4_type, name,
+ ir_var_temporary);
+ }
+ else {
+ snprintf(name, 32, "gl_%s_%s%i", mode_str, var_name, i);
+ new_var[i] =
+ new(ctx) ir_variable(glsl_type::vec4_type, name,
+ this->info->mode);
+ new_var[i]->location = start_location + i;
+ new_var[i]->explicit_location = true;
+ new_var[i]->explicit_index = 0;
+ }
+
+ ir->head->insert_before(new_var[i]);
+ }
+ }
+ }
+
virtual ir_visitor_status visit(ir_variable *var)
{
/* Remove the gl_TexCoord array. */
@@ -309,6 +376,12 @@ public:
var->remove();
}
+ /* Remove the gl_FragData array. */
+ if (this->info->lower_fragdata_array &&
+ var == this->info->fragdata_array) {
+ var->remove();
+ }
+
/* Replace set-but-unused color and fog outputs with dummy variables. */
for (int i = 0; i < 2; i++) {
if (var == this->info->color[i] && this->new_color[i]) {
@@ -350,6 +423,19 @@ public:
}
}
+ /* Same for gl_FragData. */
+ if (this->info->lower_fragdata_array) {
+ /* gl_FragData[i] occurence */
+ ir_dereference_array *const da = (*rvalue)->as_dereference_array();
+
+ if (da && da->variable_referenced() == this->info->fragdata_array) {
+ unsigned i = da->array_index->as_constant()->get_uint_component(0);
+
+ *rvalue = new(ctx) ir_dereference_variable(this->new_fragdata[i]);
+ return;
+ }
+ }
+
/* Replace set-but-unused color and fog outputs with dummy variables. */
ir_dereference_variable *const dv = (*rvalue)->as_dereference_variable();
if (!dv)
@@ -392,6 +478,7 @@ public:
private:
const varying_info_visitor *info;
+ ir_variable *new_fragdata[MAX_DRAW_BUFFERS];
ir_variable *new_texcoord[MAX_TEXTURE_COORD_UNITS];
ir_variable *new_color[2];
ir_variable *new_backcolor[2];
@@ -408,6 +495,15 @@ lower_texcoord_array(exec_list *ir, const varying_info_visitor *info)
1 | 2, true);
}
+static void
+lower_fragdata_array(exec_list *ir)
+{
+ varying_info_visitor info(ir_var_shader_out, true);
+ info.get(ir, 0, NULL);
+
+ replace_varyings_visitor(ir, &info, 0, 0, 0);
+}
+
void
do_dead_builtin_varyings(struct gl_context *ctx,
@@ -415,8 +511,13 @@ do_dead_builtin_varyings(struct gl_context *ctx,
unsigned num_tfeedback_decls,
tfeedback_decl *tfeedback_decls)
{
- /* This optimization has no effect with the core context and GLES2, because
- * the built-in varyings we're eliminating here are not available there.
+ /* Lower the gl_FragData array to separate variables. */
+ if (consumer && consumer->Type == GL_FRAGMENT_SHADER) {
+ lower_fragdata_array(consumer->ir);
+ }
+
+ /* Lowering of built-in varyings has no effect with the core context and
+ * GLES2, because they are not available there.
*
* EXT_separate_shader_objects doesn't allow this optimization,
* because a program object can be bound partially (e.g. only one
diff --git a/mesalib/src/glsl/opt_function_inlining.cpp b/mesalib/src/glsl/opt_function_inlining.cpp
index 0733d5180..f8033a095 100644
--- a/mesalib/src/glsl/opt_function_inlining.cpp
+++ b/mesalib/src/glsl/opt_function_inlining.cpp
@@ -35,9 +35,9 @@
#include "program/hash_table.h"
static void
-do_sampler_replacement(exec_list *instructions,
- ir_variable *sampler,
- ir_dereference *deref);
+do_variable_replacement(exec_list *instructions,
+ ir_variable *orig,
+ ir_dereference *repl);
namespace {
@@ -123,11 +123,11 @@ ir_call::generate_inline(ir_instruction *next_ir)
ir_rvalue *param = (ir_rvalue *) param_iter.get();
/* Generate a new variable for the parameter. */
- if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
- /* For samplers, we want the inlined sampler references
- * referencing the passed in sampler variable, since that
- * will have the location information, which an assignment of
- * a sampler wouldn't. Fix it up below.
+ if (sig_param->type->contains_opaque()) {
+ /* For opaque types, we want the inlined variable references
+ * referencing the passed in variable, since that will have
+ * the location information, which an assignment of an opaque
+ * variable wouldn't. Fix it up below.
*/
parameters[i] = NULL;
} else {
@@ -169,8 +169,8 @@ ir_call::generate_inline(ir_instruction *next_ir)
visit_tree(new_ir, replace_return_with_assignment, this->return_deref);
}
- /* If any samplers were passed in, replace any deref of the sampler
- * with a deref of the sampler argument.
+ /* If any opaque types were passed in, replace any deref of the
+ * opaque variable with a deref of the argument.
*/
param_iter = this->actual_parameters.iterator();
sig_param_iter = this->callee->parameters.iterator();
@@ -178,11 +178,11 @@ ir_call::generate_inline(ir_instruction *next_ir)
ir_instruction *const param = (ir_instruction *) param_iter.get();
ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
- if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
+ if (sig_param->type->contains_opaque()) {
ir_dereference *deref = param->as_dereference();
assert(deref);
- do_sampler_replacement(&new_instructions, sig_param, deref);
+ do_variable_replacement(&new_instructions, sig_param, deref);
}
param_iter.next();
sig_param_iter.next();
@@ -268,23 +268,23 @@ ir_function_inlining_visitor::visit_enter(ir_call *ir)
/**
- * Replaces references to the "sampler" variable with a clone of "deref."
+ * Replaces references to the "orig" variable with a clone of "repl."
*
- * From the spec, samplers can appear in the tree as function
+ * From the spec, opaque types can appear in the tree as function
* (non-out) parameters and as the result of array indexing and
* structure field selection. In our builtin implementation, they
* also appear in the sampler field of an ir_tex instruction.
*/
-class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
+class ir_variable_replacement_visitor : public ir_hierarchical_visitor {
public:
- ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
+ ir_variable_replacement_visitor(ir_variable *orig, ir_dereference *repl)
{
- this->sampler = sampler;
- this->deref = deref;
+ this->orig = orig;
+ this->repl = repl;
}
- virtual ~ir_sampler_replacement_visitor()
+ virtual ~ir_variable_replacement_visitor()
{
}
@@ -296,21 +296,21 @@ public:
void replace_deref(ir_dereference **deref);
void replace_rvalue(ir_rvalue **rvalue);
- ir_variable *sampler;
- ir_dereference *deref;
+ ir_variable *orig;
+ ir_dereference *repl;
};
void
-ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
+ir_variable_replacement_visitor::replace_deref(ir_dereference **deref)
{
ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
- if (deref_var && deref_var->var == this->sampler) {
- *deref = this->deref->clone(ralloc_parent(*deref), NULL);
+ if (deref_var && deref_var->var == this->orig) {
+ *deref = this->repl->clone(ralloc_parent(*deref), NULL);
}
}
void
-ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
+ir_variable_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
{
if (!*rvalue)
return;
@@ -325,7 +325,7 @@ ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
}
ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
+ir_variable_replacement_visitor::visit_leave(ir_texture *ir)
{
replace_deref(&ir->sampler);
@@ -333,21 +333,21 @@ ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
}
ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
+ir_variable_replacement_visitor::visit_leave(ir_dereference_array *ir)
{
replace_rvalue(&ir->array);
return visit_continue;
}
ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
+ir_variable_replacement_visitor::visit_leave(ir_dereference_record *ir)
{
replace_rvalue(&ir->record);
return visit_continue;
}
ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
+ir_variable_replacement_visitor::visit_leave(ir_call *ir)
{
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param = (ir_rvalue *)iter.get();
@@ -362,11 +362,11 @@ ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
}
static void
-do_sampler_replacement(exec_list *instructions,
- ir_variable *sampler,
- ir_dereference *deref)
+do_variable_replacement(exec_list *instructions,
+ ir_variable *orig,
+ ir_dereference *repl)
{
- ir_sampler_replacement_visitor v(sampler, deref);
+ ir_variable_replacement_visitor v(orig, repl);
visit_list_elements(&v, instructions);
}
diff --git a/mesalib/src/glsl/ralloc.h b/mesalib/src/glsl/ralloc.h
index 31682d515..4581a7a4e 100644
--- a/mesalib/src/glsl/ralloc.h
+++ b/mesalib/src/glsl/ralloc.h
@@ -415,15 +415,29 @@ bool ralloc_vasprintf_append(char **str, const char *fmt, va_list args);
* which is more idiomatic in C++ than calling ralloc.
*/
#define DECLARE_RALLOC_CXX_OPERATORS(TYPE) \
+private: \
+ static void _ralloc_destructor(void *p) \
+ { \
+ reinterpret_cast<TYPE *>(p)->~TYPE(); \
+ } \
+public: \
static void* operator new(size_t size, void *mem_ctx) \
{ \
void *p = ralloc_size(mem_ctx, size); \
assert(p != NULL); \
+ if (!HAS_TRIVIAL_DESTRUCTOR(TYPE)) \
+ ralloc_set_destructor(p, _ralloc_destructor); \
return p; \
} \
\
static void operator delete(void *p) \
{ \
+ /* The object's destructor is guaranteed to have already been \
+ * called by the delete operator at this point -- Make sure it's \
+ * not called again. \
+ */ \
+ if (!HAS_TRIVIAL_DESTRUCTOR(TYPE)) \
+ ralloc_set_destructor(p, NULL); \
ralloc_free(p); \
}