* If a conversion is possible (or unnecessary), \c true is returned.
* Otherwise \c false is returned.
*/
-bool
+static bool
apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
struct _mesa_glsl_parse_state *state)
{
-1, /* ast_float_constant doesn't conv to ir_expression. */
-1, /* ast_bool_constant doesn't conv to ir_expression. */
-1, /* ast_sequence doesn't convert to ir_expression. */
+ -1, /* ast_aggregate shouldn't ever even get here. */
};
ir_rvalue *result = NULL;
ir_rvalue *op[3];
- const struct glsl_type *type; /* a temporary variable for switch cases */
+ const struct glsl_type *type, *orig_type;
bool error_emitted = false;
YYLTYPE loc;
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
+ orig_type = op[0]->type;
type = arithmetic_result_type(op[0], op[1],
(this->oper == ast_mul_assign),
state, & loc);
+ if (type != orig_type) {
+ _mesa_glsl_error(& loc, state,
+ "could not implicitly convert "
+ "%s to %s", type->name, orig_type->name);
+ type = glsl_type::error_type;
+ }
+
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
op[0], op[1]);
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
+ orig_type = op[0]->type;
type = modulus_result_type(op[0], op[1], state, &loc);
+ if (type != orig_type) {
+ _mesa_glsl_error(& loc, state,
+ "could not implicitly convert "
+ "%s to %s", type->name, orig_type->name);
+ type = glsl_type::error_type;
+ }
+
assert(operations[this->oper] == ir_binop_mod);
ir_rvalue *temp_rhs;
this->subexpressions[0]->set_is_lhs(true);
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ orig_type = op[0]->type;
type = bit_logic_result_type(op[0], op[1], this->oper, state, &loc);
+
+ if (type != orig_type) {
+ _mesa_glsl_error(& loc, state,
+ "could not implicitly convert "
+ "%s to %s", type->name, orig_type->name);
+ type = glsl_type::error_type;
+ }
+
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
error_emitted =
* therefore add instructions to the instruction list), they get dropped
* on the floor.
*/
- exec_node *previous_tail_pred = NULL;
+ exec_node *previous_tail = NULL;
YYLTYPE previous_operand_loc = loc;
foreach_list_typed (ast_node, ast, link, &this->expressions) {
/* If one of the operands of comma operator does not generate any
* code, we want to emit a warning. At each pass through the loop
- * previous_tail_pred will point to the last instruction in the
- * stream *before* processing the previous operand. Naturally,
- * instructions->tail_pred will point to the last instruction in the
- * stream *after* processing the previous operand. If the two
+ * previous_tail will point to the last instruction in the stream
+ * *before* processing the previous operand. Naturally,
+ * instructions->get_tail_raw() will point to the last instruction in
+ * the stream *after* processing the previous operand. If the two
* pointers match, then the previous operand had no effect.
*
* The warning behavior here differs slightly from GCC. GCC will
* effect, but I don't think these cases exist in GLSL. Either way,
* it would be a giant hassle to replicate that behavior.
*/
- if (previous_tail_pred == instructions->tail_pred) {
+ if (previous_tail == instructions->get_tail_raw()) {
_mesa_glsl_warning(&previous_operand_loc, state,
"left-hand operand of comma expression has "
"no effect");
}
- /* tail_pred is directly accessed instead of using the get_tail()
+ /* The tail is directly accessed instead of using the get_tail()
* method for performance reasons. get_tail() has extra code to
* return NULL when the list is empty. We don't care about that
- * here, so using tail_pred directly is fine.
+ * here, so using get_tail_raw() is fine.
*/
- previous_tail_pred = instructions->tail_pred;
+ previous_tail = instructions->get_tail_raw();
previous_operand_loc = ast->get_location();
result = ast->hir(instructions, state);
}
}
- for (exec_node *node = array_specifier->array_dimensions.tail_pred;
+ for (exec_node *node = array_specifier->array_dimensions.get_tail_raw();
!node->is_head_sentinel(); node = node->prev) {
unsigned array_size = process_array_size(node, state);
array_type = glsl_type::get_array_instance(array_type, array_size);
*/
assert(var->data.mode != ir_var_temporary);
if (qual->flags.q.in && qual->flags.q.out)
- var->data.mode = ir_var_function_inout;
+ var->data.mode = is_parameter ? ir_var_function_inout : ir_var_shader_out;
else if (qual->flags.q.in)
var->data.mode = is_parameter ? ir_var_function_in : ir_var_shader_in;
else if (qual->flags.q.attribute
else if (qual->flags.q.shared_storage)
var->data.mode = ir_var_shader_shared;
+ var->data.fb_fetch_output = state->stage == MESA_SHADER_FRAGMENT &&
+ qual->flags.q.in && qual->flags.q.out;
+
if (!is_parameter && is_varying_var(var, state->stage)) {
/* User-defined ins/outs are not permitted in compute shaders. */
if (state->stage == MESA_SHADER_COMPUTE) {
earlier->data.depth_layout = var->data.depth_layout;
+ } else if (state->has_framebuffer_fetch() &&
+ strcmp(var->name, "gl_LastFragData") == 0 &&
+ var->type == earlier->type &&
+ var->data.mode == ir_var_auto) {
+ /* According to the EXT_shader_framebuffer_fetch spec:
+ *
+ * "By default, gl_LastFragData is declared with the mediump precision
+ * qualifier. This can be changed by redeclaring the corresponding
+ * variables with the desired precision qualifier."
+ */
+ earlier->data.precision = var->data.precision;
+
} else if (allow_all_redeclarations) {
if (earlier->data.mode != var->data.mode) {
_mesa_glsl_error(&loc, state,
if (var->data.patch)
return;
- /* Unsized arrays are implicitly sized to gl_MaxPatchVertices. */
+ /* The ARB_tessellation_shader spec says:
+ *
+ * "Declaring an array size is optional. If no size is specified, it
+ * will be taken from the implementation-dependent maximum patch size
+ * (gl_MaxPatchVertices). If a size is specified, it must match the
+ * maximum patch size; otherwise, a compile or link error will occur."
+ *
+ * This text appears twice, once for TCS inputs, and again for TES inputs.
+ */
if (var->type->is_unsized_array()) {
var->type = glsl_type::get_array_instance(var->type->fields.array,
state->Const.MaxPatchVertices);
+ } else if (var->type->length != state->Const.MaxPatchVertices) {
+ _mesa_glsl_error(&loc, state,
+ "per-vertex tessellation shader input arrays must be "
+ "sized to gl_MaxPatchVertices (%d).",
+ state->Const.MaxPatchVertices);
}
}
allowed_atomic_qual_mask.flags.q.explicit_offset = 1;
allowed_atomic_qual_mask.flags.q.uniform = 1;
- type->qualifier.validate_flags(&loc, state,
- "invalid layout qualifier for "
- "atomic_uint",
- allowed_atomic_qual_mask);
+ type->qualifier.validate_flags(&loc, state, allowed_atomic_qual_mask,
+ "invalid layout qualifier for",
+ "atomic_uint");
}
if (this->declarations.is_empty()) {
}
+/* Used for detection of duplicate case values, compare
+ * given contents directly.
+ */
+static bool
+compare_case_value(const void *a, const void *b)
+{
+ return *(unsigned *) a == *(unsigned *) b;
+}
+
+
+/* Used for detection of duplicate case values, just
+ * returns key contents as is.
+ */
+static unsigned
+key_contents(const void *key)
+{
+ return *(unsigned *) key;
+}
+
+
ir_rvalue *
ast_switch_statement::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
state->switch_state.is_switch_innermost = true;
state->switch_state.switch_nesting_ast = this;
- state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash,
- hash_table_pointer_compare);
+ state->switch_state.labels_ht = hash_table_ctor(0, key_contents,
+ compare_case_value);
state->switch_state.previous_default = NULL;
/* Initalize is_fallthru state to false.
} else {
ast_expression *previous_label = (ast_expression *)
hash_table_find(state->switch_state.labels_ht,
- (void *)(uintptr_t)label_const->value.u[0]);
+ (void *)(uintptr_t)&label_const->value.u[0]);
if (previous_label) {
YYLTYPE loc = this->test_value->get_location();
} else {
hash_table_insert(state->switch_state.labels_ht,
this->test_value,
- (void *)(uintptr_t)label_const->value.u[0]);
+ (void *)(uintptr_t)&label_const->value.u[0]);
}
}
unsigned qual_location;
if (process_qualifier_constant(state, &loc, "location",
qual->location, &qual_location)) {
- fields[i].location = VARYING_SLOT_VAR0 + qual_location;
+ fields[i].location = qual_location +
+ (fields[i].patch ? VARYING_SLOT_PATCH0 : VARYING_SLOT_VAR0);
expl_location = fields[i].location +
fields[i].type->count_attribute_slots(false);
}
this->block_name);
}
- if (!this->layout.flags.q.buffer &&
- this->layout.flags.q.std430) {
- _mesa_glsl_error(&loc, state,
- "std430 storage block layout qualifier is supported "
- "only for shader storage blocks");
+ /* Validate qualifiers:
+ *
+ * - Layout Qualifiers as per the table in Section 4.4
+ * ("Layout Qualifiers") of the GLSL 4.50 spec.
+ *
+ * - Memory Qualifiers as per Section 4.10 ("Memory Qualifiers") of the
+ * GLSL 4.50 spec:
+ *
+ * "Additionally, memory qualifiers may also be used in the declaration
+ * of shader storage blocks"
+ *
+ * Note the table in Section 4.4 says std430 is allowed on both uniform and
+ * buffer blocks however Section 4.4.5 (Uniform and Shader Storage Block
+ * Layout Qualifiers) of the GLSL 4.50 spec says:
+ *
+ * "The std430 qualifier is supported only for shader storage blocks;
+ * using std430 on a uniform block will result in a compile-time error."
+ */
+ ast_type_qualifier allowed_blk_qualifiers;
+ allowed_blk_qualifiers.flags.i = 0;
+ if (this->layout.flags.q.buffer || this->layout.flags.q.uniform) {
+ allowed_blk_qualifiers.flags.q.shared = 1;
+ allowed_blk_qualifiers.flags.q.packed = 1;
+ allowed_blk_qualifiers.flags.q.std140 = 1;
+ allowed_blk_qualifiers.flags.q.row_major = 1;
+ allowed_blk_qualifiers.flags.q.column_major = 1;
+ allowed_blk_qualifiers.flags.q.explicit_align = 1;
+ allowed_blk_qualifiers.flags.q.explicit_binding = 1;
+ if (this->layout.flags.q.buffer) {
+ allowed_blk_qualifiers.flags.q.buffer = 1;
+ allowed_blk_qualifiers.flags.q.std430 = 1;
+ allowed_blk_qualifiers.flags.q.coherent = 1;
+ allowed_blk_qualifiers.flags.q._volatile = 1;
+ allowed_blk_qualifiers.flags.q.restrict_flag = 1;
+ allowed_blk_qualifiers.flags.q.read_only = 1;
+ allowed_blk_qualifiers.flags.q.write_only = 1;
+ } else {
+ allowed_blk_qualifiers.flags.q.uniform = 1;
+ }
+ } else {
+ /* Interface block */
+ assert(this->layout.flags.q.in || this->layout.flags.q.out);
+
+ allowed_blk_qualifiers.flags.q.explicit_location = 1;
+ if (this->layout.flags.q.out) {
+ allowed_blk_qualifiers.flags.q.out = 1;
+ if (state->stage == MESA_SHADER_GEOMETRY ||
+ state->stage == MESA_SHADER_TESS_CTRL ||
+ state->stage == MESA_SHADER_TESS_EVAL ||
+ state->stage == MESA_SHADER_VERTEX ) {
+ allowed_blk_qualifiers.flags.q.explicit_xfb_offset = 1;
+ allowed_blk_qualifiers.flags.q.explicit_xfb_buffer = 1;
+ allowed_blk_qualifiers.flags.q.xfb_buffer = 1;
+ allowed_blk_qualifiers.flags.q.explicit_xfb_stride = 1;
+ allowed_blk_qualifiers.flags.q.xfb_stride = 1;
+ if (state->stage == MESA_SHADER_GEOMETRY) {
+ allowed_blk_qualifiers.flags.q.stream = 1;
+ allowed_blk_qualifiers.flags.q.explicit_stream = 1;
+ }
+ if (state->stage == MESA_SHADER_TESS_CTRL) {
+ allowed_blk_qualifiers.flags.q.patch = 1;
+ }
+ }
+ } else {
+ allowed_blk_qualifiers.flags.q.in = 1;
+ if (state->stage == MESA_SHADER_TESS_EVAL) {
+ allowed_blk_qualifiers.flags.q.patch = 1;
+ }
+ }
}
+ this->layout.validate_flags(&loc, state, allowed_blk_qualifiers,
+ "invalid qualifier for block",
+ this->block_name);
+
/* 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.
"Interface block sets both readonly and writeonly");
}
- if (this->layout.flags.q.explicit_component) {
- _mesa_glsl_error(&loc, state, "component layout qualifier cannot be "
- "applied to a matrix, a structure, a block, or an "
- "array containing any of these.");
- }
-
unsigned qual_stream;
if (!process_qualifier_constant(state, &loc, "stream", this->layout.stream,
&qual_stream) ||
layout.location, &expl_location)) {
return NULL;
} else {
- expl_location = VARYING_SLOT_VAR0 + expl_location;
+ expl_location += this->layout.flags.q.patch ? VARYING_SLOT_PATCH0
+ : VARYING_SLOT_VAR0;
}
}
_mesa_glsl_error(&loc, state, "geometry shader inputs must be arrays");
} else if ((state->stage == MESA_SHADER_TESS_CTRL ||
state->stage == MESA_SHADER_TESS_EVAL) &&
+ !this->layout.flags.q.patch &&
this->array_specifier == NULL &&
var_mode == ir_var_shader_in) {
_mesa_glsl_error(&loc, state, "per-vertex tessellation shader inputs must be arrays");
} else if (state->stage == MESA_SHADER_TESS_CTRL &&
+ !this->layout.flags.q.patch &&
this->array_specifier == NULL &&
var_mode == ir_var_shader_out) {
_mesa_glsl_error(&loc, state, "tessellation control shader outputs must be arrays");
if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform)
var->data.read_only = true;
+ var->data.patch = this->layout.flags.q.patch;
+
if (state->stage == MESA_SHADER_GEOMETRY && var_mode == ir_var_shader_in)
handle_geometry_shader_input_decl(state, loc, var);
else if ((state->stage == MESA_SHADER_TESS_CTRL ||