#include "main/core.h"
#include "glsl_symbol_table.h"
+#include "glsl_parser_extras.h"
#include "ir.h"
#include "program.h"
#include "program/hash_table.h"
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;
}
+/**
+ * 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
link_invalidate_variable_locations(gl_shader *sh, int input_base,
int output_base)
int base;
switch (var->mode) {
- case ir_var_in:
+ case ir_var_shader_in:
base = input_base;
break;
- case ir_var_out:
+ case ir_var_shader_out:
base = output_base;
break;
default:
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:
unsigned num_shaders)
{
struct gl_uniform_block *uniform_blocks = NULL;
- unsigned num_uniform_blocks = 0;
/* 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. */
- for (unsigned i = 0; i < num_shaders; i++) {
- struct gl_shader *sh = shader_list[i];
-
- for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) {
- link_assign_uniform_block_offsets(shader_list[i]);
+ /* Check that interface blocks defined in multiple shaders are consistent.
+ */
+ if (!validate_intrastage_interface_blocks((const gl_shader **)shader_list,
+ num_shaders))
+ return NULL;
- int index = link_cross_validate_uniform_block(mem_ctx,
- &uniform_blocks,
- &num_uniform_blocks,
- &sh->UniformBlocks[j]);
- if (index == -1) {
- linker_error(prog, "uniform block `%s' has mismatching definitions",
- sh->UniformBlocks[j].Name);
- 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.
if (main == NULL) {
linker_error(prog, "%s shader lacks `main'\n",
- (shader_list[0]->Type == GL_VERTEX_SHADER)
- ? "vertex" : "fragment");
+ _mesa_glsl_shader_target_name(shader_list[0]->Type));
return NULL;
}
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
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;
* will not be eliminated. Since we always do std140, just
* don't resize arrays in UBOs.
*/
- if (var->uniform_block != -1)
+ if (var->is_in_uniform_block())
continue;
unsigned int size = var->max_array_access;
? (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;
/* Temporary storage for the set of attributes that need locations assigned.
foreach_list(node, ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if (var == NULL || var->mode != ir_var_out) {
+ if (var == NULL || var->mode != ir_var_shader_out) {
continue;
}
};
const unsigned max_samplers[MESA_SHADER_TYPES] = {
- ctx->Const.MaxVertexTextureImageUnits,
- ctx->Const.MaxTextureImageUnits,
- ctx->Const.MaxGeometryTextureImageUnits
+ ctx->Const.VertexProgram.MaxTextureImageUnits,
+ ctx->Const.FragmentProgram.MaxTextureImageUnits,
+ ctx->Const.GeometryProgram.MaxTextureImageUnits
};
- const unsigned max_uniform_components[MESA_SHADER_TYPES] = {
+ const unsigned max_default_uniform_components[MESA_SHADER_TYPES] = {
ctx->Const.VertexProgram.MaxUniformComponents,
ctx->Const.FragmentProgram.MaxUniformComponents,
- 0 /* FINISHME: Geometry shaders. */
+ ctx->Const.GeometryProgram.MaxUniformComponents
+ };
+
+ const unsigned max_combined_uniform_components[MESA_SHADER_TYPES] = {
+ ctx->Const.VertexProgram.MaxCombinedUniformComponents,
+ ctx->Const.FragmentProgram.MaxCombinedUniformComponents,
+ ctx->Const.GeometryProgram.MaxCombinedUniformComponents
};
const unsigned max_uniform_blocks[MESA_SHADER_TYPES] = {
shader_names[i]);
}
- if (sh->num_uniform_components > max_uniform_components[i]) {
+ if (sh->num_uniform_components > max_default_uniform_components[i]) {
+ if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
+ linker_warning(prog, "Too many %s shader default uniform block "
+ "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 default uniform block "
+ "components",
+ shader_names[i]);
+ }
+ }
+
+ if (sh->num_combined_uniform_components >
+ max_combined_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; "
if (prog->_LinkedShaders[i] == NULL)
continue;
+ if (!validate_interstage_interface_blocks(prog->_LinkedShaders[prev],
+ prog->_LinkedShaders[i])) {
+ linker_error(prog, "interface block mismatch between shader stages\n");
+ goto done;
+ }
+
if (!cross_validate_outputs_to_inputs(prog,
prog->_LinkedShaders[prev],
prog->_LinkedShaders[i]))
prog->LinkStatus = true;
}
+
+ for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] != NULL)
+ lower_named_interface_blocks(mem_ctx, prog->_LinkedShaders[i]);
+ }
+
/* 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.
unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations;
- while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll))
+ while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll, &ctx->ShaderCompilerOptions[i]))
;
}
if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
link_invalidate_variable_locations(
prog->_LinkedShaders[MESA_SHADER_VERTEX],
- VERT_ATTRIB_GENERIC0, VERT_RESULT_VAR0);
+ 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],
- FRAG_ATTRIB_VAR0, FRAG_RESULT_DATA0);
+ VARYING_SLOT_VAR0, FRAG_RESULT_DATA0);
}
/* FINISHME: The value of the max_attribute_index parameter is
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.
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.
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