diff options
author | Jason Ekstrand <jason.ekstrand@intel.com> | 2016-04-01 14:59:38 -0700 |
---|---|---|
committer | Jason Ekstrand <jason.ekstrand@intel.com> | 2016-04-01 15:16:21 -0700 |
commit | 95106f6bfbbb87b702e4bbba98e2eaea71924cd9 (patch) | |
tree | 9650d284ec7f7417b2bcf8a906dfa43dfc547cf7 /src/compiler | |
parent | cf2257069cbde19fd177a02c079206914aac5d14 (diff) | |
parent | 14c46954c910efb1db94a068a866c7259deaa9d9 (diff) | |
download | external_mesa3d-95106f6bfbbb87b702e4bbba98e2eaea71924cd9.zip external_mesa3d-95106f6bfbbb87b702e4bbba98e2eaea71924cd9.tar.gz external_mesa3d-95106f6bfbbb87b702e4bbba98e2eaea71924cd9.tar.bz2 |
Merge remote-tracking branch 'public/master' into vulkan
Diffstat (limited to 'src/compiler')
33 files changed, 1220 insertions, 316 deletions
diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 43377f1..120ef29 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -179,10 +179,10 @@ NIR_FILES = \ nir/nir_gather_info.c \ nir/nir_gs_count_vertices.c \ nir/nir_inline_functions.c \ - nir/nir_intrinsics.c \ - nir/nir_intrinsics.h \ nir/nir_instr_set.c \ nir/nir_instr_set.h \ + nir/nir_intrinsics.c \ + nir/nir_intrinsics.h \ nir/nir_liveness.c \ nir/nir_lower_alu_to_scalar.c \ nir/nir_lower_atomics.c \ diff --git a/src/compiler/glsl/ast.h b/src/compiler/glsl/ast.h index 727aa43..7436edc 100644 --- a/src/compiler/glsl/ast.h +++ b/src/compiler/glsl/ast.h @@ -214,6 +214,7 @@ public: subexpressions[2] = NULL; primary_expression.identifier = identifier; this->non_lvalue_description = NULL; + this->is_lhs = false; } static const char *operator_string(enum ast_operators op); @@ -263,6 +264,11 @@ public: * This pointer may be \c NULL. */ const char *non_lvalue_description; + + void set_is_lhs(bool new_value); + +private: + bool is_lhs; }; class ast_expression_bin : public ast_expression { @@ -556,6 +562,15 @@ struct ast_type_qualifier { unsigned explicit_stream:1; /**< stream value assigned explicitly by shader code */ /** \} */ + /** \name Layout qualifiers for GL_ARB_enhanced_layouts */ + /** \{ */ + unsigned explicit_xfb_offset:1; /**< xfb_offset value assigned explicitly by shader code */ + unsigned xfb_buffer:1; /**< Has xfb_buffer value assigned */ + unsigned explicit_xfb_buffer:1; /**< xfb_buffer value assigned explicitly by shader code */ + unsigned xfb_stride:1; /**< Is xfb_stride value yet to be merged with global values */ + unsigned explicit_xfb_stride:1; /**< xfb_stride value assigned explicitly by shader code */ + /** \} */ + /** \name Layout qualifiers for GL_ARB_tessellation_shader */ /** \{ */ /* tess eval input layout */ @@ -612,6 +627,15 @@ struct ast_type_qualifier { /** Stream in GLSL 1.50 geometry shaders. */ ast_expression *stream; + /** xfb_buffer specified via the GL_ARB_enhanced_layouts keyword. */ + ast_expression *xfb_buffer; + + /** xfb_stride specified via the GL_ARB_enhanced_layouts keyword. */ + ast_expression *xfb_stride; + + /** global xfb_stride values for each buffer */ + ast_layout_expression *out_xfb_stride[MAX_FEEDBACK_BUFFERS]; + /** * Input or output primitive type in GLSL 1.50 geometry shaders * and tessellation shaders. @@ -627,8 +651,9 @@ struct ast_type_qualifier { ast_expression *binding; /** - * Offset specified via GL_ARB_shader_atomic_counter's "offset" - * keyword. + * Offset specified via GL_ARB_shader_atomic_counter's or + * GL_ARB_enhanced_layouts "offset" keyword, or by GL_ARB_enhanced_layouts + * "xfb_offset" keyword. * * \note * This field is only valid if \c explicit_offset is set. @@ -1199,4 +1224,10 @@ extern void _mesa_ast_process_interface_block(YYLTYPE *locp, ast_interface_block *const block, const struct ast_type_qualifier &q); +extern bool +process_qualifier_constant(struct _mesa_glsl_parse_state *state, + YYLTYPE *loc, + const char *qual_indentifier, + ast_expression *const_expression, + unsigned *value); #endif /* AST_H */ diff --git a/src/compiler/glsl/ast_function.cpp b/src/compiler/glsl/ast_function.cpp index 1a44020..db68d5d 100644 --- a/src/compiler/glsl/ast_function.cpp +++ b/src/compiler/glsl/ast_function.cpp @@ -1727,6 +1727,10 @@ ast_function_expression::handle_method(exec_list *instructions, const char *method; method = field->primary_expression.identifier; + /* This would prevent to raise "uninitialized variable" warnings when + * calling array.length. + */ + field->subexpressions[0]->set_is_lhs(true); op = field->subexpressions[0]->hir(instructions, state); if (strcmp(method, "length") == 0) { if (!this->expressions.is_empty()) { diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp index 35def8e..3fe9007 100644 --- a/src/compiler/glsl/ast_to_hir.cpp +++ b/src/compiler/glsl/ast_to_hir.cpp @@ -54,6 +54,7 @@ #include "ast.h" #include "compiler/glsl_types.h" #include "program/hash_table.h" +#include "main/macros.h" #include "main/shaderobj.h" #include "ir.h" #include "ir_builder.h" @@ -819,7 +820,7 @@ validate_assignment(struct _mesa_glsl_parse_state *state, * if the expression indicating the vertex number is not the identifier * `gl_InvocationID`. */ - if (state->stage == MESA_SHADER_TESS_CTRL) { + if (state->stage == MESA_SHADER_TESS_CTRL && !lhs->type->is_error()) { ir_variable *var = lhs->variable_referenced(); if (var->data.mode == ir_var_shader_out && !var->data.patch) { ir_rvalue *index = find_innermost_array_index(lhs); @@ -1248,6 +1249,24 @@ ast_expression::hir_no_rvalue(exec_list *instructions, do_hir(instructions, state, false); } +void +ast_expression::set_is_lhs(bool new_value) +{ + /* is_lhs is tracked only to print "variable used uninitialized" warnings, + * if we lack a identifier we can just skip it. + */ + if (this->primary_expression.identifier == NULL) + return; + + this->is_lhs = new_value; + + /* We need to go through the subexpressions tree to cover cases like + * ast_field_selection + */ + if (this->subexpressions[0] != NULL) + this->subexpressions[0]->set_is_lhs(new_value); +} + ir_rvalue * ast_expression::do_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state, @@ -1323,6 +1342,7 @@ ast_expression::do_hir(exec_list *instructions, break; case ast_assign: { + this->subexpressions[0]->set_is_lhs(true); op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); @@ -1592,6 +1612,7 @@ ast_expression::do_hir(exec_list *instructions, case ast_div_assign: case ast_add_assign: case ast_sub_assign: { + this->subexpressions[0]->set_is_lhs(true); op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); @@ -1618,6 +1639,7 @@ ast_expression::do_hir(exec_list *instructions, } case ast_mod_assign: { + this->subexpressions[0]->set_is_lhs(true); op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); @@ -1640,6 +1662,7 @@ ast_expression::do_hir(exec_list *instructions, case ast_ls_assign: case ast_rs_assign: { + this->subexpressions[0]->set_is_lhs(true); op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = shift_result_type(op[0]->type, op[1]->type, this->oper, state, @@ -1658,6 +1681,7 @@ ast_expression::do_hir(exec_list *instructions, case ast_and_assign: case ast_xor_assign: case ast_or_assign: { + this->subexpressions[0]->set_is_lhs(true); op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = bit_logic_result_type(op[0], op[1], this->oper, state, &loc); @@ -1839,6 +1863,11 @@ ast_expression::do_hir(exec_list *instructions, case ast_array_index: { YYLTYPE index_loc = subexpressions[1]->get_location(); + /* Getting if an array is being used uninitialized is beyond what we get + * from ir_value.data.assigned. Setting is_lhs as true would force to + * not raise a uninitialized warning when using an array + */ + subexpressions[0]->set_is_lhs(true); op[0] = subexpressions[0]->hir(instructions, state); op[1] = subexpressions[1]->hir(instructions, state); @@ -1873,6 +1902,14 @@ ast_expression::do_hir(exec_list *instructions, if (var != NULL) { var->data.used = true; result = new(ctx) ir_dereference_variable(var); + + if ((var->data.mode == ir_var_auto || var->data.mode == ir_var_shader_out) + && !this->is_lhs + && result->variable_referenced()->data.assigned != true + && !is_gl_identifier(var->name)) { + _mesa_glsl_warning(&loc, state, "`%s' used uninitialized", + this->primary_expression.identifier); + } } else { _mesa_glsl_error(& loc, state, "`%s' undeclared", this->primary_expression.identifier); @@ -2318,11 +2355,11 @@ get_type_name_for_precision_qualifier(const glsl_type *type) return names[type_idx]; } case GLSL_SAMPLER_DIM_BUF: { - assert(type->base_type == GLSL_TYPE_SAMPLER); - static const char *const names[4] = { - "samplerBuffer", NULL, NULL, NULL + static const char *const names[8] = { + "samplerBuffer", NULL, NULL, NULL, + "imageBuffer", NULL, NULL, NULL }; - return names[type_idx]; + return names[offset + type_idx]; } case GLSL_SAMPLER_DIM_EXTERNAL: { assert(type->base_type == GLSL_TYPE_SAMPLER); @@ -2380,11 +2417,11 @@ get_type_name_for_precision_qualifier(const glsl_type *type) return names[type_idx]; } case GLSL_SAMPLER_DIM_BUF: { - assert(type->base_type == GLSL_TYPE_SAMPLER); - static const char *const names[4] = { - "isamplerBuffer", NULL, NULL, NULL + static const char *const names[8] = { + "isamplerBuffer", NULL, NULL, NULL, + "iimageBuffer", NULL, NULL, NULL }; - return names[type_idx]; + return names[offset + type_idx]; } default: unreachable("Unsupported isampler/iimage dimensionality"); @@ -2435,11 +2472,11 @@ get_type_name_for_precision_qualifier(const glsl_type *type) return names[type_idx]; } case GLSL_SAMPLER_DIM_BUF: { - assert(type->base_type == GLSL_TYPE_SAMPLER); - static const char *const names[4] = { - "usamplerBuffer", NULL, NULL, NULL + static const char *const names[8] = { + "usamplerBuffer", NULL, NULL, NULL, + "uimageBuffer", NULL, NULL, NULL }; - return names[type_idx]; + return names[offset + type_idx]; } default: unreachable("Unsupported usampler/uimage dimensionality"); @@ -2550,43 +2587,79 @@ validate_matrix_layout_for_type(struct _mesa_glsl_parse_state *state, } static 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; +validate_xfb_buffer_qualifier(YYLTYPE *loc, + struct _mesa_glsl_parse_state *state, + unsigned xfb_buffer) { + if (xfb_buffer >= state->Const.MaxTransformFeedbackBuffers) { + _mesa_glsl_error(loc, state, + "invalid xfb_buffer specified %d is larger than " + "MAX_TRANSFORM_FEEDBACK_BUFFERS - 1 (%d).", + xfb_buffer, + state->Const.MaxTransformFeedbackBuffers - 1); + return false; } - ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state); + return true; +} - 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; - } +/* From the ARB_enhanced_layouts spec: + * + * "Variables and block members qualified with *xfb_offset* can be + * scalars, vectors, matrices, structures, and (sized) arrays of these. + * The offset must be a multiple of the size of the first component of + * the first qualified variable or block member, or a compile-time error + * results. Further, if applied to an aggregate containing a double, + * the offset must also be a multiple of 8, and the space taken in the + * buffer will be a multiple of 8. + */ +static bool +validate_xfb_offset_qualifier(YYLTYPE *loc, + struct _mesa_glsl_parse_state *state, + int xfb_offset, const glsl_type *type, + unsigned component_size) { + const glsl_type *t_without_array = type->without_array(); - 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]); + if (xfb_offset != -1 && type->is_unsized_array()) { + _mesa_glsl_error(loc, state, + "xfb_offset can't be used with unsized arrays."); 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. + /* Make sure nested structs don't contain unsized arrays, and validate + * any xfb_offsets on interface members. */ - assert(dummy_instructions.is_empty()); + if (t_without_array->is_record() || t_without_array->is_interface()) + for (unsigned int i = 0; i < t_without_array->length; i++) { + const glsl_type *member_t = t_without_array->fields.structure[i].type; + + /* When the interface block doesn't have an xfb_offset qualifier then + * we apply the component size rules at the member level. + */ + if (xfb_offset == -1) + component_size = member_t->contains_double() ? 8 : 4; + + int xfb_offset = t_without_array->fields.structure[i].offset; + validate_xfb_offset_qualifier(loc, state, xfb_offset, member_t, + component_size); + } + + /* Nested structs or interface block without offset may not have had an + * offset applied yet so return. + */ + if (xfb_offset == -1) { + return true; + } + + if (xfb_offset % component_size) { + _mesa_glsl_error(loc, state, + "invalid qualifier xfb_offset=%d must be a multiple " + "of the first component size of the first qualified " + "variable or block member. Or double if an aggregate " + "that contains a double (%d).", + xfb_offset, component_size); + return false; + } - *value = const_int->value.u[0]; return true; } @@ -3151,6 +3224,39 @@ apply_layout_qualifier_to_variable(const struct ast_type_qualifier *qual, } } + if (qual->flags.q.out && qual->flags.q.xfb_buffer) { + unsigned qual_xfb_buffer; + if (process_qualifier_constant(state, loc, "xfb_buffer", + qual->xfb_buffer, &qual_xfb_buffer) && + validate_xfb_buffer_qualifier(loc, state, qual_xfb_buffer)) { + var->data.xfb_buffer = qual_xfb_buffer; + if (qual->flags.q.explicit_xfb_buffer) + var->data.explicit_xfb_buffer = true; + } + } + + if (qual->flags.q.explicit_xfb_offset) { + unsigned qual_xfb_offset; + unsigned component_size = var->type->contains_double() ? 8 : 4; + + if (process_qualifier_constant(state, loc, "xfb_offset", + qual->offset, &qual_xfb_offset) && + validate_xfb_offset_qualifier(loc, state, (int) qual_xfb_offset, + var->type, component_size)) { + var->data.offset = qual_xfb_offset; + var->data.explicit_xfb_offset = true; + } + } + + if (qual->flags.q.explicit_xfb_stride) { + unsigned qual_xfb_stride; + if (process_qualifier_constant(state, loc, "xfb_stride", + qual->xfb_stride, &qual_xfb_stride)) { + var->data.xfb_stride = qual_xfb_stride; + var->data.explicit_xfb_stride = true; + } + } + if (var->type->contains_atomic()) { if (var->data.mode == ir_var_uniform) { if (var->data.explicit_binding) { @@ -5746,6 +5852,11 @@ ast_switch_statement::test_to_hir(exec_list *instructions, { void *ctx = state; + /* set to true to avoid a duplicate "use of uninitialized variable" warning + * on the switch test case. The first one would be already raised when + * getting the test_expression at ast_switch_statement::hir + */ + test_expression->set_is_lhs(true); /* Cache value of test expression. */ ir_rvalue *const test_val = test_expression->hir(instructions, @@ -6258,6 +6369,8 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, ir_variable_mode var_mode, ast_type_qualifier *layout, unsigned block_stream, + unsigned block_xfb_buffer, + unsigned block_xfb_offset, unsigned expl_location, unsigned expl_align) { @@ -6413,6 +6526,35 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, } } + int xfb_buffer; + unsigned explicit_xfb_buffer = 0; + if (qual->flags.q.explicit_xfb_buffer) { + unsigned qual_xfb_buffer; + if (process_qualifier_constant(state, &loc, "xfb_buffer", + qual->xfb_buffer, &qual_xfb_buffer)) { + explicit_xfb_buffer = 1; + if (qual_xfb_buffer != block_xfb_buffer) + _mesa_glsl_error(&loc, state, "xfb_buffer layout qualifier on " + "interface block member does not match " + "the interface block (%u vs %u)", + qual_xfb_buffer, block_xfb_buffer); + } + xfb_buffer = (int) qual_xfb_buffer; + } else { + if (layout) + explicit_xfb_buffer = layout->flags.q.xfb_buffer; + xfb_buffer = (int) block_xfb_buffer; + } + + int xfb_stride = -1; + if (qual->flags.q.explicit_xfb_stride) { + unsigned qual_xfb_stride; + if (process_qualifier_constant(state, &loc, "xfb_stride", + qual->xfb_stride, &qual_xfb_stride)) { + xfb_stride = (int) qual_xfb_stride; + } + } + if (qual->flags.q.uniform && qual->has_interpolation()) { _mesa_glsl_error(&loc, state, "interpolation qualifiers cannot be used " @@ -6458,6 +6600,10 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, fields[i].sample = qual->flags.q.sample ? 1 : 0; fields[i].patch = qual->flags.q.patch ? 1 : 0; fields[i].precision = qual->precision; + fields[i].offset = -1; + fields[i].explicit_xfb_buffer = explicit_xfb_buffer; + fields[i].xfb_buffer = xfb_buffer; + fields[i].xfb_stride = xfb_stride; if (qual->flags.q.explicit_location) { unsigned qual_location; @@ -6520,8 +6666,6 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, "with std430 and std140 layouts"); } } - } else { - fields[i].offset = -1; } if (qual->flags.q.explicit_align || expl_align != 0) { @@ -6554,6 +6698,32 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, next_offset = glsl_align(next_offset + size, align); } + /* From the ARB_enhanced_layouts spec: + * + * "The given offset applies to the first component of the first + * member of the qualified entity. Then, within the qualified + * entity, subsequent components are each assigned, in order, to + * the next available offset aligned to a multiple of that + * component's size. Aggregate types are flattened down to the + * component level to get this sequence of components." + */ + if (qual->flags.q.explicit_xfb_offset) { + unsigned xfb_offset; + if (process_qualifier_constant(state, &loc, "xfb_offset", + qual->offset, &xfb_offset)) { + fields[i].offset = xfb_offset; + block_xfb_offset = fields[i].offset + + MAX2(xfb_stride, (int) (4 * field_type->component_slots())); + } + } else { + if (layout && layout->flags.q.explicit_xfb_offset) { + unsigned align = field_type->is_double() ? 8 : 4; + fields[i].offset = glsl_align(block_xfb_offset, align); + block_xfb_offset += + MAX2(xfb_stride, (int) (4 * field_type->component_slots())); + } + } + /* Propogate row- / column-major information down the fields of the * structure or interface block. Structures need this data because * the structure may contain a structure that contains ... a matrix @@ -6648,6 +6818,8 @@ ast_struct_specifier::hir(exec_list *instructions, ir_var_auto, layout, 0, /* for interface only */ + 0, /* for interface only */ + 0, /* for interface only */ expl_location, 0 /* for interface only */); @@ -6807,6 +6979,29 @@ ast_interface_block::hir(exec_list *instructions, return NULL; } + unsigned qual_xfb_buffer; + if (!process_qualifier_constant(state, &loc, "xfb_buffer", + layout.xfb_buffer, &qual_xfb_buffer) || + !validate_xfb_buffer_qualifier(&loc, state, qual_xfb_buffer)) { + return NULL; + } + + unsigned qual_xfb_offset; + if (layout.flags.q.explicit_xfb_offset) { + if (!process_qualifier_constant(state, &loc, "xfb_offset", + layout.offset, &qual_xfb_offset)) { + return NULL; + } + } + + unsigned qual_xfb_stride; + if (layout.flags.q.explicit_xfb_stride) { + if (!process_qualifier_constant(state, &loc, "xfb_stride", + layout.xfb_stride, &qual_xfb_stride)) { + return NULL; + } + } + unsigned expl_location = 0; if (layout.flags.q.explicit_location) { if (!process_qualifier_constant(state, &loc, "location", @@ -6842,6 +7037,8 @@ ast_interface_block::hir(exec_list *instructions, var_mode, &this->layout, qual_stream, + qual_xfb_buffer, + qual_xfb_offset, expl_location, expl_align); @@ -6956,6 +7153,12 @@ ast_interface_block::hir(exec_list *instructions, earlier_per_vertex->fields.structure[j].patch; fields[i].precision = earlier_per_vertex->fields.structure[j].precision; + fields[i].explicit_xfb_buffer = + earlier_per_vertex->fields.structure[j].explicit_xfb_buffer; + fields[i].xfb_buffer = + earlier_per_vertex->fields.structure[j].xfb_buffer; + fields[i].xfb_stride = + earlier_per_vertex->fields.structure[j].xfb_stride; } } @@ -6986,6 +7189,12 @@ ast_interface_block::hir(exec_list *instructions, packing, this->block_name); + unsigned component_size = block_type->contains_double() ? 8 : 4; + int xfb_offset = + layout.flags.q.explicit_xfb_offset ? (int) qual_xfb_offset : -1; + validate_xfb_offset_qualifier(&loc, state, xfb_offset, block_type, + component_size); + if (!state->symbols->add_interface(block_type->name, block_type, var_mode)) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(&loc, state, "interface block `%s' with type `%s' " @@ -7207,8 +7416,17 @@ ast_interface_block::hir(exec_list *instructions, var->data.patch = fields[i].patch; var->data.stream = qual_stream; var->data.location = fields[i].location; + if (fields[i].location != -1) var->data.explicit_location = true; + + var->data.explicit_xfb_buffer = fields[i].explicit_xfb_buffer; + var->data.xfb_buffer = fields[i].xfb_buffer; + + if (fields[i].offset != -1) + var->data.explicit_xfb_offset = true; + var->data.offset = fields[i].offset; + var->init_interface_type(block_type); if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform) diff --git a/src/compiler/glsl/ast_type.cpp b/src/compiler/glsl/ast_type.cpp index 07ed4f2..c3d38cb 100644 --- a/src/compiler/glsl/ast_type.cpp +++ b/src/compiler/glsl/ast_type.cpp @@ -79,7 +79,10 @@ ast_type_qualifier::has_layout() const || this->flags.q.explicit_index || this->flags.q.explicit_binding || this->flags.q.explicit_offset - || this->flags.q.explicit_stream; + || this->flags.q.explicit_stream + || this->flags.q.explicit_xfb_buffer + || this->flags.q.explicit_xfb_offset + || this->flags.q.explicit_xfb_stride; } bool @@ -229,6 +232,43 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, } } + 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) { + /* 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); @@ -300,7 +340,7 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, if (q.flags.q.explicit_binding) this->binding = q.binding; - if (q.flags.q.explicit_offset) + if (q.flags.q.explicit_offset || q.flags.q.explicit_xfb_offset) this->offset = q.offset; if (q.precision != ast_precision_none) @@ -322,6 +362,8 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc, { 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) { @@ -340,13 +382,45 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc, /* 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 { _mesa_glsl_error(loc, state, "out layout qualifiers only valid in " - "tessellation control or geometry shaders"); + "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; @@ -566,3 +640,44 @@ ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state return true; } + +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; +} diff --git a/src/compiler/glsl/builtin_functions.cpp b/src/compiler/glsl/builtin_functions.cpp index ff6b628..65309fd 100644 --- a/src/compiler/glsl/builtin_functions.cpp +++ b/src/compiler/glsl/builtin_functions.cpp @@ -130,12 +130,6 @@ v130_fs_only(const _mesa_glsl_parse_state *state) } static bool -v140(const _mesa_glsl_parse_state *state) -{ - return state->is_version(140, 0); -} - -static bool v140_or_es3(const _mesa_glsl_parse_state *state) { return state->is_version(140, 300); @@ -184,6 +178,14 @@ v110_lod(const _mesa_glsl_parse_state *state) } static bool +texture_buffer(const _mesa_glsl_parse_state *state) +{ + return state->is_version(140, 320) || + state->EXT_texture_buffer_enable || + state->OES_texture_buffer_enable; +} + +static bool shader_texture_lod(const _mesa_glsl_parse_state *state) { return state->ARB_shader_texture_lod_enable; @@ -262,10 +264,12 @@ shader_packing_or_es31_or_gpu_shader5(const _mesa_glsl_parse_state *state) } static bool -fs_gpu_shader5(const _mesa_glsl_parse_state *state) +fs_interpolate_at(const _mesa_glsl_parse_state *state) { return state->stage == MESA_SHADER_FRAGMENT && - (state->is_version(400, 0) || state->ARB_gpu_shader5_enable); + (state->is_version(400, 320) || + state->ARB_gpu_shader5_enable || + state->OES_shader_multisample_interpolation_enable); } @@ -1581,9 +1585,9 @@ builtin_builder::create_builtins() _textureSize(v130, glsl_type::ivec2_type, glsl_type::usampler2DRect_type), _textureSize(v130, glsl_type::ivec2_type, glsl_type::sampler2DRectShadow_type), - _textureSize(v140, glsl_type::int_type, glsl_type::samplerBuffer_type), - _textureSize(v140, glsl_type::int_type, glsl_type::isamplerBuffer_type), - _textureSize(v140, glsl_type::int_type, glsl_type::usamplerBuffer_type), + _textureSize(texture_buffer, glsl_type::int_type, glsl_type::samplerBuffer_type), + _textureSize(texture_buffer, glsl_type::int_type, glsl_type::isamplerBuffer_type), + _textureSize(texture_buffer, glsl_type::int_type, glsl_type::usamplerBuffer_type), _textureSize(texture_multisample, glsl_type::ivec2_type, glsl_type::sampler2DMS_type), _textureSize(texture_multisample, glsl_type::ivec2_type, glsl_type::isampler2DMS_type), _textureSize(texture_multisample, glsl_type::ivec2_type, glsl_type::usampler2DMS_type), @@ -1855,9 +1859,9 @@ builtin_builder::create_builtins() _texelFetch(v130, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::ivec3_type), _texelFetch(v130, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::ivec3_type), - _texelFetch(v140, glsl_type::vec4_type, glsl_type::samplerBuffer_type, glsl_type::int_type), - _texelFetch(v140, glsl_type::ivec4_type, glsl_type::isamplerBuffer_type, glsl_type::int_type), - _texelFetch(v140, glsl_type::uvec4_type, glsl_type::usamplerBuffer_type, glsl_type::int_type), + _texelFetch(texture_buffer, glsl_type::vec4_type, glsl_type::samplerBuffer_type, glsl_type::int_type), + _texelFetch(texture_buffer, glsl_type::ivec4_type, glsl_type::isamplerBuffer_type, glsl_type::int_type), + _texelFetch(texture_buffer, glsl_type::uvec4_type, glsl_type::usamplerBuffer_type, glsl_type::int_type), _texelFetch(texture_multisample, glsl_type::vec4_type, glsl_type::sampler2DMS_type, glsl_type::ivec2_type), _texelFetch(texture_multisample, glsl_type::ivec4_type, glsl_type::isampler2DMS_type, glsl_type::ivec2_type), @@ -5163,7 +5167,7 @@ builtin_builder::_interpolateAtCentroid(const glsl_type *type) { ir_variable *interpolant = in_var(type, "interpolant"); interpolant->data.must_be_shader_input = 1; - MAKE_SIG(type, fs_gpu_shader5, 1, interpolant); + MAKE_SIG(type, fs_interpolate_at, 1, interpolant); body.emit(ret(interpolate_at_centroid(interpolant))); @@ -5176,7 +5180,7 @@ builtin_builder::_interpolateAtOffset(const glsl_type *type) ir_variable *interpolant = in_var(type, "interpolant"); interpolant->data.must_be_shader_input = 1; ir_variable *offset = in_var(glsl_type::vec2_type, "offset"); - MAKE_SIG(type, fs_gpu_shader5, 2, interpolant, offset); + MAKE_SIG(type, fs_interpolate_at, 2, interpolant, offset); body.emit(ret(interpolate_at_offset(interpolant, offset))); @@ -5189,7 +5193,7 @@ builtin_builder::_interpolateAtSample(const glsl_type *type) ir_variable *interpolant = in_var(type, "interpolant"); interpolant->data.must_be_shader_input = 1; ir_variable *sample_num = in_var(glsl_type::int_type, "sample_num"); - MAKE_SIG(type, fs_gpu_shader5, 2, interpolant, sample_num); + MAKE_SIG(type, fs_interpolate_at, 2, interpolant, sample_num); body.emit(ret(interpolate_at_sample(interpolant, sample_num))); diff --git a/src/compiler/glsl/builtin_types.cpp b/src/compiler/glsl/builtin_types.cpp index ee24bd5..d250234 100644 --- a/src/compiler/glsl/builtin_types.cpp +++ b/src/compiler/glsl/builtin_types.cpp @@ -179,7 +179,7 @@ static const struct builtin_type_versions { T(sampler2DArray, 130, 300) T(samplerCubeArray, 400, 999) T(sampler2DRect, 140, 999) - T(samplerBuffer, 140, 999) + T(samplerBuffer, 140, 320) T(sampler2DMS, 150, 310) T(sampler2DMSArray, 150, 999) @@ -191,7 +191,7 @@ static const struct builtin_type_versions { T(isampler2DArray, 130, 300) T(isamplerCubeArray, 400, 999) T(isampler2DRect, 140, 999) - T(isamplerBuffer, 140, 999) + T(isamplerBuffer, 140, 320) T(isampler2DMS, 150, 310) T(isampler2DMSArray, 150, 999) @@ -203,7 +203,7 @@ static const struct builtin_type_versions { T(usampler2DArray, 130, 300) T(usamplerCubeArray, 400, 999) T(usampler2DRect, 140, 999) - T(usamplerBuffer, 140, 999) + T(usamplerBuffer, 140, 320) T(usampler2DMS, 150, 310) T(usampler2DMSArray, 150, 999) @@ -222,7 +222,7 @@ static const struct builtin_type_versions { T(image3D, 420, 310) T(image2DRect, 420, 999) T(imageCube, 420, 310) - T(imageBuffer, 420, 999) + T(imageBuffer, 420, 320) T(image1DArray, 420, 999) T(image2DArray, 420, 310) T(imageCubeArray, 420, 999) @@ -233,7 +233,7 @@ static const struct builtin_type_versions { T(iimage3D, 420, 310) T(iimage2DRect, 420, 999) T(iimageCube, 420, 310) - T(iimageBuffer, 420, 999) + T(iimageBuffer, 420, 320) T(iimage1DArray, 420, 999) T(iimage2DArray, 420, 310) T(iimageCubeArray, 420, 999) @@ -244,7 +244,7 @@ static const struct builtin_type_versions { T(uimage3D, 420, 310) T(uimage2DRect, 420, 999) T(uimageCube, 420, 310) - T(uimageBuffer, 420, 999) + T(uimageBuffer, 420, 320) T(uimage1DArray, 420, 999) T(uimage2DArray, 420, 310) T(uimageCubeArray, 420, 999) @@ -371,6 +371,16 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) add_type(symbols, glsl_type::uimage2DMSArray_type); } + if (state->EXT_texture_buffer_enable || state->OES_texture_buffer_enable) { + add_type(symbols, glsl_type::samplerBuffer_type); + add_type(symbols, glsl_type::isamplerBuffer_type); + add_type(symbols, glsl_type::usamplerBuffer_type); + + add_type(symbols, glsl_type::imageBuffer_type); + add_type(symbols, glsl_type::iimageBuffer_type); + add_type(symbols, glsl_type::uimageBuffer_type); + } + if (state->has_atomic_counters()) { add_type(symbols, glsl_type::atomic_uint_type); } diff --git a/src/compiler/glsl/builtin_variables.cpp b/src/compiler/glsl/builtin_variables.cpp index 4e2de37..7d77f70 100644 --- a/src/compiler/glsl/builtin_variables.cpp +++ b/src/compiler/glsl/builtin_variables.cpp @@ -334,6 +334,9 @@ per_vertex_accumulator::add_field(int slot, const glsl_type *type, this->fields[this->num_fields].image_coherent = 0; this->fields[this->num_fields].image_volatile = 0; this->fields[this->num_fields].image_restrict = 0; + this->fields[this->num_fields].explicit_xfb_buffer = 0; + this->fields[this->num_fields].xfb_buffer = -1; + this->fields[this->num_fields].xfb_stride = -1; this->num_fields++; } @@ -812,6 +815,13 @@ builtin_variable_generator::generate_constants() */ } + if (state->has_enhanced_layouts()) { + add_const("gl_MaxTransformFeedbackBuffers", + state->Const.MaxTransformFeedbackBuffers); + add_const("gl_MaxTransformFeedbackInterleavedComponents", + state->Const.MaxTransformFeedbackInterleavedComponents); + } + if (state->is_version(420, 310) || state->ARB_shader_image_load_store_enable) { add_const("gl_MaxImageUnits", @@ -868,6 +878,10 @@ builtin_variable_generator::generate_constants() add_const("gl_MaxTessControlUniformComponents", state->Const.MaxTessControlUniformComponents); add_const("gl_MaxTessEvaluationUniformComponents", state->Const.MaxTessEvaluationUniformComponents); } + + if (state->is_version(450, 320) || + state->OES_sample_variables_enable) + add_const("gl_MaxSamples", state->Const.MaxSamples); } @@ -877,7 +891,9 @@ builtin_variable_generator::generate_constants() void builtin_variable_generator::generate_uniforms() { - if (state->is_version(400, 0) || state->ARB_sample_shading_enable) + if (state->is_version(400, 320) || + state->ARB_sample_shading_enable || + state->OES_sample_variables_enable) add_uniform(int_t, "gl_NumSamples"); add_uniform(type("gl_DepthRangeParameters"), "gl_DepthRange"); add_uniform(array(vec4_t, VERT_ATTRIB_MAX), "gl_CurrentAttribVertMESA"); @@ -1130,7 +1146,9 @@ builtin_variable_generator::generate_fs_special_vars() var->enable_extension_warning("GL_AMD_shader_stencil_export"); } - if (state->is_version(400, 0) || state->ARB_sample_shading_enable) { + if (state->is_version(400, 320) || + state->ARB_sample_shading_enable || + state->OES_sample_variables_enable) { add_system_value(SYSTEM_VALUE_SAMPLE_ID, int_t, "gl_SampleID"); add_system_value(SYSTEM_VALUE_SAMPLE_POS, vec2_t, "gl_SamplePosition"); /* From the ARB_sample_shading specification: @@ -1143,7 +1161,9 @@ builtin_variable_generator::generate_fs_special_vars() add_output(FRAG_RESULT_SAMPLE_MASK, array(int_t, 1), "gl_SampleMask"); } - if (state->is_version(400, 0) || state->ARB_gpu_shader5_enable) { + if (state->is_version(400, 320) || + state->ARB_gpu_shader5_enable || + state->OES_sample_variables_enable) { add_system_value(SYSTEM_VALUE_SAMPLE_MASK_IN, array(int_t, 1), "gl_SampleMaskIn"); } diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y b/src/compiler/glsl/glcpp/glcpp-parse.y index 007b70b..e8646c0 100644 --- a/src/compiler/glsl/glcpp/glcpp-parse.y +++ b/src/compiler/glsl/glcpp/glcpp-parse.y @@ -2371,6 +2371,10 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio if (extensions != NULL) { if (extensions->OES_EGL_image_external) add_builtin_define(parser, "GL_OES_EGL_image_external", 1); + if (extensions->OES_sample_variables) { + add_builtin_define(parser, "GL_OES_sample_variables", 1); + add_builtin_define(parser, "GL_OES_shader_multisample_interpolation", 1); + } if (extensions->OES_standard_derivatives) add_builtin_define(parser, "GL_OES_standard_derivatives", 1); if (extensions->ARB_texture_multisample) @@ -2390,6 +2394,10 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio add_builtin_define(parser, "GL_EXT_gpu_shader5", 1); add_builtin_define(parser, "GL_OES_gpu_shader5", 1); } + if (extensions->OES_texture_buffer) { + add_builtin_define(parser, "GL_EXT_texture_buffer", 1); + add_builtin_define(parser, "GL_OES_texture_buffer", 1); + } } } } else { diff --git a/src/compiler/glsl/glsl_lexer.ll b/src/compiler/glsl/glsl_lexer.ll index 1f12265..0b7695f 100644 --- a/src/compiler/glsl/glsl_lexer.ll +++ b/src/compiler/glsl/glsl_lexer.ll @@ -369,7 +369,7 @@ image2D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_l image3D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IMAGE3D); image2DRect KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IMAGE2DRECT); imageCube KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IMAGECUBE); -imageBuffer KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IMAGEBUFFER); +imageBuffer KEYWORD_WITH_ALT(130, 300, 420, 320, yyextra->ARB_shader_image_load_store_enable || yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, IMAGEBUFFER); image1DArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IMAGE1DARRAY); image2DArray KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IMAGE2DARRAY); imageCubeArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IMAGECUBEARRAY); @@ -380,7 +380,7 @@ iimage2D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_l iimage3D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IIMAGE3D); iimage2DRect KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IIMAGE2DRECT); iimageCube KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IIMAGECUBE); -iimageBuffer KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IIMAGEBUFFER); +iimageBuffer KEYWORD_WITH_ALT(130, 300, 420, 320, yyextra->ARB_shader_image_load_store_enable || yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, IIMAGEBUFFER); iimage1DArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IIMAGE1DARRAY); iimage2DArray KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, IIMAGE2DARRAY); iimageCubeArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, IIMAGECUBEARRAY); @@ -391,7 +391,7 @@ uimage2D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_l uimage3D KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, UIMAGE3D); uimage2DRect KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, UIMAGE2DRECT); uimageCube KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, UIMAGECUBE); -uimageBuffer KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, UIMAGEBUFFER); +uimageBuffer KEYWORD_WITH_ALT(130, 300, 420, 320, yyextra->ARB_shader_image_load_store_enable || yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, UIMAGEBUFFER); uimage1DArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, UIMAGE1DARRAY); uimage2DArray KEYWORD_WITH_ALT(130, 300, 420, 310, yyextra->ARB_shader_image_load_store_enable, UIMAGE2DARRAY); uimageCubeArray KEYWORD_WITH_ALT(130, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, UIMAGECUBEARRAY); @@ -472,6 +472,13 @@ layout { \.[0-9]+([eE][+-]?[0-9]+)?[fF]? | [0-9]+\.([eE][+-]?[0-9]+)?[fF]? | [0-9]+[eE][+-]?[0-9]+[fF]? { + struct _mesa_glsl_parse_state *state = yyextra; + char suffix = yytext[strlen(yytext) - 1]; + if (!state->is_version(120, 300) && + (suffix == 'f' || suffix == 'F')) { + _mesa_glsl_error(yylloc, state, + "Float suffixes are invalid in GLSL 1.10"); + } yylval->real = _mesa_strtof(yytext, NULL); return FLOATCONSTANT; } @@ -565,19 +572,19 @@ common KEYWORD(130, 300, 0, 0, COMMON); partition KEYWORD(130, 300, 0, 0, PARTITION); active KEYWORD(130, 300, 0, 0, ACTIVE); superp KEYWORD(130, 100, 0, 0, SUPERP); -samplerBuffer KEYWORD(130, 300, 140, 0, SAMPLERBUFFER); +samplerBuffer KEYWORD_WITH_ALT(130, 300, 140, 320, yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, SAMPLERBUFFER); filter KEYWORD(130, 300, 0, 0, FILTER); row_major KEYWORD_WITH_ALT(130, 0, 140, 0, yyextra->ARB_uniform_buffer_object_enable && !yyextra->es_shader, ROW_MAJOR); /* Additional reserved words in GLSL 1.40 */ isampler2DRect KEYWORD(140, 300, 140, 0, ISAMPLER2DRECT); usampler2DRect KEYWORD(140, 300, 140, 0, USAMPLER2DRECT); -isamplerBuffer KEYWORD(140, 300, 140, 0, ISAMPLERBUFFER); -usamplerBuffer KEYWORD(140, 300, 140, 0, USAMPLERBUFFER); +isamplerBuffer KEYWORD_WITH_ALT(140, 300, 140, 320, yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, ISAMPLERBUFFER); +usamplerBuffer KEYWORD_WITH_ALT(140, 300, 140, 320, yyextra->EXT_texture_buffer_enable || yyextra->OES_texture_buffer_enable, USAMPLERBUFFER); /* Additional reserved words in GLSL ES 3.00 */ resource KEYWORD(0, 300, 0, 0, RESOURCE); -sample KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_gpu_shader5_enable, SAMPLE); +sample KEYWORD_WITH_ALT(400, 300, 400, 320, yyextra->ARB_gpu_shader5_enable || yyextra->OES_shader_multisample_interpolation_enable, SAMPLE); subroutine KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_shader_subroutine_enable, SUBROUTINE); diff --git a/src/compiler/glsl/glsl_parser.yy b/src/compiler/glsl/glsl_parser.yy index 5ed051a..1cecc09 100644 --- a/src/compiler/glsl/glsl_parser.yy +++ b/src/compiler/glsl/glsl_parser.yy @@ -1541,6 +1541,25 @@ layout_qualifier_id: } } + if (state->has_enhanced_layouts()) { + if (match_layout_qualifier("xfb_buffer", $1, state) == 0) { + $$.flags.q.xfb_buffer = 1; + $$.flags.q.explicit_xfb_buffer = 1; + $$.xfb_buffer = $3; + } + + if (match_layout_qualifier("xfb_offset", $1, state) == 0) { + $$.flags.q.explicit_xfb_offset = 1; + $$.offset = $3; + } + + if (match_layout_qualifier("xfb_stride", $1, state) == 0) { + $$.flags.q.xfb_stride = 1; + $$.flags.q.explicit_xfb_stride = 1; + $$.xfb_stride = $3; + } + } + static const char * const local_size_qualifiers[3] = { "local_size_x", "local_size_y", @@ -1915,6 +1934,12 @@ storage_qualifier: $$.flags.q.explicit_stream = 0; $$.stream = state->out_qualifier->stream; } + + if (state->has_enhanced_layouts()) { + $$.flags.q.xfb_buffer = 1; + $$.flags.q.explicit_xfb_buffer = 0; + $$.xfb_buffer = state->out_qualifier->xfb_buffer; + } } | UNIFORM { diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp index 5d010fd..2941277 100644 --- a/src/compiler/glsl/glsl_parser_extras.cpp +++ b/src/compiler/glsl/glsl_parser_extras.cpp @@ -140,6 +140,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->Const.MaxAtomicCounterBufferSize = ctx->Const.MaxAtomicBufferSize; + /* ARB_enhanced_layouts constants */ + this->Const.MaxTransformFeedbackBuffers = ctx->Const.MaxTransformFeedbackBuffers; + this->Const.MaxTransformFeedbackInterleavedComponents = ctx->Const.MaxTransformFeedbackInterleavedComponents; + /* Compute shader constants */ for (unsigned i = 0; i < ARRAY_SIZE(this->Const.MaxComputeWorkGroupCount); i++) this->Const.MaxComputeWorkGroupCount[i] = ctx->Const.MaxComputeWorkGroupCount[i]; @@ -177,6 +181,9 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->Const.MaxTessControlUniformComponents = ctx->Const.Program[MESA_SHADER_TESS_CTRL].MaxUniformComponents; this->Const.MaxTessEvaluationUniformComponents = ctx->Const.Program[MESA_SHADER_TESS_EVAL].MaxUniformComponents; + /* GL 4.5 / OES_sample_variables */ + this->Const.MaxSamples = ctx->Const.MaxSamples; + this->current_function = NULL; this->toplevel_ir = NULL; this->found_return = false; @@ -610,9 +617,12 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { EXT(OES_geometry_point_size, false, true, OES_geometry_shader), EXT(OES_geometry_shader, false, true, OES_geometry_shader), EXT(OES_gpu_shader5, false, true, ARB_gpu_shader5), + EXT(OES_sample_variables, false, true, OES_sample_variables), EXT(OES_shader_image_atomic, false, true, ARB_shader_image_load_store), + EXT(OES_shader_multisample_interpolation, false, true, OES_sample_variables), EXT(OES_standard_derivatives, false, true, OES_standard_derivatives), EXT(OES_texture_3D, false, true, dummy_true), + EXT(OES_texture_buffer, false, true, OES_texture_buffer), EXT(OES_texture_storage_multisample_2d_array, false, true, ARB_texture_multisample), /* All other extensions go here, sorted alphabetically. @@ -629,6 +639,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { EXT(EXT_shader_integer_mix, true, true, EXT_shader_integer_mix), EXT(EXT_shader_samples_identical, true, true, EXT_shader_samples_identical), EXT(EXT_texture_array, true, false, EXT_texture_array), + EXT(EXT_texture_buffer, false, true, OES_texture_buffer), }; #undef EXT @@ -935,6 +946,13 @@ _mesa_ast_process_interface_block(YYLTYPE *locp, block->layout.stream = state->out_qualifier->stream; } + if (state->has_enhanced_layouts() && block->layout.flags.q.out) { + /* Assign global layout's xfb_buffer value. */ + block->layout.flags.q.xfb_buffer = 1; + block->layout.flags.q.explicit_xfb_buffer = 0; + block->layout.xfb_buffer = state->out_qualifier->xfb_buffer; + } + foreach_list_typed (ast_declarator_list, member, link, &block->declarations) { ast_type_qualifier& qualifier = member->type->qualifier; if ((qualifier.flags.i & interface_type_mask) == 0) { @@ -1206,6 +1224,7 @@ ast_expression::ast_expression(int oper, this->subexpressions[1] = ex1; this->subexpressions[2] = ex2; this->non_lvalue_description = NULL; + this->is_lhs = false; } @@ -1583,13 +1602,12 @@ set_shader_inout_layout(struct gl_shader *shader, struct _mesa_glsl_parse_state *state) { /* Should have been prevented by the parser. */ - if (shader->Stage == MESA_SHADER_TESS_CTRL) { + if (shader->Stage == MESA_SHADER_TESS_CTRL || + shader->Stage == MESA_SHADER_VERTEX) { assert(!state->in_qualifier->flags.i); - } else if (shader->Stage == MESA_SHADER_TESS_EVAL) { - assert(!state->out_qualifier->flags.i); - } else if (shader->Stage != MESA_SHADER_GEOMETRY) { + } else if (shader->Stage != MESA_SHADER_GEOMETRY && + shader->Stage != MESA_SHADER_TESS_EVAL) { assert(!state->in_qualifier->flags.i); - assert(!state->out_qualifier->flags.i); } if (shader->Stage != MESA_SHADER_COMPUTE) { @@ -1606,6 +1624,17 @@ set_shader_inout_layout(struct gl_shader *shader, assert(!state->fs_early_fragment_tests); } + for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) { + if (state->out_qualifier->out_xfb_stride[i]) { + unsigned xfb_stride; + if (state->out_qualifier->out_xfb_stride[i]-> + process_qualifier_constant(state, "xfb_stride", &xfb_stride, + true)) { + shader->TransformFeedback.BufferStride[i] = xfb_stride; + } + } + } + switch (shader->Stage) { case MESA_SHADER_TESS_CTRL: shader->TessCtrl.VerticesOut = 0; diff --git a/src/compiler/glsl/glsl_parser_extras.h b/src/compiler/glsl/glsl_parser_extras.h index 12a3a46..0cc2d25 100644 --- a/src/compiler/glsl/glsl_parser_extras.h +++ b/src/compiler/glsl/glsl_parser_extras.h @@ -383,6 +383,10 @@ struct _mesa_glsl_parse_state { /* ARB_draw_buffers */ unsigned MaxDrawBuffers; + /* ARB_enhanced_layouts */ + unsigned MaxTransformFeedbackBuffers; + unsigned MaxTransformFeedbackInterleavedComponents; + /* ARB_blend_func_extended */ unsigned MaxDualSourceDrawBuffers; @@ -457,6 +461,9 @@ struct _mesa_glsl_parse_state { unsigned MaxTessControlTotalOutputComponents; unsigned MaxTessControlUniformComponents; unsigned MaxTessEvaluationUniformComponents; + + /* GL 4.5 / OES_sample_variables */ + unsigned MaxSamples; } Const; /** @@ -597,12 +604,18 @@ struct _mesa_glsl_parse_state { bool OES_geometry_shader_warn; bool OES_gpu_shader5_enable; bool OES_gpu_shader5_warn; + bool OES_sample_variables_enable; + bool OES_sample_variables_warn; bool OES_shader_image_atomic_enable; bool OES_shader_image_atomic_warn; + bool OES_shader_multisample_interpolation_enable; + bool OES_shader_multisample_interpolation_warn; bool OES_standard_derivatives_enable; bool OES_standard_derivatives_warn; bool OES_texture_3D_enable; bool OES_texture_3D_warn; + bool OES_texture_buffer_enable; + bool OES_texture_buffer_warn; bool OES_texture_storage_multisample_2d_array_enable; bool OES_texture_storage_multisample_2d_array_warn; @@ -632,6 +645,8 @@ struct _mesa_glsl_parse_state { bool EXT_shader_samples_identical_warn; bool EXT_texture_array_enable; bool EXT_texture_array_warn; + bool EXT_texture_buffer_enable; + bool EXT_texture_buffer_warn; /*@}*/ /** Extensions supported by the OpenGL implementation. */ diff --git a/src/compiler/glsl/ir.h b/src/compiler/glsl/ir.h index b74d68a..b1a1d56 100644 --- a/src/compiler/glsl/ir.h +++ b/src/compiler/glsl/ir.h @@ -727,6 +727,21 @@ public: unsigned is_xfb_only:1; /** + * Was a transfor feedback buffer set in the shader? + */ + unsigned explicit_xfb_buffer:1; + + /** + * Was a transfor feedback offset set in the shader? + */ + unsigned explicit_xfb_offset:1; + + /** + * Was a transfor feedback stride set in the shader? + */ + unsigned explicit_xfb_stride:1; + + /** * If non-zero, then this variable may be packed along with other variables * into a single varying slot, so this offset should be applied when * accessing components. For example, an offset of 1 means that the x @@ -742,21 +757,9 @@ public: /** * Non-zero if this variable was created by lowering a named interface - * block which was not an array. - * - * Note that this variable and \c from_named_ifc_block_array will never - * both be non-zero. + * block. */ - unsigned from_named_ifc_block_nonarray:1; - - /** - * Non-zero if this variable was created by lowering a named interface - * block which was an array. - * - * Note that this variable and \c from_named_ifc_block_nonarray will never - * both be non-zero. - */ - unsigned from_named_ifc_block_array:1; + unsigned from_named_ifc_block:1; /** * Non-zero if the variable must be a shader input. This is useful for @@ -873,7 +876,7 @@ public: unsigned stream; /** - * Atomic or block member offset. + * Atomic, transform feedback or block member offset. */ unsigned offset; @@ -885,6 +888,16 @@ public: unsigned max_array_access; /** + * Transform feedback buffer. + */ + unsigned xfb_buffer; + + /** + * Transform feedback stride. + */ + unsigned xfb_stride; + + /** * Allow (only) ir_variable direct access private members. */ friend class ir_variable; diff --git a/src/compiler/glsl/ir_uniform.h b/src/compiler/glsl/ir_uniform.h index 1854279..e72e7b4 100644 --- a/src/compiler/glsl/ir_uniform.h +++ b/src/compiler/glsl/ir_uniform.h @@ -105,11 +105,6 @@ struct gl_uniform_storage { */ unsigned array_elements; - /** - * Has this uniform ever been set? - */ - bool initialized; - struct gl_opaque_uniform_index opaque[MESA_SHADER_STAGES]; /** diff --git a/src/compiler/glsl/link_interface_blocks.cpp b/src/compiler/glsl/link_interface_blocks.cpp index 4c6fb56..2607259 100644 --- a/src/compiler/glsl/link_interface_blocks.cpp +++ b/src/compiler/glsl/link_interface_blocks.cpp @@ -242,7 +242,8 @@ public: return entry ? (ir_variable *) entry->data : NULL; } else { const struct hash_entry *entry = - _mesa_hash_table_search(ht, var->get_interface_type()->name); + _mesa_hash_table_search(ht, + var->get_interface_type()->without_array()->name); return entry ? (ir_variable *) entry->data : NULL; } } @@ -263,7 +264,8 @@ public: snprintf(location_str, 11, "%d", var->data.location); _mesa_hash_table_insert(ht, ralloc_strdup(mem_ctx, location_str), var); } else { - _mesa_hash_table_insert(ht, var->get_interface_type()->name, var); + _mesa_hash_table_insert(ht, + var->get_interface_type()->without_array()->name, var); } } diff --git a/src/compiler/glsl/link_uniform_initializers.cpp b/src/compiler/glsl/link_uniform_initializers.cpp index 3609f81..870bc5b 100644 --- a/src/compiler/glsl/link_uniform_initializers.cpp +++ b/src/compiler/glsl/link_uniform_initializers.cpp @@ -162,8 +162,6 @@ set_opaque_binding(void *mem_ctx, gl_shader_program *prog, } } } - - storage->initialized = true; } } @@ -183,7 +181,7 @@ set_block_binding(gl_shader_program *prog, const char *block_name, int binding) if (stage_index != -1) { struct gl_shader *sh = prog->_LinkedShaders[i]; - sh->BufferInterfaceBlocks[stage_index].Binding = binding; + sh->BufferInterfaceBlocks[stage_index]->Binding = binding; } } } @@ -267,8 +265,6 @@ set_uniform_initializer(void *mem_ctx, gl_shader_program *prog, } } } - - storage->initialized = true; } } diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp index 940cc61..0a230ca 100644 --- a/src/compiler/glsl/link_uniforms.cpp +++ b/src/compiler/glsl/link_uniforms.cpp @@ -68,7 +68,7 @@ program_resource_visitor::process(const glsl_type *type, const char *name) unsigned packing = type->interface_packing; recursion(type, &name_copy, strlen(name), false, NULL, packing, false, - record_array_count); + record_array_count, NULL); ralloc_free(name_copy); } @@ -76,8 +76,6 @@ void program_resource_visitor::process(ir_variable *var) { unsigned record_array_count = 1; - const glsl_type *t = var->type; - const glsl_type *t_without_array = var->type->without_array(); const bool row_major = var->data.matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR; @@ -85,80 +83,28 @@ program_resource_visitor::process(ir_variable *var) var->get_interface_type()->interface_packing : var->type->interface_packing; + const glsl_type *t = + var->data.from_named_ifc_block ? var->get_interface_type() : var->type; + const glsl_type *t_without_array = t->without_array(); + /* false is always passed for the row_major parameter to the other * processing functions because no information is available to do * otherwise. See the warning in linker.h. */ - - /* Only strdup the name if we actually will need to modify it. */ - if (var->data.from_named_ifc_block_array) { - /* lower_named_interface_blocks created this variable by lowering an - * interface block array to an array variable. For example if the - * original source code was: - * - * out Blk { vec4 bar } foo[3]; - * - * Then the variable is now: - * - * out vec4 bar[3]; - * - * We need to visit each array element using the names constructed like - * so: - * - * Blk[0].bar - * Blk[1].bar - * Blk[2].bar - */ - assert(t->is_array()); - const glsl_type *ifc_type = var->get_interface_type(); - char *name = ralloc_strdup(NULL, ifc_type->name); - size_t name_length = strlen(name); - for (unsigned i = 0; i < t->length; i++) { - size_t new_length = name_length; - ralloc_asprintf_rewrite_tail(&name, &new_length, "[%u].%s", i, - var->name); - /* Note: row_major is only meaningful for uniform blocks, and - * lowering is only applied to non-uniform interface blocks, so we - * can safely pass false for row_major. - */ - recursion(var->type, &name, new_length, row_major, NULL, packing, - false, record_array_count); - } - ralloc_free(name); - } else if (var->data.from_named_ifc_block_nonarray) { - /* lower_named_interface_blocks created this variable by lowering a - * named interface block (non-array) to an ordinary variable. For - * example if the original source code was: - * - * out Blk { vec4 bar } foo; - * - * Then the variable is now: - * - * out vec4 bar; - * - * We need to visit this variable using the name: - * - * Blk.bar - */ - const glsl_type *ifc_type = var->get_interface_type(); - char *name = ralloc_asprintf(NULL, "%s.%s", ifc_type->name, var->name); - /* Note: row_major is only meaningful for uniform blocks, and lowering - * is only applied to non-uniform interface blocks, so we can safely - * pass false for row_major. - */ - recursion(var->type, &name, strlen(name), row_major, NULL, packing, - false, record_array_count); - ralloc_free(name); - } else if (t_without_array->is_record() || + if (t_without_array->is_record() || (t->is_array() && t->fields.array->is_array())) { char *name = ralloc_strdup(NULL, var->name); recursion(var->type, &name, strlen(name), row_major, NULL, packing, - false, record_array_count); + false, record_array_count, NULL); ralloc_free(name); } else if (t_without_array->is_interface()) { char *name = ralloc_strdup(NULL, t_without_array->name); - recursion(var->type, &name, strlen(name), row_major, NULL, packing, - false, record_array_count); + const glsl_struct_field *ifc_member = var->data.from_named_ifc_block ? + &t_without_array-> + fields.structure[t_without_array->field_index(var->name)] : NULL; + + recursion(t, &name, strlen(name), row_major, NULL, packing, + false, record_array_count, ifc_member); ralloc_free(name); } else { this->set_record_array_count(record_array_count); @@ -172,7 +118,8 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, const glsl_type *record_type, const unsigned packing, bool last_field, - unsigned record_array_count) + unsigned record_array_count, + const glsl_struct_field *named_ifc_member) { /* Records need to have each field processed individually. * @@ -180,7 +127,12 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, * individually, then each field of the resulting array elements processed * individually. */ - if (t->is_record() || t->is_interface()) { + if (t->is_interface() && named_ifc_member) { + ralloc_asprintf_rewrite_tail(name, &name_length, ".%s", + named_ifc_member->name); + recursion(named_ifc_member->type, name, name_length, row_major, NULL, + packing, false, record_array_count, NULL); + } else if (t->is_record() || t->is_interface()) { if (record_type == NULL && t->is_record()) record_type = t; @@ -223,7 +175,7 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, field_row_major, record_type, packing, - (i + 1) == t->length, record_array_count); + (i + 1) == t->length, record_array_count, NULL); /* Only the first leaf-field of the record gets called with the * record type pointer. @@ -258,7 +210,8 @@ program_resource_visitor::recursion(const glsl_type *t, char **name, recursion(t->fields.array, name, new_length, row_major, record_type, packing, - (i + 1) == t->length, record_array_count); + (i + 1) == t->length, record_array_count, + named_ifc_member); /* Only the first leaf-field of the record gets called with the * record type pointer. @@ -799,7 +752,6 @@ private: this->uniforms[id].name = ralloc_strdup(this->uniforms, name); this->uniforms[id].type = base_type; - this->uniforms[id].initialized = 0; this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].atomic_buffer_index = -1; @@ -954,6 +906,8 @@ link_cross_validate_uniform_block(void *mem_ctx, new_block->Uniforms, sizeof(*linked_block->Uniforms) * linked_block->NumUniforms); + linked_block->Name = ralloc_strdup(*linked_blocks, linked_block->Name); + for (unsigned int i = 0; i < linked_block->NumUniforms; i++) { struct gl_uniform_buffer_variable *ubo_var = &linked_block->Uniforms[i]; @@ -1005,9 +959,9 @@ link_update_uniform_buffer_variables(struct gl_shader *shader) const unsigned l = strlen(var->name); for (unsigned i = 0; i < shader->NumBufferInterfaceBlocks; i++) { - for (unsigned j = 0; j < shader->BufferInterfaceBlocks[i].NumUniforms; j++) { + for (unsigned j = 0; j < shader->BufferInterfaceBlocks[i]->NumUniforms; j++) { if (sentinel) { - const char *begin = shader->BufferInterfaceBlocks[i].Uniforms[j].Name; + const char *begin = shader->BufferInterfaceBlocks[i]->Uniforms[j].Name; const char *end = strchr(begin, sentinel); if (end == NULL) @@ -1022,7 +976,7 @@ link_update_uniform_buffer_variables(struct gl_shader *shader) break; } } else if (!strcmp(var->name, - shader->BufferInterfaceBlocks[i].Uniforms[j].Name)) { + shader->BufferInterfaceBlocks[i]->Uniforms[j].Name)) { found = true; var->data.location = j; break; @@ -1148,9 +1102,9 @@ link_assign_uniform_locations(struct gl_shader_program *prog, sh->num_combined_uniform_components = sh->num_uniform_components; for (unsigned i = 0; i < sh->NumBufferInterfaceBlocks; i++) { - if (!sh->BufferInterfaceBlocks[i].IsShaderStorage) { + if (!sh->BufferInterfaceBlocks[i]->IsShaderStorage) { sh->num_combined_uniform_components += - sh->BufferInterfaceBlocks[i].UniformBufferSize / 4; + sh->BufferInterfaceBlocks[i]->UniformBufferSize / 4; } } } diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index 44fc8f6..848668c 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -63,6 +63,125 @@ get_varying_type(const ir_variable *var, gl_shader_stage stage) return type; } +static void +create_xfb_varying_names(void *mem_ctx, const glsl_type *t, char **name, + size_t name_length, unsigned *count, + const char *ifc_member_name, + const glsl_type *ifc_member_t, char ***varying_names) +{ + if (t->is_interface()) { + size_t new_length = name_length; + + assert(ifc_member_name && ifc_member_t); + ralloc_asprintf_rewrite_tail(name, &new_length, ".%s", ifc_member_name); + + create_xfb_varying_names(mem_ctx, ifc_member_t, name, new_length, count, + NULL, NULL, varying_names); + } else if (t->is_record()) { + for (unsigned i = 0; i < t->length; i++) { + const char *field = t->fields.structure[i].name; + size_t new_length = name_length; + + ralloc_asprintf_rewrite_tail(name, &new_length, ".%s", field); + + create_xfb_varying_names(mem_ctx, t->fields.structure[i].type, name, + new_length, count, NULL, NULL, + varying_names); + } + } else if (t->without_array()->is_record() || + t->without_array()->is_interface() || + (t->is_array() && t->fields.array->is_array())) { + for (unsigned i = 0; i < t->length; i++) { + size_t new_length = name_length; + + /* Append the subscript to the current variable name */ + ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i); + + create_xfb_varying_names(mem_ctx, t->fields.array, name, new_length, + count, ifc_member_name, ifc_member_t, + varying_names); + } + } else { + (*varying_names)[(*count)++] = ralloc_strdup(mem_ctx, *name); + } +} + +bool +process_xfb_layout_qualifiers(void *mem_ctx, const gl_shader *sh, + unsigned *num_tfeedback_decls, + char ***varying_names) +{ + bool has_xfb_qualifiers = false; + + /* We still need to enable transform feedback mode even if xfb_stride is + * only applied to a global out. Also we don't bother to propagate + * xfb_stride to interface block members so this will catch that case also. + */ + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (sh->TransformFeedback.BufferStride[j]) { + has_xfb_qualifiers = true; + } + } + + foreach_in_list(ir_instruction, node, sh->ir) { + ir_variable *var = node->as_variable(); + if (!var || var->data.mode != ir_var_shader_out) + continue; + + /* From the ARB_enhanced_layouts spec: + * + * "Any shader making any static use (after preprocessing) of any of + * these *xfb_* qualifiers will cause the shader to be in a + * transform feedback capturing mode and hence responsible for + * describing the transform feedback setup. This mode will capture + * any output selected by *xfb_offset*, directly or indirectly, to + * a transform feedback buffer." + */ + if (var->data.explicit_xfb_buffer || var->data.explicit_xfb_stride) { + has_xfb_qualifiers = true; + } + + if (var->data.explicit_xfb_offset) { + *num_tfeedback_decls += var->type->varying_count(); + has_xfb_qualifiers = true; + } + } + + if (*num_tfeedback_decls == 0) + return has_xfb_qualifiers; + + unsigned i = 0; + *varying_names = ralloc_array(mem_ctx, char *, *num_tfeedback_decls); + foreach_in_list(ir_instruction, node, sh->ir) { + ir_variable *var = node->as_variable(); + if (!var || var->data.mode != ir_var_shader_out) + continue; + + if (var->data.explicit_xfb_offset) { + char *name; + const glsl_type *type, *member_type; + + if (var->data.from_named_ifc_block) { + type = var->get_interface_type(); + /* Find the member type before it was altered by lowering */ + member_type = + type->fields.structure[type->field_index(var->name)].type; + name = ralloc_strdup(NULL, type->without_array()->name); + } else { + type = var->type; + member_type = NULL; + name = ralloc_strdup(NULL, var->name); + } + create_xfb_varying_names(mem_ctx, type, &name, strlen(name), &i, + var->name, member_type, varying_names); + ralloc_free(name); + } + } + + assert(i == *num_tfeedback_decls); + return has_xfb_qualifiers; +} + /** * Validate the types and qualifiers of an output from one stage against the * matching input to another stage. @@ -397,6 +516,8 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx, this->next_buffer_separator = false; this->matched_candidate = NULL; this->stream_id = 0; + this->buffer = 0; + this->offset = 0; if (ctx->Extensions.ARB_transform_feedback3) { /* Parse gl_NextBuffer. */ @@ -489,6 +610,8 @@ tfeedback_decl::assign_location(struct gl_context *ctx, = this->matched_candidate->toplevel_var->data.location * 4 + this->matched_candidate->toplevel_var->data.location_frac + this->matched_candidate->offset; + const unsigned dmul = + this->matched_candidate->type->without_array()->is_double() ? 2 : 1; if (this->matched_candidate->type->is_array()) { /* Array variable */ @@ -496,8 +619,6 @@ tfeedback_decl::assign_location(struct gl_context *ctx, this->matched_candidate->type->fields.array->matrix_columns; const unsigned vector_elements = this->matched_candidate->type->fields.array->vector_elements; - const unsigned dmul = - this->matched_candidate->type->fields.array->is_double() ? 2 : 1; unsigned actual_array_size; switch (this->lowered_builtin_array_variable) { case clip_distance: @@ -575,6 +696,12 @@ tfeedback_decl::assign_location(struct gl_context *ctx, */ this->stream_id = this->matched_candidate->toplevel_var->data.stream; + unsigned array_offset = this->array_subscript * 4 * dmul; + unsigned struct_offset = this->matched_candidate->offset * 4 * dmul; + this->buffer = this->matched_candidate->toplevel_var->data.xfb_buffer; + this->offset = this->matched_candidate->toplevel_var->data.offset + + array_offset + struct_offset; + return true; } @@ -598,55 +725,108 @@ tfeedback_decl::get_num_outputs() const bool tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, - unsigned buffer, const unsigned max_outputs) const + unsigned buffer, unsigned buffer_index, + const unsigned max_outputs, bool *explicit_stride, + bool has_xfb_qualifiers) const { assert(!this->next_buffer_separator); /* Handle gl_SkipComponents. */ if (this->skip_components) { - info->BufferStride[buffer] += this->skip_components; + info->Buffers[buffer].Stride += this->skip_components; return true; } + unsigned xfb_offset = 0; + if (has_xfb_qualifiers) { + xfb_offset = this->offset / 4; + } else { + xfb_offset = info->Buffers[buffer].Stride; + } + info->Varyings[info->NumVarying].Offset = xfb_offset * 4; + + unsigned location = this->location; + unsigned location_frac = this->location_frac; + unsigned num_components = this->num_components(); + while (num_components > 0) { + unsigned output_size = MIN2(num_components, 4 - location_frac); + assert((info->NumOutputs == 0 && max_outputs == 0) || + info->NumOutputs < max_outputs); + + /* From the ARB_enhanced_layouts spec: + * + * "If such a block member or variable is not written during a shader + * invocation, the buffer contents at the assigned offset will be + * undefined. Even if there are no static writes to a variable or + * member that is assigned a transform feedback offset, the space is + * still allocated in the buffer and still affects the stride." + */ + if (this->is_varying_written()) { + info->Outputs[info->NumOutputs].ComponentOffset = location_frac; + info->Outputs[info->NumOutputs].OutputRegister = location; + info->Outputs[info->NumOutputs].NumComponents = output_size; + info->Outputs[info->NumOutputs].StreamId = stream_id; + info->Outputs[info->NumOutputs].OutputBuffer = buffer; + info->Outputs[info->NumOutputs].DstOffset = xfb_offset; + ++info->NumOutputs; + } + info->Buffers[buffer].Stream = this->stream_id; + xfb_offset += output_size; + + num_components -= output_size; + location++; + location_frac = 0; + } + + if (explicit_stride && explicit_stride[buffer]) { + if (this->is_double() && info->Buffers[buffer].Stride % 2) { + linker_error(prog, "invalid qualifier xfb_stride=%d must be a " + "multiple of 8 as its applied to a type that is or " + "contains a double.", + info->Buffers[buffer].Stride * 4); + return false; + } + + if ((this->offset / 4) / info->Buffers[buffer].Stride != + (xfb_offset - 1) / info->Buffers[buffer].Stride) { + linker_error(prog, "xfb_offset (%d) overflows xfb_stride (%d) for " + "buffer (%d)", xfb_offset * 4, + info->Buffers[buffer].Stride * 4, buffer); + return false; + } + } else { + info->Buffers[buffer].Stride = xfb_offset; + } + /* From GL_EXT_transform_feedback: * A program will fail to link if: * * * the total number of components to capture is greater than * the constant MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT * and the buffer mode is INTERLEAVED_ATTRIBS_EXT. + * + * From GL_ARB_enhanced_layouts: + * + * "The resulting stride (implicit or explicit) must be less than or + * equal to the implementation-dependent constant + * gl_MaxTransformFeedbackInterleavedComponents." */ - if (prog->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS && - info->BufferStride[buffer] + this->num_components() > + if ((prog->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS || + has_xfb_qualifiers) && + info->Buffers[buffer].Stride > ctx->Const.MaxTransformFeedbackInterleavedComponents) { linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS " "limit has been exceeded."); return false; } - unsigned location = this->location; - unsigned location_frac = this->location_frac; - unsigned num_components = this->num_components(); - while (num_components > 0) { - unsigned output_size = MIN2(num_components, 4 - location_frac); - assert(info->NumOutputs < max_outputs); - info->Outputs[info->NumOutputs].ComponentOffset = location_frac; - info->Outputs[info->NumOutputs].OutputRegister = location; - info->Outputs[info->NumOutputs].NumComponents = output_size; - info->Outputs[info->NumOutputs].StreamId = stream_id; - info->Outputs[info->NumOutputs].OutputBuffer = buffer; - info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer]; - ++info->NumOutputs; - info->BufferStride[buffer] += output_size; - info->BufferStream[buffer] = this->stream_id; - num_components -= output_size; - location++; - location_frac = 0; - } - - info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, this->orig_name); + info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, + this->orig_name); info->Varyings[info->NumVarying].Type = this->type; info->Varyings[info->NumVarying].Size = this->size; + info->Varyings[info->NumVarying].BufferIndex = buffer_index; info->NumVarying++; + info->Buffers[buffer].NumVaryings++; return true; } @@ -731,6 +911,17 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog, } +static int +cmp_xfb_offset(const void * x_generic, const void * y_generic) +{ + tfeedback_decl *x = (tfeedback_decl *) x_generic; + tfeedback_decl *y = (tfeedback_decl *) y_generic; + + if (x->get_buffer() != y->get_buffer()) + return x->get_buffer() - y->get_buffer(); + return x->get_offset() - y->get_offset(); +} + /** * Store transform feedback location assignments into * prog->LinkedTransformFeedback based on the data stored in tfeedback_decls. @@ -741,8 +932,13 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog, bool store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, unsigned num_tfeedback_decls, - tfeedback_decl *tfeedback_decls) + tfeedback_decl *tfeedback_decls, bool has_xfb_qualifiers) { + /* Make sure MaxTransformFeedbackBuffers is less than 32 so the bitmask for + * tracking the number of buffers doesn't overflow. + */ + assert(ctx->Const.MaxTransformFeedbackBuffers < 32); + bool separate_attribs_mode = prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS; @@ -752,14 +948,24 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, memset(&prog->LinkedTransformFeedback, 0, sizeof(prog->LinkedTransformFeedback)); + /* The xfb_offset qualifier does not have to be used in increasing order + * however some drivers expect to receive the list of transform feedback + * declarations in order so sort it now for convenience. + */ + if (has_xfb_qualifiers) + qsort(tfeedback_decls, num_tfeedback_decls, sizeof(*tfeedback_decls), + cmp_xfb_offset); + prog->LinkedTransformFeedback.Varyings = rzalloc_array(prog, struct gl_transform_feedback_varying_info, num_tfeedback_decls); unsigned num_outputs = 0; - for (unsigned i = 0; i < num_tfeedback_decls; ++i) - num_outputs += tfeedback_decls[i].get_num_outputs(); + for (unsigned i = 0; i < num_tfeedback_decls; ++i) { + if (tfeedback_decls[i].is_varying_written()) + num_outputs += tfeedback_decls[i].get_num_outputs(); + } prog->LinkedTransformFeedback.Outputs = rzalloc_array(prog, @@ -767,21 +973,47 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, num_outputs); unsigned num_buffers = 0; + unsigned buffers = 0; - if (separate_attribs_mode) { + if (!has_xfb_qualifiers && separate_attribs_mode) { /* GL_SEPARATE_ATTRIBS */ for (unsigned i = 0; i < num_tfeedback_decls; ++i) { if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback, - num_buffers, num_outputs)) + num_buffers, num_buffers, num_outputs, + NULL, has_xfb_qualifiers)) return false; + buffers |= 1 << num_buffers; num_buffers++; } } else { /* GL_INVERLEAVED_ATTRIBS */ int buffer_stream_id = -1; + unsigned buffer = + num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0; + bool explicit_stride[MAX_FEEDBACK_BUFFERS] = { false }; + + /* Apply any xfb_stride global qualifiers */ + if (has_xfb_qualifiers) { + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (prog->TransformFeedback.BufferStride[j]) { + buffers |= 1 << j; + explicit_stride[j] = true; + prog->LinkedTransformFeedback.Buffers[j].Stride = + prog->TransformFeedback.BufferStride[j] / 4; + } + } + } + for (unsigned i = 0; i < num_tfeedback_decls; ++i) { + if (has_xfb_qualifiers && + buffer != tfeedback_decls[i].get_buffer()) { + /* we have moved to the next buffer so reset stream id */ + buffer_stream_id = -1; + num_buffers++; + } + if (tfeedback_decls[i].is_next_buffer_separator()) { num_buffers++; buffer_stream_id = -1; @@ -803,17 +1035,24 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, return false; } + if (has_xfb_qualifiers) { + buffer = tfeedback_decls[i].get_buffer(); + } else { + buffer = num_buffers; + } + buffers |= 1 << buffer; + if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback, - num_buffers, num_outputs)) + buffer, num_buffers, num_outputs, + explicit_stride, has_xfb_qualifiers)) return false; } - num_buffers++; } assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs); - prog->LinkedTransformFeedback.NumBuffers = num_buffers; + prog->LinkedTransformFeedback.ActiveBuffers = buffers; return true; } @@ -1466,8 +1705,8 @@ populate_consumer_input_sets(void *mem_ctx, exec_list *ir, } else if (input_var->get_interface_type() != NULL) { char *const iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", - input_var->get_interface_type()->name, - input_var->name); + input_var->get_interface_type()->without_array()->name, + input_var->name); hash_table_insert(consumer_interface_inputs, input_var, iface_field_name); } else { @@ -1498,8 +1737,8 @@ get_matching_input(void *mem_ctx, } else if (output_var->get_interface_type() != NULL) { char *const iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", - output_var->get_interface_type()->name, - output_var->name); + output_var->get_interface_type()->without_array()->name, + output_var->name); input_var = (ir_variable *) hash_table_find(consumer_interface_inputs, iface_field_name); diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h index b2812614..543b80f 100644 --- a/src/compiler/glsl/link_varyings.h +++ b/src/compiler/glsl/link_varyings.h @@ -98,7 +98,8 @@ public: unsigned get_num_outputs() const; bool store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, - const unsigned max_outputs) const; + unsigned buffer_index, const unsigned max_outputs, + bool *explicit_stride, bool has_xfb_qualifiers) const; const tfeedback_candidate *find_candidate(gl_shader_program *prog, hash_table *tfeedback_candidates); @@ -107,6 +108,14 @@ public: return this->next_buffer_separator; } + bool is_varying_written() const + { + if (this->next_buffer_separator || this->skip_components) + return false; + + return this->matched_candidate->toplevel_var->data.assigned; + } + bool is_varying() const { return !this->next_buffer_separator && !this->skip_components; @@ -122,6 +131,16 @@ public: return this->stream_id; } + unsigned get_buffer() const + { + return this->buffer; + } + + unsigned get_offset() const + { + return this->offset; + } + /** * The total number of varying components taken up by this variable. Only * valid if assign_location() has been called. @@ -202,6 +221,16 @@ private: int location; /** + * Used to store the buffer assigned by xfb_buffer. + */ + unsigned buffer; + + /** + * Used to store the offset assigned by xfb_offset. + */ + unsigned offset; + + /** * If non-zero, then this variable may be packed along with other variables * into a single varying slot, so this offset should be applied when * accessing components. For example, an offset of 1 means that the x @@ -268,6 +297,11 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog, const void *mem_ctx, unsigned num_names, char **varying_names, tfeedback_decl *decls); +bool +process_xfb_layout_qualifiers(void *mem_ctx, const gl_shader *sh, + unsigned *num_tfeedback_decls, + char ***varying_names); + void remove_unused_shader_inputs_and_outputs(bool is_separate_shader_object, gl_shader *sh, @@ -276,7 +310,8 @@ remove_unused_shader_inputs_and_outputs(bool is_separate_shader_object, bool store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, unsigned num_tfeedback_decls, - tfeedback_decl *tfeedback_decls); + tfeedback_decl *tfeedback_decls, + bool has_xfb_qualifiers); bool assign_varying_locations(struct gl_context *ctx, diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index 76b700d..510a22e 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -1192,11 +1192,11 @@ interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog) int index = link_cross_validate_uniform_block(prog, &prog->BufferInterfaceBlocks, &prog->NumBufferInterfaceBlocks, - &sh->BufferInterfaceBlocks[j]); + sh->BufferInterfaceBlocks[j]); if (index == -1) { linker_error(prog, "uniform block `%s' has mismatching definitions\n", - sh->BufferInterfaceBlocks[j].Name); + sh->BufferInterfaceBlocks[j]->Name); return false; } @@ -1204,6 +1204,23 @@ interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog) } } + /* Update per stage block pointers to point to the program list. + * FIXME: We should be able to free the per stage blocks here. + */ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + for (unsigned j = 0; j < prog->NumBufferInterfaceBlocks; j++) { + int stage_index = + prog->InterfaceBlockStageIndex[i][j]; + + if (stage_index != -1) { + struct gl_shader *sh = prog->_LinkedShaders[i]; + + sh->BufferInterfaceBlocks[stage_index] = + &prog->BufferInterfaceBlocks[j]; + } + } + } + return true; } @@ -1567,6 +1584,69 @@ private: hash_table *unnamed_interfaces; }; +/** + * Check for conflicting xfb_stride default qualifiers and store buffer stride + * for later use. + */ +static void +link_xfb_stride_layout_qualifiers(struct gl_context *ctx, + struct gl_shader_program *prog, + struct gl_shader *linked_shader, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) { + linked_shader->TransformFeedback.BufferStride[i] = 0; + } + + for (unsigned i = 0; i < num_shaders; i++) { + struct gl_shader *shader = shader_list[i]; + + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (shader->TransformFeedback.BufferStride[j]) { + if (linked_shader->TransformFeedback.BufferStride[j] != 0 && + shader->TransformFeedback.BufferStride[j] != 0 && + linked_shader->TransformFeedback.BufferStride[j] != + shader->TransformFeedback.BufferStride[j]) { + linker_error(prog, + "intrastage shaders defined with conflicting " + "xfb_stride for buffer %d (%d and %d)\n", j, + linked_shader->TransformFeedback.BufferStride[j], + shader->TransformFeedback.BufferStride[j]); + return; + } + + if (shader->TransformFeedback.BufferStride[j]) + linked_shader->TransformFeedback.BufferStride[j] = + shader->TransformFeedback.BufferStride[j]; + } + } + } + + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (linked_shader->TransformFeedback.BufferStride[j]) { + prog->TransformFeedback.BufferStride[j] = + linked_shader->TransformFeedback.BufferStride[j]; + + /* We will validate doubles at a later stage */ + if (prog->TransformFeedback.BufferStride[j] % 4) { + linker_error(prog, "invalid qualifier xfb_stride=%d must be a " + "multiple of 4 or if its applied to a type that is " + "or contains a double a multiple of 8.", + prog->TransformFeedback.BufferStride[j]); + return; + } + + if (prog->TransformFeedback.BufferStride[j] / 4 > + ctx->Const.MaxTransformFeedbackInterleavedComponents) { + linker_error(prog, + "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS " + "limit has been exceeded."); + return; + } + } + } +} /** * Performs the cross-validation of tessellation control shader vertices and @@ -2069,15 +2149,23 @@ link_intrastage_shaders(void *mem_ctx, linked->ir = new(linked) exec_list; clone_ir_list(mem_ctx, linked->ir, main->ir); - linked->BufferInterfaceBlocks = uniform_blocks; + linked->BufferInterfaceBlocks = + ralloc_array(linked, gl_uniform_block *, num_uniform_blocks); + + ralloc_steal(linked, uniform_blocks); + for (unsigned i = 0; i < num_uniform_blocks; i++) { + linked->BufferInterfaceBlocks[i] = &uniform_blocks[i]; + } + linked->NumBufferInterfaceBlocks = num_uniform_blocks; - ralloc_steal(linked, linked->BufferInterfaceBlocks); link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); link_tcs_out_layout_qualifiers(prog, linked, shader_list, num_shaders); link_tes_in_layout_qualifiers(prog, linked, shader_list, num_shaders); link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders); link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); + link_xfb_stride_layout_qualifiers(ctx, prog, linked, shader_list, + num_shaders); populate_symbol_table(linked); @@ -2869,7 +2957,8 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog) if (prog->InterfaceBlockStageIndex[j][i] != -1) { struct gl_shader *sh = prog->_LinkedShaders[j]; int stage_index = prog->InterfaceBlockStageIndex[j][i]; - if (sh && sh->BufferInterfaceBlocks[stage_index].IsShaderStorage) { + if (sh && + sh->BufferInterfaceBlocks[stage_index]->IsShaderStorage) { shader_blocks[j]++; total_shader_storage_blocks++; } else { @@ -2986,7 +3075,8 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog) for (unsigned j = 0; j < prog->NumBufferInterfaceBlocks; j++) { int stage_index = prog->InterfaceBlockStageIndex[i][j]; - if (stage_index != -1 && sh->BufferInterfaceBlocks[stage_index].IsShaderStorage) + if (stage_index != -1 && + sh->BufferInterfaceBlocks[stage_index]->IsShaderStorage) total_shader_storage_blocks++; } @@ -3762,7 +3852,8 @@ write_top_level_array_size_and_stride: * resource data. */ void -build_program_resource_list(struct gl_shader_program *shProg) +build_program_resource_list(struct gl_context *ctx, + struct gl_shader_program *shProg) { /* Rebuild resource list. */ if (shProg->ProgramResourceList) { @@ -3820,6 +3911,17 @@ build_program_resource_list(struct gl_shader_program *shProg) } } + /* Add transform feedback buffers. */ + for (unsigned i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) { + if ((shProg->LinkedTransformFeedback.ActiveBuffers >> i) & 1) { + shProg->LinkedTransformFeedback.Buffers[i].Binding = i; + if (!add_program_resource(shProg, GL_TRANSFORM_FEEDBACK_BUFFER, + &shProg->LinkedTransformFeedback.Buffers[i], + 0)) + return; + } + } + /* Add uniforms from uniform storage. */ for (unsigned i = 0; i < shProg->NumUniformStorage; i++) { /* Do not add uniforms internally used by Mesa. */ @@ -4006,20 +4108,22 @@ link_assign_subroutine_types(struct gl_shader_program *prog) static void split_ubos_and_ssbos(void *mem_ctx, - struct gl_uniform_block *blocks, + struct gl_uniform_block **s_blks, + struct gl_uniform_block *p_blks, unsigned num_blocks, struct gl_uniform_block ***ubos, unsigned *num_ubos, - unsigned **ubo_interface_block_indices, struct gl_uniform_block ***ssbos, - unsigned *num_ssbos, - unsigned **ssbo_interface_block_indices) + unsigned *num_ssbos) { unsigned num_ubo_blocks = 0; unsigned num_ssbo_blocks = 0; + /* Are we spliting the list of blocks for the shader or the program */ + bool is_shader = p_blks == NULL; + for (unsigned i = 0; i < num_blocks; i++) { - if (blocks[i].IsShaderStorage) + if (is_shader ? s_blks[i]->IsShaderStorage : p_blks[i].IsShaderStorage) num_ssbo_blocks++; else num_ubo_blocks++; @@ -4031,24 +4135,13 @@ split_ubos_and_ssbos(void *mem_ctx, *ssbos = ralloc_array(mem_ctx, gl_uniform_block *, num_ssbo_blocks); *num_ssbos = 0; - if (ubo_interface_block_indices) - *ubo_interface_block_indices = - ralloc_array(mem_ctx, unsigned, num_ubo_blocks); - - if (ssbo_interface_block_indices) - *ssbo_interface_block_indices = - ralloc_array(mem_ctx, unsigned, num_ssbo_blocks); - for (unsigned i = 0; i < num_blocks; i++) { - if (blocks[i].IsShaderStorage) { - (*ssbos)[*num_ssbos] = &blocks[i]; - if (ssbo_interface_block_indices) - (*ssbo_interface_block_indices)[*num_ssbos] = i; + struct gl_uniform_block *blk = is_shader ? s_blks[i] : &p_blks[i]; + if (blk->IsShaderStorage) { + (*ssbos)[*num_ssbos] = blk; (*num_ssbos)++; } else { - (*ubos)[*num_ubos] = &blocks[i]; - if (ubo_interface_block_indices) - (*ubo_interface_block_indices)[*num_ubos] = i; + (*ubos)[*num_ubos] = blk; (*num_ubos)++; } } @@ -4153,9 +4246,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) return; } - tfeedback_decl *tfeedback_decls = NULL; - unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying; + unsigned num_tfeedback_decls = 0; unsigned int num_explicit_uniform_locs = 0; + bool has_xfb_qualifiers = false; + char **varying_names = NULL; + tfeedback_decl *tfeedback_decls = NULL; void *mem_ctx = ralloc_context(NULL); // temporary linker context @@ -4465,6 +4560,30 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) goto done; } + /* From the ARB_enhanced_layouts spec: + * + * "If the shader used to record output variables for transform feedback + * varyings uses the "xfb_buffer", "xfb_offset", or "xfb_stride" layout + * qualifiers, the values specified by TransformFeedbackVaryings are + * ignored, and the set of variables captured for transform feedback is + * instead derived from the specified layout qualifiers." + */ + for (int i = MESA_SHADER_FRAGMENT - 1; i >= 0; i--) { + /* Find last stage before fragment shader */ + if (prog->_LinkedShaders[i]) { + has_xfb_qualifiers = + process_xfb_layout_qualifiers(mem_ctx, prog->_LinkedShaders[i], + &num_tfeedback_decls, + &varying_names); + break; + } + } + + if (!has_xfb_qualifiers) { + num_tfeedback_decls = prog->TransformFeedback.NumVarying; + varying_names = prog->TransformFeedback.VaryingNames; + } + if (num_tfeedback_decls != 0) { /* From GL_EXT_transform_feedback: * A program will fail to link if: @@ -4481,10 +4600,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } tfeedback_decls = ralloc_array(mem_ctx, tfeedback_decl, - prog->TransformFeedback.NumVarying); + num_tfeedback_decls); if (!parse_tfeedback_decls(ctx, prog, mem_ctx, num_tfeedback_decls, - prog->TransformFeedback.VaryingNames, - tfeedback_decls)) + varying_names, tfeedback_decls)) goto done; } @@ -4564,7 +4682,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } - if (!store_tfeedback_info(ctx, prog, num_tfeedback_decls, tfeedback_decls)) + if (!store_tfeedback_info(ctx, prog, num_tfeedback_decls, tfeedback_decls, + has_xfb_qualifiers)) goto done; update_array_sizes(prog); @@ -4627,25 +4746,23 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) gl_shader *sh = prog->_LinkedShaders[i]; split_ubos_and_ssbos(sh, sh->BufferInterfaceBlocks, + NULL, sh->NumBufferInterfaceBlocks, &sh->UniformBlocks, &sh->NumUniformBlocks, - NULL, &sh->ShaderStorageBlocks, - &sh->NumShaderStorageBlocks, - NULL); + &sh->NumShaderStorageBlocks); } } split_ubos_and_ssbos(prog, + NULL, prog->BufferInterfaceBlocks, prog->NumBufferInterfaceBlocks, &prog->UniformBlocks, &prog->NumUniformBlocks, - &prog->UboInterfaceBlockIndex, &prog->ShaderStorageBlocks, - &prog->NumShaderStorageBlocks, - &prog->SsboInterfaceBlockIndex); + &prog->NumShaderStorageBlocks); for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { if (prog->_LinkedShaders[i] == NULL) diff --git a/src/compiler/glsl/linker.h b/src/compiler/glsl/linker.h index 4311d16..97144df 100644 --- a/src/compiler/glsl/linker.h +++ b/src/compiler/glsl/linker.h @@ -197,7 +197,8 @@ private: void recursion(const glsl_type *t, char **name, size_t name_length, bool row_major, const glsl_type *record_type, const unsigned packing, - bool last_field, unsigned record_array_count); + bool last_field, unsigned record_array_count, + const glsl_struct_field *named_ifc_member); }; void diff --git a/src/compiler/glsl/lower_named_interface_blocks.cpp b/src/compiler/glsl/lower_named_interface_blocks.cpp index f29eba4..f780eca 100644 --- a/src/compiler/glsl/lower_named_interface_blocks.cpp +++ b/src/compiler/glsl/lower_named_interface_blocks.cpp @@ -169,7 +169,6 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) new(mem_ctx) ir_variable(iface_t->fields.structure[i].type, var_name, (ir_variable_mode) var->data.mode); - new_var->data.from_named_ifc_block_nonarray = 1; } else { const glsl_type *new_array_type = process_array_type(var->type, i); @@ -177,10 +176,16 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) new(mem_ctx) ir_variable(new_array_type, var_name, (ir_variable_mode) var->data.mode); - new_var->data.from_named_ifc_block_array = 1; } new_var->data.location = iface_t->fields.structure[i].location; new_var->data.explicit_location = (new_var->data.location >= 0); + new_var->data.offset = iface_t->fields.structure[i].offset; + new_var->data.explicit_xfb_offset = + (iface_t->fields.structure[i].offset >= 0); + new_var->data.xfb_buffer = + iface_t->fields.structure[i].xfb_buffer; + new_var->data.explicit_xfb_buffer = + iface_t->fields.structure[i].explicit_xfb_buffer; new_var->data.interpolation = iface_t->fields.structure[i].interpolation; new_var->data.centroid = iface_t->fields.structure[i].centroid; @@ -188,8 +193,9 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) new_var->data.patch = iface_t->fields.structure[i].patch; new_var->data.stream = var->data.stream; new_var->data.how_declared = var->data.how_declared; + new_var->data.from_named_ifc_block = 1; - new_var->init_interface_type(iface_t); + new_var->init_interface_type(var->type); hash_table_insert(interface_namespace, new_var, iface_field_name); insert_pos->insert_after(new_var); @@ -211,12 +217,23 @@ ir_visitor_status flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir) { ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record(); + + ir_variable *lhs_var = ir->lhs->variable_referenced(); + if (lhs_var && lhs_var->get_interface_type()) { + lhs_var->data.assigned = 1; + } + if (lhs_rec) { ir_rvalue *lhs_rec_tmp = lhs_rec; handle_rvalue(&lhs_rec_tmp); if (lhs_rec_tmp != lhs_rec) { ir->set_lhs(lhs_rec_tmp); } + + ir_variable *lhs_var = lhs_rec_tmp->variable_referenced(); + if (lhs_var) { + lhs_var->data.assigned = 1; + } } return rvalue_visit(ir); } diff --git a/src/compiler/glsl/program.h b/src/compiler/glsl/program.h index 31bb9aa..8f5a31b 100644 --- a/src/compiler/glsl/program.h +++ b/src/compiler/glsl/program.h @@ -43,7 +43,8 @@ extern void link_shaders(struct gl_context *ctx, struct gl_shader_program *prog); extern void -build_program_resource_list(struct gl_shader_program *shProg); +build_program_resource_list(struct gl_context *ctx, + struct gl_shader_program *shProg); extern void linker_error(struct gl_shader_program *prog, const char *fmt, ...) diff --git a/src/compiler/glsl/standalone_scaffolding.cpp b/src/compiler/glsl/standalone_scaffolding.cpp index 0f7a16a..5ce804e 100644 --- a/src/compiler/glsl/standalone_scaffolding.cpp +++ b/src/compiler/glsl/standalone_scaffolding.cpp @@ -130,11 +130,6 @@ _mesa_clear_shader_program_data(struct gl_shader_program *shProg) shProg->InterfaceBlockStageIndex[i] = NULL; } - ralloc_free(shProg->UboInterfaceBlockIndex); - shProg->UboInterfaceBlockIndex = NULL; - ralloc_free(shProg->SsboInterfaceBlockIndex); - shProg->SsboInterfaceBlockIndex = NULL; - ralloc_free(shProg->AtomicBuffers); shProg->AtomicBuffers = NULL; shProg->NumAtomicBuffers = 0; diff --git a/src/compiler/glsl/tests/set_uniform_initializer_tests.cpp b/src/compiler/glsl/tests/set_uniform_initializer_tests.cpp index 0b1f66c..a36ffdc 100644 --- a/src/compiler/glsl/tests/set_uniform_initializer_tests.cpp +++ b/src/compiler/glsl/tests/set_uniform_initializer_tests.cpp @@ -115,7 +115,6 @@ establish_uniform_storage(struct gl_shader_program *prog, unsigned num_storage, prog->UniformStorage[index_to_set].name = (char *) name; prog->UniformStorage[index_to_set].type = type; prog->UniformStorage[index_to_set].array_elements = array_size; - prog->UniformStorage[index_to_set].initialized = false; for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) { prog->UniformStorage[index_to_set].opaque[sh].index = ~0; prog->UniformStorage[index_to_set].opaque[sh].active = false; @@ -136,7 +135,6 @@ establish_uniform_storage(struct gl_shader_program *prog, unsigned num_storage, prog->UniformStorage[i].name = (char *) "invalid slot"; prog->UniformStorage[i].type = glsl_type::void_type; prog->UniformStorage[i].array_elements = 0; - prog->UniformStorage[i].initialized = false; for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) { prog->UniformStorage[i].opaque[sh].index = ~0; prog->UniformStorage[i].opaque[sh].active = false; @@ -149,21 +147,6 @@ establish_uniform_storage(struct gl_shader_program *prog, unsigned num_storage, return red_zone_components; } -/** - * Verify that the correct uniform is marked as having been initialized. - */ -static void -verify_initialization(struct gl_shader_program *prog, unsigned actual_index) -{ - for (unsigned i = 0; i < prog->NumUniformStorage; i++) { - if (i == actual_index) { - EXPECT_TRUE(prog->UniformStorage[actual_index].initialized); - } else { - EXPECT_FALSE(prog->UniformStorage[i].initialized); - } - } -} - static void non_array_test(void *mem_ctx, struct gl_shader_program *prog, unsigned actual_index, const char *name, @@ -181,7 +164,6 @@ non_array_test(void *mem_ctx, struct gl_shader_program *prog, linker::set_uniform_initializer(mem_ctx, prog, name, type, val, 0xF00F); - verify_initialization(prog, actual_index); verify_data(prog->UniformStorage[actual_index].storage, 0, val, red_zone_components, 0xF00F); } @@ -338,7 +320,6 @@ array_test(void *mem_ctx, struct gl_shader_program *prog, linker::set_uniform_initializer(mem_ctx, prog, name, element_type, val, 0xF00F); - verify_initialization(prog, actual_index); verify_data(prog->UniformStorage[actual_index].storage, array_size, val, red_zone_components, 0xF00F); } diff --git a/src/compiler/glsl_types.cpp b/src/compiler/glsl_types.cpp index 2421bd6..39585bf 100644 --- a/src/compiler/glsl_types.cpp +++ b/src/compiler/glsl_types.cpp @@ -132,6 +132,10 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].image_volatile = fields[i].image_volatile; this->fields.structure[i].image_restrict = fields[i].image_restrict; this->fields.structure[i].precision = fields[i].precision; + this->fields.structure[i].explicit_xfb_buffer = + fields[i].explicit_xfb_buffer; + this->fields.structure[i].xfb_buffer = fields[i].xfb_buffer; + this->fields.structure[i].xfb_stride = fields[i].xfb_stride; } mtx_unlock(&glsl_type::mutex); @@ -172,6 +176,10 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].image_volatile = fields[i].image_volatile; this->fields.structure[i].image_restrict = fields[i].image_restrict; this->fields.structure[i].precision = fields[i].precision; + this->fields.structure[i].explicit_xfb_buffer = + fields[i].explicit_xfb_buffer; + this->fields.structure[i].xfb_buffer = fields[i].xfb_buffer; + this->fields.structure[i].xfb_stride = fields[i].xfb_stride; } mtx_unlock(&glsl_type::mutex); @@ -915,6 +923,15 @@ glsl_type::record_compare(const glsl_type *b) const if (this->fields.structure[i].precision != b->fields.structure[i].precision) return false; + if (this->fields.structure[i].explicit_xfb_buffer + != b->fields.structure[i].explicit_xfb_buffer) + return false; + if (this->fields.structure[i].xfb_buffer + != b->fields.structure[i].xfb_buffer) + return false; + if (this->fields.structure[i].xfb_stride + != b->fields.structure[i].xfb_stride) + return false; } return true; @@ -1333,6 +1350,38 @@ glsl_type::uniform_locations() const } } +unsigned +glsl_type::varying_count() const +{ + unsigned size = 0; + + switch (this->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_DOUBLE: + case GLSL_TYPE_BOOL: + return 1; + + case GLSL_TYPE_STRUCT: + case GLSL_TYPE_INTERFACE: + for (unsigned i = 0; i < this->length; i++) + size += this->fields.structure[i].type->varying_count(); + return size; + case GLSL_TYPE_ARRAY: + /* Don't count innermost array elements */ + if (this->without_array()->is_record() || + this->without_array()->is_interface() || + this->fields.array->is_array()) + return this->length * this->fields.array->varying_count(); + else + return this->fields.array->varying_count(); + default: + assert(!"unsupported varying type"); + return 0; + } +} + bool glsl_type::can_implicitly_convert_to(const glsl_type *desired, _mesa_glsl_parse_state *state) const diff --git a/src/compiler/glsl_types.h b/src/compiler/glsl_types.h index b0e6f3f..dd46479 100644 --- a/src/compiler/glsl_types.h +++ b/src/compiler/glsl_types.h @@ -327,6 +327,12 @@ struct glsl_type { unsigned uniform_locations() const; /** + * Used to count the number of varyings contained in the type ignoring + * innermost array elements. + */ + unsigned varying_count() const; + + /** * Calculate the number of attribute slots required to hold this type * * This implements the language rules of GLSL 1.50 for counting the number @@ -839,13 +845,25 @@ struct glsl_struct_field { /** * For interface blocks, members may have an explicit byte offset - * specified; -1 otherwise. + * specified; -1 otherwise. Also used for xfb_offset layout qualifier. * - * Ignored for structs. + * Unless used for xfb_offset this field is ignored for structs. */ int offset; /** + * For interface blocks, members may define a transform feedback buffer; + * -1 otherwise. + */ + int xfb_buffer; + + /** + * For interface blocks, members may define a transform feedback stride; + * -1 otherwise. + */ + int xfb_stride; + + /** * For interface blocks, the interpolation mode (as in * ir_variable::interpolation). 0 otherwise. */ @@ -889,6 +907,13 @@ struct glsl_struct_field { unsigned image_volatile:1; unsigned image_restrict:1; + /** + * Any of the xfb_* qualifiers trigger the shader to be in transform + * feedback mode so we need to keep track of whether the buffer was + * explicitly set or if its just been assigned the default global value. + */ + unsigned explicit_xfb_buffer:1; + #ifdef __cplusplus glsl_struct_field(const struct glsl_type *_type, const char *_name) : type(_type), name(_name), location(-1), interpolation(0), centroid(0), diff --git a/src/compiler/nir/Makefile.sources b/src/compiler/nir/Makefile.sources index a876eff..e6367d9 100644 --- a/src/compiler/nir/Makefile.sources +++ b/src/compiler/nir/Makefile.sources @@ -22,10 +22,10 @@ NIR_FILES = \ nir_gather_info.c \ nir_gs_count_vertices.c \ nir_inline_functions.c \ - nir_intrinsics.c \ - nir_intrinsics.h \ nir_instr_set.c \ nir_instr_set.h \ + nir_intrinsics.c \ + nir_intrinsics.h \ nir_liveness.c \ nir_lower_alu_to_scalar.c \ nir_lower_atomics.c \ diff --git a/src/compiler/nir/glsl_to_nir.cpp b/src/compiler/nir/glsl_to_nir.cpp index 2a469ec..14affee 100644 --- a/src/compiler/nir/glsl_to_nir.cpp +++ b/src/compiler/nir/glsl_to_nir.cpp @@ -143,16 +143,7 @@ glsl_to_nir(const struct gl_shader_program *shader_prog, v2.run(sh->ir); visit_exec_list(sh->ir, &v1); - nir_function *main = NULL; - nir_foreach_function(shader, func) { - if (strcmp(func->name, "main") == 0) { - main = func; - break; - } - } - assert(main); - - nir_lower_outputs_to_temporaries(shader, main); + nir_lower_outputs_to_temporaries(shader, nir_shader_get_entrypoint(shader)); shader->info.name = ralloc_asprintf(shader, "GLSL%d", shader_prog->Name); if (shader_prog->Label) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index de6b93c..d9e0d67 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -1822,6 +1822,8 @@ nir_shader_get_entrypoint(nir_shader *shader) assert(exec_list_length(&shader->functions) == 1); struct exec_node *func_node = exec_list_get_head(&shader->functions); nir_function *func = exec_node_data(nir_function, func_node, node); + assert(func->return_type == glsl_void_type()); + assert(func->num_params == 0); return func; } diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py index 2e9cd5f..ddfe94d 100644 --- a/src/compiler/nir/nir_opt_algebraic.py +++ b/src/compiler/nir/nir_opt_algebraic.py @@ -127,6 +127,7 @@ optimizations = [ (('bcsel', ('flt', a, b), b, a), ('fmax', a, b)), (('bcsel', ('inot', 'a@bool'), b, c), ('bcsel', a, c, b)), (('bcsel', a, ('bcsel', a, b, c), d), ('bcsel', a, b, d)), + (('bcsel', a, True, 'b@bool'), ('ior', a, b)), (('fmin', a, a), a), (('fmax', a, a), a), (('imin', a, a), a), @@ -270,6 +271,10 @@ optimizations = [ (('fabs', ('fsub', 0.0, a)), ('fabs', a)), (('iabs', ('isub', 0, a)), ('iabs', a)), + # Propagate negation up multiplication chains + (('fmul', ('fneg', a), b), ('fneg', ('fmul', a, b))), + (('imul', ('ineg', a), b), ('ineg', ('imul', a, b))), + # Misc. lowering (('fmod', a, b), ('fsub', a, ('fmul', b, ('ffloor', ('fdiv', a, b)))), 'options->lower_fmod'), (('frem', a, b), ('fsub', a, ('fmul', b, ('ftrunc', ('fdiv', a, b)))), 'options->lower_fmod'), diff --git a/src/compiler/shader_enums.h b/src/compiler/shader_enums.h index d44aabf..0c27408 100644 --- a/src/compiler/shader_enums.h +++ b/src/compiler/shader_enums.h @@ -31,7 +31,7 @@ extern "C" { #endif /** - * Shader stages. Note that these will become 5 with tessellation. + * Shader stages. * * The order must match how shaders are ordered in the pipeline. * The GLSL linker assumes that if i<j, then the j-th shader is |