ir_rvalue * _mesa_ast_field_selection_to_hir(const ast_expression *expr, exec_list *instructions, struct _mesa_glsl_parse_state *state) { void *ctx = state; ir_rvalue *result = NULL; ir_rvalue *op; op = expr->subexpressions[0]->hir(instructions, state); /* There are two kinds of field selection. There is the selection of a * specific field from a structure, and there is the selection of a * swizzle / mask from a vector. Which is which is determined entirely * by the base type of the thing to which the field selection operator is * being applied. */ YYLTYPE loc = expr->get_location(); if (op->type->is_error()) { /* silently propagate the error */ } else if (op->type->base_type == GLSL_TYPE_STRUCT || op->type->base_type == GLSL_TYPE_INTERFACE) { result = new(ctx) ir_dereference_record(op, expr->primary_expression.identifier); if (result->type->is_error()) { _mesa_glsl_error(& loc, state, "cannot access field `%s' of " "structure", expr->primary_expression.identifier); } } else if (op->type->is_vector() || (state->has_420pack() && op->type->is_scalar())) { ir_swizzle *swiz = ir_swizzle::create(op, expr->primary_expression.identifier, op->type->vector_elements); if (swiz != NULL) { result = swiz; } else { /* FINISHME: Logging of error messages should be moved into * FINISHME: ir_swizzle::create. This allows the generation of more * FINISHME: specific error messages. */ _mesa_glsl_error(& loc, state, "invalid swizzle / mask `%s'", expr->primary_expression.identifier); } } else { _mesa_glsl_error(& loc, state, "cannot access field `%s' of " "non-structure / non-vector", expr->primary_expression.identifier); } return result ? result : ir_rvalue::error_value(ctx); }
bool process_qualifier_constant(struct _mesa_glsl_parse_state *state, YYLTYPE *loc, const char *qual_indentifier, ast_expression *const_expression, unsigned *value) { exec_list dummy_instructions; if (const_expression == NULL) { *value = 0; return true; } ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state); ir_constant *const const_int = ir->constant_expression_value(); if (const_int == NULL || !const_int->type->is_integer()) { _mesa_glsl_error(loc, state, "%s must be an integral constant " "expression", qual_indentifier); return false; } if (const_int->value.i[0] < 0) { _mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)", qual_indentifier, const_int->value.u[0]); return false; } /* If the location is const (and we've verified that * it is) then no instructions should have been emitted * when we converted it to HIR. If they were emitted, * then either the location isn't const after all, or * we are emitting unnecessary instructions. */ assert(dummy_instructions.is_empty()); *value = const_int->value.u[0]; return true; }
bool ast_type_qualifier::merge_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, ast_type_qualifier q) { ast_type_qualifier ubo_mat_mask; ubo_mat_mask.flags.i = 0; ubo_mat_mask.flags.q.row_major = 1; ubo_mat_mask.flags.q.column_major = 1; ast_type_qualifier ubo_layout_mask; ubo_layout_mask.flags.i = 0; ubo_layout_mask.flags.q.std140 = 1; ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; /* Uniform block layout qualifiers get to overwrite each * other (rightmost having priority), while all other * qualifiers currently don't allow duplicates. */ if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i | ubo_layout_mask.flags.i)) != 0) { _mesa_glsl_error(loc, state, "duplicate layout qualifiers used\n"); return false; } if ((q.flags.i & ubo_mat_mask.flags.i) != 0) this->flags.i &= ~ubo_mat_mask.flags.i; if ((q.flags.i & ubo_layout_mask.flags.i) != 0) this->flags.i &= ~ubo_layout_mask.flags.i; this->flags.i |= q.flags.i; if (q.flags.q.explicit_location) this->location = q.location; if (q.flags.q.explicit_index) this->index = q.index; if (q.flags.q.explicit_binding) this->binding = q.binding; if (q.precision != ast_precision_none) this->precision = q.precision; return true; }
ir_rvalue * _mesa_ast_field_selection_to_hir(const ast_expression *expr, exec_list *instructions, struct _mesa_glsl_parse_state *state) { void *ctx = state; ir_rvalue *result = NULL; ir_rvalue *op; op = expr->subexpressions[0]->hir(instructions, state); /* There are two kinds of field selection. There is the selection of a * specific field from a structure, and there is the selection of a * swizzle / mask from a vector. Which is which is determined entirely * by the base type of the thing to which the field selection operator is * being applied. */ YYLTYPE loc = expr->get_location(); if (op->type->is_error()) { /* silently propagate the error */ } else if (op->type->is_vector() || op->type->is_scalar()) { ir_swizzle *swiz = ir_swizzle::create(op, expr->primary_expression.identifier, op->type->vector_elements); if (swiz != NULL) { result = swiz; } else { /* FINISHME: Logging of error messages should be moved into * FINISHME: ir_swizzle::create. This allows the generation of more * FINISHME: specific error messages. */ _mesa_glsl_error(& loc, state, "Invalid swizzle / mask '%s'", expr->primary_expression.identifier); } } else if (op->type->is_matrix() && expr->primary_expression.identifier) { int src_components = op->type->components(); int components[4] = {0}; uint32 num_components = 0; ir_swizzle_mask mask = {0}; const char* mask_str = expr->primary_expression.identifier; if (mask_str[0] == '_' && mask_str[1] == 'm') { do { mask_str += 2; int col = (*mask_str) ? (*mask_str++) - '0' : -1; int row = (*mask_str) ? (*mask_str++) - '0' : -1; if (col >= 0 && col <= op->type->matrix_columns && row >= 0 && row <= op->type->vector_elements) { components[num_components++] = col * op->type->vector_elements + row; } else { components[num_components++] = -1; } } while (*mask_str != 0 && num_components < 4); } else if (mask_str[0] == '_' && mask_str[1] >= '1' && mask_str[2] <= '4') { do { mask_str += 1; int col = (*mask_str) ? (*mask_str++) - '1' : -1; int row = (*mask_str) ? (*mask_str++) - '1' : -1; if (col >= 0 && col <= op->type->matrix_columns && row >= 0 && row <= op->type->vector_elements) { components[num_components++] = col * op->type->vector_elements + row; } else { components[num_components++] = -1; } } while (*mask_str != 0 && num_components < 4); } if (*mask_str == 0) { if (num_components > 0 && components[0] >= 0 && components[0] <= src_components) { mask.x = (unsigned)components[0]; mask.num_components++; } if (num_components > 1 && components[1] >= 0 && components[1] <= src_components) { mask.y = (unsigned)components[1]; mask.has_duplicates = (mask.y == mask.x); mask.num_components++; } if (num_components > 2 && components[2] >= 0 && components[2] <= src_components) { mask.z = (unsigned)components[2]; mask.has_duplicates = mask.has_duplicates || (mask.z == mask.y) || (mask.z == mask.x); mask.num_components++; } if (num_components > 3 && components[3] >= 0 && components[3] <= src_components) { mask.w = (unsigned)components[3]; mask.has_duplicates = mask.has_duplicates || (mask.w == mask.z) || (mask.w == mask.y) || (mask.w == mask.x); mask.num_components++; } } if (mask.num_components == num_components) { result = new(ctx)ir_swizzle(op, mask); } if (result == NULL) { _mesa_glsl_error(&loc, state, "invalid matrix swizzle '%s'", expr->primary_expression.identifier); } } else if (op->type->base_type == GLSL_TYPE_STRUCT) { result = new(ctx)ir_dereference_record(op, expr->primary_expression.identifier); if (result->type->is_error()) { _mesa_glsl_error(& loc, state, "Cannot access field '%s' of " "structure", expr->primary_expression.identifier); } } else if (expr->subexpressions[1] != NULL) { /* Handle "method calls" in GLSL 1.20+ */ if (state->language_version < 120) _mesa_glsl_error(&loc, state, "Methods not supported in GLSL 1.10."); ast_expression *call = expr->subexpressions[1]; check(call->oper == ast_function_call); const char *method; method = call->subexpressions[0]->primary_expression.identifier; if (op->type->is_array() && strcmp(method, "length") == 0) { if (!call->expressions.is_empty()) _mesa_glsl_error(&loc, state, "length method takes no arguments."); if (op->type->array_size() == 0) _mesa_glsl_error(&loc, state, "length called on unsized array."); result = new(ctx)ir_constant(op->type->array_size()); } else if (op->type->is_sampler() && op->as_dereference() != NULL) { return gen_texture_op(expr, op->as_dereference(), instructions, state); } else if (op->type->is_image() && op->as_dereference() != NULL) { return gen_image_op(expr, op->as_dereference(), instructions, state); } else if (op->type->is_outputstream() && strcmp(method, "Append") == 0) { check(op->variable_referenced()->type->inner_type->is_record()); check(op->variable_referenced()->type->inner_type->name); const char* function_name = "OutputStream_Append"; ir_function *func = state->symbols->get_function(function_name); if (!func) { // Prepare the function, add it to global symbols. It will be added to declarations at GenerateGlslMain(). func = new(ctx)ir_function(function_name); state->symbols->add_global_function(func); // _mesa_glsl_warning(state, "Append function generation for type '%s'", op->variable_referenced()->type->inner_type->name ); // { // const glsl_type* output_type = op->variable_referenced()->type->inner_type; // for (int i = 0; i < output_type->length; i++) // { // _mesa_glsl_warning(state, " name '%s' : semantic '%s'", output_type->fields.structure[i].name, output_type->fields.structure[i].semantic ); // } // } } exec_list comparison_parameter; ir_variable* var = new(ctx)ir_variable(op->variable_referenced()->type->inner_type, ralloc_asprintf(ctx, "arg0"), ir_var_in); comparison_parameter.push_tail(var); bool is_exact = false; ir_function_signature *sig = func->matching_signature(&comparison_parameter, &is_exact); if (!sig || !is_exact) { sig = new(ctx)ir_function_signature(glsl_type::void_type); sig->parameters.push_tail(var); sig->is_builtin = false; sig->is_defined = true; func->add_signature(sig); } if (call->expressions.is_empty() || (call->expressions.get_head() != call->expressions.get_tail())) { _mesa_glsl_error(&loc, state, "Append method takes one argument."); } else { exec_list actual_parameter; ast_node *const ast = exec_node_data(ast_node, call->expressions.get_head(), link); ir_rvalue *result = ast->hir(instructions, state); actual_parameter.push_tail(result); instructions->push_tail(new(ctx)ir_call(sig, NULL, &actual_parameter)); } return NULL; } else if (op->type->is_outputstream() && strcmp(method, "RestartStrip") == 0) { exec_list actual_parameters; // empty, as no parameters ir_function *func = state->symbols->get_function("EndPrimitive"); check(func); bool is_exact = false; ir_function_signature *sig = func->matching_signature(&actual_parameters, &is_exact); check(sig && is_exact); instructions->push_tail(new(ctx)ir_call(sig, NULL, &actual_parameters)); return NULL; } else { _mesa_glsl_error(&loc, state, "Unknown method: '%s'.", method); } } else { _mesa_glsl_error(& loc, state, "Cannot access field '%s' of " "non-structure / non-vector.", expr->primary_expression.identifier); } return result ? result : ir_rvalue::error_value(ctx); }
bool ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state *state, const char *qual_indentifier, unsigned *value, bool can_be_zero, bool must_match) { int min_value = 0; bool first_pass = true; *value = 0; if (!can_be_zero) min_value = 1; for (exec_node *node = layout_const_expressions.get_head_raw(); !node->is_tail_sentinel(); node = node->next) { exec_list dummy_instructions; ast_node *const_expression = exec_node_data(ast_node, node, link); ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state); ir_constant *const const_int = ir->constant_expression_value(); if (const_int == NULL || !const_int->type->is_integer()) { YYLTYPE loc = const_expression->get_location(); _mesa_glsl_error(&loc, state, "%s must be an integral constant " "expression", qual_indentifier); return false; } if (const_int->value.i[0] < min_value) { YYLTYPE loc = const_expression->get_location(); _mesa_glsl_error(&loc, state, "%s layout qualifier is invalid " "(%d < %d)", qual_indentifier, const_int->value.i[0], min_value); return false; } /* From section 4.4 "Layout Qualifiers" of the GLSL 4.50 spec: * "When the same layout-qualifier-name occurs multiple times, * in a single declaration, the last occurrence overrides the * former occurrence(s)." */ if (!first_pass) { if ((must_match || !state->has_420pack()) && *value != const_int->value.u[0]) { YYLTYPE loc = const_expression->get_location(); _mesa_glsl_error(&loc, state, "%s layout qualifier does not " "match previous declaration (%d vs %d)", qual_indentifier, *value, const_int->value.i[0]); return false; } } else { first_pass = false; *value = const_int->value.u[0]; } /* If the location is const (and we've verified that * it is) then no instructions should have been emitted * when we converted it to HIR. If they were emitted, * then either the location isn't const after all, or * we are emitting unnecessary instructions. */ assert(dummy_instructions.is_empty()); } return true; }
/** * Check if the current type qualifier has any illegal flags. * * If so, print an error message, followed by a list of illegal flags. * * \param message The error message to print. * \param allowed_flags A list of valid flags. */ bool ast_type_qualifier::validate_flags(YYLTYPE *loc, _mesa_glsl_parse_state *state, const ast_type_qualifier &allowed_flags, const char *message, const char *name) { ast_type_qualifier bad; bad.flags.i = this->flags.i & ~allowed_flags.flags.i; if (bad.flags.i == 0) return true; _mesa_glsl_error(loc, state, "%s '%s':" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", message, name, bad.flags.q.invariant ? " invariant" : "", bad.flags.q.precise ? " precise" : "", bad.flags.q.constant ? " constant" : "", bad.flags.q.attribute ? " attribute" : "", bad.flags.q.varying ? " varying" : "", bad.flags.q.in ? " in" : "", bad.flags.q.out ? " out" : "", bad.flags.q.centroid ? " centroid" : "", bad.flags.q.sample ? " sample" : "", bad.flags.q.patch ? " patch" : "", bad.flags.q.uniform ? " uniform" : "", bad.flags.q.buffer ? " buffer" : "", bad.flags.q.shared_storage ? " shared_storage" : "", bad.flags.q.smooth ? " smooth" : "", bad.flags.q.flat ? " flat" : "", bad.flags.q.noperspective ? " noperspective" : "", bad.flags.q.origin_upper_left ? " origin_upper_left" : "", bad.flags.q.pixel_center_integer ? " pixel_center_integer" : "", bad.flags.q.explicit_align ? " align" : "", bad.flags.q.explicit_component ? " component" : "", bad.flags.q.explicit_location ? " location" : "", bad.flags.q.explicit_index ? " index" : "", bad.flags.q.explicit_binding ? " binding" : "", bad.flags.q.explicit_offset ? " offset" : "", bad.flags.q.depth_any ? " depth_any" : "", bad.flags.q.depth_greater ? " depth_greater" : "", bad.flags.q.depth_less ? " depth_less" : "", bad.flags.q.depth_unchanged ? " depth_unchanged" : "", bad.flags.q.std140 ? " std140" : "", bad.flags.q.std430 ? " std430" : "", bad.flags.q.shared ? " shared" : "", bad.flags.q.packed ? " packed" : "", bad.flags.q.column_major ? " column_major" : "", bad.flags.q.row_major ? " row_major" : "", bad.flags.q.prim_type ? " prim_type" : "", bad.flags.q.max_vertices ? " max_vertices" : "", bad.flags.q.local_size ? " local_size" : "", bad.flags.q.early_fragment_tests ? " early_fragment_tests" : "", bad.flags.q.explicit_image_format ? " image_format" : "", bad.flags.q.coherent ? " coherent" : "", bad.flags.q._volatile ? " _volatile" : "", bad.flags.q.restrict_flag ? " restrict_flag" : "", bad.flags.q.read_only ? " read_only" : "", bad.flags.q.write_only ? " write_only" : "", bad.flags.q.invocations ? " invocations" : "", bad.flags.q.stream ? " stream" : "", bad.flags.q.explicit_stream ? " stream" : "", bad.flags.q.explicit_xfb_offset ? " xfb_offset" : "", bad.flags.q.xfb_buffer ? " xfb_buffer" : "", bad.flags.q.explicit_xfb_buffer ? " xfb_buffer" : "", bad.flags.q.xfb_stride ? " xfb_stride" : "", bad.flags.q.explicit_xfb_stride ? " xfb_stride" : "", bad.flags.q.vertex_spacing ? " vertex_spacing" : "", bad.flags.q.ordering ? " ordering" : "", bad.flags.q.point_mode ? " point_mode" : "", bad.flags.q.vertices ? " vertices" : "", bad.flags.q.subroutine ? " subroutine" : "", bad.flags.q.subroutine_def ? " subroutine_def" : ""); return false; }
bool ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, const ast_type_qualifier &q, ast_node* &node, bool create_node) { void *mem_ctx = state; bool create_gs_ast = false; bool create_cs_ast = false; ast_type_qualifier valid_in_mask; valid_in_mask.flags.i = 0; switch (state->stage) { case MESA_SHADER_TESS_EVAL: if (q.flags.q.prim_type) { /* Make sure this is a valid input primitive type. */ switch (q.prim_type) { case GL_TRIANGLES: case GL_QUADS: case GL_ISOLINES: break; default: _mesa_glsl_error(loc, state, "invalid tessellation evaluation " "shader input primitive type"); break; } } valid_in_mask.flags.q.prim_type = 1; valid_in_mask.flags.q.vertex_spacing = 1; valid_in_mask.flags.q.ordering = 1; valid_in_mask.flags.q.point_mode = 1; break; case MESA_SHADER_GEOMETRY: if (q.flags.q.prim_type) { /* Make sure this is a valid input primitive type. */ switch (q.prim_type) { case GL_POINTS: case GL_LINES: case GL_LINES_ADJACENCY: case GL_TRIANGLES: case GL_TRIANGLES_ADJACENCY: break; default: _mesa_glsl_error(loc, state, "invalid geometry shader input primitive type"); break; } } create_gs_ast |= q.flags.q.prim_type && !state->in_qualifier->flags.q.prim_type; valid_in_mask.flags.q.prim_type = 1; valid_in_mask.flags.q.invocations = 1; break; case MESA_SHADER_FRAGMENT: valid_in_mask.flags.q.early_fragment_tests = 1; break; case MESA_SHADER_COMPUTE: create_cs_ast |= q.flags.q.local_size != 0 && state->in_qualifier->flags.q.local_size == 0; valid_in_mask.flags.q.local_size = 7; break; default: _mesa_glsl_error(loc, state, "input layout qualifiers only valid in " "geometry, fragment and compute shaders"); break; } /* Generate an error when invalid input layout qualifiers are used. */ if ((q.flags.i & ~valid_in_mask.flags.i) != 0) { _mesa_glsl_error(loc, state, "invalid input layout qualifiers used"); return false; } /* Input layout qualifiers can be specified multiple * times in separate declarations, as long as they match. */ if (this->flags.q.prim_type) { if (q.flags.q.prim_type && this->prim_type != q.prim_type) { _mesa_glsl_error(loc, state, "conflicting input primitive %s specified", state->stage == MESA_SHADER_GEOMETRY ? "type" : "mode"); } } else if (q.flags.q.prim_type) { state->in_qualifier->flags.q.prim_type = 1; state->in_qualifier->prim_type = q.prim_type; } if (q.flags.q.invocations) { this->flags.q.invocations = 1; if (this->invocations) { this->invocations->merge_qualifier(q.invocations); } else { this->invocations = q.invocations; } } if (q.flags.q.early_fragment_tests) { state->fs_early_fragment_tests = true; } if (this->flags.q.vertex_spacing) { if (q.flags.q.vertex_spacing && this->vertex_spacing != q.vertex_spacing) { _mesa_glsl_error(loc, state, "conflicting vertex spacing specified"); } } else if (q.flags.q.vertex_spacing) { this->flags.q.vertex_spacing = 1; this->vertex_spacing = q.vertex_spacing; } if (this->flags.q.ordering) { if (q.flags.q.ordering && this->ordering != q.ordering) { _mesa_glsl_error(loc, state, "conflicting ordering specified"); } } else if (q.flags.q.ordering) { this->flags.q.ordering = 1; this->ordering = q.ordering; } if (this->flags.q.point_mode) { if (q.flags.q.point_mode && this->point_mode != q.point_mode) { _mesa_glsl_error(loc, state, "conflicting point mode specified"); } } else if (q.flags.q.point_mode) { this->flags.q.point_mode = 1; this->point_mode = q.point_mode; } if (create_node) { if (create_gs_ast) { node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type); } else if (create_cs_ast) { node = new(mem_ctx) ast_cs_input_layout(*loc, q.local_size); } } return true; }
bool ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, const ast_type_qualifier &q, ast_node* &node, bool create_node) { void *mem_ctx = state; const bool r = this->merge_qualifier(loc, state, q, false); ast_type_qualifier valid_out_mask; valid_out_mask.flags.i = 0; if (state->stage == MESA_SHADER_GEOMETRY) { if (q.flags.q.prim_type) { /* Make sure this is a valid output primitive type. */ switch (q.prim_type) { case GL_POINTS: case GL_LINE_STRIP: case GL_TRIANGLE_STRIP: break; default: _mesa_glsl_error(loc, state, "invalid geometry shader output " "primitive type"); break; } } /* Allow future assigments of global out's stream id value */ this->flags.q.explicit_stream = 0; valid_out_mask.flags.q.stream = 1; valid_out_mask.flags.q.explicit_stream = 1; valid_out_mask.flags.q.explicit_xfb_buffer = 1; valid_out_mask.flags.q.xfb_buffer = 1; valid_out_mask.flags.q.explicit_xfb_stride = 1; valid_out_mask.flags.q.xfb_stride = 1; valid_out_mask.flags.q.max_vertices = 1; valid_out_mask.flags.q.prim_type = 1; } else if (state->stage == MESA_SHADER_TESS_CTRL) { if (create_node) { node = new(mem_ctx) ast_tcs_output_layout(*loc); } valid_out_mask.flags.q.vertices = 1; valid_out_mask.flags.q.explicit_xfb_buffer = 1; valid_out_mask.flags.q.xfb_buffer = 1; valid_out_mask.flags.q.explicit_xfb_stride = 1; valid_out_mask.flags.q.xfb_stride = 1; } else if (state->stage == MESA_SHADER_TESS_EVAL || state->stage == MESA_SHADER_VERTEX) { valid_out_mask.flags.q.explicit_xfb_buffer = 1; valid_out_mask.flags.q.xfb_buffer = 1; valid_out_mask.flags.q.explicit_xfb_stride = 1; valid_out_mask.flags.q.xfb_stride = 1; } else if (state->stage == MESA_SHADER_FRAGMENT) { valid_out_mask.flags.q.blend_support = 1; } else { _mesa_glsl_error(loc, state, "out layout qualifiers only valid in " "geometry, tessellation and vertex shaders"); return false; } /* Allow future assigments of global out's */ this->flags.q.explicit_xfb_buffer = 0; this->flags.q.explicit_xfb_stride = 0; /* Generate an error when invalid input layout qualifiers are used. */ if ((q.flags.i & ~valid_out_mask.flags.i) != 0) { _mesa_glsl_error(loc, state, "invalid output layout qualifiers used"); return false; } return r; }
/** * This function merges both duplicate identifies within a single layout and * multiple layout qualifiers on a single variable declaration. The * is_single_layout_merge param is used differentiate between the two. */ bool ast_type_qualifier::merge_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, const ast_type_qualifier &q, bool is_single_layout_merge) { ast_type_qualifier ubo_mat_mask; ubo_mat_mask.flags.i = 0; ubo_mat_mask.flags.q.row_major = 1; ubo_mat_mask.flags.q.column_major = 1; ast_type_qualifier ubo_layout_mask; ubo_layout_mask.flags.i = 0; ubo_layout_mask.flags.q.std140 = 1; ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; ubo_layout_mask.flags.q.std430 = 1; ast_type_qualifier ubo_binding_mask; ubo_binding_mask.flags.i = 0; ubo_binding_mask.flags.q.explicit_binding = 1; ubo_binding_mask.flags.q.explicit_offset = 1; ast_type_qualifier stream_layout_mask; stream_layout_mask.flags.i = 0; stream_layout_mask.flags.q.stream = 1; /* FIXME: We should probably do interface and function param validation * separately. */ ast_type_qualifier input_layout_mask; input_layout_mask.flags.i = 0; input_layout_mask.flags.q.centroid = 1; /* Function params can have constant */ input_layout_mask.flags.q.constant = 1; input_layout_mask.flags.q.explicit_component = 1; input_layout_mask.flags.q.explicit_location = 1; input_layout_mask.flags.q.flat = 1; input_layout_mask.flags.q.in = 1; input_layout_mask.flags.q.invariant = 1; input_layout_mask.flags.q.noperspective = 1; input_layout_mask.flags.q.origin_upper_left = 1; /* Function params 'inout' will set this */ input_layout_mask.flags.q.out = 1; input_layout_mask.flags.q.patch = 1; input_layout_mask.flags.q.pixel_center_integer = 1; input_layout_mask.flags.q.precise = 1; input_layout_mask.flags.q.sample = 1; input_layout_mask.flags.q.smooth = 1; /* Uniform block layout qualifiers get to overwrite each * other (rightmost having priority), while all other * qualifiers currently don't allow duplicates. */ ast_type_qualifier allowed_duplicates_mask; allowed_duplicates_mask.flags.i = ubo_mat_mask.flags.i | ubo_layout_mask.flags.i | ubo_binding_mask.flags.i; /* Geometry shaders can have several layout qualifiers * assigning different stream values. */ if (state->stage == MESA_SHADER_GEOMETRY) { allowed_duplicates_mask.flags.i |= stream_layout_mask.flags.i; } if (is_single_layout_merge && !state->has_enhanced_layouts() && (this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) { _mesa_glsl_error(loc, state, "duplicate layout qualifiers used"); return false; } if (q.flags.q.prim_type) { if (this->flags.q.prim_type && this->prim_type != q.prim_type) { _mesa_glsl_error(loc, state, "conflicting primitive type qualifiers used"); return false; } this->prim_type = q.prim_type; } if (q.flags.q.max_vertices) { if (this->max_vertices) { this->max_vertices->merge_qualifier(q.max_vertices); } else { this->max_vertices = q.max_vertices; } } if (q.flags.q.subroutine_def) { if (this->flags.q.subroutine_def) { _mesa_glsl_error(loc, state, "conflicting subroutine qualifiers used"); } else { this->subroutine_list = q.subroutine_list; } } if (q.flags.q.invocations) { if (this->invocations) { this->invocations->merge_qualifier(q.invocations); } else { this->invocations = q.invocations; } } if (state->stage == MESA_SHADER_GEOMETRY && state->has_explicit_attrib_stream()) { if (!this->flags.q.explicit_stream) { if (q.flags.q.stream) { this->flags.q.stream = 1; this->stream = q.stream; } else if (!this->flags.q.stream && this->flags.q.out && !this->flags.q.in) { /* Assign default global stream value */ this->flags.q.stream = 1; this->stream = state->out_qualifier->stream; } } } if (state->has_enhanced_layouts()) { if (!this->flags.q.explicit_xfb_buffer) { if (q.flags.q.xfb_buffer) { this->flags.q.xfb_buffer = 1; this->xfb_buffer = q.xfb_buffer; } else if (!this->flags.q.xfb_buffer && this->flags.q.out && !this->flags.q.in) { /* Assign global xfb_buffer value */ this->flags.q.xfb_buffer = 1; this->xfb_buffer = state->out_qualifier->xfb_buffer; } } if (q.flags.q.explicit_xfb_stride) this->xfb_stride = q.xfb_stride; /* Merge all we xfb_stride qualifiers into the global out */ if (q.flags.q.explicit_xfb_stride || this->flags.q.xfb_stride) { /* Set xfb_stride flag to 0 to avoid adding duplicates every time * there is a merge. */ this->flags.q.xfb_stride = 0; unsigned buff_idx; if (process_qualifier_constant(state, loc, "xfb_buffer", this->xfb_buffer, &buff_idx)) { if (state->out_qualifier->out_xfb_stride[buff_idx]) { state->out_qualifier->out_xfb_stride[buff_idx]->merge_qualifier( new(state) ast_layout_expression(*loc, this->xfb_stride)); } else { state->out_qualifier->out_xfb_stride[buff_idx] = new(state) ast_layout_expression(*loc, this->xfb_stride); } } } } if (q.flags.q.vertices) { if (this->vertices) { this->vertices->merge_qualifier(q.vertices); } else { this->vertices = q.vertices; } } if (q.flags.q.vertex_spacing) { if (this->flags.q.vertex_spacing && this->vertex_spacing != q.vertex_spacing) { _mesa_glsl_error(loc, state, "conflicting vertex spacing used"); return false; } this->vertex_spacing = q.vertex_spacing; } if (q.flags.q.ordering) { if (this->flags.q.ordering && this->ordering != q.ordering) { _mesa_glsl_error(loc, state, "conflicting ordering used"); return false; } this->ordering = q.ordering; } if (q.flags.q.point_mode) { if (this->flags.q.point_mode && this->point_mode != q.point_mode) { _mesa_glsl_error(loc, state, "conflicting point mode used"); return false; } this->point_mode = q.point_mode; } if ((q.flags.i & ubo_mat_mask.flags.i) != 0) this->flags.i &= ~ubo_mat_mask.flags.i; if ((q.flags.i & ubo_layout_mask.flags.i) != 0) this->flags.i &= ~ubo_layout_mask.flags.i; for (int i = 0; i < 3; i++) { if (q.flags.q.local_size & (1 << i)) { if (this->local_size[i]) { this->local_size[i]->merge_qualifier(q.local_size[i]); } else { this->local_size[i] = q.local_size[i]; } } } this->flags.i |= q.flags.i; if (this->flags.q.in && (this->flags.i & ~input_layout_mask.flags.i) != 0) { _mesa_glsl_error(loc, state, "invalid input layout qualifier used"); return false; } if (q.flags.q.explicit_align) this->align = q.align; if (q.flags.q.explicit_location) this->location = q.location; if (q.flags.q.explicit_index) this->index = q.index; if (q.flags.q.explicit_component) this->component = q.component; if (q.flags.q.explicit_binding) this->binding = q.binding; if (q.flags.q.explicit_offset || q.flags.q.explicit_xfb_offset) this->offset = q.offset; if (q.precision != ast_precision_none) this->precision = q.precision; if (q.flags.q.explicit_image_format) { this->image_format = q.image_format; this->image_base_type = q.image_base_type; } return true; }
bool ast_type_qualifier::merge_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, ast_type_qualifier q) { ast_type_qualifier ubo_mat_mask; ubo_mat_mask.flags.i = 0; ubo_mat_mask.flags.q.row_major = 1; ubo_mat_mask.flags.q.column_major = 1; ast_type_qualifier ubo_layout_mask; ubo_layout_mask.flags.i = 0; ubo_layout_mask.flags.q.std140 = 1; ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; ast_type_qualifier ubo_binding_mask; ubo_binding_mask.flags.q.explicit_binding = 1; ubo_binding_mask.flags.q.explicit_offset = 1; /* Uniform block layout qualifiers get to overwrite each * other (rightmost having priority), while all other * qualifiers currently don't allow duplicates. */ if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i | ubo_layout_mask.flags.i | ubo_binding_mask.flags.i)) != 0) { _mesa_glsl_error(loc, state, "duplicate layout qualifiers used"); return false; } if (q.flags.q.prim_type) { if (this->flags.q.prim_type && this->prim_type != q.prim_type) { _mesa_glsl_error(loc, state, "conflicting primitive type qualifiers used"); return false; } this->prim_type = q.prim_type; } if (q.flags.q.max_vertices) { if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) { _mesa_glsl_error(loc, state, "geometry shader set conflicting max_vertices " "(%d and %d)", this->max_vertices, q.max_vertices); return false; } this->max_vertices = q.max_vertices; } if ((q.flags.i & ubo_mat_mask.flags.i) != 0) this->flags.i &= ~ubo_mat_mask.flags.i; if ((q.flags.i & ubo_layout_mask.flags.i) != 0) this->flags.i &= ~ubo_layout_mask.flags.i; this->flags.i |= q.flags.i; if (q.flags.q.explicit_location) this->location = q.location; if (q.flags.q.explicit_index) this->index = q.index; if (q.flags.q.explicit_binding) this->binding = q.binding; if (q.flags.q.explicit_offset) this->offset = q.offset; if (q.precision != ast_precision_none) this->precision = q.precision; return true; }
ir_rvalue * _mesa_ast_field_selection_to_hir(const ast_expression *expr, exec_list *instructions, struct _mesa_glsl_parse_state *state) { void *ctx = state; ir_rvalue *result = NULL; ir_rvalue *op; op = expr->subexpressions[0]->hir(instructions, state); /* There are two kinds of field selection. There is the selection of a * specific field from a structure, and there is the selection of a * swizzle / mask from a vector. Which is which is determined entirely * by the base type of the thing to which the field selection operator is * being applied. */ YYLTYPE loc = expr->get_location(); if (op->type->is_error()) { /* silently propagate the error */ } else if (op->type->is_vector()) { ir_swizzle *swiz = ir_swizzle::create(op, expr->primary_expression.identifier, op->type->vector_elements); if (swiz != NULL) { result = swiz; } else { /* FINISHME: Logging of error messages should be moved into * FINISHME: ir_swizzle::create. This allows the generation of more * FINISHME: specific error messages. */ _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'", expr->primary_expression.identifier); } } else if (op->type->base_type == GLSL_TYPE_STRUCT) { result = new(ctx) ir_dereference_record(op, expr->primary_expression.identifier); if (result->type->is_error()) { _mesa_glsl_error(& loc, state, "Cannot access field `%s' of " "structure", expr->primary_expression.identifier); } } else if (expr->subexpressions[1] != NULL) { /* Handle "method calls" in GLSL 1.20 - namely, array.length() */ if (state->language_version < 120) _mesa_glsl_error(&loc, state, "Methods not supported in GLSL 1.10."); ast_expression *call = expr->subexpressions[1]; assert(call->oper == ast_function_call); const char *method; method = call->subexpressions[0]->primary_expression.identifier; if (op->type->is_array() && strcmp(method, "length") == 0) { if (!call->expressions.is_empty()) _mesa_glsl_error(&loc, state, "length method takes no arguments."); if (op->type->array_size() == 0) _mesa_glsl_error(&loc, state, "length called on unsized array."); result = new(ctx) ir_constant(op->type->array_size()); } else { _mesa_glsl_error(&loc, state, "Unknown method: `%s'.", method); } } else { _mesa_glsl_error(& loc, state, "Cannot access field `%s' of " "non-structure / non-vector.", expr->primary_expression.identifier); } return result ? result : ir_rvalue::error_value(ctx); }