#include "program.h"
#include "program/hash_table.h"
#include "linker.h"
+#include "link_varyings.h"
#include "ir_optimization.h"
extern "C" {
virtual ir_visitor_status visit_enter(ir_call *ir)
{
- exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+ exec_list_iterator sig_iter = ir->callee->parameters.iterator();
foreach_iter(exec_list_iterator, iter, *ir) {
ir_rvalue *param_rval = (ir_rvalue *)iter.get();
ir_variable *sig_param = (ir_variable *)sig_iter.get();
- if (sig_param->mode == ir_var_out ||
- sig_param->mode == ir_var_inout) {
+ if (sig_param->mode == ir_var_function_out ||
+ sig_param->mode == ir_var_function_inout) {
ir_variable *var = param_rval->variable_referenced();
if (var && strcmp(name, var->name) == 0) {
found = true;
sig_iter.next();
}
+ if (ir->return_deref != NULL) {
+ ir_variable *const var = ir->return_deref->variable_referenced();
+
+ if (strcmp(name, var->name) == 0) {
+ found = true;
+ return visit_stop;
+ }
+ }
+
return visit_continue_with_parent;
}
}
+/**
+ * Given a string identifying a program resource, break it into a base name
+ * and an optional array index in square brackets.
+ *
+ * If an array index is present, \c out_base_name_end is set to point to the
+ * "[" that precedes the array index, and the array index itself is returned
+ * as a long.
+ *
+ * If no array index is present (or if the array index is negative or
+ * mal-formed), \c out_base_name_end, is set to point to the null terminator
+ * at the end of the input string, and -1 is returned.
+ *
+ * Only the final array index is parsed; if the string contains other array
+ * indices (or structure field accesses), they are left in the base name.
+ *
+ * No attempt is made to check that the base name is properly formed;
+ * typically the caller will look up the base name in a hash table, so
+ * ill-formed base names simply turn into hash table lookup failures.
+ */
+long
+parse_program_resource_name(const GLchar *name,
+ const GLchar **out_base_name_end)
+{
+ /* Section 7.3.1 ("Program Interfaces") of the OpenGL 4.3 spec says:
+ *
+ * "When an integer array element or block instance number is part of
+ * the name string, it will be specified in decimal form without a "+"
+ * or "-" sign or any extra leading zeroes. Additionally, the name
+ * string will not include white space anywhere in the string."
+ */
+
+ const size_t len = strlen(name);
+ *out_base_name_end = name + len;
+
+ if (len == 0 || name[len-1] != ']')
+ return -1;
+
+ /* Walk backwards over the string looking for a non-digit character. This
+ * had better be the opening bracket for an array index.
+ *
+ * Initially, i specifies the location of the ']'. Since the string may
+ * contain only the ']' charcater, walk backwards very carefully.
+ */
+ unsigned i;
+ for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i)
+ /* empty */ ;
+
+ if ((i == 0) || name[i-1] != '[')
+ return -1;
+
+ long array_index = strtol(&name[i], NULL, 10);
+ if (array_index < 0)
+ return -1;
+
+ *out_base_name_end = name + (i - 1);
+ return array_index;
+}
+
+
void
-invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
- int generic_base)
+link_invalidate_variable_locations(gl_shader *sh, int input_base,
+ int output_base)
{
foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != (unsigned) mode))
- continue;
+ if (var == NULL)
+ continue;
+
+ int base;
+ switch (var->mode) {
+ case ir_var_shader_in:
+ base = input_base;
+ break;
+ case ir_var_shader_out:
+ base = output_base;
+ break;
+ default:
+ continue;
+ }
/* Only assign locations for generic attributes / varyings / etc.
*/
- if ((var->location >= generic_base) && !var->explicit_location)
- var->location = -1;
+ if ((var->location >= base) && !var->explicit_location)
+ var->location = -1;
+
+ if ((var->location == -1) && !var->explicit_location) {
+ var->is_unmatched_generic_inout = 1;
+ var->location_frac = 0;
+ } else {
+ var->is_unmatched_generic_inout = 0;
+ }
}
}
/**
* Verify that a vertex shader executable meets all semantic requirements.
*
- * Also sets prog->Vert.UsesClipDistance as a side effect.
+ * Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize
+ * as a side effect.
*
* \param shader Vertex shader executable to be verified
*/
if (shader == NULL)
return true;
- find_assignment_visitor find("gl_Position");
- find.run(shader->ir);
- if (!find.variable_found()) {
- linker_error(prog, "vertex shader does not write to `gl_Position'\n");
- return false;
+ /* From the GLSL 1.10 spec, page 48:
+ *
+ * "The variable gl_Position is available only in the vertex
+ * language and is intended for writing the homogeneous vertex
+ * position. All executions of a well-formed vertex shader
+ * executable must write a value into this variable. [...] The
+ * variable gl_Position is available only in the vertex
+ * language and is intended for writing the homogeneous vertex
+ * position. All executions of a well-formed vertex shader
+ * executable must write a value into this variable."
+ *
+ * while in GLSL 1.40 this text is changed to:
+ *
+ * "The variable gl_Position is available only in the vertex
+ * language and is intended for writing the homogeneous vertex
+ * position. It can be written at any time during shader
+ * execution. It may also be read back by a vertex shader
+ * after being written. This value will be used by primitive
+ * assembly, clipping, culling, and other fixed functionality
+ * operations, if present, that operate on primitives after
+ * vertex processing has occurred. Its value is undefined if
+ * the vertex shader executable does not write gl_Position."
+ *
+ * GLSL ES 3.00 is similar to GLSL 1.40--failing to write to gl_Position is
+ * not an error.
+ */
+ if (prog->Version < (prog->IsES ? 300 : 140)) {
+ find_assignment_visitor find("gl_Position");
+ find.run(shader->ir);
+ if (!find.variable_found()) {
+ linker_error(prog, "vertex shader does not write to `gl_Position'\n");
+ return false;
+ }
}
- if (prog->Version >= 130) {
+ prog->Vert.ClipDistanceArraySize = 0;
+
+ if (!prog->IsES && prog->Version >= 130) {
/* From section 7.1 (Vertex Shader Special Variables) of the
* GLSL 1.30 spec:
*
* "It is an error for a shader to statically write both
* gl_ClipVertex and gl_ClipDistance."
+ *
+ * This does not apply to GLSL ES shaders, since GLSL ES defines neither
+ * gl_ClipVertex nor gl_ClipDistance.
*/
find_assignment_visitor clip_vertex("gl_ClipVertex");
find_assignment_visitor clip_distance("gl_ClipDistance");
return false;
}
prog->Vert.UsesClipDistance = clip_distance.variable_found();
+ ir_variable *clip_distance_var =
+ shader->symbols->get_variable("gl_ClipDistance");
+ if (clip_distance_var)
+ prog->Vert.ClipDistanceArraySize = clip_distance_var->type->length;
}
return true;
case ir_var_auto:
return (var->read_only) ? "global constant" : "global variable";
- case ir_var_uniform: return "uniform";
- case ir_var_in: return "shader input";
- case ir_var_out: return "shader output";
- case ir_var_inout: return "shader inout";
+ case ir_var_uniform: return "uniform";
+ case ir_var_shader_in: return "shader input";
+ case ir_var_shader_out: return "shader output";
case ir_var_const_in:
case ir_var_temporary:
existing->explicit_location = true;
}
- /* Validate layout qualifiers for gl_FragDepth.
- *
- * From the AMD/ARB_conservative_depth specs:
- * "If gl_FragDepth is redeclared in any fragment shader in
- * a program, it must be redeclared in all fragment shaders in that
- * program that have static assignments to gl_FragDepth. All
- * redeclarations of gl_FragDepth in all fragment shaders in
- * a single program must have the same set of qualifiers."
- */
- if (strcmp(var->name, "gl_FragDepth") == 0) {
- bool layout_declared = var->depth_layout != ir_depth_layout_none;
- bool layout_differs = var->depth_layout != existing->depth_layout;
- if (layout_declared && layout_differs) {
- linker_error(prog,
- "All redeclarations of gl_FragDepth in all fragment shaders "
- "in a single program must have the same set of qualifiers.");
- }
- if (var->used && layout_differs) {
- linker_error(prog,
- "If gl_FragDepth is redeclared with a layout qualifier in"
- "any fragment shader, it must be redeclared with the same"
- "layout qualifier in all fragment shaders that have"
- "assignments to gl_FragDepth");
- }
- }
-
- /* FINISHME: Handle non-constant initializers.
+ /* Validate layout qualifiers for gl_FragDepth.
+ *
+ * From the AMD/ARB_conservative_depth specs:
+ *
+ * "If gl_FragDepth is redeclared in any fragment shader in a
+ * program, it must be redeclared in all fragment shaders in
+ * that program that have static assignments to
+ * gl_FragDepth. All redeclarations of gl_FragDepth in all
+ * fragment shaders in a single program must have the same set
+ * of qualifiers."
+ */
+ if (strcmp(var->name, "gl_FragDepth") == 0) {
+ bool layout_declared = var->depth_layout != ir_depth_layout_none;
+ bool layout_differs =
+ var->depth_layout != existing->depth_layout;
+
+ if (layout_declared && layout_differs) {
+ linker_error(prog,
+ "All redeclarations of gl_FragDepth in all "
+ "fragment shaders in a single program must have "
+ "the same set of qualifiers.");
+ }
+
+ if (var->used && layout_differs) {
+ linker_error(prog,
+ "If gl_FragDepth is redeclared with a layout "
+ "qualifier in any fragment shader, it must be "
+ "redeclared with the same layout qualifier in "
+ "all fragment shaders that have assignments to "
+ "gl_FragDepth");
+ }
+ }
+
+ /* Page 35 (page 41 of the PDF) of the GLSL 4.20 spec says:
+ *
+ * "If a shared global has multiple initializers, the
+ * initializers must all be constant expressions, and they
+ * must all have the same value. Otherwise, a link error will
+ * result. (A shared global having only one initializer does
+ * not require that initializer to be a constant expression.)"
+ *
+ * Previous to 4.20 the GLSL spec simply said that initializers
+ * must have the same value. In this case of non-constant
+ * initializers, this was impossible to determine. As a result,
+ * no vendor actually implemented that behavior. The 4.20
+ * behavior matches the implemented behavior of at least one other
+ * vendor, so we'll implement that for all GLSL versions.
*/
- if (var->constant_value != NULL) {
- if (existing->constant_value != NULL) {
- if (!var->constant_value->has_value(existing->constant_value)) {
+ if (var->constant_initializer != NULL) {
+ if (existing->constant_initializer != NULL) {
+ if (!var->constant_initializer->has_value(existing->constant_initializer)) {
linker_error(prog, "initializers for %s "
"`%s' have differing values\n",
mode_string(var), var->name);
return false;
}
- } else
+ } else {
/* If the first-seen instance of a particular uniform did not
* have an initializer but a later instance does, copy the
* initializer to the version stored in the symbol table.
* FINISHME: modify the shader, and linking with the second
* FINISHME: will fail.
*/
- existing->constant_value =
- var->constant_value->clone(ralloc_parent(existing), NULL);
+ existing->constant_initializer =
+ var->constant_initializer->clone(ralloc_parent(existing),
+ NULL);
+ }
+ }
+
+ if (var->has_initializer) {
+ if (existing->has_initializer
+ && (var->constant_initializer == NULL
+ || existing->constant_initializer == NULL)) {
+ linker_error(prog,
+ "shared global variable `%s' has multiple "
+ "non-constant initializers.\n",
+ var->name);
+ return false;
+ }
+
+ /* Some instance had an initializer, so keep track of that. In
+ * this location, all sorts of initializers (constant or
+ * otherwise) will propagate the existence to the variable
+ * stored in the symbol table.
+ */
+ existing->has_initializer = true;
}
if (existing->invariant != var->invariant) {
MESA_SHADER_TYPES, true);
}
-
/**
- * Validate that outputs from one stage match inputs of another
+ * Accumulates the array of prog->UniformBlocks and checks that all
+ * definitons of blocks agree on their contents.
*/
-bool
-cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
- gl_shader *producer, gl_shader *consumer)
+static bool
+interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
{
- glsl_symbol_table parameters;
- /* FINISHME: Figure these out dynamically. */
- const char *const producer_stage = "vertex";
- const char *const consumer_stage = "fragment";
-
- /* Find all shader outputs in the "producer" stage.
- */
- foreach_list(node, producer->ir) {
- ir_variable *const var = ((ir_instruction *) node)->as_variable();
-
- /* FINISHME: For geometry shaders, this should also look for inout
- * FINISHME: variables.
- */
- if ((var == NULL) || (var->mode != ir_var_out))
- continue;
-
- parameters.add_variable(var);
+ unsigned max_num_uniform_blocks = 0;
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i])
+ max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks;
}
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *sh = prog->_LinkedShaders[i];
- /* Find all shader inputs in the "consumer" stage. Any variables that have
- * matching outputs already in the symbol table must have the same type and
- * qualifiers.
- */
- foreach_list(node, consumer->ir) {
- ir_variable *const input = ((ir_instruction *) node)->as_variable();
+ prog->UniformBlockStageIndex[i] = ralloc_array(prog, int,
+ max_num_uniform_blocks);
+ for (unsigned int j = 0; j < max_num_uniform_blocks; j++)
+ prog->UniformBlockStageIndex[i][j] = -1;
- /* FINISHME: For geometry shaders, this should also look for inout
- * FINISHME: variables.
- */
- if ((input == NULL) || (input->mode != ir_var_in))
+ if (sh == NULL)
continue;
- ir_variable *const output = parameters.get_variable(input->name);
- if (output != NULL) {
- /* Check that the types match between stages.
- */
- if (input->type != output->type) {
- /* There is a bit of a special case for gl_TexCoord. This
- * built-in is unsized by default. Applications that variable
- * access it must redeclare it with a size. There is some
- * language in the GLSL spec that implies the fragment shader
- * and vertex shader do not have to agree on this size. Other
- * driver behave this way, and one or two applications seem to
- * rely on it.
- *
- * Neither declaration needs to be modified here because the array
- * sizes are fixed later when update_array_sizes is called.
- *
- * From page 48 (page 54 of the PDF) of the GLSL 1.10 spec:
- *
- * "Unlike user-defined varying variables, the built-in
- * varying variables don't have a strict one-to-one
- * correspondence between the vertex language and the
- * fragment language."
- */
- if (!output->type->is_array()
- || (strncmp("gl_", output->name, 3) != 0)) {
- linker_error(prog,
- "%s shader output `%s' declared as type `%s', "
- "but %s shader input declared as type `%s'\n",
- producer_stage, output->name,
- output->type->name,
- consumer_stage, input->type->name);
- return false;
- }
- }
+ for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) {
+ int index = link_cross_validate_uniform_block(prog,
+ &prog->UniformBlocks,
+ &prog->NumUniformBlocks,
+ &sh->UniformBlocks[j]);
- /* Check that all of the qualifiers match between stages.
- */
- if (input->centroid != output->centroid) {
- linker_error(prog,
- "%s shader output `%s' %s centroid qualifier, "
- "but %s shader input %s centroid qualifier\n",
- producer_stage,
- output->name,
- (output->centroid) ? "has" : "lacks",
- consumer_stage,
- (input->centroid) ? "has" : "lacks");
+ if (index == -1) {
+ linker_error(prog, "uniform block `%s' has mismatching definitions",
+ sh->UniformBlocks[j].Name);
return false;
}
- if (input->invariant != output->invariant) {
- linker_error(prog,
- "%s shader output `%s' %s invariant qualifier, "
- "but %s shader input %s invariant qualifier\n",
- producer_stage,
- output->name,
- (output->invariant) ? "has" : "lacks",
- consumer_stage,
- (input->invariant) ? "has" : "lacks");
- return false;
- }
-
- if (input->interpolation != output->interpolation) {
- linker_error(prog,
- "%s shader output `%s' specifies %s "
- "interpolation qualifier, "
- "but %s shader input specifies %s "
- "interpolation qualifier\n",
- producer_stage,
- output->name,
- output->interpolation_string(),
- consumer_stage,
- input->interpolation_string());
- return false;
- }
+ prog->UniformBlockStageIndex[i][index] = j;
}
}
continue;
assert(inst->as_assignment()
+ || inst->as_call()
+ || inst->as_if() /* for initializers with the ?: operator */
|| ((var != NULL) && (var->mode == ir_var_temporary)));
if (make_copies) {
}
+/**
+ * This class is only used in link_intrastage_shaders() below but declaring
+ * it inside that function leads to compiler warnings with some versions of
+ * gcc.
+ */
+class array_sizing_visitor : public ir_hierarchical_visitor {
+public:
+ virtual ir_visitor_status visit(ir_variable *var)
+ {
+ if (var->type->is_array() && (var->type->length == 0)) {
+ const glsl_type *type =
+ glsl_type::get_array_instance(var->type->fields.array,
+ var->max_array_access + 1);
+ assert(type != NULL);
+ var->type = type;
+ }
+ return visit_continue;
+ }
+};
+
/**
* Combine a group of shaders for a single stage to generate a linked shader
*
struct gl_shader **shader_list,
unsigned num_shaders)
{
+ struct gl_uniform_block *uniform_blocks = NULL;
+
/* Check that global variables defined in multiple shaders are consistent.
*/
if (!cross_validate_globals(prog, shader_list, num_shaders, false))
return NULL;
+ /* Check that uniform blocks between shaders for a stage agree. */
+ const int num_uniform_blocks =
+ link_uniform_blocks(mem_ctx, prog, shader_list, num_shaders,
+ &uniform_blocks);
+ if (num_uniform_blocks < 0)
+ return NULL;
+
/* Check that there is only a single definition of each function signature
* across all shaders.
*/
linked->ir = new(linked) exec_list;
clone_ir_list(mem_ctx, linked->ir, main->ir);
+ linked->UniformBlocks = uniform_blocks;
+ linked->NumUniformBlocks = num_uniform_blocks;
+ ralloc_steal(linked, linked->UniformBlocks);
+
populate_symbol_table(linked);
/* The a pointer to the main function in the final linked shader (i.e., the
free(linking_shaders);
-#ifdef DEBUG
/* At this point linked should contain all of the linked IR, so
* validate it to make sure nothing went wrong.
*/
if (linked)
validate_ir_tree(linked->ir);
-#endif
/* Make a pass over all variable declarations to ensure that arrays with
* unspecified sizes have a size specified. The size is inferred from the
* max_array_access field.
*/
if (linked != NULL) {
- class array_sizing_visitor : public ir_hierarchical_visitor {
- public:
- virtual ir_visitor_status visit(ir_variable *var)
- {
- if (var->type->is_array() && (var->type->length == 0)) {
- const glsl_type *type =
- glsl_type::get_array_instance(var->type->fields.array,
- var->max_array_access + 1);
-
- assert(type != NULL);
- var->type = type;
- }
-
- return visit_continue;
- }
- } v;
+ array_sizing_visitor v;
v.run(linked->ir);
}
return linked;
}
-
-struct uniform_node {
- exec_node link;
- struct gl_uniform *u;
- unsigned slots;
-};
-
/**
* Update the sizes of linked shader uniform arrays to the maximum
* array index used.
ir_variable *const var = ((ir_instruction *) node)->as_variable();
if ((var == NULL) || (var->mode != ir_var_uniform &&
- var->mode != ir_var_in &&
- var->mode != ir_var_out) ||
+ var->mode != ir_var_shader_in &&
+ var->mode != ir_var_shader_out) ||
!var->type->is_array())
continue;
+ /* GL_ARB_uniform_buffer_object says that std140 uniforms
+ * will not be eliminated. Since we always do std140, just
+ * don't resize arrays in UBOs.
+ */
+ if (var->is_in_uniform_block())
+ continue;
+
unsigned int size = var->max_array_access;
for (unsigned j = 0; j < MESA_SHADER_TYPES; j++) {
if (prog->_LinkedShaders[j] == NULL)
}
}
-static void
-add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht,
- const char *name, const glsl_type *type, GLenum shader_type,
- unsigned *next_shader_pos, unsigned *total_uniforms)
-{
- if (type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- const glsl_type *field_type = type->fields.structure[i].type;
- char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
- type->fields.structure[i].name);
-
- add_uniform(mem_ctx, uniforms, ht, field_name, field_type,
- shader_type, next_shader_pos, total_uniforms);
- }
- } else {
- uniform_node *n = (uniform_node *) hash_table_find(ht, name);
- unsigned int vec4_slots;
- const glsl_type *array_elem_type = NULL;
-
- if (type->is_array()) {
- array_elem_type = type->fields.array;
- /* Array of structures. */
- if (array_elem_type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- char *elem_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);
- add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type,
- shader_type, next_shader_pos, total_uniforms);
- }
- return;
- }
- }
-
- /* Fix the storage size of samplers at 1 vec4 each. Be sure to pad out
- * vectors to vec4 slots.
- */
- if (type->is_array()) {
- if (array_elem_type->is_sampler())
- vec4_slots = type->length;
- else
- vec4_slots = type->length * array_elem_type->matrix_columns;
- } else if (type->is_sampler()) {
- vec4_slots = 1;
- } else {
- vec4_slots = type->matrix_columns;
- }
-
- if (n == NULL) {
- n = (uniform_node *) calloc(1, sizeof(struct uniform_node));
- n->u = (gl_uniform *) calloc(1, sizeof(struct gl_uniform));
- n->slots = vec4_slots;
-
- n->u->Name = strdup(name);
- n->u->Type = type;
- n->u->VertPos = -1;
- n->u->FragPos = -1;
- n->u->GeomPos = -1;
- (*total_uniforms)++;
-
- hash_table_insert(ht, n, name);
- uniforms->push_tail(& n->link);
- }
-
- switch (shader_type) {
- case GL_VERTEX_SHADER:
- n->u->VertPos = *next_shader_pos;
- break;
- case GL_FRAGMENT_SHADER:
- n->u->FragPos = *next_shader_pos;
- break;
- case GL_GEOMETRY_SHADER:
- n->u->GeomPos = *next_shader_pos;
- break;
- }
-
- (*next_shader_pos) += vec4_slots;
- }
-}
-
-void
-assign_uniform_locations(struct gl_shader_program *prog)
-{
- /* */
- exec_list uniforms;
- unsigned total_uniforms = 0;
- hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
- hash_table_string_compare);
- void *mem_ctx = ralloc_context(NULL);
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- if (prog->_LinkedShaders[i] == NULL)
- continue;
-
- unsigned next_position = 0;
-
- foreach_list(node, prog->_LinkedShaders[i]->ir) {
- ir_variable *const var = ((ir_instruction *) node)->as_variable();
-
- if ((var == NULL) || (var->mode != ir_var_uniform))
- continue;
-
- if (strncmp(var->name, "gl_", 3) == 0) {
- /* At the moment, we don't allocate uniform locations for
- * builtin uniforms. It's permitted by spec, and we'll
- * likely switch to doing that at some point, but not yet.
- */
- continue;
- }
-
- var->location = next_position;
- add_uniform(mem_ctx, &uniforms, ht, var->name, var->type,
- prog->_LinkedShaders[i]->Type,
- &next_position, &total_uniforms);
- }
- }
-
- ralloc_free(mem_ctx);
-
- gl_uniform_list *ul = (gl_uniform_list *)
- calloc(1, sizeof(gl_uniform_list));
-
- ul->Size = total_uniforms;
- ul->NumUniforms = total_uniforms;
- ul->Uniforms = (gl_uniform *) calloc(total_uniforms, sizeof(gl_uniform));
-
- unsigned idx = 0;
- uniform_node *next;
- for (uniform_node *node = (uniform_node *) uniforms.head
- ; node->link.next != NULL
- ; node = next) {
- next = (uniform_node *) node->link.next;
-
- node->link.remove();
- memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform));
- idx++;
-
- free(node->u);
- free(node);
- }
-
- hash_table_dtor(ht);
-
- prog->Uniforms = ul;
-}
-
-
/**
* Find a contiguous set of available bits in a bitmask.
*
* \return
* If locations are successfully assigned, true is returned. Otherwise an
* error is emitted to the shader link log and false is returned.
- *
- * \bug
- * Locations set via \c glBindFragDataLocation are not currently supported.
- * Only locations assigned automatically by the linker, explicitly set by a
- * layout qualifier, or explicitly set by a built-in variable (e.g., \c
- * gl_FragColor) are supported for fragment shaders.
*/
bool
assign_attribute_or_color_locations(gl_shader_program *prog,
* 1. Invalidate the location assignments for all vertex shader inputs.
*
* 2. Assign locations for inputs that have user-defined (via
- * glBindVertexAttribLocation) locations.
+ * glBindVertexAttribLocation) locations and outputs that have
+ * user-defined locations (via glBindFragDataLocation).
*
* 3. Sort the attributes without assigned locations by number of slots
* required in decreasing order. Fragmentation caused by attribute
? (int) VERT_ATTRIB_GENERIC0 : (int) FRAG_RESULT_DATA0;
const enum ir_variable_mode direction =
- (target_index == MESA_SHADER_VERTEX) ? ir_var_in : ir_var_out;
+ (target_index == MESA_SHADER_VERTEX)
+ ? ir_var_shader_in : ir_var_shader_out;
- invalidate_variable_locations(sh, direction, generic_base);
-
/* Temporary storage for the set of attributes that need locations assigned.
*/
struct temp_attr {
if (prog->AttributeBindings->get(binding, var->name)) {
assert(binding >= VERT_ATTRIB_GENERIC0);
var->location = binding;
+ var->is_unmatched_generic_inout = 0;
+ }
+ } else if (target_index == MESA_SHADER_FRAGMENT) {
+ unsigned binding;
+ unsigned index;
+
+ if (prog->FragDataBindings->get(binding, var->name)) {
+ assert(binding >= FRAG_RESULT_DATA0);
+ var->location = binding;
+ var->is_unmatched_generic_inout = 0;
+
+ if (prog->FragDataIndexBindings->get(index, var->name)) {
+ var->index = index;
+ }
}
}
- /* The location was explicitly assigned, nothing to do here.
+ /* If the variable is not a built-in and has a location statically
+ * assigned in the shader (presumably via a layout qualifier), make sure
+ * that it doesn't collide with other assigned locations. Otherwise,
+ * add it to the list of variables that need linker-assigned locations.
*/
const unsigned slots = count_attribute_slots(var->type);
if (var->location != -1) {
- if (var->location >= generic_base) {
+ if (var->location >= generic_base && var->index < 1) {
/* From page 61 of the OpenGL 4.0 spec:
*
* "LinkProgram will fail if the attribute bindings assigned
* attribute overlaps any previously allocated bits.
*/
if ((~(use_mask << attr) & used_locations) != used_locations) {
+ const char *const string = (target_index == MESA_SHADER_VERTEX)
+ ? "vertex shader input" : "fragment shader output";
linker_error(prog,
- "insufficient contiguous attribute locations "
- "available for vertex shader input `%s'",
- var->name);
+ "insufficient contiguous locations "
+ "available for %s `%s' %d %d %d", string,
+ var->name, used_locations, use_mask, attr);
return false;
}
? "vertex shader input" : "fragment shader output";
linker_error(prog,
- "insufficient contiguous attribute locations "
+ "insufficient contiguous locations "
"available for %s `%s'",
string, to_assign[i].var->name);
return false;
}
to_assign[i].var->location = generic_base + location;
+ to_assign[i].var->is_unmatched_generic_inout = 0;
used_locations |= (use_mask << location);
}
* its value is used by other shader stages. This will cause the variable
* to have a location assigned.
*/
- if (var->location == -1) {
+ if (var->is_unmatched_generic_inout) {
var->mode = ir_var_auto;
}
}
}
-bool
-assign_varying_locations(struct gl_context *ctx,
- struct gl_shader_program *prog,
- gl_shader *producer, gl_shader *consumer)
+/**
+ * Store the gl_FragDepth layout in the gl_shader_program struct.
+ */
+static void
+store_fragdepth_layout(struct gl_shader_program *prog)
{
- /* FINISHME: Set dynamically when geometry shader support is added. */
- unsigned output_index = VERT_RESULT_VAR0;
- unsigned input_index = FRAG_ATTRIB_VAR0;
+ if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) {
+ return;
+ }
- /* Operate in a total of three passes.
- *
- * 1. Assign locations for any matching inputs and outputs.
- *
- * 2. Mark output variables in the producer that do not have locations as
- * not being outputs. This lets the optimizer eliminate them.
+ struct exec_list *ir = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
+
+ /* We don't look up the gl_FragDepth symbol directly because if
+ * gl_FragDepth is not used in the shader, it's removed from the IR.
+ * However, the symbol won't be removed from the symbol table.
*
- * 3. Mark input variables in the consumer that do not have locations as
- * not being inputs. This lets the optimizer eliminate them.
+ * We're only interested in the cases where the variable is NOT removed
+ * from the IR.
*/
+ foreach_list(node, ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
- invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0);
- invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
-
- foreach_list(node, producer->ir) {
- ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
+ if (var == NULL || var->mode != ir_var_shader_out) {
+ continue;
+ }
- if ((output_var == NULL) || (output_var->mode != ir_var_out)
- || (output_var->location != -1))
- continue;
+ if (strcmp(var->name, "gl_FragDepth") == 0) {
+ switch (var->depth_layout) {
+ case ir_depth_layout_none:
+ prog->FragDepthLayout = FRAG_DEPTH_LAYOUT_NONE;
+ return;
+ case ir_depth_layout_any:
+ prog->FragDepthLayout = FRAG_DEPTH_LAYOUT_ANY;
+ return;
+ case ir_depth_layout_greater:
+ prog->FragDepthLayout = FRAG_DEPTH_LAYOUT_GREATER;
+ return;
+ case ir_depth_layout_less:
+ prog->FragDepthLayout = FRAG_DEPTH_LAYOUT_LESS;
+ return;
+ case ir_depth_layout_unchanged:
+ prog->FragDepthLayout = FRAG_DEPTH_LAYOUT_UNCHANGED;
+ return;
+ default:
+ assert(0);
+ return;
+ }
+ }
+ }
+}
- ir_variable *const input_var =
- consumer->symbols->get_variable(output_var->name);
+/**
+ * Validate the resources used by a program versus the implementation limits
+ */
+static bool
+check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ static const char *const shader_names[MESA_SHADER_TYPES] = {
+ "vertex", "fragment", "geometry"
+ };
- if ((input_var == NULL) || (input_var->mode != ir_var_in))
- continue;
+ const unsigned max_samplers[MESA_SHADER_TYPES] = {
+ ctx->Const.MaxVertexTextureImageUnits,
+ ctx->Const.MaxTextureImageUnits,
+ ctx->Const.MaxGeometryTextureImageUnits
+ };
- assert(input_var->location == -1);
+ const unsigned max_uniform_components[MESA_SHADER_TYPES] = {
+ ctx->Const.VertexProgram.MaxUniformComponents,
+ ctx->Const.FragmentProgram.MaxUniformComponents,
+ 0 /* FINISHME: Geometry shaders. */
+ };
- output_var->location = output_index;
- input_var->location = input_index;
+ const unsigned max_uniform_blocks[MESA_SHADER_TYPES] = {
+ ctx->Const.VertexProgram.MaxUniformBlocks,
+ ctx->Const.FragmentProgram.MaxUniformBlocks,
+ ctx->Const.GeometryProgram.MaxUniformBlocks,
+ };
- /* FINISHME: Support for "varying" records in GLSL 1.50. */
- assert(!output_var->type->is_record());
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *sh = prog->_LinkedShaders[i];
- if (output_var->type->is_array()) {
- const unsigned slots = output_var->type->length
- * output_var->type->fields.array->matrix_columns;
+ if (sh == NULL)
+ continue;
- output_index += slots;
- input_index += slots;
- } else {
- const unsigned slots = output_var->type->matrix_columns;
+ if (sh->num_samplers > max_samplers[i]) {
+ linker_error(prog, "Too many %s shader texture samplers",
+ shader_names[i]);
+ }
- output_index += slots;
- input_index += slots;
+ if (sh->num_uniform_components > max_uniform_components[i]) {
+ if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
+ linker_warning(prog, "Too many %s shader uniform components, "
+ "but the driver will try to optimize them out; "
+ "this is non-portable out-of-spec behavior\n",
+ shader_names[i]);
+ } else {
+ linker_error(prog, "Too many %s shader uniform components",
+ shader_names[i]);
+ }
}
}
- unsigned varying_vectors = 0;
+ unsigned blocks[MESA_SHADER_TYPES] = {0};
+ unsigned total_uniform_blocks = 0;
- foreach_list(node, consumer->ir) {
- ir_variable *const var = ((ir_instruction *) node)->as_variable();
-
- if ((var == NULL) || (var->mode != ir_var_in))
- continue;
-
- if (var->location == -1) {
- if (prog->Version <= 120) {
- /* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec:
- *
- * Only those varying variables used (i.e. read) in
- * the fragment shader executable must be written to
- * by the vertex shader executable; declaring
- * superfluous varying variables in a vertex shader is
- * permissible.
- *
- * We interpret this text as meaning that the VS must
- * write the variable for the FS to read it. See
- * "glsl1-varying read but not written" in piglit.
- */
-
- linker_error(prog, "fragment shader varying %s not written "
- "by vertex shader\n.", var->name);
+ for (unsigned i = 0; i < prog->NumUniformBlocks; i++) {
+ for (unsigned j = 0; j < MESA_SHADER_TYPES; j++) {
+ if (prog->UniformBlockStageIndex[j][i] != -1) {
+ blocks[j]++;
+ total_uniform_blocks++;
}
-
- /* An 'in' variable is only really a shader input if its
- * value is written by the previous stage.
- */
- var->mode = ir_var_auto;
- } else {
- /* The packing rules are used for vertex shader inputs are also used
- * for fragment shader inputs.
- */
- varying_vectors += count_attribute_slots(var->type);
}
- }
- if (ctx->API == API_OPENGLES2 || prog->Version == 100) {
- if (varying_vectors > ctx->Const.MaxVarying) {
- linker_error(prog, "shader uses too many varying vectors "
- "(%u > %u)\n",
- varying_vectors, ctx->Const.MaxVarying);
- return false;
- }
- } else {
- const unsigned float_components = varying_vectors * 4;
- if (float_components > ctx->Const.MaxVarying * 4) {
- linker_error(prog, "shader uses too many varying components "
- "(%u > %u)\n",
- float_components, ctx->Const.MaxVarying * 4);
- return false;
+ if (total_uniform_blocks > ctx->Const.MaxCombinedUniformBlocks) {
+ linker_error(prog, "Too many combined uniform blocks (%d/%d)",
+ prog->NumUniformBlocks,
+ ctx->Const.MaxCombinedUniformBlocks);
+ } else {
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (blocks[i] > max_uniform_blocks[i]) {
+ linker_error(prog, "Too many %s uniform blocks (%d/%d)",
+ shader_names[i],
+ blocks[i],
+ max_uniform_blocks[i]);
+ break;
+ }
+ }
}
}
- return true;
+ return prog->LinkStatus;
}
-
void
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
{
+ tfeedback_decl *tfeedback_decls = NULL;
+ unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying;
+
void *mem_ctx = ralloc_context(NULL); // temporary linker context
prog->LinkStatus = false;
prog->Validated = false;
prog->_Used = false;
- if (prog->InfoLog != NULL)
- ralloc_free(prog->InfoLog);
-
+ ralloc_free(prog->InfoLog);
prog->InfoLog = ralloc_strdup(NULL, "");
+ ralloc_free(prog->UniformBlocks);
+ prog->UniformBlocks = NULL;
+ prog->NumUniformBlocks = 0;
+ for (int i = 0; i < MESA_SHADER_TYPES; i++) {
+ ralloc_free(prog->UniformBlockStageIndex[i]);
+ prog->UniformBlockStageIndex[i] = NULL;
+ }
+
/* Separate the shaders into groups based on their type.
*/
struct gl_shader **vert_shader_list;
unsigned min_version = UINT_MAX;
unsigned max_version = 0;
+ const bool is_es_prog =
+ (prog->NumShaders > 0 && prog->Shaders[0]->IsES) ? true : false;
for (unsigned i = 0; i < prog->NumShaders; i++) {
min_version = MIN2(min_version, prog->Shaders[i]->Version);
max_version = MAX2(max_version, prog->Shaders[i]->Version);
+ if (prog->Shaders[i]->IsES != is_es_prog) {
+ linker_error(prog, "all shaders must use same shading "
+ "language version\n");
+ goto done;
+ }
+
switch (prog->Shaders[i]->Type) {
case GL_VERTEX_SHADER:
vert_shader_list[num_vert_shaders] = prog->Shaders[i];
/* Previous to GLSL version 1.30, different compilation units could mix and
* match shading language versions. With GLSL 1.30 and later, the versions
* of all shaders must match.
+ *
+ * GLSL ES has never allowed mixing of shading language versions.
*/
- assert(min_version >= 100);
- assert(max_version <= 130);
- if ((max_version >= 130 || min_version == 100)
+ if ((is_es_prog || max_version >= 130)
&& min_version != max_version) {
linker_error(prog, "all shaders must use same shading "
"language version\n");
}
prog->Version = max_version;
+ prog->IsES = is_es_prog;
for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] != NULL)
prog->LinkStatus = true;
}
+ /* Implement the GLSL 1.30+ rule for discard vs infinite loops Do
+ * it before optimization because we want most of the checks to get
+ * dropped thanks to constant propagation.
+ *
+ * This rule also applies to GLSL ES 3.00.
+ */
+ if (max_version >= (is_es_prog ? 300 : 130)) {
+ struct gl_shader *sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
+ if (sh) {
+ lower_discard_flow(sh->ir);
+ }
+ }
+
+ if (!interstage_cross_validate_uniform_blocks(prog))
+ goto done;
+
/* Do common optimization before assigning storage for attributes,
* uniforms, and varyings. Later optimization could possibly make
* some of that unused.
if (!prog->LinkStatus)
goto done;
- if (ctx->ShaderCompilerOptions[i].LowerClipDistance)
- lower_clip_distance(prog->_LinkedShaders[i]->ir);
+ if (ctx->ShaderCompilerOptions[i].LowerClipDistance) {
+ lower_clip_distance(prog->_LinkedShaders[i]);
+ }
- while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, 32))
+ unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations;
+
+ while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll))
;
}
- update_array_sizes(prog);
-
- assign_uniform_locations(prog);
+ /* Mark all generic shader inputs and outputs as unpaired. */
+ if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
+ link_invalidate_variable_locations(
+ prog->_LinkedShaders[MESA_SHADER_VERTEX],
+ VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0);
+ }
+ /* FINISHME: Geometry shaders not implemented yet */
+ if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
+ link_invalidate_variable_locations(
+ prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
+ VARYING_SLOT_VAR0, FRAG_RESULT_DATA0);
+ }
/* FINISHME: The value of the max_attribute_index parameter is
* FINISHME: implementation dependent based on the value of
goto done;
}
- if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, ctx->Const.MaxDrawBuffers)) {
+ if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, MAX2(ctx->Const.MaxDrawBuffers, ctx->Const.MaxDualSourceDrawBuffers))) {
goto done;
}
break;
}
+ if (num_tfeedback_decls != 0) {
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * the <count> specified by TransformFeedbackVaryingsEXT is
+ * non-zero, but the program object has no vertex or geometry
+ * shader;
+ */
+ if (prev >= MESA_SHADER_FRAGMENT) {
+ linker_error(prog, "Transform feedback varyings specified, but "
+ "no vertex or geometry shader is present.");
+ goto done;
+ }
+
+ tfeedback_decls = ralloc_array(mem_ctx, tfeedback_decl,
+ prog->TransformFeedback.NumVarying);
+ if (!parse_tfeedback_decls(ctx, prog, mem_ctx, num_tfeedback_decls,
+ prog->TransformFeedback.VaryingNames,
+ tfeedback_decls))
+ goto done;
+ }
+
for (unsigned i = prev + 1; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] == NULL)
continue;
- if (!assign_varying_locations(ctx, prog,
- prog->_LinkedShaders[prev],
- prog->_LinkedShaders[i])) {
+ if (!assign_varying_locations(
+ ctx, mem_ctx, prog, prog->_LinkedShaders[prev], prog->_LinkedShaders[i],
+ i == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
+ tfeedback_decls))
goto done;
- }
prev = i;
}
+ if (prev != MESA_SHADER_FRAGMENT && num_tfeedback_decls != 0) {
+ /* There was no fragment shader, but we still have to assign varying
+ * locations for use by transform feedback.
+ */
+ if (!assign_varying_locations(
+ ctx, mem_ctx, prog, prog->_LinkedShaders[prev], NULL, num_tfeedback_decls,
+ tfeedback_decls))
+ goto done;
+ }
+
+ if (!store_tfeedback_info(ctx, prog, num_tfeedback_decls, tfeedback_decls))
+ goto done;
+
if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
demote_shader_inputs_and_outputs(prog->_LinkedShaders[MESA_SHADER_VERTEX],
- ir_var_out);
+ ir_var_shader_out);
+
+ /* Eliminate code that is now dead due to unused vertex outputs being
+ * demoted.
+ */
+ while (do_dead_code(prog->_LinkedShaders[MESA_SHADER_VERTEX]->ir, false))
+ ;
}
if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
- demote_shader_inputs_and_outputs(sh, ir_var_in);
- demote_shader_inputs_and_outputs(sh, ir_var_inout);
- demote_shader_inputs_and_outputs(sh, ir_var_out);
+ demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
+ demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
+
+ /* Eliminate code that is now dead due to unused geometry outputs being
+ * demoted.
+ */
+ while (do_dead_code(prog->_LinkedShaders[MESA_SHADER_GEOMETRY]->ir, false))
+ ;
}
if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
- demote_shader_inputs_and_outputs(sh, ir_var_in);
+ demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
+
+ /* Eliminate code that is now dead due to unused fragment inputs being
+ * demoted. This shouldn't actually do anything other than remove
+ * declarations of the (now unused) global variables.
+ */
+ while (do_dead_code(prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir, false))
+ ;
}
+ update_array_sizes(prog);
+ link_assign_uniform_locations(prog);
+ store_fragdepth_layout(prog);
+
+ if (!check_resources(ctx, prog))
+ goto done;
+
/* OpenGL ES requires that a vertex shader and a fragment shader both be
- * present in a linked program. By checking for use of shading language
- * version 1.00, we also catch the GL_ARB_ES2_compatibility case.
+ * present in a linked program. By checking prog->IsES, we also
+ * catch the GL_ARB_ES2_compatibility case.
*/
- if (ctx->API == API_OPENGLES2 || prog->Version == 100) {
+ if (!prog->InternalSeparateShader &&
+ (ctx->API == API_OPENGLES2 || prog->IsES)) {
if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
linker_error(prog, "program lacks a vertex shader\n");
} else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) {