#include "util/set.h"
#include "string_to_uint_map.h"
#include "linker.h"
+#include "linker_util.h"
#include "link_varyings.h"
#include "ir_optimization.h"
#include "ir_rvalue_visitor.h"
#include "ir_uniform.h"
#include "builtin_functions.h"
#include "shader_cache.h"
+#include "util/u_string.h"
+#include "util/u_math.h"
#include "main/imports.h"
#include "main/shaderobj.h"
* Perform validation of global variables used across multiple shaders
*/
static void
-cross_validate_globals(struct gl_shader_program *prog,
+cross_validate_globals(struct gl_context *ctx, struct gl_shader_program *prog,
struct exec_list *ir, glsl_symbol_table *variables,
bool uniforms_only)
{
/* Check the precision qualifier matches for uniform variables on
* GLSL ES.
*/
- if (prog->IsES && !var->get_interface_type() &&
+ if (!ctx->Const.AllowGLSLRelaxedES &&
+ prog->IsES && !var->get_interface_type() &&
existing->data.precision != var->data.precision) {
if ((existing->data.used && var->data.used) || prog->data->Version >= 300) {
linker_error(prog, "declarations for %s `%s` have "
* Perform validation of uniforms used across multiple shader stages
*/
static void
-cross_validate_uniforms(struct gl_shader_program *prog)
+cross_validate_uniforms(struct gl_context *ctx,
+ struct gl_shader_program *prog)
{
glsl_symbol_table variables;
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
if (prog->_LinkedShaders[i] == NULL)
continue;
- cross_validate_globals(prog, prog->_LinkedShaders[i]->ir, &variables,
- true);
+ cross_validate_globals(ctx, prog, prog->_LinkedShaders[i]->ir,
+ &variables, true);
}
}
return true;
}
+/**
+ * Verifies the invariance of built-in special variables.
+ */
+static bool
+validate_invariant_builtins(struct gl_shader_program *prog,
+ const gl_linked_shader *vert,
+ const gl_linked_shader *frag)
+{
+ const ir_variable *var_vert;
+ const ir_variable *var_frag;
+
+ if (!vert || !frag)
+ return true;
+
+ /*
+ * From OpenGL ES Shading Language 1.0 specification
+ * (4.6.4 Invariance and Linkage):
+ * "The invariance of varyings that are declared in both the vertex and
+ * fragment shaders must match. For the built-in special variables,
+ * gl_FragCoord can only be declared invariant if and only if
+ * gl_Position is declared invariant. Similarly gl_PointCoord can only
+ * be declared invariant if and only if gl_PointSize is declared
+ * invariant. It is an error to declare gl_FrontFacing as invariant.
+ * The invariance of gl_FrontFacing is the same as the invariance of
+ * gl_Position."
+ */
+ var_frag = frag->symbols->get_variable("gl_FragCoord");
+ if (var_frag && var_frag->data.invariant) {
+ var_vert = vert->symbols->get_variable("gl_Position");
+ if (var_vert && !var_vert->data.invariant) {
+ linker_error(prog,
+ "fragment shader built-in `%s' has invariant qualifier, "
+ "but vertex shader built-in `%s' lacks invariant qualifier\n",
+ var_frag->name, var_vert->name);
+ return false;
+ }
+ }
+
+ var_frag = frag->symbols->get_variable("gl_PointCoord");
+ if (var_frag && var_frag->data.invariant) {
+ var_vert = vert->symbols->get_variable("gl_PointSize");
+ if (var_vert && !var_vert->data.invariant) {
+ linker_error(prog,
+ "fragment shader built-in `%s' has invariant qualifier, "
+ "but vertex shader built-in `%s' lacks invariant qualifier\n",
+ var_frag->name, var_vert->name);
+ return false;
+ }
+ }
+
+ var_frag = frag->symbols->get_variable("gl_FrontFacing");
+ if (var_frag && var_frag->data.invariant) {
+ linker_error(prog,
+ "fragment shader built-in `%s' can not be declared as invariant\n",
+ var_frag->name);
+ return false;
+ }
+
+ return true;
+}
/**
* Populates a shaders symbol table with all global declarations
linked_shader->Program->info.fs.inner_coverage |= shader->InnerCoverage;
linked_shader->Program->info.fs.post_depth_coverage |=
shader->PostDepthCoverage;
+ linked_shader->Program->info.fs.pixel_interlock_ordered |=
+ shader->PixelInterlockOrdered;
+ linked_shader->Program->info.fs.pixel_interlock_unordered |=
+ shader->PixelInterlockUnordered;
+ linked_shader->Program->info.fs.sample_interlock_ordered |=
+ shader->SampleInterlockOrdered;
+ linked_shader->Program->info.fs.sample_interlock_unordered |=
+ shader->SampleInterlockUnordered;
linked_shader->Program->sh.fs.BlendSupport |= shader->BlendSupport;
}
}
}
+/**
+ * Link all out variables on a single stage which are not
+ * directly used in a shader with the main function.
+ */
+static void
+link_output_variables(struct gl_linked_shader *linked_shader,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ struct glsl_symbol_table *symbols = linked_shader->symbols;
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+
+ /* Skip shader object with main function */
+ if (shader_list[i]->symbols->get_function("main"))
+ continue;
+
+ foreach_in_list(ir_instruction, ir, shader_list[i]->ir) {
+ if (ir->ir_type != ir_type_variable)
+ continue;
+
+ ir_variable *const var = (ir_variable *) ir;
+
+ if (var->data.mode == ir_var_shader_out &&
+ !symbols->get_variable(var->name)) {
+ symbols->add_variable(var);
+ linked_shader->ir->push_head(var);
+ }
+ }
+ }
+
+ return;
+}
+
/**
* Combine a group of shaders for a single stage to generate a linked shader
for (unsigned i = 0; i < num_shaders; i++) {
if (shader_list[i] == NULL)
continue;
- cross_validate_globals(prog, shader_list[i]->ir, &variables, false);
+ cross_validate_globals(ctx, prog, shader_list[i]->ir, &variables,
+ false);
}
if (!prog->data->LinkStatus)
return NULL;
}
+ if (linked->Stage != MESA_SHADER_FRAGMENT)
+ link_output_variables(linked, shader_list, num_shaders);
+
/* 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 (target_index == MESA_SHADER_VERTEX) {
unsigned total_attribs_size =
- _mesa_bitcount(used_locations & SAFE_MASK_FROM_INDEX(max_index)) +
- _mesa_bitcount(double_storage_locations);
+ util_bitcount(used_locations & SAFE_MASK_FROM_INDEX(max_index)) +
+ util_bitcount(double_storage_locations);
if (total_attribs_size > max_index) {
linker_error(prog,
"attempt to use %d vertex attribute slots only %d available ",
*/
if (target_index == MESA_SHADER_VERTEX) {
unsigned total_attribs_size =
- _mesa_bitcount(used_locations & SAFE_MASK_FROM_INDEX(max_index)) +
- _mesa_bitcount(double_storage_locations);
+ util_bitcount(used_locations & SAFE_MASK_FROM_INDEX(max_index)) +
+ util_bitcount(double_storage_locations);
if (total_attribs_size > max_index) {
linker_error(prog,
"attempt to use %d vertex attribute slots only %d available ",
}
}
- struct empty_uniform_block *current_block = NULL;
-
- for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
- /* We found empty space in UniformRemapTable. */
- if (prog->UniformRemapTable[i] == NULL) {
- /* We've found the beginning of a new continous block of empty slots */
- if (!current_block || current_block->start + current_block->slots != i) {
- current_block = rzalloc(prog, struct empty_uniform_block);
- current_block->start = i;
- exec_list_push_tail(&prog->EmptyUniformLocations,
- ¤t_block->link);
- }
-
- /* The current block continues, so we simply increment its slots */
- current_block->slots++;
- }
- }
+ link_util_update_empty_uniform_locations(prog);
delete uniform_map;
prog->NumExplicitUniformLocations = entries_total;
return false;
}
-static bool
-add_program_resource(struct gl_shader_program *prog,
- struct set *resource_set,
- GLenum type, const void *data, uint8_t stages)
-{
- assert(data);
-
- /* If resource already exists, do not add it again. */
- if (_mesa_set_search(resource_set, data))
- return true;
-
- prog->data->ProgramResourceList =
- reralloc(prog->data,
- prog->data->ProgramResourceList,
- gl_program_resource,
- prog->data->NumProgramResourceList + 1);
-
- if (!prog->data->ProgramResourceList) {
- linker_error(prog, "Out of memory during linking.\n");
- return false;
- }
-
- struct gl_program_resource *res =
- &prog->data->ProgramResourceList[prog->data->NumProgramResourceList];
-
- res->Type = type;
- res->Data = data;
- res->StageReferences = stages;
-
- prog->data->NumProgramResourceList++;
-
- _mesa_set_add(resource_set, data);
-
- return true;
-}
-
/* Function checks if a variable var is a packed varying and
* if given name is part of packed varying's list.
*
if (!sha_v)
return false;
- return add_program_resource(shProg, resource_set,
- programInterface, sha_v, stage_mask);
+ return link_util_add_program_resource(shProg, resource_set,
+ programInterface, sha_v, stage_mask);
}
}
}
return false;
}
- snprintf(full_instanced_name, name_length, "%s.%s",
- interface_name, field_name);
+ util_snprintf(full_instanced_name, name_length, "%s.%s",
+ interface_name, field_name);
/* Check if its top-level shader storage block member of an
* instanced interface block, or of a unnamed interface block.
/* Add transform feedback varyings. */
if (linked_xfb->NumVarying > 0) {
for (int i = 0; i < linked_xfb->NumVarying; i++) {
- if (!add_program_resource(shProg, resource_set,
- GL_TRANSFORM_FEEDBACK_VARYING,
- &linked_xfb->Varyings[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set,
+ GL_TRANSFORM_FEEDBACK_VARYING,
+ &linked_xfb->Varyings[i], 0))
return;
}
}
for (unsigned i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
if ((linked_xfb->ActiveBuffers >> i) & 1) {
linked_xfb->Buffers[i].Binding = i;
- if (!add_program_resource(shProg, resource_set,
- GL_TRANSFORM_FEEDBACK_BUFFER,
- &linked_xfb->Buffers[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set,
+ GL_TRANSFORM_FEEDBACK_BUFFER,
+ &linked_xfb->Buffers[i], 0))
return;
}
}
&shProg->data->UniformStorage[i]);
}
- if (!add_program_resource(shProg, resource_set, type,
- &shProg->data->UniformStorage[i], stageref))
+ if (!link_util_add_program_resource(shProg, resource_set, type,
+ &shProg->data->UniformStorage[i], stageref))
return;
}
/* Add program uniform blocks. */
for (unsigned i = 0; i < shProg->data->NumUniformBlocks; i++) {
- if (!add_program_resource(shProg, resource_set, GL_UNIFORM_BLOCK,
- &shProg->data->UniformBlocks[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set, GL_UNIFORM_BLOCK,
+ &shProg->data->UniformBlocks[i], 0))
return;
}
/* Add program shader storage blocks. */
for (unsigned i = 0; i < shProg->data->NumShaderStorageBlocks; i++) {
- if (!add_program_resource(shProg, resource_set, GL_SHADER_STORAGE_BLOCK,
- &shProg->data->ShaderStorageBlocks[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set, GL_SHADER_STORAGE_BLOCK,
+ &shProg->data->ShaderStorageBlocks[i], 0))
return;
}
/* Add atomic counter buffers. */
for (unsigned i = 0; i < shProg->data->NumAtomicBuffers; i++) {
- if (!add_program_resource(shProg, resource_set, GL_ATOMIC_COUNTER_BUFFER,
- &shProg->data->AtomicBuffers[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set, GL_ATOMIC_COUNTER_BUFFER,
+ &shProg->data->AtomicBuffers[i], 0))
return;
}
type = _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j);
/* add shader subroutines */
- if (!add_program_resource(shProg, resource_set,
- type, &shProg->data->UniformStorage[i], 0))
+ if (!link_util_add_program_resource(shProg, resource_set,
+ type, &shProg->data->UniformStorage[i], 0))
return;
}
}
GLuint type = _mesa_shader_stage_to_subroutine((gl_shader_stage)i);
for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
- if (!add_program_resource(shProg, resource_set,
- type, &p->sh.SubroutineFunctions[j], 0))
+ if (!link_util_add_program_resource(shProg, resource_set,
+ type, &p->sh.SubroutineFunctions[j], 0))
return;
}
}
min_version = MIN2(min_version, prog->Shaders[i]->Version);
max_version = MAX2(max_version, prog->Shaders[i]->Version);
- if (prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) {
+ if (!ctx->Const.AllowGLSLRelaxedES &&
+ prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) {
linker_error(prog, "all shaders must use same shading "
"language version\n");
goto done;
/* In desktop GLSL, different shader versions may be linked together. In
* GLSL ES, all shader versions must be the same.
*/
- if (prog->Shaders[0]->IsES && min_version != max_version) {
+ if (!ctx->Const.AllowGLSLRelaxedES && prog->Shaders[0]->IsES &&
+ min_version != max_version) {
linker_error(prog, "all shaders must use same shading "
"language version\n");
goto done;
* performed, then locations are assigned for uniforms, attributes, and
* varyings.
*/
- cross_validate_uniforms(prog);
+ cross_validate_uniforms(ctx, prog);
if (!prog->data->LinkStatus)
goto done;
lower_named_interface_blocks(mem_ctx, prog->_LinkedShaders[i]);
}
+ if (prog->IsES && prog->data->Version == 100)
+ if (!validate_invariant_builtins(prog,
+ prog->_LinkedShaders[MESA_SHADER_VERTEX],
+ prog->_LinkedShaders[MESA_SHADER_FRAGMENT]))
+ goto done;
+
/* 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.