#include "program.h"
#include "program/prog_instruction.h"
#include "program/program.h"
+#include "util/mesa-sha1.h"
#include "util/set.h"
-#include "util/string_to_uint_map.h"
+#include "string_to_uint_map.h"
#include "linker.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 "main/shaderobj.h"
#include "main/enums.h"
namespace {
+struct find_variable {
+ const char *name;
+ bool found;
+
+ find_variable(const char *name) : name(name), found(false) {}
+};
+
/**
* Visitor that determines whether or not a variable is ever written.
+ *
+ * Use \ref find_assignments for convenience.
*/
class find_assignment_visitor : public ir_hierarchical_visitor {
public:
- find_assignment_visitor(const char *name)
- : name(name), found(false)
+ find_assignment_visitor(unsigned num_vars,
+ find_variable * const *vars)
+ : num_variables(num_vars), num_found(0), variables(vars)
{
- /* empty */
}
virtual ir_visitor_status visit_enter(ir_assignment *ir)
{
ir_variable *const var = ir->lhs->variable_referenced();
- if (strcmp(name, var->name) == 0) {
- found = true;
- return visit_stop;
- }
-
- return visit_continue_with_parent;
+ return check_variable_name(var->name);
}
virtual ir_visitor_status visit_enter(ir_call *ir)
if (sig_param->data.mode == ir_var_function_out ||
sig_param->data.mode == ir_var_function_inout) {
ir_variable *var = param_rval->variable_referenced();
- if (var && strcmp(name, var->name) == 0) {
- found = true;
+ if (var && check_variable_name(var->name) == visit_stop)
return visit_stop;
- }
}
}
if (ir->return_deref != NULL) {
ir_variable *const var = ir->return_deref->variable_referenced();
- if (strcmp(name, var->name) == 0) {
- found = true;
+ if (check_variable_name(var->name) == visit_stop)
return visit_stop;
- }
}
return visit_continue_with_parent;
}
- bool variable_found()
+private:
+ ir_visitor_status check_variable_name(const char *name)
{
- return found;
+ for (unsigned i = 0; i < num_variables; ++i) {
+ if (strcmp(variables[i]->name, name) == 0) {
+ if (!variables[i]->found) {
+ variables[i]->found = true;
+
+ assert(num_found < num_variables);
+ if (++num_found == num_variables)
+ return visit_stop;
+ }
+ break;
+ }
+ }
+
+ return visit_continue_with_parent;
}
private:
- const char *name; /**< Find writes to a variable with this name. */
- bool found; /**< Was a write to the variable found? */
+ unsigned num_variables; /**< Number of variables to find */
+ unsigned num_found; /**< Number of variables already found */
+ find_variable * const *variables; /**< Variables to find */
};
+/**
+ * Determine whether or not any of NULL-terminated list of variables is ever
+ * written to.
+ */
+static void
+find_assignments(exec_list *ir, find_variable * const *vars)
+{
+ unsigned num_variables = 0;
+
+ for (find_variable * const *v = vars; *v; ++v)
+ num_variables++;
+
+ find_assignment_visitor visitor(num_variables, vars);
+ visitor.run(ir);
+}
+
+/**
+ * Determine whether or not the given variable is ever written to.
+ */
+static void
+find_assignments(exec_list *ir, find_variable *var)
+{
+ find_assignment_visitor visitor(1, &var);
+ visitor.run(ir);
+}
/**
* Visitor that determines whether or not a variable is ever read.
virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
{
- for (unsigned i = 0; i < ir->record->type->length; i++) {
- const struct glsl_struct_field *field =
- &ir->record->type->fields.structure[i];
- if (strcmp(field->name, ir->field) == 0) {
- ir->type = field->type;
- break;
- }
- }
+ ir->type = ir->record->type->fields.structure[ir->field_idx].type;
return visit_continue;
}
};
if (!ir->variable_referenced()->type->contains_sampler())
return visit_continue;
- if (!ir->array_index->constant_expression_value()) {
+ if (!ir->array_index->constant_expression_value(ralloc_parent(ir))) {
dynamic_sampler_array_indexing = true;
return visit_stop;
}
ralloc_vasprintf_append(&prog->data->InfoLog, fmt, ap);
va_end(ap);
- prog->data->LinkStatus = false;
+ prog->data->LinkStatus = linking_failure;
}
* gl_ClipVertex nor gl_ClipDistance. However with
* GL_EXT_clip_cull_distance, this functionality is exposed in ES 3.0.
*/
- find_assignment_visitor clip_distance("gl_ClipDistance");
- find_assignment_visitor cull_distance("gl_CullDistance");
-
- clip_distance.run(shader->ir);
- cull_distance.run(shader->ir);
+ find_variable gl_ClipDistance("gl_ClipDistance");
+ find_variable gl_CullDistance("gl_CullDistance");
+ find_variable gl_ClipVertex("gl_ClipVertex");
+ find_variable * const variables[] = {
+ &gl_ClipDistance,
+ &gl_CullDistance,
+ !prog->IsES ? &gl_ClipVertex : NULL,
+ NULL
+ };
+ find_assignments(shader->ir, variables);
/* From the ARB_cull_distance spec:
*
* gl_ClipVertex.
*/
if (!prog->IsES) {
- find_assignment_visitor clip_vertex("gl_ClipVertex");
-
- clip_vertex.run(shader->ir);
-
- if (clip_vertex.variable_found() && clip_distance.variable_found()) {
+ if (gl_ClipVertex.found && gl_ClipDistance.found) {
linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
"and `gl_ClipDistance'\n",
_mesa_shader_stage_to_string(shader->Stage));
return;
}
- if (clip_vertex.variable_found() && cull_distance.variable_found()) {
+ if (gl_ClipVertex.found && gl_CullDistance.found) {
linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
"and `gl_CullDistance'\n",
_mesa_shader_stage_to_string(shader->Stage));
}
}
- if (clip_distance.variable_found()) {
+ if (gl_ClipDistance.found) {
ir_variable *clip_distance_var =
shader->symbols->get_variable("gl_ClipDistance");
assert(clip_distance_var);
*clip_distance_array_size = clip_distance_var->type->length;
}
- if (cull_distance.variable_found()) {
+ if (gl_CullDistance.found) {
ir_variable *cull_distance_var =
shader->symbols->get_variable("gl_CullDistance");
assert(cull_distance_var);
/**
* Verify that a vertex shader executable meets all semantic requirements.
*
- * Also sets prog->Vert.ClipDistanceArraySize and
- * prog->Vert.CullDistanceArraySize as a side effect.
+ * Also sets info.clip_distance_array_size and
+ * info.cull_distance_array_size as a side effect.
*
* \param shader Vertex shader executable to be verified
*/
-void
+static void
validate_vertex_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
* gl_Position is not an error.
*/
if (prog->data->Version < (prog->IsES ? 300 : 140)) {
- find_assignment_visitor find("gl_Position");
- find.run(shader->ir);
- if (!find.variable_found()) {
+ find_variable gl_Position("gl_Position");
+ find_assignments(shader->ir, &gl_Position);
+ if (!gl_Position.found) {
if (prog->IsES) {
linker_warning(prog,
"vertex shader does not write to `gl_Position'. "
}
analyze_clip_cull_usage(prog, shader, ctx,
- &prog->Vert.ClipDistanceArraySize,
- &prog->Vert.CullDistanceArraySize);
+ &shader->Program->info.clip_distance_array_size,
+ &shader->Program->info.cull_distance_array_size);
}
-void
+static void
validate_tess_eval_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
return;
analyze_clip_cull_usage(prog, shader, ctx,
- &prog->TessEval.ClipDistanceArraySize,
- &prog->TessEval.CullDistanceArraySize);
+ &shader->Program->info.clip_distance_array_size,
+ &shader->Program->info.cull_distance_array_size);
}
*
* \param shader Fragment shader executable to be verified
*/
-void
+static void
validate_fragment_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader)
{
if (shader == NULL)
return;
- find_assignment_visitor frag_color("gl_FragColor");
- find_assignment_visitor frag_data("gl_FragData");
-
- frag_color.run(shader->ir);
- frag_data.run(shader->ir);
+ find_variable gl_FragColor("gl_FragColor");
+ find_variable gl_FragData("gl_FragData");
+ find_variable * const variables[] = { &gl_FragColor, &gl_FragData, NULL };
+ find_assignments(shader->ir, variables);
- if (frag_color.variable_found() && frag_data.variable_found()) {
+ if (gl_FragColor.found && gl_FragData.found) {
linker_error(prog, "fragment shader writes to both "
"`gl_FragColor' and `gl_FragData'\n");
}
/**
* Verify that a geometry shader executable meets all semantic requirements
*
- * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize and
- * prog->Geom.CullDistanceArraySize as a side effect.
+ * Also sets prog->Geom.VerticesIn, and info.clip_distance_array_sizeand
+ * info.cull_distance_array_size as a side effect.
*
* \param shader Geometry shader executable to be verified
*/
-void
+static void
validate_geometry_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
if (shader == NULL)
return;
- unsigned num_vertices = vertices_per_prim(shader->info.Geom.InputType);
+ unsigned num_vertices =
+ vertices_per_prim(shader->Program->info.gs.input_primitive);
prog->Geom.VerticesIn = num_vertices;
analyze_clip_cull_usage(prog, shader, ctx,
- &prog->Geom.ClipDistanceArraySize,
- &prog->Geom.CullDistanceArraySize);
+ &shader->Program->info.clip_distance_array_size,
+ &shader->Program->info.cull_distance_array_size);
}
/**
* EmitStreamVertex() or EmitEndPrimitive() are called with a non-zero
* stream.
*/
- if (prog->Geom.UsesStreams && sh->info.Geom.OutputType != GL_POINTS) {
+ if (prog->Geom.UsesStreams &&
+ sh->Program->info.gs.output_primitive != GL_POINTS) {
linker_error(prog, "EmitStreamVertex(n) and EndStreamPrimitive(n) "
"with n>0 requires point output\n");
}
}
return true;
}
- } else {
- /* The arrays of structs could have different glsl_type pointers but
- * they are actually the same type. Use record_compare() to check that.
- */
- if (existing->type->fields.array->is_record() &&
- var->type->fields.array->is_record() &&
- existing->type->fields.array->record_compare(var->type->fields.array))
- return true;
}
}
return false;
/**
* Perform validation of global variables used across multiple shaders
*/
-void
+static void
cross_validate_globals(struct gl_shader_program *prog,
struct exec_list *ir, glsl_symbol_table *variables,
bool uniforms_only)
if (var->type->contains_subroutine())
continue;
+ /* Don't cross validate interface instances. These are only relevant
+ * inside a shader. The cross validation is done at the Interface Block
+ * name level.
+ */
+ if (var->is_interface_instance())
+ continue;
+
/* Don't cross validate temporaries that are at global scope. These
* will eventually get pulled into the shaders 'main'.
*/
*/
ir_variable *const existing = variables->get_variable(var->name);
if (existing != NULL) {
- /* Check if types match. Interface blocks have some special
- * rules so we handle those elsewhere.
- */
- if (var->type != existing->type &&
- !var->is_interface_instance()) {
+ /* Check if types match. */
+ if (var->type != existing->type) {
if (!validate_intrastage_arrays(prog, var, existing)) {
- if (var->type->is_record() && existing->type->is_record()
- && existing->type->record_compare(var->type)) {
- existing->type = var->type;
- } else {
- /* If it is an unsized array in a Shader Storage Block,
- * two different shaders can access to different elements.
- * Because of that, they might be converted to different
- * sized arrays, then check that they are compatible but
- * ignore the array size.
- */
- if (!(var->data.mode == ir_var_shader_storage &&
- var->data.from_ssbo_unsized_array &&
- existing->data.mode == ir_var_shader_storage &&
- existing->data.from_ssbo_unsized_array &&
- var->type->gl_type == existing->type->gl_type)) {
- linker_error(prog, "%s `%s' declared as type "
- "`%s' and type `%s'\n",
- mode_string(var),
- var->name, var->type->name,
- existing->type->name);
- return;
- }
+ /* If it is an unsized array in a Shader Storage Block,
+ * two different shaders can access to different elements.
+ * Because of that, they might be converted to different
+ * sized arrays, then check that they are compatible but
+ * ignore the array size.
+ */
+ if (!(var->data.mode == ir_var_shader_storage &&
+ var->data.from_ssbo_unsized_array &&
+ existing->data.mode == ir_var_shader_storage &&
+ existing->data.from_ssbo_unsized_array &&
+ var->type->gl_type == existing->type->gl_type)) {
+ linker_error(prog, "%s `%s' declared as type "
+ "`%s' and type `%s'\n",
+ mode_string(var),
+ var->name, var->type->name,
+ existing->type->name);
+ return;
}
}
}
if (prog->IsES && (prog->data->Version != 310 ||
!var->get_interface_type()) &&
existing->data.precision != var->data.precision) {
- linker_error(prog, "declarations for %s `%s` have "
- "mismatching precision qualifiers\n",
- mode_string(var), var->name);
- return;
+ if ((existing->data.used && var->data.used) || prog->data->Version >= 300) {
+ linker_error(prog, "declarations for %s `%s` have "
+ "mismatching precision qualifiers\n",
+ mode_string(var), var->name);
+ return;
+ } else {
+ linker_warning(prog, "declarations for %s `%s` have "
+ "mismatching precision qualifiers\n",
+ mode_string(var), var->name);
+ }
}
} else
variables->add_variable(var);
/**
* Perform validation of uniforms used across multiple shader stages
*/
-void
+static void
cross_validate_uniforms(struct gl_shader_program *prog)
{
glsl_symbol_table variables;
for (unsigned k = 0; k <= i; k++) {
delete[] InterfaceBlockStageIndex[k];
}
+
+ /* Reset the block count. This will help avoid various segfaults
+ * from api calls that assume the array exists due to the count
+ * being non-zero.
+ */
+ *num_blks = 0;
return false;
}
* Populates a shaders symbol table with all global declarations
*/
static void
-populate_symbol_table(gl_linked_shader *sh)
+populate_symbol_table(gl_linked_shader *sh, glsl_symbol_table *symbols)
{
sh->symbols = new(sh) glsl_symbol_table;
- foreach_in_list(ir_instruction, inst, sh->ir) {
- ir_variable *var;
- ir_function *func;
-
- if ((func = inst->as_function()) != NULL) {
- sh->symbols->add_function(func);
- } else if ((var = inst->as_variable()) != NULL) {
- if (var->data.mode != ir_var_temporary)
- sh->symbols->add_variable(var);
- }
- }
+ _mesa_glsl_copy_symbols_from_table(sh->ir, symbols, sh->symbols);
}
* \param instructions Instruction stream where new variable declarations
* should be added.
*/
-void
+static void
remap_variables(ir_instruction *inst, struct gl_linked_shader *target,
hash_table *temps)
{
* is suitable for use as the \c last parameter of a later call to this
* function.
*/
-exec_node *
+static exec_node *
move_non_declarations(exec_list *instructions, exec_node *last,
bool make_copies, gl_linked_shader *target)
{
hash_table *unnamed_interfaces;
};
+static bool
+validate_xfb_buffer_stride(struct gl_context *ctx, unsigned idx,
+ struct gl_shader_program *prog)
+{
+ /* We will validate doubles at a later stage */
+ if (prog->TransformFeedback.BufferStride[idx] % 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[idx]);
+ return false;
+ }
+
+ if (prog->TransformFeedback.BufferStride[idx] / 4 >
+ ctx->Const.MaxTransformFeedbackInterleavedComponents) {
+ linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
+ "limit has been exceeded.");
+ return false;
+ }
+
+ return true;
+}
+
/**
* 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_linked_shader *linked_shader,
struct gl_shader **shader_list,
unsigned num_shaders)
{
for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
- linked_shader->info.TransformFeedback.BufferStride[i] = 0;
+ prog->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->info.TransformFeedback.BufferStride[j]) {
- if (linked_shader->info.TransformFeedback.BufferStride[j] != 0 &&
- shader->info.TransformFeedback.BufferStride[j] != 0 &&
- linked_shader->info.TransformFeedback.BufferStride[j] !=
- shader->info.TransformFeedback.BufferStride[j]) {
+ if (shader->TransformFeedbackBufferStride[j]) {
+ if (prog->TransformFeedback.BufferStride[j] == 0) {
+ prog->TransformFeedback.BufferStride[j] =
+ shader->TransformFeedbackBufferStride[j];
+ if (!validate_xfb_buffer_stride(ctx, j, prog))
+ return;
+ } else if (prog->TransformFeedback.BufferStride[j] !=
+ shader->TransformFeedbackBufferStride[j]){
linker_error(prog,
"intrastage shaders defined with conflicting "
"xfb_stride for buffer %d (%d and %d)\n", j,
- linked_shader->
- info.TransformFeedback.BufferStride[j],
- shader->info.TransformFeedback.BufferStride[j]);
+ prog->TransformFeedback.BufferStride[j],
+ shader->TransformFeedbackBufferStride[j]);
return;
}
-
- if (shader->info.TransformFeedback.BufferStride[j])
- linked_shader->info.TransformFeedback.BufferStride[j] =
- shader->info.TransformFeedback.BufferStride[j];
}
}
}
+}
+
+/**
+ * Check for conflicting bindless/bound sampler/image layout qualifiers at
+ * global scope.
+ */
+static void
+link_bindless_layout_qualifiers(struct gl_shader_program *prog,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ bool bindless_sampler, bindless_image;
+ bool bound_sampler, bound_image;
- for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
- if (linked_shader->info.TransformFeedback.BufferStride[j]) {
- prog->TransformFeedback.BufferStride[j] =
- linked_shader->info.TransformFeedback.BufferStride[j];
+ bindless_sampler = bindless_image = false;
+ bound_sampler = bound_image = false;
- /* 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;
- }
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *shader = shader_list[i];
- if (prog->TransformFeedback.BufferStride[j] / 4 >
- ctx->Const.MaxTransformFeedbackInterleavedComponents) {
- linker_error(prog,
- "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
- "limit has been exceeded.");
- return;
- }
+ if (shader->bindless_sampler)
+ bindless_sampler = true;
+ if (shader->bindless_image)
+ bindless_image = true;
+ if (shader->bound_sampler)
+ bound_sampler = true;
+ if (shader->bound_image)
+ bound_image = true;
+
+ if ((bindless_sampler && bound_sampler) ||
+ (bindless_image && bound_image)) {
+ /* From section 4.4.6 of the ARB_bindless_texture spec:
+ *
+ * "If both bindless_sampler and bound_sampler, or bindless_image
+ * and bound_image, are declared at global scope in any
+ * compilation unit, a link- time error will be generated."
+ */
+ linker_error(prog, "both bindless_sampler and bound_sampler, or "
+ "bindless_image and bound_image, can't be declared at "
+ "global scope");
}
}
}
*/
static void
link_tcs_out_layout_qualifiers(struct gl_shader_program *prog,
- struct gl_linked_shader *linked_shader,
+ struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
- linked_shader->info.TessCtrl.VerticesOut = 0;
-
- if (linked_shader->Stage != MESA_SHADER_TESS_CTRL)
+ if (gl_prog->info.stage != MESA_SHADER_TESS_CTRL)
return;
+ gl_prog->info.tess.tcs_vertices_out = 0;
+
/* From the GLSL 4.0 spec (chapter 4.3.8.2):
*
* "All tessellation control shader layout declarations in a program
struct gl_shader *shader = shader_list[i];
if (shader->info.TessCtrl.VerticesOut != 0) {
- if (linked_shader->info.TessCtrl.VerticesOut != 0 &&
- linked_shader->info.TessCtrl.VerticesOut !=
- shader->info.TessCtrl.VerticesOut) {
+ if (gl_prog->info.tess.tcs_vertices_out != 0 &&
+ gl_prog->info.tess.tcs_vertices_out !=
+ (unsigned) shader->info.TessCtrl.VerticesOut) {
linker_error(prog, "tessellation control shader defined with "
"conflicting output vertex count (%d and %d)\n",
- linked_shader->info.TessCtrl.VerticesOut,
+ gl_prog->info.tess.tcs_vertices_out,
shader->info.TessCtrl.VerticesOut);
return;
}
- linked_shader->info.TessCtrl.VerticesOut =
+ gl_prog->info.tess.tcs_vertices_out =
shader->info.TessCtrl.VerticesOut;
}
}
* since we already know we're in the right type of shader program
* for doing it.
*/
- if (linked_shader->info.TessCtrl.VerticesOut == 0) {
+ if (gl_prog->info.tess.tcs_vertices_out == 0) {
linker_error(prog, "tessellation control shader didn't declare "
"vertices out layout qualifier\n");
return;
*/
static void
link_tes_in_layout_qualifiers(struct gl_shader_program *prog,
- struct gl_linked_shader *linked_shader,
+ struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
- linked_shader->info.TessEval.PrimitiveMode = PRIM_UNKNOWN;
- linked_shader->info.TessEval.Spacing = TESS_SPACING_UNSPECIFIED;
- linked_shader->info.TessEval.VertexOrder = 0;
- linked_shader->info.TessEval.PointMode = -1;
-
- if (linked_shader->Stage != MESA_SHADER_TESS_EVAL)
+ if (gl_prog->info.stage != MESA_SHADER_TESS_EVAL)
return;
+ int point_mode = -1;
+ unsigned vertex_order = 0;
+
+ gl_prog->info.tess.primitive_mode = PRIM_UNKNOWN;
+ gl_prog->info.tess.spacing = TESS_SPACING_UNSPECIFIED;
+
/* From the GLSL 4.0 spec (chapter 4.3.8.1):
*
* "At least one tessellation evaluation shader (compilation unit) in
struct gl_shader *shader = shader_list[i];
if (shader->info.TessEval.PrimitiveMode != PRIM_UNKNOWN) {
- if (linked_shader->info.TessEval.PrimitiveMode != PRIM_UNKNOWN &&
- linked_shader->info.TessEval.PrimitiveMode !=
+ if (gl_prog->info.tess.primitive_mode != PRIM_UNKNOWN &&
+ gl_prog->info.tess.primitive_mode !=
shader->info.TessEval.PrimitiveMode) {
linker_error(prog, "tessellation evaluation shader defined with "
"conflicting input primitive modes.\n");
return;
}
- linked_shader->info.TessEval.PrimitiveMode = shader->info.TessEval.PrimitiveMode;
+ gl_prog->info.tess.primitive_mode =
+ shader->info.TessEval.PrimitiveMode;
}
if (shader->info.TessEval.Spacing != 0) {
- if (linked_shader->info.TessEval.Spacing != 0 &&
- linked_shader->info.TessEval.Spacing !=
+ if (gl_prog->info.tess.spacing != 0 && gl_prog->info.tess.spacing !=
shader->info.TessEval.Spacing) {
linker_error(prog, "tessellation evaluation shader defined with "
"conflicting vertex spacing.\n");
return;
}
- linked_shader->info.TessEval.Spacing = shader->info.TessEval.Spacing;
+ gl_prog->info.tess.spacing = shader->info.TessEval.Spacing;
}
if (shader->info.TessEval.VertexOrder != 0) {
- if (linked_shader->info.TessEval.VertexOrder != 0 &&
- linked_shader->info.TessEval.VertexOrder !=
- shader->info.TessEval.VertexOrder) {
+ if (vertex_order != 0 &&
+ vertex_order != shader->info.TessEval.VertexOrder) {
linker_error(prog, "tessellation evaluation shader defined with "
"conflicting ordering.\n");
return;
}
- linked_shader->info.TessEval.VertexOrder =
- shader->info.TessEval.VertexOrder;
+ vertex_order = shader->info.TessEval.VertexOrder;
}
if (shader->info.TessEval.PointMode != -1) {
- if (linked_shader->info.TessEval.PointMode != -1 &&
- linked_shader->info.TessEval.PointMode !=
- shader->info.TessEval.PointMode) {
+ if (point_mode != -1 &&
+ point_mode != shader->info.TessEval.PointMode) {
linker_error(prog, "tessellation evaluation shader defined with "
"conflicting point modes.\n");
return;
}
- linked_shader->info.TessEval.PointMode =
- shader->info.TessEval.PointMode;
+ point_mode = shader->info.TessEval.PointMode;
}
}
* since we already know we're in the right type of shader program
* for doing it.
*/
- if (linked_shader->info.TessEval.PrimitiveMode == PRIM_UNKNOWN) {
+ if (gl_prog->info.tess.primitive_mode == PRIM_UNKNOWN) {
linker_error(prog,
"tessellation evaluation shader didn't declare input "
"primitive modes.\n");
return;
}
- if (linked_shader->info.TessEval.Spacing == TESS_SPACING_UNSPECIFIED)
- linked_shader->info.TessEval.Spacing = TESS_SPACING_EQUAL;
+ if (gl_prog->info.tess.spacing == TESS_SPACING_UNSPECIFIED)
+ gl_prog->info.tess.spacing = TESS_SPACING_EQUAL;
+
+ if (vertex_order == 0 || vertex_order == GL_CCW)
+ gl_prog->info.tess.ccw = true;
+ else
+ gl_prog->info.tess.ccw = false;
- if (linked_shader->info.TessEval.VertexOrder == 0)
- linked_shader->info.TessEval.VertexOrder = GL_CCW;
- if (linked_shader->info.TessEval.PointMode == -1)
- linked_shader->info.TessEval.PointMode = GL_FALSE;
+ if (point_mode == -1 || point_mode == GL_FALSE)
+ gl_prog->info.tess.point_mode = false;
+ else
+ gl_prog->info.tess.point_mode = true;
}
struct gl_shader **shader_list,
unsigned num_shaders)
{
- linked_shader->info.redeclares_gl_fragcoord = false;
- linked_shader->info.uses_gl_fragcoord = false;
- linked_shader->info.origin_upper_left = false;
- linked_shader->info.pixel_center_integer = false;
+ bool redeclares_gl_fragcoord = false;
+ bool uses_gl_fragcoord = false;
+ bool origin_upper_left = false;
+ bool pixel_center_integer = false;
if (linked_shader->Stage != MESA_SHADER_FRAGMENT ||
(prog->data->Version < 150 &&
* it must be redeclared in all the fragment shaders in that program
* that have a static use gl_FragCoord."
*/
- if ((linked_shader->info.redeclares_gl_fragcoord
- && !shader->info.redeclares_gl_fragcoord
- && shader->info.uses_gl_fragcoord)
- || (shader->info.redeclares_gl_fragcoord
- && !linked_shader->info.redeclares_gl_fragcoord
- && linked_shader->info.uses_gl_fragcoord)) {
+ if ((redeclares_gl_fragcoord && !shader->redeclares_gl_fragcoord &&
+ shader->uses_gl_fragcoord)
+ || (shader->redeclares_gl_fragcoord && !redeclares_gl_fragcoord &&
+ uses_gl_fragcoord)) {
linker_error(prog, "fragment shader defined with conflicting "
"layout qualifiers for gl_FragCoord\n");
}
* "All redeclarations of gl_FragCoord in all fragment shaders in a
* single program must have the same set of qualifiers."
*/
- if (linked_shader->info.redeclares_gl_fragcoord &&
- shader->info.redeclares_gl_fragcoord &&
- (shader->info.origin_upper_left !=
- linked_shader->info.origin_upper_left ||
- shader->info.pixel_center_integer !=
- linked_shader->info.pixel_center_integer)) {
+ if (redeclares_gl_fragcoord && shader->redeclares_gl_fragcoord &&
+ (shader->origin_upper_left != origin_upper_left ||
+ shader->pixel_center_integer != pixel_center_integer)) {
linker_error(prog, "fragment shader defined with conflicting "
"layout qualifiers for gl_FragCoord\n");
}
* are multiple redeclarations, all the fields except uses_gl_fragcoord
* are already known to be the same.
*/
- if (shader->info.redeclares_gl_fragcoord ||
- shader->info.uses_gl_fragcoord) {
- linked_shader->info.redeclares_gl_fragcoord =
- shader->info.redeclares_gl_fragcoord;
- linked_shader->info.uses_gl_fragcoord =
- linked_shader->info.uses_gl_fragcoord ||
- shader->info.uses_gl_fragcoord;
- linked_shader->info.origin_upper_left =
- shader->info.origin_upper_left;
- linked_shader->info.pixel_center_integer =
- shader->info.pixel_center_integer;
+ if (shader->redeclares_gl_fragcoord || shader->uses_gl_fragcoord) {
+ redeclares_gl_fragcoord = shader->redeclares_gl_fragcoord;
+ uses_gl_fragcoord |= shader->uses_gl_fragcoord;
+ origin_upper_left = shader->origin_upper_left;
+ pixel_center_integer = shader->pixel_center_integer;
}
- linked_shader->info.EarlyFragmentTests |=
- shader->info.EarlyFragmentTests;
- linked_shader->info.InnerCoverage |=
- shader->info.InnerCoverage;
+ linked_shader->Program->info.fs.early_fragment_tests |=
+ shader->EarlyFragmentTests || shader->PostDepthCoverage;
+ linked_shader->Program->info.fs.inner_coverage |= shader->InnerCoverage;
linked_shader->Program->info.fs.post_depth_coverage |=
- shader->info.PostDepthCoverage;
+ shader->PostDepthCoverage;
linked_shader->Program->sh.fs.BlendSupport |= shader->BlendSupport;
}
*/
static void
link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
- struct gl_linked_shader *linked_shader,
+ struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
- linked_shader->info.Geom.VerticesOut = -1;
- linked_shader->info.Geom.Invocations = 0;
- linked_shader->info.Geom.InputType = PRIM_UNKNOWN;
- linked_shader->info.Geom.OutputType = PRIM_UNKNOWN;
-
/* No in/out qualifiers defined for anything but GLSL 1.50+
* geometry shaders so far.
*/
- if (linked_shader->Stage != MESA_SHADER_GEOMETRY ||
+ if (gl_prog->info.stage != MESA_SHADER_GEOMETRY ||
prog->data->Version < 150)
return;
+ int vertices_out = -1;
+
+ gl_prog->info.gs.invocations = 0;
+ gl_prog->info.gs.input_primitive = PRIM_UNKNOWN;
+ gl_prog->info.gs.output_primitive = PRIM_UNKNOWN;
+
/* From the GLSL 1.50 spec, page 46:
*
* "All geometry shader output layout declarations in a program
struct gl_shader *shader = shader_list[i];
if (shader->info.Geom.InputType != PRIM_UNKNOWN) {
- if (linked_shader->info.Geom.InputType != PRIM_UNKNOWN &&
- linked_shader->info.Geom.InputType !=
+ if (gl_prog->info.gs.input_primitive != PRIM_UNKNOWN &&
+ gl_prog->info.gs.input_primitive !=
shader->info.Geom.InputType) {
linker_error(prog, "geometry shader defined with conflicting "
"input types\n");
return;
}
- linked_shader->info.Geom.InputType = shader->info.Geom.InputType;
+ gl_prog->info.gs.input_primitive = shader->info.Geom.InputType;
}
if (shader->info.Geom.OutputType != PRIM_UNKNOWN) {
- if (linked_shader->info.Geom.OutputType != PRIM_UNKNOWN &&
- linked_shader->info.Geom.OutputType !=
+ if (gl_prog->info.gs.output_primitive != PRIM_UNKNOWN &&
+ gl_prog->info.gs.output_primitive !=
shader->info.Geom.OutputType) {
linker_error(prog, "geometry shader defined with conflicting "
"output types\n");
return;
}
- linked_shader->info.Geom.OutputType = shader->info.Geom.OutputType;
+ gl_prog->info.gs.output_primitive = shader->info.Geom.OutputType;
}
if (shader->info.Geom.VerticesOut != -1) {
- if (linked_shader->info.Geom.VerticesOut != -1 &&
- linked_shader->info.Geom.VerticesOut !=
- shader->info.Geom.VerticesOut) {
+ if (vertices_out != -1 &&
+ vertices_out != shader->info.Geom.VerticesOut) {
linker_error(prog, "geometry shader defined with conflicting "
"output vertex count (%d and %d)\n",
- linked_shader->info.Geom.VerticesOut,
- shader->info.Geom.VerticesOut);
+ vertices_out, shader->info.Geom.VerticesOut);
return;
}
- linked_shader->info.Geom.VerticesOut = shader->info.Geom.VerticesOut;
+ vertices_out = shader->info.Geom.VerticesOut;
}
if (shader->info.Geom.Invocations != 0) {
- if (linked_shader->info.Geom.Invocations != 0 &&
- linked_shader->info.Geom.Invocations !=
- shader->info.Geom.Invocations) {
+ if (gl_prog->info.gs.invocations != 0 &&
+ gl_prog->info.gs.invocations !=
+ (unsigned) shader->info.Geom.Invocations) {
linker_error(prog, "geometry shader defined with conflicting "
"invocation count (%d and %d)\n",
- linked_shader->info.Geom.Invocations,
+ gl_prog->info.gs.invocations,
shader->info.Geom.Invocations);
return;
}
- linked_shader->info.Geom.Invocations = shader->info.Geom.Invocations;
+ gl_prog->info.gs.invocations = shader->info.Geom.Invocations;
}
}
* since we already know we're in the right type of shader program
* for doing it.
*/
- if (linked_shader->info.Geom.InputType == PRIM_UNKNOWN) {
+ if (gl_prog->info.gs.input_primitive == PRIM_UNKNOWN) {
linker_error(prog,
"geometry shader didn't declare primitive input type\n");
return;
}
- if (linked_shader->info.Geom.OutputType == PRIM_UNKNOWN) {
+ if (gl_prog->info.gs.output_primitive == PRIM_UNKNOWN) {
linker_error(prog,
"geometry shader didn't declare primitive output type\n");
return;
}
- if (linked_shader->info.Geom.VerticesOut == -1) {
+ if (vertices_out == -1) {
linker_error(prog,
"geometry shader didn't declare max_vertices\n");
return;
+ } else {
+ gl_prog->info.gs.vertices_out = vertices_out;
}
- if (linked_shader->info.Geom.Invocations == 0)
- linked_shader->info.Geom.Invocations = 1;
+ if (gl_prog->info.gs.invocations == 0)
+ gl_prog->info.gs.invocations = 1;
}
*/
static void
link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
- struct gl_linked_shader *linked_shader,
+ struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
- for (int i = 0; i < 3; i++)
- linked_shader->info.Comp.LocalSize[i] = 0;
-
- linked_shader->info.Comp.LocalSizeVariable = false;
-
/* This function is called for all shader stages, but it only has an effect
* for compute shaders.
*/
- if (linked_shader->Stage != MESA_SHADER_COMPUTE)
+ if (gl_prog->info.stage != MESA_SHADER_COMPUTE)
return;
+ for (int i = 0; i < 3; i++)
+ gl_prog->info.cs.local_size[i] = 0;
+
+ gl_prog->info.cs.local_size_variable = false;
+
/* From the ARB_compute_shader spec, in the section describing local size
* declarations:
*
struct gl_shader *shader = shader_list[sh];
if (shader->info.Comp.LocalSize[0] != 0) {
- if (linked_shader->info.Comp.LocalSize[0] != 0) {
+ if (gl_prog->info.cs.local_size[0] != 0) {
for (int i = 0; i < 3; i++) {
- if (linked_shader->info.Comp.LocalSize[i] !=
+ if (gl_prog->info.cs.local_size[i] !=
shader->info.Comp.LocalSize[i]) {
linker_error(prog, "compute shader defined with conflicting "
"local sizes\n");
}
}
for (int i = 0; i < 3; i++) {
- linked_shader->info.Comp.LocalSize[i] =
+ gl_prog->info.cs.local_size[i] =
shader->info.Comp.LocalSize[i];
}
} else if (shader->info.Comp.LocalSizeVariable) {
- if (linked_shader->info.Comp.LocalSize[0] != 0) {
+ if (gl_prog->info.cs.local_size[0] != 0) {
/* The ARB_compute_variable_group_size spec says:
*
* If one compute shader attached to a program declares a
"variable local group size\n");
return;
}
- linked_shader->info.Comp.LocalSizeVariable = true;
+ gl_prog->info.cs.local_size_variable = true;
}
}
* since we already know we're in the right type of shader program
* for doing it.
*/
- if (linked_shader->info.Comp.LocalSize[0] == 0 &&
- !linked_shader->info.Comp.LocalSizeVariable) {
+ if (gl_prog->info.cs.local_size[0] == 0 &&
+ !gl_prog->info.cs.local_size_variable) {
linker_error(prog, "compute shader must contain a fixed or a variable "
"local group size\n");
return;
}
- for (int i = 0; i < 3; i++)
- prog->Comp.LocalSize[i] = linked_shader->info.Comp.LocalSize[i];
-
- prog->Comp.LocalSizeVariable =
- linked_shader->info.Comp.LocalSizeVariable;
}
_mesa_shader_stage_to_program(shader_list[0]->Stage),
prog->Name, false);
if (!gl_prog) {
- prog->data->LinkStatus = false;
+ prog->data->LinkStatus = linking_failure;
_mesa_delete_linked_shader(ctx, linked);
return NULL;
}
clone_ir_list(mem_ctx, linked->ir, main->ir);
link_fs_inout_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);
+ link_tcs_out_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
+ link_tes_in_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
+ link_gs_inout_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
+ link_cs_input_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
- populate_symbol_table(linked);
+ if (linked->Stage != MESA_SHADER_FRAGMENT)
+ link_xfb_stride_layout_qualifiers(ctx, prog, shader_list, num_shaders);
+
+ link_bindless_layout_qualifiers(prog, shader_list, num_shaders);
+
+ populate_symbol_table(linked, shader_list[0]->symbols);
/* The pointer to the main function in the final linked shader (i.e., the
* copy of the original shader that contained the main function).
/* Set the size of geometry shader input arrays */
if (linked->Stage == MESA_SHADER_GEOMETRY) {
- unsigned num_vertices = vertices_per_prim(linked->info.Geom.InputType);
+ unsigned num_vertices =
+ vertices_per_prim(gl_prog->info.gs.input_primitive);
array_resize_visitor input_resize_visitor(num_vertices, prog,
MESA_SHADER_GEOMETRY);
foreach_in_list(ir_instruction, ir, linked->ir) {
if (ctx->Const.VertexID_is_zero_based)
lower_vertex_id(linked);
+ if (ctx->Const.LowerCsDerivedVariables)
+ lower_cs_derived(linked);
+
#ifdef DEBUG
/* Compute the source checksum. */
linked->SourceChecksum = 0;
* known until draw time.
*/
const int num_vertices = tcs
- ? tcs->info.TessCtrl.VerticesOut
+ ? tcs->Program->info.tess.tcs_vertices_out
: ctx->Const.MaxPatchVertices;
array_resize_visitor input_resize_visitor(num_vertices, prog,
* \return
* Base location of the available bits on success or -1 on failure.
*/
-int
+static int
find_available_slots(unsigned used_mask, unsigned needed_count)
{
unsigned needed_mask = (1 << needed_count) - 1;
* If locations are successfully assigned, true is returned. Otherwise an
* error is emitted to the shader link log and false is returned.
*/
-bool
+static bool
assign_attribute_or_color_locations(void *mem_ctx,
gl_shader_program *prog,
struct gl_constants *constants,
} to_assign[32];
assert(max_index <= 32);
- /* Temporary array for the set of attributes that have locations assigned.
+ /* Temporary array for the set of attributes that have locations assigned,
+ * for the purpose of checking overlapping slots/components of (non-ES)
+ * fragment shader outputs.
*/
- ir_variable *assigned[16];
+ ir_variable *assigned[12 * 4]; /* (max # of FS outputs) * # components */
+ unsigned assigned_attr = 0;
unsigned num_attr = 0;
- unsigned assigned_attr = 0;
foreach_in_list(ir_instruction, node, sh->ir) {
ir_variable *const var = node->as_variable();
}
}
+ if (target_index == MESA_SHADER_FRAGMENT && !prog->IsES) {
+ /* Only track assigned variables for non-ES fragment shaders
+ * to avoid overflowing the array.
+ *
+ * At most one variable per fragment output component should
+ * reach this.
+ */
+ assert(assigned_attr < ARRAY_SIZE(assigned));
+ assigned[assigned_attr] = var;
+ assigned_attr++;
+ }
+
used_locations |= (use_mask << attr);
/* From the GL 4.5 core spec, section 11.1.1 (Vertex Attributes):
double_storage_locations |= (use_mask << attr);
}
- assigned[assigned_attr] = var;
- assigned_attr++;
-
continue;
}
* any optimizations happen to handle also inactive uniforms and
* inactive array elements that may get trimmed away.
*/
-static unsigned
+static void
check_explicit_uniform_locations(struct gl_context *ctx,
struct gl_shader_program *prog)
{
+ prog->NumExplicitUniformLocations = 0;
+
if (!ctx->Extensions.ARB_explicit_uniform_location)
- return 0;
+ return;
/* This map is used to detect if overlapping explicit locations
* occur with the same uniform (from different stage) or a different one.
if (!uniform_map) {
linker_error(prog, "Out of memory during linking.\n");
- return 0;
+ return;
}
unsigned entries_total = 0;
}
if (!ret) {
delete uniform_map;
- return 0;
+ return;
}
}
}
}
delete uniform_map;
- return entries_total;
+ prog->NumExplicitUniformLocations = entries_total;
}
static bool
if (_mesa_set_search(resource_set, data))
return true;
- prog->ProgramResourceList =
+ prog->data->ProgramResourceList =
reralloc(prog,
- prog->ProgramResourceList,
+ prog->data->ProgramResourceList,
gl_program_resource,
- prog->NumProgramResourceList + 1);
+ prog->data->NumProgramResourceList + 1);
- if (!prog->ProgramResourceList) {
+ if (!prog->data->ProgramResourceList) {
linker_error(prog, "Out of memory during linking.\n");
return false;
}
struct gl_program_resource *res =
- &prog->ProgramResourceList[prog->NumProgramResourceList];
+ &prog->data->ProgramResourceList[prog->data->NumProgramResourceList];
res->Type = type;
res->Data = data;
res->StageReferences = stages;
- prog->NumProgramResourceList++;
+ prog->data->NumProgramResourceList++;
_mesa_set_add(resource_set, data);
bool use_implicit_location, int location,
const glsl_type *outermost_struct_type)
{
- gl_shader_variable *out = ralloc(shProg, struct gl_shader_variable);
+ /* Allocate zero-initialized memory to ensure that bitfield padding
+ * is zero.
+ */
+ gl_shader_variable *out = rzalloc(shProg, struct gl_shader_variable);
if (!out)
return NULL;
* qualifier, except for vertex shader inputs and fragment shader
* outputs."
*/
- if (in->type->base_type == GLSL_TYPE_ATOMIC_UINT ||
- is_gl_identifier(in->name) ||
+ if (in->type->is_atomic_uint() || is_gl_identifier(in->name) ||
!(in->data.explicit_location || use_implicit_location)) {
out->location = -1;
} else {
return out;
}
-static const glsl_type *
-resize_to_max_patch_vertices(const struct gl_context *ctx,
- const glsl_type *type)
-{
- if (!type)
- return NULL;
-
- return glsl_type::get_array_instance(type->fields.array,
- ctx->Const.MaxPatchVertices);
-}
-
static bool
add_shader_variable(const struct gl_context *ctx,
struct gl_shader_program *shProg,
GLenum programInterface, ir_variable *var,
const char *name, const glsl_type *type,
bool use_implicit_location, int location,
+ bool inouts_share_location,
const glsl_type *outermost_struct_type = NULL)
{
const glsl_type *interface_type = var->get_interface_type();
if (outermost_struct_type == NULL) {
- /* Unsized (non-patch) TCS output/TES input arrays are implicitly
- * sized to gl_MaxPatchVertices. Internally, we shrink them to a
- * smaller size.
- *
- * This can cause trouble with SSO programs. Since the TCS declares
- * the number of output vertices, we can always shrink TCS output
- * arrays. However, the TES might not be linked with a TCS, in
- * which case it won't know the size of the patch. In other words,
- * the TCS and TES may disagree on the (smaller) array sizes. This
- * can result in the resource names differing across stages, causing
- * SSO validation failures and other cascading issues.
- *
- * Expanding the array size to the full gl_MaxPatchVertices fixes
- * these issues. It's also what program interface queries expect,
- * as that is the official size of the array.
- */
- if (var->data.tess_varying_implicit_sized_array) {
- type = resize_to_max_patch_vertices(ctx, type);
- interface_type = resize_to_max_patch_vertices(ctx, interface_type);
- }
-
if (var->data.from_named_ifc_block) {
const char *interface_name = interface_type->name;
stage_mask, programInterface,
var, field_name, field->type,
use_implicit_location, field_location,
- outermost_struct_type))
+ false, outermost_struct_type))
return false;
field_location += field->type->count_attribute_slots(false);
return true;
}
+ case GLSL_TYPE_ARRAY: {
+ /* The ARB_program_interface_query spec says:
+ *
+ * "For an active variable declared as an array of basic types, a
+ * single entry will be generated, with its name string formed by
+ * concatenating the name of the array and the string "[0]"."
+ *
+ * "For an active variable declared as an array of an aggregate data
+ * type (structures or arrays), a separate entry will be generated
+ * for each active array element, unless noted immediately below.
+ * The name of each entry is formed by concatenating the name of
+ * the array, the "[" character, an integer identifying the element
+ * number, and the "]" character. These enumeration rules are
+ * applied recursively, treating each enumerated array element as a
+ * separate active variable."
+ */
+ const struct glsl_type *array_type = type->fields.array;
+ if (array_type->base_type == GLSL_TYPE_STRUCT ||
+ array_type->base_type == GLSL_TYPE_ARRAY) {
+ unsigned elem_location = location;
+ unsigned stride = inouts_share_location ? 0 :
+ array_type->count_attribute_slots(false);
+ for (unsigned i = 0; i < type->length; i++) {
+ char *elem = ralloc_asprintf(shProg, "%s[%d]", name, i);
+ if (!add_shader_variable(ctx, shProg, resource_set,
+ stage_mask, programInterface,
+ var, elem, array_type,
+ use_implicit_location, elem_location,
+ false, outermost_struct_type))
+ return false;
+ elem_location += stride;
+ }
+ return true;
+ }
+ /* fallthrough */
+ }
+
default: {
/* The ARB_program_interface_query spec says:
*
}
}
+static bool
+inout_has_same_location(const ir_variable *var, unsigned stage)
+{
+ if (!var->data.patch &&
+ ((var->data.mode == ir_var_shader_out &&
+ stage == MESA_SHADER_TESS_CTRL) ||
+ (var->data.mode == ir_var_shader_in &&
+ (stage == MESA_SHADER_TESS_CTRL || stage == MESA_SHADER_TESS_EVAL ||
+ stage == MESA_SHADER_GEOMETRY))))
+ return true;
+ else
+ return false;
+}
+
static bool
add_interface_variables(const struct gl_context *ctx,
struct gl_shader_program *shProg,
if (!add_shader_variable(ctx, shProg, resource_set,
1 << stage, programInterface,
var, var->name, var->type, vs_input_or_fs_output,
- var->data.location - loc_bias))
+ var->data.location - loc_bias,
+ inout_has_same_location(var, stage)))
return false;
}
return true;
if (!add_shader_variable(ctx, shProg, resource_set,
stage_mask,
iface, var, var->name, var->type, false,
- var->data.location - VARYING_SLOT_VAR0))
+ var->data.location - VARYING_SLOT_VAR0,
+ inout_has_same_location(var, stage)))
return false;
}
}
if (!add_shader_variable(ctx, shProg, resource_set,
1 << MESA_SHADER_FRAGMENT,
GL_PROGRAM_OUTPUT, var, var->name, var->type,
- true, var->data.location - FRAG_RESULT_DATA0))
+ true, var->data.location - FRAG_RESULT_DATA0,
+ false))
return false;
}
}
}
static int
-get_array_stride(struct gl_uniform_storage *uni, const glsl_type *interface,
- const glsl_struct_field *field, char *interface_name,
- char *var_name)
+get_array_stride(struct gl_context *ctx, struct gl_uniform_storage *uni,
+ const glsl_type *interface, const glsl_struct_field *field,
+ char *interface_name, char *var_name)
{
/* The ARB_program_interface_query spec says:
*
var_name))
return 0;
- if (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) {
+ if (GLSL_INTERFACE_PACKING_STD140 ==
+ interface->
+ get_internal_ifc_packing(ctx->Const.UseSTD430AsDefaultPacking)) {
if (array_type->is_record() || array_type->is_array())
return glsl_align(array_type->std140_size(row_major), 16);
else
}
static void
-calculate_array_size_and_stride(struct gl_shader_program *shProg,
+calculate_array_size_and_stride(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
struct gl_uniform_storage *uni)
{
int block_index = uni->block_index;
if (strcmp(field->name, var_name) != 0)
continue;
- array_stride = get_array_stride(uni, interface, field,
+ array_stride = get_array_stride(ctx, uni, interface, field,
interface_name, var_name);
array_size = get_array_size(uni, field, interface_name, var_name);
goto write_top_level_array_size_and_stride;
struct gl_shader_program *shProg)
{
/* Rebuild resource list. */
- if (shProg->ProgramResourceList) {
- ralloc_free(shProg->ProgramResourceList);
- shProg->ProgramResourceList = NULL;
- shProg->NumProgramResourceList = 0;
+ if (shProg->data->ProgramResourceList) {
+ ralloc_free(shProg->data->ProgramResourceList);
+ shProg->data->ProgramResourceList = NULL;
+ shProg->data->NumProgramResourceList = 0;
}
int input_stage = MESA_SHADER_STAGES, output_stage = 0;
output_stage, GL_PROGRAM_OUTPUT))
return;
- struct gl_transform_feedback_info *linked_xfb =
- shProg->xfb_program->sh.LinkedTransformFeedback;
+ if (shProg->last_vert_prog) {
+ struct gl_transform_feedback_info *linked_xfb =
+ shProg->last_vert_prog->sh.LinkedTransformFeedback;
- /* 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))
- return;
+ /* 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))
+ return;
+ }
}
- }
- /* Add transform feedback buffers. */
- 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))
- return;
+ /* Add transform feedback buffers. */
+ 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))
+ return;
+ }
}
}
continue;
if (is_shader_storage) {
- calculate_array_size_and_stride(shProg,
+ calculate_array_size_and_stride(ctx, shProg,
&shProg->data->UniformStorage[i]);
}
if (!sh)
continue;
- if (first == last) {
- /* For a single shader program only allow inputs to the vertex shader
- * and outputs from the fragment shader to be removed.
- */
- if (stage != MESA_SHADER_VERTEX)
- set_always_active_io(sh->ir, ir_var_shader_in);
- if (stage != MESA_SHADER_FRAGMENT)
- set_always_active_io(sh->ir, ir_var_shader_out);
- } else {
- /* For multi-stage separate shader programs only allow inputs and
- * outputs between the shader stages to be removed as well as inputs
- * to the vertex shader and outputs from the fragment shader.
- */
- if (stage == first && stage != MESA_SHADER_VERTEX)
- set_always_active_io(sh->ir, ir_var_shader_in);
- else if (stage == last && stage != MESA_SHADER_FRAGMENT)
- set_always_active_io(sh->ir, ir_var_shader_out);
- }
+ /* Prevent the removal of inputs to the first and outputs from the last
+ * stage, unless they are the initial pipeline inputs or final pipeline
+ * outputs, respectively.
+ *
+ * The removal of IO between shaders in the same program is always
+ * allowed.
+ */
+ if (stage == first && stage != MESA_SHADER_VERTEX)
+ set_always_active_io(sh->ir, ir_var_shader_in);
+ if (stage == last && stage != MESA_SHADER_FRAGMENT)
+ set_always_active_io(sh->ir, ir_var_shader_out);
}
}
+static void
+link_and_validate_uniforms(struct gl_context *ctx,
+ struct gl_shader_program *prog)
+{
+ update_array_sizes(prog);
+ link_assign_uniform_locations(prog, ctx);
+
+ link_assign_atomic_counter_resources(ctx, prog);
+ link_calculate_subroutine_compat(prog);
+ check_resources(ctx, prog);
+ check_subroutine_resources(prog);
+ check_image_resources(ctx, prog);
+ link_check_atomic_counter_resources(ctx, prog);
+}
+
static bool
link_varyings_and_uniforms(unsigned first, unsigned last,
- unsigned num_explicit_uniform_locs,
struct gl_context *ctx,
struct gl_shader_program *prog, void *mem_ctx)
{
return false;
}
- /* Find the program used for xfb. Even if we don't use xfb we still want to
- * set this so we can fill the default values for program interface query.
- */
- prog->xfb_program = prog->_LinkedShaders[last]->Program;
+ prog->last_vert_prog = NULL;
for (int i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) {
if (prog->_LinkedShaders[i] == NULL)
continue;
- prog->xfb_program = prog->_LinkedShaders[i]->Program;
+ prog->last_vert_prog = prog->_LinkedShaders[i]->Program;
break;
}
if (!link_varyings(prog, first, last, ctx, mem_ctx))
return false;
- update_array_sizes(prog);
- link_assign_uniform_locations(prog, ctx, num_explicit_uniform_locs);
- link_assign_atomic_counter_resources(ctx, prog);
-
- link_calculate_subroutine_compat(prog);
- check_resources(ctx, prog);
- check_subroutine_resources(prog);
- check_image_resources(ctx, prog);
- link_check_atomic_counter_resources(ctx, prog);
+ link_and_validate_uniforms(ctx, prog);
if (!prog->data->LinkStatus)
return false;
if (options->LowerBufferInterfaceBlocks)
lower_ubo_reference(prog->_LinkedShaders[i],
- options->ClampBlockIndicesToArrayBounds);
+ options->ClampBlockIndicesToArrayBounds,
+ ctx->Const.UseSTD430AsDefaultPacking);
if (i == MESA_SHADER_COMPUTE)
- lower_shared_reference(prog->_LinkedShaders[i],
- &prog->Comp.SharedSize);
+ lower_shared_reference(ctx, prog, prog->_LinkedShaders[i]);
lower_vector_derefs(prog->_LinkedShaders[i]);
do_vec_index_to_swizzle(prog->_LinkedShaders[i]->ir);
return true;
}
+static void
+linker_optimisation_loop(struct gl_context *ctx, exec_list *ir,
+ unsigned stage)
+{
+ if (ctx->Const.GLSLOptimizeConservatively) {
+ /* Run it just once. */
+ do_common_optimization(ir, true, false,
+ &ctx->Const.ShaderCompilerOptions[stage],
+ ctx->Const.NativeIntegers);
+ } else {
+ /* Repeat it until it stops making changes. */
+ while (do_common_optimization(ir, true, false,
+ &ctx->Const.ShaderCompilerOptions[stage],
+ ctx->Const.NativeIntegers))
+ ;
+ }
+}
+
void
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
{
- prog->data->LinkStatus = true; /* All error paths will set this to false */
+ prog->data->LinkStatus = linking_success; /* All error paths will set this to false */
prog->data->Validated = false;
/* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec says:
return;
}
- unsigned int num_explicit_uniform_locs = 0;
+#ifdef ENABLE_SHADER_CACHE
+ /* If transform feedback used on the program then compile all shaders. */
+ bool skip_cache = false;
+ if (prog->TransformFeedback.NumVarying > 0) {
+ for (unsigned i = 0; i < prog->NumShaders; i++) {
+ _mesa_glsl_compile_shader(ctx, prog->Shaders[i], false, false, true);
+ }
+ skip_cache = true;
+ }
+
+ if (!skip_cache && shader_cache_read_program_metadata(ctx, prog))
+ return;
+#endif
void *mem_ctx = ralloc_context(NULL); // temporary linker context
goto done;
}
- if (prog->Shaders[i]->info.ARB_fragment_coord_conventions_enable) {
+ if (prog->Shaders[i]->ARB_fragment_coord_conventions_enable) {
prog->ARB_fragment_coord_conventions_enable = true;
}
goto done;
}
- /* The spec is self-contradictory here. It allows linking without a tess
+ /* Section 7.3 of the OpenGL ES 3.2 specification says:
+ *
+ * "Linking can fail for [...] any of the following reasons:
+ *
+ * * program contains an object to form a tessellation control
+ * shader [...] and [...] the program is not separable and
+ * contains no object to form a tessellation evaluation shader"
+ *
+ * The OpenGL spec is contradictory. It allows linking without a tess
* eval shader, but that can only be used with transform feedback and
* rasterization disabled. However, transform feedback isn't allowed
* with GL_PATCHES, so it can't be used.
"tessellation evaluation shader\n");
goto done;
}
+
+ if (prog->IsES) {
+ if (num_shaders[MESA_SHADER_TESS_EVAL] > 0 &&
+ num_shaders[MESA_SHADER_TESS_CTRL] == 0) {
+ linker_error(prog, "GLSL ES requires non-separable programs "
+ "containing a tessellation evaluation shader to also "
+ "be linked with a tessellation control shader\n");
+ goto done;
+ }
+ }
}
/* Compute shaders have additional restrictions. */
}
}
- if (num_shaders[MESA_SHADER_GEOMETRY] > 0) {
- prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize;
- prog->LastCullDistanceArraySize = prog->Geom.CullDistanceArraySize;
- } else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0) {
- prog->LastClipDistanceArraySize = prog->TessEval.ClipDistanceArraySize;
- prog->LastCullDistanceArraySize = prog->TessEval.CullDistanceArraySize;
- } else if (num_shaders[MESA_SHADER_VERTEX] > 0) {
- prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
- prog->LastCullDistanceArraySize = prog->Vert.CullDistanceArraySize;
- } else {
- prog->LastClipDistanceArraySize = 0; /* Not used */
- prog->LastCullDistanceArraySize = 0; /* Not used */
- }
-
/* Here begins the inter-stage linking phase. Some initial validation is
* performed, then locations are assigned for uniforms, attributes, and
* varyings.
last = i;
}
- num_explicit_uniform_locs = check_explicit_uniform_locations(ctx, prog);
+ check_explicit_uniform_locations(ctx, prog);
link_assign_subroutine_types(prog);
if (!prog->data->LinkStatus)
if (!prog->data->LinkStatus)
goto done;
- cross_validate_outputs_to_inputs(prog,
+ cross_validate_outputs_to_inputs(ctx, prog,
prog->_LinkedShaders[prev],
prog->_LinkedShaders[i]);
if (!prog->data->LinkStatus)
prev = i;
}
+ /* The cross validation of outputs/inputs above validates explicit locations
+ * but for SSO programs we need to do this also for the inputs in the
+ * first stage and outputs of the last stage included in the program, since
+ * there is no cross validation for these.
+ */
+ if (prog->SeparateShader)
+ validate_sso_explicit_locations(ctx, prog,
+ (gl_shader_stage) first,
+ (gl_shader_stage) last);
+
/* Cross-validate uniform blocks between shader stages */
validate_interstage_uniform_blocks(prog, prog->_LinkedShaders);
if (!prog->data->LinkStatus)
lower_tess_level(prog->_LinkedShaders[i]);
}
- if (ctx->Const.GLSLOptimizeConservatively) {
- /* Run it just once. */
- do_common_optimization(prog->_LinkedShaders[i]->ir, true, false,
- &ctx->Const.ShaderCompilerOptions[i],
- ctx->Const.NativeIntegers);
- } else {
- /* Repeat it until it stops making changes. */
- while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false,
- &ctx->Const.ShaderCompilerOptions[i],
- ctx->Const.NativeIntegers))
- ;
- }
+ /* Call opts before lowering const arrays to uniforms so we can const
+ * propagate any elements accessed directly.
+ */
+ linker_optimisation_loop(ctx, prog->_LinkedShaders[i]->ir, i);
+
+ /* Call opts after lowering const arrays to copy propagate things. */
+ if (lower_const_arrays_to_uniforms(prog->_LinkedShaders[i]->ir, i))
+ linker_optimisation_loop(ctx, prog->_LinkedShaders[i]->ir, i);
- lower_const_arrays_to_uniforms(prog->_LinkedShaders[i]->ir, i);
propagate_invariance(prog->_LinkedShaders[i]->ir);
}
store_fragdepth_layout(prog);
- if(!link_varyings_and_uniforms(first, last, num_explicit_uniform_locs, ctx,
- prog, mem_ctx))
+ if(!link_varyings_and_uniforms(first, last, ctx, prog, mem_ctx))
goto done;
/* OpenGL ES < 3.1 requires that a vertex shader and a fragment shader both