2010-06-17 15:04:20 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2010 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \file linker.cpp
|
|
|
|
|
* GLSL linker implementation
|
|
|
|
|
*
|
|
|
|
|
* Given a set of shaders that are to be linked to generate a final program,
|
|
|
|
|
* there are three distinct stages.
|
|
|
|
|
*
|
|
|
|
|
* In the first stage shaders are partitioned into groups based on the shader
|
|
|
|
|
* type. All shaders of a particular type (e.g., vertex shaders) are linked
|
|
|
|
|
* together.
|
|
|
|
|
*
|
|
|
|
|
* - Undefined references in each shader are resolve to definitions in
|
|
|
|
|
* another shader.
|
|
|
|
|
* - Types and qualifiers of uniforms, outputs, and global variables defined
|
|
|
|
|
* in multiple shaders with the same name are verified to be the same.
|
|
|
|
|
* - Initializers for uniforms and global variables defined
|
|
|
|
|
* in multiple shaders with the same name are verified to be the same.
|
|
|
|
|
*
|
|
|
|
|
* The result, in the terminology of the GLSL spec, is a set of shader
|
|
|
|
|
* executables for each processing unit.
|
|
|
|
|
*
|
|
|
|
|
* After the first stage is complete, a series of semantic checks are performed
|
|
|
|
|
* on each of the shader executables.
|
|
|
|
|
*
|
|
|
|
|
* - Each shader executable must define a \c main function.
|
|
|
|
|
* - Each vertex shader executable must write to \c gl_Position.
|
|
|
|
|
* - Each fragment shader executable must write to either \c gl_FragData or
|
|
|
|
|
* \c gl_FragColor.
|
|
|
|
|
*
|
|
|
|
|
* In the final stage individual shader executables are linked to create a
|
|
|
|
|
* complete exectuable.
|
|
|
|
|
*
|
|
|
|
|
* - Types of uniforms defined in multiple shader stages with the same name
|
|
|
|
|
* are verified to be the same.
|
|
|
|
|
* - Initializers for uniforms defined in multiple shader stages with the
|
|
|
|
|
* same name are verified to be the same.
|
|
|
|
|
* - Types and qualifiers of outputs defined in one stage are verified to
|
|
|
|
|
* be the same as the types and qualifiers of inputs defined with the same
|
|
|
|
|
* name in a later stage.
|
|
|
|
|
*
|
|
|
|
|
* \author Ian Romanick <ian.d.romanick@intel.com>
|
|
|
|
|
*/
|
2010-06-23 12:07:22 -07:00
|
|
|
|
2015-02-24 16:56:54 -07:00
|
|
|
#include <ctype.h>
|
2015-10-14 11:50:06 +01:00
|
|
|
#include "util/strndup.h"
|
2010-06-17 15:04:20 -07:00
|
|
|
#include "glsl_symbol_table.h"
|
2013-06-12 16:57:11 -07:00
|
|
|
#include "glsl_parser_extras.h"
|
2010-06-17 15:04:20 -07:00
|
|
|
#include "ir.h"
|
2022-05-11 22:53:46 +10:00
|
|
|
#include "nir.h"
|
2010-06-17 15:04:20 -07:00
|
|
|
#include "program.h"
|
2016-05-26 20:21:58 -07:00
|
|
|
#include "program/prog_instruction.h"
|
2016-10-31 23:54:03 +11:00
|
|
|
#include "program/program.h"
|
2017-01-24 08:39:13 +11:00
|
|
|
#include "util/mesa-sha1.h"
|
2016-08-09 00:43:15 -07:00
|
|
|
#include "util/set.h"
|
2017-08-26 02:37:11 +01:00
|
|
|
#include "string_to_uint_map.h"
|
2010-07-13 17:36:13 -07:00
|
|
|
#include "linker.h"
|
2018-06-26 16:28:59 +02:00
|
|
|
#include "linker_util.h"
|
2010-07-20 13:36:32 -07:00
|
|
|
#include "ir_optimization.h"
|
2013-02-15 09:46:50 -06:00
|
|
|
#include "ir_rvalue_visitor.h"
|
2014-04-08 08:45:36 +03:00
|
|
|
#include "ir_uniform.h"
|
2016-10-14 11:02:18 -07:00
|
|
|
#include "builtin_functions.h"
|
2017-01-24 08:39:13 +11:00
|
|
|
#include "shader_cache.h"
|
2018-08-01 13:22:00 +03:00
|
|
|
#include "util/u_string.h"
|
2018-08-21 09:46:46 -07:00
|
|
|
#include "util/u_math.h"
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2018-09-14 12:57:32 -07:00
|
|
|
|
2010-10-14 13:28:42 -07:00
|
|
|
#include "main/shaderobj.h"
|
2013-06-12 18:12:40 -07:00
|
|
|
#include "main/enums.h"
|
2018-04-08 13:13:08 -04:00
|
|
|
#include "main/mtypes.h"
|
2023-02-27 15:19:30 +02:00
|
|
|
#include "main/context.h"
|
2014-12-15 16:41:58 -07:00
|
|
|
|
2010-10-14 13:28:42 -07:00
|
|
|
|
2013-09-20 11:03:44 -07:00
|
|
|
namespace {
|
|
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
struct find_variable {
|
|
|
|
|
const char *name;
|
|
|
|
|
bool found;
|
|
|
|
|
|
|
|
|
|
find_variable(const char *name) : name(name), found(false) {}
|
|
|
|
|
};
|
|
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
/**
|
|
|
|
|
* Visitor that determines whether or not a variable is ever written.
|
2021-09-16 13:11:30 +02:00
|
|
|
* Note: this is only considering if the variable is statically written
|
|
|
|
|
* (= regardless of the runtime flow of control)
|
2017-06-22 12:12:44 +02:00
|
|
|
*
|
|
|
|
|
* Use \ref find_assignments for convenience.
|
2010-06-17 15:04:20 -07:00
|
|
|
*/
|
|
|
|
|
class find_assignment_visitor : public ir_hierarchical_visitor {
|
|
|
|
|
public:
|
2017-06-22 12:12:44 +02:00
|
|
|
find_assignment_visitor(unsigned num_vars,
|
|
|
|
|
find_variable * const *vars)
|
|
|
|
|
: num_variables(num_vars), num_found(0), variables(vars)
|
2010-06-17 15:04:20 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit_enter(ir_assignment *ir)
|
|
|
|
|
{
|
|
|
|
|
ir_variable *const var = ir->lhs->variable_referenced();
|
|
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
return check_variable_name(var->name);
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
2010-08-23 11:29:25 -07:00
|
|
|
virtual ir_visitor_status visit_enter(ir_call *ir)
|
|
|
|
|
{
|
glsl: Use a new foreach_two_lists macro for walking two lists at once.
When handling function calls, we often want to walk through the list of
formal parameters and list of actual parameters at the same time.
(Both are guaranteed to be the same length.)
Previously, we used a pattern of:
exec_list_iterator 1st_iter = <1st list>.iterator();
foreach_iter(exec_list_iterator, 2nd_iter, <2nd list>) {
...
1st_iter.next();
}
This was awkward, since you had to manually iterate through one of
the two lists.
This patch introduces a foreach_two_lists macro which safely walks
through two lists at the same time, so you can simply do:
foreach_two_lists(1st_node, <1st list>, 2nd_node, <2nd list>) {
...
}
v2: Rename macro from foreach_list2 to foreach_two_lists, as suggested
by Ian Romanick.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2014-01-10 16:39:17 -08:00
|
|
|
foreach_two_lists(formal_node, &ir->callee->parameters,
|
|
|
|
|
actual_node, &ir->actual_parameters) {
|
2016-09-28 16:04:05 +10:00
|
|
|
ir_rvalue *param_rval = (ir_rvalue *) actual_node;
|
|
|
|
|
ir_variable *sig_param = (ir_variable *) formal_node;
|
|
|
|
|
|
|
|
|
|
if (sig_param->data.mode == ir_var_function_out ||
|
|
|
|
|
sig_param->data.mode == ir_var_function_inout) {
|
|
|
|
|
ir_variable *var = param_rval->variable_referenced();
|
2017-06-22 12:12:44 +02:00
|
|
|
if (var && check_variable_name(var->name) == visit_stop)
|
2016-09-28 16:04:05 +10:00
|
|
|
return visit_stop;
|
|
|
|
|
}
|
2010-08-23 11:29:25 -07:00
|
|
|
}
|
|
|
|
|
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
if (ir->return_deref != NULL) {
|
2016-09-28 16:04:05 +10:00
|
|
|
ir_variable *const var = ir->return_deref->variable_referenced();
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
if (check_variable_name(var->name) == visit_stop)
|
2016-09-28 16:04:05 +10:00
|
|
|
return visit_stop;
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
}
|
|
|
|
|
|
2010-08-23 11:29:25 -07:00
|
|
|
return visit_continue_with_parent;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
private:
|
|
|
|
|
ir_visitor_status check_variable_name(const char *name)
|
2010-06-17 15:04:20 -07:00
|
|
|
{
|
2017-06-22 12:12:44 +02:00
|
|
|
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;
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2017-06-22 12:12:44 +02:00
|
|
|
unsigned num_variables; /**< Number of variables to find */
|
|
|
|
|
unsigned num_found; /**< Number of variables already found */
|
|
|
|
|
find_variable * const *variables; /**< Variables to find */
|
2010-06-17 15:04:20 -07:00
|
|
|
};
|
|
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
/**
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
2010-06-17 15:20:22 -07:00
|
|
|
|
2010-08-13 12:30:41 -07:00
|
|
|
/**
|
|
|
|
|
* Visitor that determines whether or not a variable is ever read.
|
|
|
|
|
*/
|
|
|
|
|
class find_deref_visitor : public ir_hierarchical_visitor {
|
|
|
|
|
public:
|
|
|
|
|
find_deref_visitor(const char *name)
|
|
|
|
|
: name(name), found(false)
|
|
|
|
|
{
|
|
|
|
|
/* empty */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit(ir_dereference_variable *ir)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(this->name, ir->var->name) == 0) {
|
2016-09-28 16:04:05 +10:00
|
|
|
this->found = true;
|
|
|
|
|
return visit_stop;
|
2010-08-13 12:30:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool variable_found() const
|
|
|
|
|
{
|
|
|
|
|
return this->found;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const char *name; /**< Find writes to a variable with this name. */
|
|
|
|
|
bool found; /**< Was a write to the variable found? */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-11-02 13:35:30 -07:00
|
|
|
/**
|
|
|
|
|
* A visitor helper that provides methods for updating the types of
|
|
|
|
|
* ir_dereferences. Classes that update variable types (say, updating
|
|
|
|
|
* array sizes) will want to use this so that dereference types stay in sync.
|
|
|
|
|
*/
|
|
|
|
|
class deref_type_updater : public ir_hierarchical_visitor {
|
|
|
|
|
public:
|
|
|
|
|
virtual ir_visitor_status visit(ir_dereference_variable *ir)
|
|
|
|
|
{
|
|
|
|
|
ir->type = ir->var->type;
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
|
|
|
|
|
{
|
|
|
|
|
const glsl_type *const vt = ir->array->type;
|
|
|
|
|
if (vt->is_array())
|
|
|
|
|
ir->type = vt->fields.array;
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
|
|
|
|
|
{
|
2017-08-09 13:34:04 +10:00
|
|
|
ir->type = ir->record->type->fields.structure[ir->field_idx].type;
|
2016-11-02 13:35:30 -07:00
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class array_resize_visitor : public deref_type_updater {
|
2013-07-30 21:13:48 -07:00
|
|
|
public:
|
2020-02-03 12:43:19 -08:00
|
|
|
using deref_type_updater::visit;
|
|
|
|
|
|
2013-07-30 21:13:48 -07:00
|
|
|
unsigned num_vertices;
|
|
|
|
|
gl_shader_program *prog;
|
2016-07-08 13:29:31 -07:00
|
|
|
gl_shader_stage stage;
|
2013-07-30 21:13:48 -07:00
|
|
|
|
2016-07-08 13:29:31 -07:00
|
|
|
array_resize_visitor(unsigned num_vertices,
|
|
|
|
|
gl_shader_program *prog,
|
|
|
|
|
gl_shader_stage stage)
|
2013-07-30 21:13:48 -07:00
|
|
|
{
|
|
|
|
|
this->num_vertices = num_vertices;
|
|
|
|
|
this->prog = prog;
|
2016-07-08 13:29:31 -07:00
|
|
|
this->stage = stage;
|
2013-07-30 21:13:48 -07:00
|
|
|
}
|
|
|
|
|
|
2016-07-08 13:29:31 -07:00
|
|
|
virtual ~array_resize_visitor()
|
2013-07-30 21:13:48 -07:00
|
|
|
{
|
|
|
|
|
/* empty */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit(ir_variable *var)
|
|
|
|
|
{
|
2016-07-08 13:29:31 -07:00
|
|
|
if (!var->type->is_array() || var->data.mode != ir_var_shader_in ||
|
|
|
|
|
var->data.patch)
|
2013-07-30 21:13:48 -07:00
|
|
|
return visit_continue;
|
|
|
|
|
|
|
|
|
|
unsigned size = var->type->length;
|
|
|
|
|
|
2016-07-08 13:29:31 -07:00
|
|
|
if (stage == MESA_SHADER_GEOMETRY) {
|
|
|
|
|
/* Generate a link error if the shader has declared this array with
|
|
|
|
|
* an incorrect size.
|
|
|
|
|
*/
|
|
|
|
|
if (!var->data.implicit_sized_array &&
|
|
|
|
|
size && size != this->num_vertices) {
|
|
|
|
|
linker_error(this->prog, "size of array %s declared as %u, "
|
|
|
|
|
"but number of input vertices is %u\n",
|
|
|
|
|
var->name, size, this->num_vertices);
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
2013-07-30 21:13:48 -07:00
|
|
|
|
2016-07-08 13:29:31 -07:00
|
|
|
/* Generate a link error if the shader attempts to access an input
|
|
|
|
|
* array using an index too large for its actual size assigned at
|
|
|
|
|
* link time.
|
|
|
|
|
*/
|
|
|
|
|
if (var->data.max_array_access >= (int)this->num_vertices) {
|
|
|
|
|
linker_error(this->prog, "%s shader accesses element %i of "
|
|
|
|
|
"%s, but only %i input vertices\n",
|
|
|
|
|
_mesa_shader_stage_to_string(this->stage),
|
|
|
|
|
var->data.max_array_access, var->name, this->num_vertices);
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
2013-07-30 21:13:48 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-30 20:45:54 +10:00
|
|
|
var->type = glsl_type::get_array_instance(var->type->fields.array,
|
2013-07-30 21:13:48 -07:00
|
|
|
this->num_vertices);
|
glsl: move variables in to ir_variable::data, part II
This patch moves following bitfields and variables to the data
structure:
explicit_location, explicit_index, explicit_binding, has_initializer,
is_unmatched_generic_inout, location_frac, from_named_ifc_block_nonarray,
from_named_ifc_block_array, depth_layout, location, index, binding,
max_array_access, atomic
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-12-12 15:08:59 +02:00
|
|
|
var->data.max_array_access = this->num_vertices - 1;
|
2013-07-30 21:13:48 -07:00
|
|
|
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-07-14 20:39:45 +03:00
|
|
|
class array_length_to_const_visitor : public ir_rvalue_visitor {
|
|
|
|
|
public:
|
|
|
|
|
array_length_to_const_visitor()
|
|
|
|
|
{
|
|
|
|
|
this->progress = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~array_length_to_const_visitor()
|
|
|
|
|
{
|
|
|
|
|
/* empty */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool progress;
|
|
|
|
|
|
|
|
|
|
virtual void handle_rvalue(ir_rvalue **rvalue)
|
|
|
|
|
{
|
|
|
|
|
if (*rvalue == NULL || (*rvalue)->ir_type != ir_type_expression)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ir_expression *expr = (*rvalue)->as_expression();
|
|
|
|
|
if (expr) {
|
|
|
|
|
if (expr->operation == ir_unop_implicitly_sized_array_length) {
|
|
|
|
|
assert(!expr->operands[0]->type->is_unsized_array());
|
|
|
|
|
ir_constant *constant = new(expr)
|
|
|
|
|
ir_constant(expr->operands[0]->type->array_size());
|
|
|
|
|
if (constant) {
|
|
|
|
|
*rvalue = constant;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-08-18 20:59:37 -07:00
|
|
|
/**
|
2014-06-16 16:09:53 +02:00
|
|
|
* Visitor that determines the highest stream id to which a (geometry) shader
|
|
|
|
|
* emits vertices. It also checks whether End{Stream}Primitive is ever called.
|
2013-08-18 20:59:37 -07:00
|
|
|
*/
|
2014-06-16 16:09:53 +02:00
|
|
|
class find_emit_vertex_visitor : public ir_hierarchical_visitor {
|
2013-08-18 20:59:37 -07:00
|
|
|
public:
|
2014-06-16 16:09:53 +02:00
|
|
|
find_emit_vertex_visitor(int max_allowed)
|
|
|
|
|
: max_stream_allowed(max_allowed),
|
|
|
|
|
invalid_stream_id(0),
|
|
|
|
|
invalid_stream_id_from_emit_vertex(false),
|
|
|
|
|
end_primitive_found(false),
|
2020-03-19 04:59:27 -04:00
|
|
|
used_streams(0)
|
2013-08-18 20:59:37 -07:00
|
|
|
{
|
|
|
|
|
/* empty */
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 16:09:53 +02:00
|
|
|
virtual ir_visitor_status visit_leave(ir_emit_vertex *ir)
|
2013-08-18 20:59:37 -07:00
|
|
|
{
|
2014-06-16 16:09:53 +02:00
|
|
|
int stream_id = ir->stream_id();
|
|
|
|
|
|
|
|
|
|
if (stream_id < 0) {
|
|
|
|
|
invalid_stream_id = stream_id;
|
|
|
|
|
invalid_stream_id_from_emit_vertex = true;
|
|
|
|
|
return visit_stop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream_id > max_stream_allowed) {
|
|
|
|
|
invalid_stream_id = stream_id;
|
|
|
|
|
invalid_stream_id_from_emit_vertex = true;
|
|
|
|
|
return visit_stop;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-19 04:59:27 -04:00
|
|
|
used_streams |= 1 << stream_id;
|
2014-06-16 16:09:53 +02:00
|
|
|
|
|
|
|
|
return visit_continue;
|
2013-08-18 20:59:37 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-16 16:09:53 +02:00
|
|
|
virtual ir_visitor_status visit_leave(ir_end_primitive *ir)
|
2013-08-18 20:59:37 -07:00
|
|
|
{
|
2014-06-16 16:09:53 +02:00
|
|
|
end_primitive_found = true;
|
|
|
|
|
|
|
|
|
|
int stream_id = ir->stream_id();
|
|
|
|
|
|
|
|
|
|
if (stream_id < 0) {
|
|
|
|
|
invalid_stream_id = stream_id;
|
|
|
|
|
invalid_stream_id_from_emit_vertex = false;
|
|
|
|
|
return visit_stop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream_id > max_stream_allowed) {
|
|
|
|
|
invalid_stream_id = stream_id;
|
|
|
|
|
invalid_stream_id_from_emit_vertex = false;
|
|
|
|
|
return visit_stop;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-19 04:59:27 -04:00
|
|
|
used_streams |= 1 << stream_id;
|
2014-06-16 16:09:53 +02:00
|
|
|
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool error()
|
|
|
|
|
{
|
|
|
|
|
return invalid_stream_id != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *error_func()
|
|
|
|
|
{
|
|
|
|
|
return invalid_stream_id_from_emit_vertex ?
|
|
|
|
|
"EmitStreamVertex" : "EndStreamPrimitive";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int error_stream()
|
|
|
|
|
{
|
|
|
|
|
return invalid_stream_id;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-19 04:59:27 -04:00
|
|
|
unsigned active_stream_mask()
|
2014-06-16 16:09:53 +02:00
|
|
|
{
|
2020-03-19 04:59:27 -04:00
|
|
|
return used_streams;
|
2014-06-16 16:09:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool uses_end_primitive()
|
|
|
|
|
{
|
|
|
|
|
return end_primitive_found;
|
2013-08-18 20:59:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2014-06-16 16:09:53 +02:00
|
|
|
int max_stream_allowed;
|
|
|
|
|
int invalid_stream_id;
|
|
|
|
|
bool invalid_stream_id_from_emit_vertex;
|
|
|
|
|
bool end_primitive_found;
|
2020-03-19 04:59:27 -04:00
|
|
|
unsigned used_streams;
|
2013-08-18 20:59:37 -07:00
|
|
|
};
|
|
|
|
|
|
2013-09-20 11:03:44 -07:00
|
|
|
} /* anonymous namespace */
|
2013-08-18 20:59:37 -07:00
|
|
|
|
2010-06-23 12:07:22 -07:00
|
|
|
void
|
2011-07-28 14:04:09 -07:00
|
|
|
linker_error(gl_shader_program *prog, const char *fmt, ...)
|
2010-06-23 12:07:22 -07:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2016-11-07 14:47:18 +11:00
|
|
|
ralloc_strcat(&prog->data->InfoLog, "error: ");
|
2010-06-23 12:07:22 -07:00
|
|
|
va_start(ap, fmt);
|
2016-11-07 14:47:18 +11:00
|
|
|
ralloc_vasprintf_append(&prog->data->InfoLog, fmt, ap);
|
2010-06-23 12:07:22 -07:00
|
|
|
va_end(ap);
|
2011-07-28 14:04:09 -07:00
|
|
|
|
2018-01-25 12:50:12 -07:00
|
|
|
prog->data->LinkStatus = LINKING_FAILURE;
|
2010-06-23 12:07:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-28 14:09:06 -07:00
|
|
|
void
|
|
|
|
|
linker_warning(gl_shader_program *prog, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2016-11-07 14:47:18 +11:00
|
|
|
ralloc_strcat(&prog->data->InfoLog, "warning: ");
|
2011-07-28 14:09:06 -07:00
|
|
|
va_start(ap, fmt);
|
2016-11-07 14:47:18 +11:00
|
|
|
ralloc_vasprintf_append(&prog->data->InfoLog, fmt, ap);
|
2011-07-28 14:09:06 -07:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-11 14:11:05 -07:00
|
|
|
/**
|
2016-05-08 22:44:06 +02:00
|
|
|
* Set clip_distance_array_size based and cull_distance_array_size on the given
|
|
|
|
|
* shader.
|
2013-06-11 14:11:05 -07:00
|
|
|
*
|
|
|
|
|
* Also check for errors based on incorrect usage of gl_ClipVertex and
|
2016-05-08 22:44:06 +02:00
|
|
|
* gl_ClipDistance and gl_CullDistance.
|
|
|
|
|
* Additionally test whether the arrays gl_ClipDistance and gl_CullDistance
|
|
|
|
|
* exceed the maximum size defined by gl_MaxCombinedClipAndCullDistances.
|
2013-06-11 14:11:05 -07:00
|
|
|
*
|
|
|
|
|
* Return false if an error was reported.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-05-08 22:44:06 +02:00
|
|
|
analyze_clip_cull_usage(struct gl_shader_program *prog,
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *shader,
|
2022-01-07 10:31:10 +10:00
|
|
|
const struct gl_constants *consts,
|
2019-11-05 19:20:35 -05:00
|
|
|
struct shader_info *info)
|
2013-06-11 14:11:05 -07:00
|
|
|
{
|
2022-01-07 10:31:10 +10:00
|
|
|
if (consts->DoDCEBeforeClipCullAnalysis) {
|
2021-09-16 13:11:30 +02:00
|
|
|
/* Remove dead functions to avoid raising an error (eg: dead function
|
|
|
|
|
* writes to gl_ClipVertex, and main() writes to gl_ClipDistance).
|
|
|
|
|
*/
|
|
|
|
|
do_dead_functions(shader->ir);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 19:20:35 -05:00
|
|
|
info->clip_distance_array_size = 0;
|
|
|
|
|
info->cull_distance_array_size = 0;
|
2013-06-11 14:11:05 -07:00
|
|
|
|
2023-02-08 15:28:08 +01:00
|
|
|
if (prog->GLSL_Version >= (prog->IsES ? 300 : 130)) {
|
2013-06-11 14:11:05 -07:00
|
|
|
/* 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
|
2016-05-23 21:38:38 -04:00
|
|
|
* gl_ClipVertex nor gl_ClipDistance. However with
|
|
|
|
|
* GL_EXT_clip_cull_distance, this functionality is exposed in ES 3.0.
|
2013-06-11 14:11:05 -07:00
|
|
|
*/
|
2017-06-22 12:12:44 +02:00
|
|
|
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);
|
2016-05-08 22:44:06 +02:00
|
|
|
|
|
|
|
|
/* From the ARB_cull_distance spec:
|
|
|
|
|
*
|
|
|
|
|
* It is a compile-time or link-time error for the set of shaders forming
|
|
|
|
|
* a program to statically read or write both gl_ClipVertex and either
|
|
|
|
|
* gl_ClipDistance or gl_CullDistance.
|
|
|
|
|
*
|
2016-05-23 21:38:38 -04:00
|
|
|
* This does not apply to GLSL ES shaders, since GLSL ES doesn't define
|
|
|
|
|
* gl_ClipVertex.
|
2016-05-08 22:44:06 +02:00
|
|
|
*/
|
2016-05-23 21:38:38 -04:00
|
|
|
if (!prog->IsES) {
|
2017-06-22 12:12:44 +02:00
|
|
|
if (gl_ClipVertex.found && gl_ClipDistance.found) {
|
2016-05-23 21:38:38 -04:00
|
|
|
linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
|
|
|
|
|
"and `gl_ClipDistance'\n",
|
|
|
|
|
_mesa_shader_stage_to_string(shader->Stage));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-06-22 12:12:44 +02:00
|
|
|
if (gl_ClipVertex.found && gl_CullDistance.found) {
|
2016-05-23 21:38:38 -04:00
|
|
|
linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
|
|
|
|
|
"and `gl_CullDistance'\n",
|
|
|
|
|
_mesa_shader_stage_to_string(shader->Stage));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-05-08 22:44:06 +02:00
|
|
|
}
|
2015-10-17 22:50:11 +02:00
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
if (gl_ClipDistance.found) {
|
2015-10-17 22:50:11 +02:00
|
|
|
ir_variable *clip_distance_var =
|
2016-05-08 22:44:06 +02:00
|
|
|
shader->symbols->get_variable("gl_ClipDistance");
|
2015-10-17 22:50:11 +02:00
|
|
|
assert(clip_distance_var);
|
2019-11-05 19:20:35 -05:00
|
|
|
info->clip_distance_array_size = clip_distance_var->type->length;
|
2015-10-17 22:50:11 +02:00
|
|
|
}
|
2017-06-22 12:12:44 +02:00
|
|
|
if (gl_CullDistance.found) {
|
2016-05-08 22:44:06 +02:00
|
|
|
ir_variable *cull_distance_var =
|
|
|
|
|
shader->symbols->get_variable("gl_CullDistance");
|
|
|
|
|
assert(cull_distance_var);
|
2019-11-05 19:20:35 -05:00
|
|
|
info->cull_distance_array_size = cull_distance_var->type->length;
|
2016-05-08 22:44:06 +02:00
|
|
|
}
|
|
|
|
|
/* From the ARB_cull_distance spec:
|
|
|
|
|
*
|
|
|
|
|
* It is a compile-time or link-time error for the set of shaders forming
|
|
|
|
|
* a program to have the sum of the sizes of the gl_ClipDistance and
|
|
|
|
|
* gl_CullDistance arrays to be larger than
|
|
|
|
|
* gl_MaxCombinedClipAndCullDistances.
|
|
|
|
|
*/
|
2019-11-05 19:20:35 -05:00
|
|
|
if ((uint32_t)(info->clip_distance_array_size + info->cull_distance_array_size) >
|
2022-01-07 10:31:10 +10:00
|
|
|
consts->MaxClipPlanes) {
|
2016-05-08 22:44:06 +02:00
|
|
|
linker_error(prog, "%s shader: the combined size of "
|
|
|
|
|
"'gl_ClipDistance' and 'gl_CullDistance' size cannot "
|
|
|
|
|
"be larger than "
|
|
|
|
|
"gl_MaxCombinedClipAndCullDistances (%u)",
|
|
|
|
|
_mesa_shader_stage_to_string(shader->Stage),
|
2022-01-07 10:31:10 +10:00
|
|
|
consts->MaxClipPlanes);
|
2016-05-08 22:44:06 +02:00
|
|
|
}
|
2013-06-11 14:11:05 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-17 15:20:22 -07:00
|
|
|
/**
|
2011-09-17 09:42:02 -07:00
|
|
|
* Verify that a vertex shader executable meets all semantic requirements.
|
|
|
|
|
*
|
2016-11-20 23:05:42 +11:00
|
|
|
* Also sets info.clip_distance_array_size and
|
|
|
|
|
* info.cull_distance_array_size as a side effect.
|
2010-06-17 15:20:22 -07:00
|
|
|
*
|
|
|
|
|
* \param shader Vertex shader executable to be verified
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2010-06-30 11:49:17 -07:00
|
|
|
validate_vertex_shader_executable(struct gl_shader_program *prog,
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *shader,
|
2022-01-07 10:31:10 +10:00
|
|
|
const struct gl_constants *consts)
|
2010-06-17 15:04:20 -07:00
|
|
|
{
|
|
|
|
|
if (shader == NULL)
|
2013-07-27 11:08:31 -07:00
|
|
|
return;
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2012-03-19 22:43:27 -07:00
|
|
|
/* 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."
|
2012-08-02 17:51:02 -07:00
|
|
|
*
|
2014-09-08 11:10:42 +03:00
|
|
|
* All GLSL ES Versions are similar to GLSL 1.40--failing to write to
|
|
|
|
|
* gl_Position is not an error.
|
2012-03-19 22:43:27 -07:00
|
|
|
*/
|
2023-02-08 15:28:08 +01:00
|
|
|
if (prog->GLSL_Version < (prog->IsES ? 300 : 140)) {
|
2017-06-22 12:12:44 +02:00
|
|
|
find_variable gl_Position("gl_Position");
|
|
|
|
|
find_assignments(shader->ir, &gl_Position);
|
|
|
|
|
if (!gl_Position.found) {
|
2014-09-10 20:20:23 -07:00
|
|
|
if (prog->IsES) {
|
|
|
|
|
linker_warning(prog,
|
2016-09-14 15:28:28 +01:00
|
|
|
"vertex shader does not write to `gl_Position'. "
|
|
|
|
|
"Its value is undefined. \n");
|
2014-09-10 20:20:23 -07:00
|
|
|
} else {
|
|
|
|
|
linker_error(prog,
|
|
|
|
|
"vertex shader does not write to `gl_Position'. \n");
|
|
|
|
|
}
|
2016-09-28 16:04:05 +10:00
|
|
|
return;
|
2012-03-19 22:43:27 -07:00
|
|
|
}
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-07 10:31:10 +10:00
|
|
|
analyze_clip_cull_usage(prog, shader, consts, &shader->Program->info);
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2014-09-09 19:25:02 +12:00
|
|
|
validate_tess_eval_shader_executable(struct gl_shader_program *prog,
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *shader,
|
2022-01-07 10:31:10 +10:00
|
|
|
const struct gl_constants *consts)
|
2014-09-09 19:25:02 +12:00
|
|
|
{
|
|
|
|
|
if (shader == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-01-07 10:31:10 +10:00
|
|
|
analyze_clip_cull_usage(prog, shader, consts, &shader->Program->info);
|
2014-09-09 19:25:02 +12:00
|
|
|
}
|
|
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2010-06-17 15:20:22 -07:00
|
|
|
/**
|
|
|
|
|
* Verify that a fragment shader executable meets all semantic requirements
|
|
|
|
|
*
|
|
|
|
|
* \param shader Fragment shader executable to be verified
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2010-06-30 11:49:17 -07:00
|
|
|
validate_fragment_shader_executable(struct gl_shader_program *prog,
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *shader)
|
2010-06-17 15:04:20 -07:00
|
|
|
{
|
|
|
|
|
if (shader == NULL)
|
2013-07-27 11:08:31 -07:00
|
|
|
return;
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
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);
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2017-06-22 12:12:44 +02:00
|
|
|
if (gl_FragColor.found && gl_FragData.found) {
|
2011-07-28 14:04:09 -07:00
|
|
|
linker_error(prog, "fragment shader writes to both "
|
2016-09-28 16:04:05 +10:00
|
|
|
"`gl_FragColor' and `gl_FragData'\n");
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-15 09:46:50 -06:00
|
|
|
/**
|
|
|
|
|
* Verify that a geometry shader executable meets all semantic requirements
|
|
|
|
|
*
|
2016-11-20 23:05:42 +11:00
|
|
|
* Also sets prog->Geom.VerticesIn, and info.clip_distance_array_sizeand
|
|
|
|
|
* info.cull_distance_array_size as a side effect.
|
2013-02-15 09:46:50 -06:00
|
|
|
*
|
|
|
|
|
* \param shader Geometry shader executable to be verified
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2013-02-15 09:46:50 -06:00
|
|
|
validate_geometry_shader_executable(struct gl_shader_program *prog,
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *shader,
|
2022-01-07 10:31:10 +10:00
|
|
|
const struct gl_constants *consts)
|
2013-02-15 09:46:50 -06:00
|
|
|
{
|
|
|
|
|
if (shader == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-22 21:45:16 +11:00
|
|
|
unsigned num_vertices =
|
2023-08-21 18:09:22 -05:00
|
|
|
mesa_vertices_per_prim(shader->Program->info.gs.input_primitive);
|
2013-02-15 09:46:50 -06:00
|
|
|
prog->Geom.VerticesIn = num_vertices;
|
2013-06-11 14:11:05 -07:00
|
|
|
|
2022-01-07 10:31:10 +10:00
|
|
|
analyze_clip_cull_usage(prog, shader, consts, &shader->Program->info);
|
2014-06-16 16:09:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if geometry shaders emit to non-zero streams and do corresponding
|
|
|
|
|
* validations.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2022-01-07 10:31:10 +10:00
|
|
|
validate_geometry_shader_emissions(const struct gl_constants *consts,
|
2014-06-16 16:09:53 +02:00
|
|
|
struct gl_shader_program *prog)
|
|
|
|
|
{
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *sh = prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
|
2016-06-22 12:41:28 +10:00
|
|
|
|
|
|
|
|
if (sh != NULL) {
|
2022-01-07 10:31:10 +10:00
|
|
|
find_emit_vertex_visitor emit_vertex(consts->MaxVertexStreams - 1);
|
2016-06-22 12:41:28 +10:00
|
|
|
emit_vertex.run(sh->ir);
|
2014-06-16 16:09:53 +02:00
|
|
|
if (emit_vertex.error()) {
|
|
|
|
|
linker_error(prog, "Invalid call %s(%d). Accepted values for the "
|
2014-11-18 08:43:35 -07:00
|
|
|
"stream parameter are in the range [0, %d].\n",
|
2014-06-16 16:09:53 +02:00
|
|
|
emit_vertex.error_func(),
|
|
|
|
|
emit_vertex.error_stream(),
|
2022-01-07 10:31:10 +10:00
|
|
|
consts->MaxVertexStreams - 1);
|
2014-06-16 16:09:53 +02:00
|
|
|
}
|
2020-03-19 04:59:27 -04:00
|
|
|
prog->Geom.ActiveStreamMask = emit_vertex.active_stream_mask();
|
2014-06-16 16:09:53 +02:00
|
|
|
prog->Geom.UsesEndPrimitive = emit_vertex.uses_end_primitive();
|
2013-08-18 20:59:37 -07:00
|
|
|
|
2014-06-16 16:09:53 +02:00
|
|
|
/* From the ARB_gpu_shader5 spec:
|
|
|
|
|
*
|
|
|
|
|
* "Multiple vertex streams are supported only if the output primitive
|
|
|
|
|
* type is declared to be "points". A program will fail to link if it
|
|
|
|
|
* contains a geometry shader calling EmitStreamVertex() or
|
|
|
|
|
* EndStreamPrimitive() if its output primitive type is not "points".
|
|
|
|
|
*
|
|
|
|
|
* However, in the same spec:
|
|
|
|
|
*
|
|
|
|
|
* "The function EmitVertex() is equivalent to calling EmitStreamVertex()
|
|
|
|
|
* with <stream> set to zero."
|
|
|
|
|
*
|
|
|
|
|
* And:
|
|
|
|
|
*
|
|
|
|
|
* "The function EndPrimitive() is equivalent to calling
|
|
|
|
|
* EndStreamPrimitive() with <stream> set to zero."
|
|
|
|
|
*
|
|
|
|
|
* Since we can call EmitVertex() and EndPrimitive() when we output
|
|
|
|
|
* primitives other than points, calling EmitStreamVertex(0) or
|
|
|
|
|
* EmitEndPrimitive(0) should not produce errors. This it also what Nvidia
|
2020-03-19 04:59:27 -04:00
|
|
|
* does. We can use prog->Geom.ActiveStreamMask to check whether only the
|
|
|
|
|
* first (zero) stream is active.
|
2014-06-16 16:09:53 +02:00
|
|
|
* stream.
|
|
|
|
|
*/
|
2020-03-19 04:59:27 -04:00
|
|
|
if (prog->Geom.ActiveStreamMask & ~(1 << 0) &&
|
2023-08-21 18:09:22 -05:00
|
|
|
sh->Program->info.gs.output_primitive != MESA_PRIM_POINTS) {
|
2014-06-16 16:09:53 +02:00
|
|
|
linker_error(prog, "EmitStreamVertex(n) and EndStreamPrimitive(n) "
|
2014-11-18 08:43:35 -07:00
|
|
|
"with n>0 requires point output\n");
|
2014-06-16 16:09:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
2013-02-15 09:46:50 -06:00
|
|
|
}
|
|
|
|
|
|
2015-02-21 21:47:14 +11:00
|
|
|
bool
|
|
|
|
|
validate_intrastage_arrays(struct gl_shader_program *prog,
|
|
|
|
|
ir_variable *const var,
|
2019-04-23 16:52:36 +02:00
|
|
|
ir_variable *const existing,
|
|
|
|
|
bool match_precision)
|
2015-02-21 21:47:14 +11:00
|
|
|
{
|
|
|
|
|
/* Consider the types to be "the same" if both types are arrays
|
|
|
|
|
* of the same type and one of the arrays is implicitly sized.
|
|
|
|
|
* In addition, set the type of the linked variable to the
|
|
|
|
|
* explicitly sized array.
|
|
|
|
|
*/
|
2015-03-18 15:32:03 +01:00
|
|
|
if (var->type->is_array() && existing->type->is_array()) {
|
2019-04-23 16:52:36 +02:00
|
|
|
const glsl_type *no_array_var = var->type->fields.array;
|
|
|
|
|
const glsl_type *no_array_existing = existing->type->fields.array;
|
|
|
|
|
bool type_matches;
|
|
|
|
|
|
|
|
|
|
type_matches = (match_precision ?
|
|
|
|
|
no_array_var == no_array_existing :
|
|
|
|
|
no_array_var->compare_no_precision(no_array_existing));
|
|
|
|
|
|
|
|
|
|
if (type_matches &&
|
2015-03-18 15:32:03 +01:00
|
|
|
((var->type->length == 0)|| (existing->type->length == 0))) {
|
|
|
|
|
if (var->type->length != 0) {
|
2016-05-20 10:19:14 +10:00
|
|
|
if ((int)var->type->length <= existing->data.max_array_access) {
|
2015-03-18 15:32:03 +01:00
|
|
|
linker_error(prog, "%s `%s' declared as type "
|
|
|
|
|
"`%s' but outermost dimension has an index"
|
|
|
|
|
" of `%i'\n",
|
|
|
|
|
mode_string(var),
|
2023-09-12 12:11:18 -07:00
|
|
|
var->name, glsl_get_type_name(var->type),
|
2015-03-18 15:32:03 +01:00
|
|
|
existing->data.max_array_access);
|
|
|
|
|
}
|
|
|
|
|
existing->type = var->type;
|
|
|
|
|
return true;
|
|
|
|
|
} else if (existing->type->length != 0) {
|
2016-05-20 10:19:14 +10:00
|
|
|
if((int)existing->type->length <= var->data.max_array_access &&
|
2015-03-18 15:32:03 +01:00
|
|
|
!existing->data.from_ssbo_unsized_array) {
|
|
|
|
|
linker_error(prog, "%s `%s' declared as type "
|
|
|
|
|
"`%s' but outermost dimension has an index"
|
|
|
|
|
" of `%i'\n",
|
|
|
|
|
mode_string(var),
|
2023-09-12 12:11:18 -07:00
|
|
|
var->name, glsl_get_type_name(existing->type),
|
2015-03-18 15:32:03 +01:00
|
|
|
var->data.max_array_access);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-02-21 21:47:14 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2010-06-29 18:47:11 -07:00
|
|
|
/**
|
|
|
|
|
* Perform validation of global variables used across multiple shaders
|
2010-06-18 17:13:42 -07:00
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2022-01-07 12:37:56 +10:00
|
|
|
cross_validate_globals(const struct gl_constants *consts,
|
|
|
|
|
struct gl_shader_program *prog,
|
2016-06-27 15:38:51 +10:00
|
|
|
struct exec_list *ir, glsl_symbol_table *variables,
|
|
|
|
|
bool uniforms_only)
|
2010-06-18 17:13:42 -07:00
|
|
|
{
|
2016-06-27 15:38:51 +10:00
|
|
|
foreach_in_list(ir_instruction, node, ir) {
|
|
|
|
|
ir_variable *const var = node->as_variable();
|
2010-10-14 13:28:42 -07:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (var == NULL)
|
|
|
|
|
continue;
|
2010-06-18 17:13:42 -07:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (uniforms_only && (var->data.mode != ir_var_uniform && var->data.mode != ir_var_shader_storage))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* don't cross validate subroutine uniforms */
|
|
|
|
|
if (var->type->contains_subroutine())
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-02-20 17:20:58 +02:00
|
|
|
/* 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;
|
|
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
/* Don't cross validate temporaries that are at global scope. These
|
|
|
|
|
* will eventually get pulled into the shaders 'main'.
|
|
|
|
|
*/
|
|
|
|
|
if (var->data.mode == ir_var_temporary)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* If a global with this name has already been seen, verify that the
|
|
|
|
|
* new instance has the same type. In addition, if the globals have
|
|
|
|
|
* initializers, the values of the initializers must be the same.
|
|
|
|
|
*/
|
|
|
|
|
ir_variable *const existing = variables->get_variable(var->name);
|
|
|
|
|
if (existing != NULL) {
|
2017-02-20 17:20:58 +02:00
|
|
|
/* Check if types match. */
|
|
|
|
|
if (var->type != existing->type) {
|
2016-06-27 15:38:51 +10:00
|
|
|
if (!validate_intrastage_arrays(prog, var, existing)) {
|
2017-05-14 20:06:35 +02:00
|
|
|
/* 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),
|
2023-09-12 12:11:18 -07:00
|
|
|
var->name, glsl_get_type_name(var->type),
|
|
|
|
|
glsl_get_type_name(existing->type));
|
2017-05-14 20:06:35 +02:00
|
|
|
return;
|
2016-01-14 14:10:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
2010-10-07 17:21:22 -07:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (var->data.explicit_location) {
|
|
|
|
|
if (existing->data.explicit_location
|
|
|
|
|
&& (var->data.location != existing->data.location)) {
|
|
|
|
|
linker_error(prog, "explicit locations for %s "
|
|
|
|
|
"`%s' have differing values\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-07-16 12:18:57 -07:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (var->data.location_frac != existing->data.location_frac) {
|
|
|
|
|
linker_error(prog, "explicit components for %s `%s' have "
|
|
|
|
|
"differing values\n", mode_string(var), var->name);
|
|
|
|
|
return;
|
2013-07-16 12:18:57 -07:00
|
|
|
}
|
|
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
existing->data.location = var->data.location;
|
|
|
|
|
existing->data.explicit_location = true;
|
|
|
|
|
} else {
|
|
|
|
|
/* Check if uniform with implicit location was marked explicit
|
|
|
|
|
* by earlier shader stage. If so, mark it explicit in this stage
|
|
|
|
|
* too to make sure later processing does not treat it as
|
|
|
|
|
* implicit one.
|
|
|
|
|
*/
|
|
|
|
|
if (existing->data.explicit_location) {
|
|
|
|
|
var->data.location = existing->data.location;
|
|
|
|
|
var->data.explicit_location = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* From the GLSL 4.20 specification:
|
|
|
|
|
* "A link error will result if two compilation units in a program
|
|
|
|
|
* specify different integer-constant bindings for the same
|
|
|
|
|
* opaque-uniform name. However, it is not an error to specify a
|
|
|
|
|
* binding on some but not all declarations for the same name"
|
|
|
|
|
*/
|
|
|
|
|
if (var->data.explicit_binding) {
|
|
|
|
|
if (existing->data.explicit_binding &&
|
|
|
|
|
var->data.binding != existing->data.binding) {
|
|
|
|
|
linker_error(prog, "explicit bindings for %s "
|
2013-09-11 12:14:46 -07:00
|
|
|
"`%s' have differing values\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
existing->data.binding = var->data.binding;
|
|
|
|
|
existing->data.explicit_binding = true;
|
|
|
|
|
}
|
2011-01-27 01:40:31 -08:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (var->type->contains_atomic() &&
|
|
|
|
|
var->data.offset != existing->data.offset) {
|
|
|
|
|
linker_error(prog, "offset specifications for %s "
|
|
|
|
|
"`%s' have differing values\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-10-31 14:31:07 -07:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
/* 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->data.depth_layout != ir_depth_layout_none;
|
|
|
|
|
bool layout_differs =
|
|
|
|
|
var->data.depth_layout != existing->data.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.\n");
|
|
|
|
|
}
|
2010-11-17 14:34:38 -08:00
|
|
|
|
2016-06-27 15:38:51 +10:00
|
|
|
if (var->data.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\n");
|
2011-01-10 15:29:30 -08:00
|
|
|
}
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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.
|
2020-04-30 15:06:08 +02:00
|
|
|
* If (at least) one of these constant expressions is implicit,
|
|
|
|
|
* because it was added by glsl_zero_init, we skip the verification.
|
2016-06-27 15:38:51 +10:00
|
|
|
*/
|
|
|
|
|
if (var->constant_initializer != NULL) {
|
2020-04-30 15:06:08 +02:00
|
|
|
if (existing->constant_initializer != NULL &&
|
|
|
|
|
!existing->data.is_implicit_initializer &&
|
|
|
|
|
!var->data.is_implicit_initializer) {
|
2016-06-27 15:38:51 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* If the first-seen instance of a particular uniform did
|
|
|
|
|
* not have an initializer but a later instance does,
|
|
|
|
|
* replace the former with the later.
|
|
|
|
|
*/
|
2020-04-30 15:06:08 +02:00
|
|
|
if (!var->data.is_implicit_initializer)
|
|
|
|
|
variables->replace_variable(existing->name, var);
|
2013-11-29 21:26:10 +13:00
|
|
|
}
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (var->data.has_initializer) {
|
|
|
|
|
if (existing->data.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);
|
2016-01-05 13:21:17 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
|
|
|
|
|
2018-09-04 11:42:04 +03:00
|
|
|
if (existing->data.explicit_invariant != var->data.explicit_invariant) {
|
2016-06-27 15:38:51 +10:00
|
|
|
linker_error(prog, "declarations for %s `%s' have "
|
|
|
|
|
"mismatching invariant qualifiers\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (existing->data.centroid != var->data.centroid) {
|
|
|
|
|
linker_error(prog, "declarations for %s `%s' have "
|
|
|
|
|
"mismatching centroid qualifiers\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (existing->data.sample != var->data.sample) {
|
|
|
|
|
linker_error(prog, "declarations for %s `%s` have "
|
|
|
|
|
"mismatching sample qualifiers\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (existing->data.image_format != var->data.image_format) {
|
|
|
|
|
linker_error(prog, "declarations for %s `%s` have "
|
|
|
|
|
"mismatching image format qualifiers\n",
|
|
|
|
|
mode_string(var), var->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-05-24 12:04:53 -07:00
|
|
|
|
2018-01-29 13:46:28 +01:00
|
|
|
/* Check the precision qualifier matches for uniform variables on
|
|
|
|
|
* GLSL ES.
|
2016-10-18 09:38:30 +02:00
|
|
|
*/
|
2022-01-07 12:37:56 +10:00
|
|
|
if (!consts->AllowGLSLRelaxedES &&
|
2018-06-14 11:00:24 +10:00
|
|
|
prog->IsES && !var->get_interface_type() &&
|
2016-10-18 09:38:30 +02:00
|
|
|
existing->data.precision != var->data.precision) {
|
2023-02-08 15:28:08 +01:00
|
|
|
if ((existing->data.used && var->data.used) ||
|
|
|
|
|
prog->GLSL_Version >= 300) {
|
glsl: Allow precision mismatch on dead data with GLSL ES 1.00
Commit 259fc505454ea6a67aeacf6cdebf1398d9947759 added linker error for
mismatching uniform precision, as required by GLES 3.0 specification and
conformance test-suite.
Several Android applications, including Forge of Empires, have shaders
which violate this rule, on a dead varying that will be eliminated.
The problem affects a big number of applications using Cocos2D engine
and other GLES implementations accept this, this poses a serious
application compatibility issue.
Starting from GLSL ES 3.0, declarations with conflicting precision
qualifiers are explicitly prohibited. However GLSL ES 1.00 does not
clearly specify the behavior, except that
"Uniforms are defined to behave as if they are using the same storage in
the vertex and fragment processors and may be implemented this way.
If uniforms are used in both the vertex and fragment shaders, developers
should be warned if the precisions are different. Conversion of
precision should never be implicit."
The word "used" is not clear in this context and might refer to
1) declared (same as GLES 3.x)
2) referred after post-processing, or
3) linked after all optimizations are done.
Looking at existing applications, 2) or 3) seems to be widely adopted.
To avoid compatibility issues, turn the error into a warning if GLSL ES
version is lower than 3.0 and the data is dead in at least one of the
shaders.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97532
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2017-09-26 17:35:56 +09:00
|
|
|
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);
|
|
|
|
|
}
|
2016-05-24 12:04:53 -07:00
|
|
|
}
|
glsl/linker: check same name is not used in block and outside
According with OpenGL GLSL 3.20 spec, section 4.3.9:
"It is a link-time error if any particular shader interface
contains:
- two different blocks, each having no instance name, and each
having a member of the same name, or
- a variable outside a block, and a block with no instance name,
where the variable has the same name as a member in the block."
This fixes a previous commit 9b894c8 ("glsl/linker: link-error using the
same name in unnamed block and outside") that covered this case, but
did not take in account that precision qualifiers are ignored when
comparing blocks with no instance name.
With this commit, the original tests
KHR-GL*.shaders.uniform_block.common.name_matching keep fixed, and also
dEQP-GLES31.functional.shaders.linkage.uniform.block.differing_precision
regression is fixed, which was broken by previous commit.
v2: use helper varibles (Matteo Bruni)
Fixes: 9b894c8 ("glsl/linker: link-error using the same name in unnamed block and outside")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104668
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104777
CC: Mark Janes <mark.a.janes@intel.com>
CC: "18.0" <mesa-stable@lists.freedesktop.org>
Tested-by: Matteo Bruni <matteo.mystral@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Juan A. Suarez Romero <jasuarez@igalia.com>
2018-02-05 17:38:39 +01:00
|
|
|
|
|
|
|
|
/* In OpenGL GLSL 3.20 spec, section 4.3.9:
|
|
|
|
|
*
|
|
|
|
|
* "It is a link-time error if any particular shader interface
|
|
|
|
|
* contains:
|
|
|
|
|
*
|
|
|
|
|
* - two different blocks, each having no instance name, and each
|
|
|
|
|
* having a member of the same name, or
|
|
|
|
|
*
|
|
|
|
|
* - a variable outside a block, and a block with no instance name,
|
|
|
|
|
* where the variable has the same name as a member in the block."
|
|
|
|
|
*/
|
|
|
|
|
const glsl_type *var_itype = var->get_interface_type();
|
|
|
|
|
const glsl_type *existing_itype = existing->get_interface_type();
|
|
|
|
|
if (var_itype != existing_itype) {
|
|
|
|
|
if (!var_itype || !existing_itype) {
|
|
|
|
|
linker_error(prog, "declarations for %s `%s` are inside block "
|
|
|
|
|
"`%s` and outside a block",
|
|
|
|
|
mode_string(var), var->name,
|
2023-09-12 12:11:18 -07:00
|
|
|
glsl_get_type_name(var_itype ? var_itype : existing_itype));
|
glsl/linker: check same name is not used in block and outside
According with OpenGL GLSL 3.20 spec, section 4.3.9:
"It is a link-time error if any particular shader interface
contains:
- two different blocks, each having no instance name, and each
having a member of the same name, or
- a variable outside a block, and a block with no instance name,
where the variable has the same name as a member in the block."
This fixes a previous commit 9b894c8 ("glsl/linker: link-error using the
same name in unnamed block and outside") that covered this case, but
did not take in account that precision qualifiers are ignored when
comparing blocks with no instance name.
With this commit, the original tests
KHR-GL*.shaders.uniform_block.common.name_matching keep fixed, and also
dEQP-GLES31.functional.shaders.linkage.uniform.block.differing_precision
regression is fixed, which was broken by previous commit.
v2: use helper varibles (Matteo Bruni)
Fixes: 9b894c8 ("glsl/linker: link-error using the same name in unnamed block and outside")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104668
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104777
CC: Mark Janes <mark.a.janes@intel.com>
CC: "18.0" <mesa-stable@lists.freedesktop.org>
Tested-by: Matteo Bruni <matteo.mystral@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Juan A. Suarez Romero <jasuarez@igalia.com>
2018-02-05 17:38:39 +01:00
|
|
|
return;
|
2023-09-12 12:11:18 -07:00
|
|
|
} else if (strcmp(glsl_get_type_name(var_itype), glsl_get_type_name(existing_itype)) != 0) {
|
glsl/linker: check same name is not used in block and outside
According with OpenGL GLSL 3.20 spec, section 4.3.9:
"It is a link-time error if any particular shader interface
contains:
- two different blocks, each having no instance name, and each
having a member of the same name, or
- a variable outside a block, and a block with no instance name,
where the variable has the same name as a member in the block."
This fixes a previous commit 9b894c8 ("glsl/linker: link-error using the
same name in unnamed block and outside") that covered this case, but
did not take in account that precision qualifiers are ignored when
comparing blocks with no instance name.
With this commit, the original tests
KHR-GL*.shaders.uniform_block.common.name_matching keep fixed, and also
dEQP-GLES31.functional.shaders.linkage.uniform.block.differing_precision
regression is fixed, which was broken by previous commit.
v2: use helper varibles (Matteo Bruni)
Fixes: 9b894c8 ("glsl/linker: link-error using the same name in unnamed block and outside")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104668
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104777
CC: Mark Janes <mark.a.janes@intel.com>
CC: "18.0" <mesa-stable@lists.freedesktop.org>
Tested-by: Matteo Bruni <matteo.mystral@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Juan A. Suarez Romero <jasuarez@igalia.com>
2018-02-05 17:38:39 +01:00
|
|
|
linker_error(prog, "declarations for %s `%s` are inside blocks "
|
|
|
|
|
"`%s` and `%s`",
|
|
|
|
|
mode_string(var), var->name,
|
2023-09-12 12:11:18 -07:00
|
|
|
glsl_get_type_name(existing_itype),
|
|
|
|
|
glsl_get_type_name(var_itype));
|
glsl/linker: check same name is not used in block and outside
According with OpenGL GLSL 3.20 spec, section 4.3.9:
"It is a link-time error if any particular shader interface
contains:
- two different blocks, each having no instance name, and each
having a member of the same name, or
- a variable outside a block, and a block with no instance name,
where the variable has the same name as a member in the block."
This fixes a previous commit 9b894c8 ("glsl/linker: link-error using the
same name in unnamed block and outside") that covered this case, but
did not take in account that precision qualifiers are ignored when
comparing blocks with no instance name.
With this commit, the original tests
KHR-GL*.shaders.uniform_block.common.name_matching keep fixed, and also
dEQP-GLES31.functional.shaders.linkage.uniform.block.differing_precision
regression is fixed, which was broken by previous commit.
v2: use helper varibles (Matteo Bruni)
Fixes: 9b894c8 ("glsl/linker: link-error using the same name in unnamed block and outside")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104668
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104777
CC: Mark Janes <mark.a.janes@intel.com>
CC: "18.0" <mesa-stable@lists.freedesktop.org>
Tested-by: Matteo Bruni <matteo.mystral@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Juan A. Suarez Romero <jasuarez@igalia.com>
2018-02-05 17:38:39 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-27 15:38:51 +10:00
|
|
|
} else
|
|
|
|
|
variables->add_variable(var);
|
2010-06-18 17:13:42 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-29 18:47:11 -07:00
|
|
|
/**
|
|
|
|
|
* Perform validation of uniforms used across multiple shader stages
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2022-01-07 12:37:56 +10:00
|
|
|
cross_validate_uniforms(const struct gl_constants *consts,
|
2018-06-14 11:00:24 +10:00
|
|
|
struct gl_shader_program *prog)
|
2010-06-29 18:47:11 -07:00
|
|
|
{
|
2016-06-27 15:38:51 +10:00
|
|
|
glsl_symbol_table variables;
|
|
|
|
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
|
|
|
|
if (prog->_LinkedShaders[i] == NULL)
|
2016-09-28 16:04:05 +10:00
|
|
|
continue;
|
2016-06-27 15:38:51 +10:00
|
|
|
|
2022-01-07 12:37:56 +10:00
|
|
|
cross_validate_globals(consts, prog, prog->_LinkedShaders[i]->ir,
|
2018-06-14 11:00:24 +10:00
|
|
|
&variables, true);
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
2010-06-29 18:47:11 -07:00
|
|
|
}
|
|
|
|
|
|
2018-09-07 15:14:52 +03:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
2010-06-18 19:02:10 -07:00
|
|
|
|
2010-07-09 14:09:34 -07:00
|
|
|
/**
|
|
|
|
|
* Populates a shaders symbol table with all global declarations
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-03-05 20:28:42 +01:00
|
|
|
populate_symbol_table(gl_linked_shader *sh, glsl_symbol_table *symbols)
|
2010-07-09 14:09:34 -07:00
|
|
|
{
|
|
|
|
|
sh->symbols = new(sh) glsl_symbol_table;
|
|
|
|
|
|
2017-03-05 20:28:42 +01:00
|
|
|
_mesa_glsl_copy_symbols_from_table(sh->ir, symbols, sh->symbols);
|
2010-07-09 14:09:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-07-12 18:48:50 -07:00
|
|
|
/**
|
|
|
|
|
* Remap variables referenced in an instruction tree
|
|
|
|
|
*
|
|
|
|
|
* This is used when instruction trees are cloned from one shader and placed in
|
|
|
|
|
* another. These trees will contain references to \c ir_variable nodes that
|
|
|
|
|
* do not exist in the target shader. This function finds these \c ir_variable
|
|
|
|
|
* references and replaces the references with matching variables in the target
|
|
|
|
|
* shader.
|
|
|
|
|
*
|
|
|
|
|
* If there is no matching variable in the target shader, a clone of the
|
|
|
|
|
* \c ir_variable is made and added to the target shader. The new variable is
|
|
|
|
|
* added to \b both the instruction stream and the symbol table.
|
|
|
|
|
*
|
|
|
|
|
* \param inst IR tree that is to be processed.
|
|
|
|
|
* \param symbols Symbol table containing global scope symbols in the
|
|
|
|
|
* linked shader.
|
|
|
|
|
* \param instructions Instruction stream where new variable declarations
|
|
|
|
|
* should be added.
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static void
|
2016-06-30 14:55:40 +10:00
|
|
|
remap_variables(ir_instruction *inst, struct gl_linked_shader *target,
|
2016-09-28 16:04:05 +10:00
|
|
|
hash_table *temps)
|
2010-07-12 18:48:50 -07:00
|
|
|
{
|
|
|
|
|
class remap_visitor : public ir_hierarchical_visitor {
|
|
|
|
|
public:
|
2016-09-28 16:04:05 +10:00
|
|
|
remap_visitor(struct gl_linked_shader *target, hash_table *temps)
|
2010-07-12 18:48:50 -07:00
|
|
|
{
|
2016-09-28 16:04:05 +10:00
|
|
|
this->target = target;
|
|
|
|
|
this->symbols = target->symbols;
|
|
|
|
|
this->instructions = target->ir;
|
|
|
|
|
this->temps = temps;
|
2010-07-12 18:48:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ir_visitor_status visit(ir_dereference_variable *ir)
|
|
|
|
|
{
|
2016-09-28 16:04:05 +10:00
|
|
|
if (ir->var->data.mode == ir_var_temporary) {
|
|
|
|
|
hash_entry *entry = _mesa_hash_table_search(temps, ir->var);
|
|
|
|
|
ir_variable *var = entry ? (ir_variable *) entry->data : NULL;
|
|
|
|
|
|
|
|
|
|
assert(var != NULL);
|
|
|
|
|
ir->var = var;
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_variable *const existing =
|
|
|
|
|
this->symbols->get_variable(ir->var->name);
|
|
|
|
|
if (existing != NULL)
|
|
|
|
|
ir->var = existing;
|
|
|
|
|
else {
|
|
|
|
|
ir_variable *copy = ir->var->clone(this->target, NULL);
|
|
|
|
|
|
|
|
|
|
this->symbols->add_variable(copy);
|
|
|
|
|
this->instructions->push_head(copy);
|
|
|
|
|
ir->var = copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return visit_continue;
|
2010-07-12 18:48:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *target;
|
2010-07-12 18:48:50 -07:00
|
|
|
glsl_symbol_table *symbols;
|
|
|
|
|
exec_list *instructions;
|
2010-07-19 17:12:42 -07:00
|
|
|
hash_table *temps;
|
2010-07-12 18:48:50 -07:00
|
|
|
};
|
|
|
|
|
|
2010-08-04 12:34:56 -07:00
|
|
|
remap_visitor v(target, temps);
|
2010-07-12 18:48:50 -07:00
|
|
|
|
|
|
|
|
inst->accept(&v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Move non-declarations from one instruction stream to another
|
|
|
|
|
*
|
|
|
|
|
* The intended usage pattern of this function is to pass the pointer to the
|
2010-07-29 13:52:25 -07:00
|
|
|
* head sentinel of a list (i.e., a pointer to the list cast to an \c exec_node
|
2010-07-12 18:48:50 -07:00
|
|
|
* pointer) for \c last and \c false for \c make_copies on the first
|
|
|
|
|
* call. Successive calls pass the return value of the previous call for
|
|
|
|
|
* \c last and \c true for \c make_copies.
|
|
|
|
|
*
|
|
|
|
|
* \param instructions Source instruction stream
|
|
|
|
|
* \param last Instruction after which new instructions should be
|
|
|
|
|
* inserted in the target instruction stream
|
|
|
|
|
* \param make_copies Flag selecting whether instructions in \c instructions
|
|
|
|
|
* should be copied (via \c ir_instruction::clone) into the
|
|
|
|
|
* target list or moved.
|
|
|
|
|
*
|
|
|
|
|
* \return
|
|
|
|
|
* The new "last" instruction in the target instruction stream. This pointer
|
|
|
|
|
* is suitable for use as the \c last parameter of a later call to this
|
|
|
|
|
* function.
|
|
|
|
|
*/
|
2017-07-09 14:12:31 -07:00
|
|
|
static exec_node *
|
2010-07-12 18:48:50 -07:00
|
|
|
move_non_declarations(exec_list *instructions, exec_node *last,
|
2016-09-28 16:04:05 +10:00
|
|
|
bool make_copies, gl_linked_shader *target)
|
2010-07-12 18:48:50 -07:00
|
|
|
{
|
2010-07-19 17:12:42 -07:00
|
|
|
hash_table *temps = NULL;
|
|
|
|
|
|
|
|
|
|
if (make_copies)
|
2019-01-11 11:50:53 -08:00
|
|
|
temps = _mesa_pointer_hash_table_create(NULL);
|
2010-07-19 17:12:42 -07:00
|
|
|
|
2014-06-24 21:58:35 -07:00
|
|
|
foreach_in_list_safe(ir_instruction, inst, instructions) {
|
2010-07-19 17:12:42 -07:00
|
|
|
if (inst->as_function())
|
2016-09-28 16:04:05 +10:00
|
|
|
continue;
|
2010-07-19 17:12:42 -07:00
|
|
|
|
|
|
|
|
ir_variable *var = inst->as_variable();
|
2013-12-12 13:51:01 +02:00
|
|
|
if ((var != NULL) && (var->data.mode != ir_var_temporary))
|
2016-09-28 16:04:05 +10:00
|
|
|
continue;
|
2010-07-12 18:48:50 -07:00
|
|
|
|
2010-07-19 17:12:42 -07:00
|
|
|
assert(inst->as_assignment()
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
|| inst->as_call()
|
2012-10-24 13:17:24 -07:00
|
|
|
|| inst->as_if() /* for initializers with the ?: operator */
|
2016-09-28 16:04:05 +10:00
|
|
|
|| ((var != NULL) && (var->data.mode == ir_var_temporary)));
|
2010-07-12 18:48:50 -07:00
|
|
|
|
|
|
|
|
if (make_copies) {
|
2016-09-28 16:04:05 +10:00
|
|
|
inst = inst->clone(target, NULL);
|
2010-07-19 17:12:42 -07:00
|
|
|
|
2016-09-28 16:04:05 +10:00
|
|
|
if (var != NULL)
|
|
|
|
|
_mesa_hash_table_insert(temps, var, inst);
|
|
|
|
|
else
|
|
|
|
|
remap_variables(inst, target, temps);
|
2010-07-12 18:48:50 -07:00
|
|
|
} else {
|
2016-09-28 16:04:05 +10:00
|
|
|
inst->remove();
|
2010-07-12 18:48:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last->insert_after(inst);
|
|
|
|
|
last = inst;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-19 17:12:42 -07:00
|
|
|
if (make_copies)
|
2016-08-16 22:10:27 +02:00
|
|
|
_mesa_hash_table_destroy(temps, NULL);
|
2010-07-19 17:12:42 -07:00
|
|
|
|
2010-07-12 18:48:50 -07:00
|
|
|
return last;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-09 15:28:22 -07:00
|
|
|
|
2012-02-02 20:10:40 -07:00
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2016-11-02 13:35:30 -07:00
|
|
|
class array_sizing_visitor : public deref_type_updater {
|
2012-02-02 20:10:40 -07:00
|
|
|
public:
|
2020-02-03 12:43:19 -08:00
|
|
|
using deref_type_updater::visit;
|
|
|
|
|
|
2013-09-25 14:07:37 -07:00
|
|
|
array_sizing_visitor()
|
|
|
|
|
: mem_ctx(ralloc_context(NULL)),
|
2019-01-11 11:50:53 -08:00
|
|
|
unnamed_interfaces(_mesa_pointer_hash_table_create(NULL))
|
2013-09-25 14:07:37 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~array_sizing_visitor()
|
|
|
|
|
{
|
2016-08-16 22:10:27 +02:00
|
|
|
_mesa_hash_table_destroy(this->unnamed_interfaces, NULL);
|
2013-09-25 14:07:37 -07:00
|
|
|
ralloc_free(this->mem_ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-02 20:10:40 -07:00
|
|
|
virtual ir_visitor_status visit(ir_variable *var)
|
|
|
|
|
{
|
2015-03-12 19:52:47 +11:00
|
|
|
const glsl_type *type_without_array;
|
2016-05-25 13:31:41 +10:00
|
|
|
bool implicit_sized_array = var->data.implicit_sized_array;
|
2015-03-18 15:32:03 +01:00
|
|
|
fixup_type(&var->type, var->data.max_array_access,
|
2016-05-25 13:31:41 +10:00
|
|
|
var->data.from_ssbo_unsized_array,
|
|
|
|
|
&implicit_sized_array);
|
|
|
|
|
var->data.implicit_sized_array = implicit_sized_array;
|
2015-03-12 19:52:47 +11:00
|
|
|
type_without_array = var->type->without_array();
|
2013-09-23 10:44:19 -07:00
|
|
|
if (var->type->is_interface()) {
|
|
|
|
|
if (interface_contains_unsized_arrays(var->type)) {
|
|
|
|
|
const glsl_type *new_type =
|
2014-05-23 18:57:36 -07:00
|
|
|
resize_interface_members(var->type,
|
2015-03-18 15:32:03 +01:00
|
|
|
var->get_max_ifc_array_access(),
|
|
|
|
|
var->is_in_shader_storage_block());
|
2013-09-23 10:44:19 -07:00
|
|
|
var->type = new_type;
|
|
|
|
|
var->change_interface_type(new_type);
|
|
|
|
|
}
|
2015-03-12 19:52:47 +11:00
|
|
|
} else if (type_without_array->is_interface()) {
|
|
|
|
|
if (interface_contains_unsized_arrays(type_without_array)) {
|
2013-09-23 10:44:19 -07:00
|
|
|
const glsl_type *new_type =
|
2015-03-12 19:52:47 +11:00
|
|
|
resize_interface_members(type_without_array,
|
2015-03-18 15:32:03 +01:00
|
|
|
var->get_max_ifc_array_access(),
|
|
|
|
|
var->is_in_shader_storage_block());
|
2013-09-23 10:44:19 -07:00
|
|
|
var->change_interface_type(new_type);
|
2015-03-14 12:40:20 +11:00
|
|
|
var->type = update_interface_members_array(var->type, new_type);
|
2013-09-23 10:44:19 -07:00
|
|
|
}
|
2013-09-25 14:07:37 -07:00
|
|
|
} else if (const glsl_type *ifc_type = var->get_interface_type()) {
|
|
|
|
|
/* Store a pointer to the variable in the unnamed_interfaces
|
|
|
|
|
* hashtable.
|
|
|
|
|
*/
|
2016-08-16 22:10:27 +02:00
|
|
|
hash_entry *entry =
|
|
|
|
|
_mesa_hash_table_search(this->unnamed_interfaces,
|
|
|
|
|
ifc_type);
|
|
|
|
|
|
|
|
|
|
ir_variable **interface_vars = entry ? (ir_variable **) entry->data : NULL;
|
|
|
|
|
|
2013-09-25 14:07:37 -07:00
|
|
|
if (interface_vars == NULL) {
|
|
|
|
|
interface_vars = rzalloc_array(mem_ctx, ir_variable *,
|
|
|
|
|
ifc_type->length);
|
2016-08-16 22:10:27 +02:00
|
|
|
_mesa_hash_table_insert(this->unnamed_interfaces, ifc_type,
|
|
|
|
|
interface_vars);
|
2013-09-25 14:07:37 -07:00
|
|
|
}
|
|
|
|
|
unsigned index = ifc_type->field_index(var->name);
|
|
|
|
|
assert(index < ifc_type->length);
|
|
|
|
|
assert(interface_vars[index] == NULL);
|
|
|
|
|
interface_vars[index] = var;
|
2012-02-02 20:10:40 -07:00
|
|
|
}
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|
2013-09-23 10:44:19 -07:00
|
|
|
|
2013-09-25 14:07:37 -07:00
|
|
|
/**
|
|
|
|
|
* For each unnamed interface block that was discovered while running the
|
|
|
|
|
* visitor, adjust the interface type to reflect the newly assigned array
|
|
|
|
|
* sizes, and fix up the ir_variable nodes to point to the new interface
|
|
|
|
|
* type.
|
|
|
|
|
*/
|
|
|
|
|
void fixup_unnamed_interface_types()
|
|
|
|
|
{
|
|
|
|
|
hash_table_call_foreach(this->unnamed_interfaces,
|
|
|
|
|
fixup_unnamed_interface_type, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-23 10:44:19 -07:00
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* If the type pointed to by \c type represents an unsized array, replace
|
|
|
|
|
* it with a sized array whose size is determined by max_array_access.
|
|
|
|
|
*/
|
2015-03-18 15:32:03 +01:00
|
|
|
static void fixup_type(const glsl_type **type, unsigned max_array_access,
|
2016-05-25 13:31:41 +10:00
|
|
|
bool from_ssbo_unsized_array, bool *implicit_sized)
|
2013-09-23 10:44:19 -07:00
|
|
|
{
|
2015-03-18 15:32:03 +01:00
|
|
|
if (!from_ssbo_unsized_array && (*type)->is_unsized_array()) {
|
2013-09-23 10:44:19 -07:00
|
|
|
*type = glsl_type::get_array_instance((*type)->fields.array,
|
|
|
|
|
max_array_access + 1);
|
2016-05-25 13:31:41 +10:00
|
|
|
*implicit_sized = true;
|
2013-09-23 10:44:19 -07:00
|
|
|
assert(*type != NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-14 12:40:20 +11:00
|
|
|
static const glsl_type *
|
|
|
|
|
update_interface_members_array(const glsl_type *type,
|
|
|
|
|
const glsl_type *new_interface_type)
|
|
|
|
|
{
|
|
|
|
|
const glsl_type *element_type = type->fields.array;
|
|
|
|
|
if (element_type->is_array()) {
|
|
|
|
|
const glsl_type *new_array_type =
|
|
|
|
|
update_interface_members_array(element_type, new_interface_type);
|
|
|
|
|
return glsl_type::get_array_instance(new_array_type, type->length);
|
|
|
|
|
} else {
|
|
|
|
|
return glsl_type::get_array_instance(new_interface_type,
|
|
|
|
|
type->length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-23 10:44:19 -07:00
|
|
|
/**
|
|
|
|
|
* Determine whether the given interface type contains unsized arrays (if
|
|
|
|
|
* it doesn't, array_sizing_visitor doesn't need to process it).
|
|
|
|
|
*/
|
|
|
|
|
static bool interface_contains_unsized_arrays(const glsl_type *type)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < type->length; i++) {
|
|
|
|
|
const glsl_type *elem_type = type->fields.structure[i].type;
|
2013-10-23 21:31:27 +11:00
|
|
|
if (elem_type->is_unsized_array())
|
2013-09-23 10:44:19 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new interface type based on the given type, with unsized arrays
|
|
|
|
|
* replaced by sized arrays whose size is determined by
|
|
|
|
|
* max_ifc_array_access.
|
|
|
|
|
*/
|
|
|
|
|
static const glsl_type *
|
|
|
|
|
resize_interface_members(const glsl_type *type,
|
2016-05-20 10:19:14 +10:00
|
|
|
const int *max_ifc_array_access,
|
2015-03-18 15:32:03 +01:00
|
|
|
bool is_ssbo)
|
2013-09-23 10:44:19 -07:00
|
|
|
{
|
|
|
|
|
unsigned num_fields = type->length;
|
|
|
|
|
glsl_struct_field *fields = new glsl_struct_field[num_fields];
|
|
|
|
|
memcpy(fields, type->fields.structure,
|
|
|
|
|
num_fields * sizeof(*fields));
|
|
|
|
|
for (unsigned i = 0; i < num_fields; i++) {
|
2016-05-25 13:31:41 +10:00
|
|
|
bool implicit_sized_array = fields[i].implicit_sized_array;
|
2015-03-18 15:32:03 +01:00
|
|
|
/* If SSBO last member is unsized array, we don't replace it by a sized
|
|
|
|
|
* array.
|
|
|
|
|
*/
|
|
|
|
|
if (is_ssbo && i == (num_fields - 1))
|
|
|
|
|
fixup_type(&fields[i].type, max_ifc_array_access[i],
|
2016-05-25 13:31:41 +10:00
|
|
|
true, &implicit_sized_array);
|
2015-03-18 15:32:03 +01:00
|
|
|
else
|
|
|
|
|
fixup_type(&fields[i].type, max_ifc_array_access[i],
|
2016-05-25 13:31:41 +10:00
|
|
|
false, &implicit_sized_array);
|
|
|
|
|
fields[i].implicit_sized_array = implicit_sized_array;
|
2013-09-23 10:44:19 -07:00
|
|
|
}
|
|
|
|
|
glsl_interface_packing packing =
|
|
|
|
|
(glsl_interface_packing) type->interface_packing;
|
2016-10-21 13:15:41 +02:00
|
|
|
bool row_major = (bool) type->interface_row_major;
|
2013-09-23 10:44:19 -07:00
|
|
|
const glsl_type *new_ifc_type =
|
|
|
|
|
glsl_type::get_interface_instance(fields, num_fields,
|
2023-09-12 12:11:18 -07:00
|
|
|
packing, row_major, glsl_get_type_name(type));
|
2013-09-23 10:44:19 -07:00
|
|
|
delete [] fields;
|
|
|
|
|
return new_ifc_type;
|
|
|
|
|
}
|
2013-09-25 14:07:37 -07:00
|
|
|
|
|
|
|
|
static void fixup_unnamed_interface_type(const void *key, void *data,
|
|
|
|
|
void *)
|
|
|
|
|
{
|
|
|
|
|
const glsl_type *ifc_type = (const glsl_type *) key;
|
|
|
|
|
ir_variable **interface_vars = (ir_variable **) data;
|
|
|
|
|
unsigned num_fields = ifc_type->length;
|
|
|
|
|
glsl_struct_field *fields = new glsl_struct_field[num_fields];
|
|
|
|
|
memcpy(fields, ifc_type->fields.structure,
|
|
|
|
|
num_fields * sizeof(*fields));
|
|
|
|
|
bool interface_type_changed = false;
|
|
|
|
|
for (unsigned i = 0; i < num_fields; i++) {
|
|
|
|
|
if (interface_vars[i] != NULL &&
|
|
|
|
|
fields[i].type != interface_vars[i]->type) {
|
|
|
|
|
fields[i].type = interface_vars[i]->type;
|
|
|
|
|
interface_type_changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!interface_type_changed) {
|
|
|
|
|
delete [] fields;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
glsl_interface_packing packing =
|
|
|
|
|
(glsl_interface_packing) ifc_type->interface_packing;
|
2016-10-21 13:15:41 +02:00
|
|
|
bool row_major = (bool) ifc_type->interface_row_major;
|
2013-09-25 14:07:37 -07:00
|
|
|
const glsl_type *new_ifc_type =
|
|
|
|
|
glsl_type::get_interface_instance(fields, num_fields, packing,
|
2023-09-12 12:11:18 -07:00
|
|
|
row_major, glsl_get_type_name(ifc_type));
|
2013-09-25 14:07:37 -07:00
|
|
|
delete [] fields;
|
|
|
|
|
for (unsigned i = 0; i < num_fields; i++) {
|
|
|
|
|
if (interface_vars[i] != NULL)
|
|
|
|
|
interface_vars[i]->change_interface_type(new_ifc_type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Memory context used to allocate the data in \c unnamed_interfaces.
|
|
|
|
|
*/
|
|
|
|
|
void *mem_ctx;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hash table from const glsl_type * to an array of ir_variable *'s
|
|
|
|
|
* pointing to the ir_variables constituting each unnamed interface block.
|
|
|
|
|
*/
|
|
|
|
|
hash_table *unnamed_interfaces;
|
2012-02-02 20:10:40 -07:00
|
|
|
};
|
|
|
|
|
|
2016-11-22 20:24:33 +11:00
|
|
|
static bool
|
2022-01-07 10:35:02 +10:00
|
|
|
validate_xfb_buffer_stride(const struct gl_constants *consts, unsigned idx,
|
2016-11-22 20:24:33 +11:00
|
|
|
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 >
|
2022-01-07 10:35:02 +10:00
|
|
|
consts->MaxTransformFeedbackInterleavedComponents) {
|
2016-11-22 20:24:33 +11:00
|
|
|
linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
|
|
|
|
|
"limit has been exceeded.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 11:57:52 +11:00
|
|
|
/**
|
|
|
|
|
* Check for conflicting xfb_stride default qualifiers and store buffer stride
|
|
|
|
|
* for later use.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2022-01-07 10:35:02 +10:00
|
|
|
link_xfb_stride_layout_qualifiers(const struct gl_constants *consts,
|
2016-03-11 11:57:52 +11:00
|
|
|
struct gl_shader_program *prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
2016-03-11 11:57:52 +11:00
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
|
2016-11-22 20:24:33 +11:00
|
|
|
prog->TransformFeedback.BufferStride[i] = 0;
|
2016-03-11 11:57:52 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
|
|
|
|
|
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
2016-11-22 20:24:33 +11:00
|
|
|
if (shader->TransformFeedbackBufferStride[j]) {
|
|
|
|
|
if (prog->TransformFeedback.BufferStride[j] == 0) {
|
|
|
|
|
prog->TransformFeedback.BufferStride[j] =
|
|
|
|
|
shader->TransformFeedbackBufferStride[j];
|
2022-01-07 10:35:02 +10:00
|
|
|
if (!validate_xfb_buffer_stride(consts, j, prog))
|
2016-11-22 20:24:33 +11:00
|
|
|
return;
|
|
|
|
|
} else if (prog->TransformFeedback.BufferStride[j] !=
|
|
|
|
|
shader->TransformFeedbackBufferStride[j]){
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog,
|
2016-03-11 11:57:52 +11:00
|
|
|
"intrastage shaders defined with conflicting "
|
|
|
|
|
"xfb_stride for buffer %d (%d and %d)\n", j,
|
2016-11-22 20:24:33 +11:00
|
|
|
prog->TransformFeedback.BufferStride[j],
|
|
|
|
|
shader->TransformFeedbackBufferStride[j]);
|
2016-09-28 16:04:05 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2016-03-11 11:57:52 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-21 13:33:14 +12:00
|
|
|
|
2017-03-21 13:31:05 +01:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
|
|
bindless_sampler = bindless_image = false;
|
|
|
|
|
bound_sampler = bound_image = false;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 16:02:09 -04:00
|
|
|
/**
|
|
|
|
|
* Check for conflicting viewport_relative settings across shaders, and sets
|
|
|
|
|
* the value for the linked shader.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
link_layer_viewport_relative_qualifier(struct gl_shader_program *prog,
|
|
|
|
|
struct gl_program *gl_prog,
|
|
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/* Find first shader with explicit layer declaration */
|
|
|
|
|
for (i = 0; i < num_shaders; i++) {
|
|
|
|
|
if (shader_list[i]->redeclares_gl_layer) {
|
|
|
|
|
gl_prog->info.layer_viewport_relative =
|
|
|
|
|
shader_list[i]->layer_viewport_relative;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now make sure that each subsequent shader's explicit layer declaration
|
|
|
|
|
* matches the first one's.
|
|
|
|
|
*/
|
|
|
|
|
for (; i < num_shaders; i++) {
|
|
|
|
|
if (shader_list[i]->redeclares_gl_layer &&
|
|
|
|
|
shader_list[i]->layer_viewport_relative !=
|
|
|
|
|
gl_prog->info.layer_viewport_relative) {
|
|
|
|
|
linker_error(prog, "all gl_Layer redeclarations must have identical "
|
|
|
|
|
"viewport_relative settings");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 13:33:14 +12:00
|
|
|
/**
|
|
|
|
|
* Performs the cross-validation of tessellation control shader vertices and
|
|
|
|
|
* layout qualifiers for the attached tessellation control shaders,
|
|
|
|
|
* and propagates them to the linked TCS and linked shader program.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
link_tcs_out_layout_qualifiers(struct gl_shader_program *prog,
|
2016-11-22 13:10:18 +11:00
|
|
|
struct gl_program *gl_prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
2014-09-21 13:33:14 +12:00
|
|
|
{
|
2016-11-22 13:10:18 +11:00
|
|
|
if (gl_prog->info.stage != MESA_SHADER_TESS_CTRL)
|
2014-09-21 13:33:14 +12:00
|
|
|
return;
|
|
|
|
|
|
2016-11-22 13:10:18 +11:00
|
|
|
gl_prog->info.tess.tcs_vertices_out = 0;
|
|
|
|
|
|
2014-09-21 13:33:14 +12:00
|
|
|
/* From the GLSL 4.0 spec (chapter 4.3.8.2):
|
|
|
|
|
*
|
|
|
|
|
* "All tessellation control shader layout declarations in a program
|
|
|
|
|
* must specify the same output patch vertex count. There must be at
|
|
|
|
|
* least one layout qualifier specifying an output patch vertex count
|
|
|
|
|
* in any program containing tessellation control shaders; however,
|
|
|
|
|
* such a declaration is not required in all tessellation control
|
|
|
|
|
* shaders."
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.TessCtrl.VerticesOut != 0) {
|
2016-11-22 13:10:18 +11:00
|
|
|
if (gl_prog->info.tess.tcs_vertices_out != 0 &&
|
|
|
|
|
gl_prog->info.tess.tcs_vertices_out !=
|
|
|
|
|
(unsigned) shader->info.TessCtrl.VerticesOut) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "tessellation control shader defined with "
|
|
|
|
|
"conflicting output vertex count (%d and %d)\n",
|
2016-11-22 13:10:18 +11:00
|
|
|
gl_prog->info.tess.tcs_vertices_out,
|
2016-09-28 16:04:05 +10:00
|
|
|
shader->info.TessCtrl.VerticesOut);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 13:10:18 +11:00
|
|
|
gl_prog->info.tess.tcs_vertices_out =
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.TessCtrl.VerticesOut;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just do the intrastage -> interstage propagation right now,
|
|
|
|
|
* since we already know we're in the right type of shader program
|
|
|
|
|
* for doing it.
|
|
|
|
|
*/
|
2016-11-22 13:10:18 +11:00
|
|
|
if (gl_prog->info.tess.tcs_vertices_out == 0) {
|
2014-09-21 13:33:14 +12:00
|
|
|
linker_error(prog, "tessellation control shader didn't declare "
|
2016-09-28 16:04:05 +10:00
|
|
|
"vertices out layout qualifier\n");
|
2014-09-21 13:33:14 +12:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Performs the cross-validation of tessellation evaluation shader
|
|
|
|
|
* primitive type, vertex spacing, ordering and point_mode layout qualifiers
|
|
|
|
|
* for the attached tessellation evaluation shaders, and propagates them
|
|
|
|
|
* to the linked TES and linked shader program.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
link_tes_in_layout_qualifiers(struct gl_shader_program *prog,
|
2016-11-22 21:14:14 +11:00
|
|
|
struct gl_program *gl_prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
2014-09-21 13:33:14 +12:00
|
|
|
{
|
2016-11-22 21:14:14 +11:00
|
|
|
if (gl_prog->info.stage != MESA_SHADER_TESS_EVAL)
|
2014-09-21 13:33:14 +12:00
|
|
|
return;
|
|
|
|
|
|
2016-11-22 21:14:14 +11:00
|
|
|
int point_mode = -1;
|
|
|
|
|
unsigned vertex_order = 0;
|
|
|
|
|
|
2022-01-19 11:43:15 +10:00
|
|
|
gl_prog->info.tess._primitive_mode = TESS_PRIMITIVE_UNSPECIFIED;
|
2016-11-22 21:14:14 +11:00
|
|
|
gl_prog->info.tess.spacing = TESS_SPACING_UNSPECIFIED;
|
|
|
|
|
|
2014-09-21 13:33:14 +12:00
|
|
|
/* From the GLSL 4.0 spec (chapter 4.3.8.1):
|
|
|
|
|
*
|
|
|
|
|
* "At least one tessellation evaluation shader (compilation unit) in
|
|
|
|
|
* a program must declare a primitive mode in its input layout.
|
|
|
|
|
* Declaration vertex spacing, ordering, and point mode identifiers is
|
|
|
|
|
* optional. It is not required that all tessellation evaluation
|
|
|
|
|
* shaders in a program declare a primitive mode. If spacing or
|
|
|
|
|
* vertex ordering declarations are omitted, the tessellation
|
|
|
|
|
* primitive generator will use equal spacing or counter-clockwise
|
|
|
|
|
* vertex ordering, respectively. If a point mode declaration is
|
|
|
|
|
* omitted, the tessellation primitive generator will produce lines or
|
|
|
|
|
* triangles according to the primitive mode."
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
|
2022-01-19 11:43:15 +10:00
|
|
|
if (shader->info.TessEval._PrimitiveMode != TESS_PRIMITIVE_UNSPECIFIED) {
|
|
|
|
|
if (gl_prog->info.tess._primitive_mode != TESS_PRIMITIVE_UNSPECIFIED &&
|
|
|
|
|
gl_prog->info.tess._primitive_mode !=
|
|
|
|
|
shader->info.TessEval._PrimitiveMode) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "tessellation evaluation shader defined with "
|
|
|
|
|
"conflicting input primitive modes.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-01-19 11:43:15 +10:00
|
|
|
gl_prog->info.tess._primitive_mode =
|
|
|
|
|
shader->info.TessEval._PrimitiveMode;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.TessEval.Spacing != 0) {
|
2016-11-22 21:14:14 +11:00
|
|
|
if (gl_prog->info.tess.spacing != 0 && gl_prog->info.tess.spacing !=
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.TessEval.Spacing) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "tessellation evaluation shader defined with "
|
|
|
|
|
"conflicting vertex spacing.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 21:14:14 +11:00
|
|
|
gl_prog->info.tess.spacing = shader->info.TessEval.Spacing;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.TessEval.VertexOrder != 0) {
|
2016-11-22 21:14:14 +11:00
|
|
|
if (vertex_order != 0 &&
|
|
|
|
|
vertex_order != shader->info.TessEval.VertexOrder) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "tessellation evaluation shader defined with "
|
|
|
|
|
"conflicting ordering.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 21:14:14 +11:00
|
|
|
vertex_order = shader->info.TessEval.VertexOrder;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.TessEval.PointMode != -1) {
|
2016-11-22 21:14:14 +11:00
|
|
|
if (point_mode != -1 &&
|
|
|
|
|
point_mode != shader->info.TessEval.PointMode) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "tessellation evaluation shader defined with "
|
|
|
|
|
"conflicting point modes.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 21:14:14 +11:00
|
|
|
point_mode = shader->info.TessEval.PointMode;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just do the intrastage -> interstage propagation right now,
|
|
|
|
|
* since we already know we're in the right type of shader program
|
|
|
|
|
* for doing it.
|
|
|
|
|
*/
|
2022-01-19 11:43:15 +10:00
|
|
|
if (gl_prog->info.tess._primitive_mode == TESS_PRIMITIVE_UNSPECIFIED) {
|
2014-09-21 13:33:14 +12:00
|
|
|
linker_error(prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
"tessellation evaluation shader didn't declare input "
|
|
|
|
|
"primitive modes.\n");
|
2014-09-21 13:33:14 +12:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-22 21:14:14 +11:00
|
|
|
if (gl_prog->info.tess.spacing == TESS_SPACING_UNSPECIFIED)
|
|
|
|
|
gl_prog->info.tess.spacing = TESS_SPACING_EQUAL;
|
|
|
|
|
|
2017-01-23 18:06:37 +11:00
|
|
|
if (vertex_order == 0 || vertex_order == GL_CCW)
|
2016-11-22 21:14:14 +11:00
|
|
|
gl_prog->info.tess.ccw = true;
|
|
|
|
|
else
|
|
|
|
|
gl_prog->info.tess.ccw = false;
|
2014-09-21 13:33:14 +12:00
|
|
|
|
|
|
|
|
|
2017-01-23 18:06:37 +11:00
|
|
|
if (point_mode == -1 || point_mode == GL_FALSE)
|
2016-11-22 21:14:14 +11:00
|
|
|
gl_prog->info.tess.point_mode = false;
|
|
|
|
|
else
|
|
|
|
|
gl_prog->info.tess.point_mode = true;
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-02-05 15:01:58 -08:00
|
|
|
/**
|
|
|
|
|
* Performs the cross-validation of layout qualifiers specified in
|
|
|
|
|
* redeclaration of gl_FragCoord for the attached fragment shaders,
|
|
|
|
|
* and propagates them to the linked FS and linked shader program.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2016-06-28 10:00:18 -07:00
|
|
|
link_fs_inout_layout_qualifiers(struct gl_shader_program *prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_linked_shader *linked_shader,
|
|
|
|
|
struct gl_shader **shader_list,
|
2023-09-08 13:36:04 +10:00
|
|
|
unsigned num_shaders,
|
|
|
|
|
bool arb_fragment_coord_conventions_enable)
|
2014-02-05 15:01:58 -08:00
|
|
|
{
|
2016-11-22 18:25:20 +11:00
|
|
|
bool redeclares_gl_fragcoord = false;
|
2016-11-22 18:37:06 +11:00
|
|
|
bool uses_gl_fragcoord = false;
|
2016-11-22 18:50:03 +11:00
|
|
|
bool origin_upper_left = false;
|
2016-11-22 19:47:48 +11:00
|
|
|
bool pixel_center_integer = false;
|
2014-02-05 15:01:58 -08:00
|
|
|
|
2014-02-10 14:12:40 -08:00
|
|
|
if (linked_shader->Stage != MESA_SHADER_FRAGMENT ||
|
2023-09-08 13:36:04 +10:00
|
|
|
(prog->GLSL_Version < 150 && !arb_fragment_coord_conventions_enable))
|
2014-02-05 15:01:58 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
/* From the GLSL 1.50 spec, page 39:
|
|
|
|
|
*
|
|
|
|
|
* "If gl_FragCoord is redeclared in any fragment shader in a program,
|
|
|
|
|
* it must be redeclared in all the fragment shaders in that program
|
|
|
|
|
* that have a static use gl_FragCoord."
|
|
|
|
|
*/
|
2016-11-22 18:25:20 +11:00
|
|
|
if ((redeclares_gl_fragcoord && !shader->redeclares_gl_fragcoord &&
|
2016-11-22 18:37:06 +11:00
|
|
|
shader->uses_gl_fragcoord)
|
2016-11-22 18:25:20 +11:00
|
|
|
|| (shader->redeclares_gl_fragcoord && !redeclares_gl_fragcoord &&
|
2016-11-22 18:37:06 +11:00
|
|
|
uses_gl_fragcoord)) {
|
2014-02-05 15:01:58 -08:00
|
|
|
linker_error(prog, "fragment shader defined with conflicting "
|
|
|
|
|
"layout qualifiers for gl_FragCoord\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* From the GLSL 1.50 spec, page 39:
|
|
|
|
|
*
|
|
|
|
|
* "All redeclarations of gl_FragCoord in all fragment shaders in a
|
|
|
|
|
* single program must have the same set of qualifiers."
|
|
|
|
|
*/
|
2016-11-22 18:25:20 +11:00
|
|
|
if (redeclares_gl_fragcoord && shader->redeclares_gl_fragcoord &&
|
2016-11-22 18:50:03 +11:00
|
|
|
(shader->origin_upper_left != origin_upper_left ||
|
2016-11-22 19:47:48 +11:00
|
|
|
shader->pixel_center_integer != pixel_center_integer)) {
|
2014-02-05 15:01:58 -08:00
|
|
|
linker_error(prog, "fragment shader defined with conflicting "
|
|
|
|
|
"layout qualifiers for gl_FragCoord\n");
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 15:51:09 +03:00
|
|
|
/* Update the linked shader state. Note that uses_gl_fragcoord should
|
|
|
|
|
* accumulate the results. The other values should replace. If there
|
2014-02-05 15:01:58 -08:00
|
|
|
* are multiple redeclarations, all the fields except uses_gl_fragcoord
|
|
|
|
|
* are already known to be the same.
|
|
|
|
|
*/
|
2016-11-22 18:37:06 +11:00
|
|
|
if (shader->redeclares_gl_fragcoord || shader->uses_gl_fragcoord) {
|
2016-11-22 18:25:20 +11:00
|
|
|
redeclares_gl_fragcoord = shader->redeclares_gl_fragcoord;
|
2016-11-22 18:37:06 +11:00
|
|
|
uses_gl_fragcoord |= shader->uses_gl_fragcoord;
|
2016-11-22 18:50:03 +11:00
|
|
|
origin_upper_left = shader->origin_upper_left;
|
2016-11-22 19:47:48 +11:00
|
|
|
pixel_center_integer = shader->pixel_center_integer;
|
2014-02-05 15:01:58 -08:00
|
|
|
}
|
2015-01-28 17:42:37 +02:00
|
|
|
|
2016-11-22 13:10:18 +11:00
|
|
|
linked_shader->Program->info.fs.early_fragment_tests |=
|
2017-02-22 09:06:31 +01:00
|
|
|
shader->EarlyFragmentTests || shader->PostDepthCoverage;
|
2016-12-20 09:44:20 +11:00
|
|
|
linked_shader->Program->info.fs.inner_coverage |= shader->InnerCoverage;
|
2016-12-06 21:32:36 +02:00
|
|
|
linked_shader->Program->info.fs.post_depth_coverage |=
|
2016-12-20 09:39:00 +11:00
|
|
|
shader->PostDepthCoverage;
|
2018-04-27 14:12:30 +01:00
|
|
|
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;
|
2021-09-10 17:06:43 -07:00
|
|
|
linked_shader->Program->info.fs.advanced_blend_modes |= shader->BlendSupport;
|
2014-02-05 15:01:58 -08:00
|
|
|
}
|
nir, glsl: move pixel_center_integer/origin_upper_left to shader_info.fs
On GLSL that info is set as a layout qualifier when redeclaring
gl_FragCoord, so somehow tied to a specific variable. But in practice,
they behave as a global of the shader. On ARB programs they are set
using a global OPTION (defined at ARB_fragment_coord_conventions), and
on SPIR-V using ExecutionModes, that are also not tied specifically to
the builtin.
This patch moves that info from nir variable and ir variable to nir
shader and gl_program shader_info respectively, so the map is more
similar to SPIR-V, and ARB programs, instead of more similar to GLSL.
FWIW, shader_info.fs already had pixel_center_integer, so this change
also removes some redundancy. Also, as struct gl_program also includes
a shader_info, we removed gl_program::OriginUpperLeft and
PixelCenterInteger, as it would be superfluous.
This change was needed because recently spirv_to_nir changed the order
in which execution modes and variables are handled, so the variables
didn't get the correct values. Now the info is set on the shader
itself, and we don't need to go back to the builtin variable to set
it.
Fixes: e68871f6a ("spirv: Handle constants and types before execution
modes")
v2: (Jason)
* glsl_to_nir: get the info before glsl_to_nir, while all the rest
of the info gathering is happening
* prog_to_nir: gather the info on a general info-gathering pass,
not on variable setup.
v3: (Jason)
* Squash with the patch that removes that info from ir variable
* anv: assert that OriginUpperLeft is true. It should be already
set by spirv_to_nir.
* blorp: set origin_upper_left on its core "compile fragment
shader", not just on some specific places (for this we added an
helper on a previous patch).
* prog_to_nir: no need to gather specifically this fragcoord modes
as the full gl_program shader_info is copied.
* spirv_to_nir: assert that we are a fragment shader when handling
this execution modes.
v4: (reported by failing gitlab pipeline #18750)
* state_tracker: update too due changes on ir.h/gl_program
v5:
* blorp: minor change after change on previous patch
* radeonsi: update due this change.
v6: (Timothy Arceri)
* prog_to_nir: remove extra whitespace
* shader_info: don't use :1 on origin_upper_left
* glsl: program.fs.origin_upper_left/pixel_center_integer can be
move out of the shader list loop
2019-02-07 18:43:58 +01:00
|
|
|
|
|
|
|
|
linked_shader->Program->info.fs.pixel_center_integer = pixel_center_integer;
|
|
|
|
|
linked_shader->Program->info.fs.origin_upper_left = origin_upper_left;
|
2014-02-05 15:01:58 -08:00
|
|
|
}
|
|
|
|
|
|
2013-06-12 18:12:40 -07:00
|
|
|
/**
|
|
|
|
|
* Performs the cross-validation of geometry shader max_vertices and
|
|
|
|
|
* primitive type layout qualifiers for the attached geometry shaders,
|
|
|
|
|
* and propagates them to the linked GS and linked shader program.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
|
2016-11-22 21:45:16 +11:00
|
|
|
struct gl_program *gl_prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
2013-06-12 18:12:40 -07:00
|
|
|
{
|
|
|
|
|
/* No in/out qualifiers defined for anything but GLSL 1.50+
|
|
|
|
|
* geometry shaders so far.
|
|
|
|
|
*/
|
2023-02-08 15:28:08 +01:00
|
|
|
if (gl_prog->info.stage != MESA_SHADER_GEOMETRY || prog->GLSL_Version < 150)
|
2013-06-12 18:12:40 -07:00
|
|
|
return;
|
|
|
|
|
|
2016-11-22 21:45:16 +11:00
|
|
|
int vertices_out = -1;
|
|
|
|
|
|
|
|
|
|
gl_prog->info.gs.invocations = 0;
|
2023-06-01 23:03:34 +08:00
|
|
|
gl_prog->info.gs.input_primitive = MESA_PRIM_UNKNOWN;
|
|
|
|
|
gl_prog->info.gs.output_primitive = MESA_PRIM_UNKNOWN;
|
2016-11-22 21:45:16 +11:00
|
|
|
|
2013-06-12 18:12:40 -07:00
|
|
|
/* From the GLSL 1.50 spec, page 46:
|
|
|
|
|
*
|
|
|
|
|
* "All geometry shader output layout declarations in a program
|
|
|
|
|
* must declare the same layout and same value for
|
|
|
|
|
* max_vertices. There must be at least one geometry output
|
|
|
|
|
* layout declaration somewhere in a program, but not all
|
|
|
|
|
* geometry shaders (compilation units) are required to
|
|
|
|
|
* declare it."
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[i];
|
|
|
|
|
|
2023-06-01 23:03:34 +08:00
|
|
|
if (shader->info.Geom.InputType != MESA_PRIM_UNKNOWN) {
|
|
|
|
|
if (gl_prog->info.gs.input_primitive != MESA_PRIM_UNKNOWN &&
|
2016-11-22 21:45:16 +11:00
|
|
|
gl_prog->info.gs.input_primitive !=
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.Geom.InputType) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "geometry shader defined with conflicting "
|
|
|
|
|
"input types\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-06-01 23:03:34 +08:00
|
|
|
gl_prog->info.gs.input_primitive = (enum mesa_prim)shader->info.Geom.InputType;
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-01 23:03:34 +08:00
|
|
|
if (shader->info.Geom.OutputType != MESA_PRIM_UNKNOWN) {
|
|
|
|
|
if (gl_prog->info.gs.output_primitive != MESA_PRIM_UNKNOWN &&
|
2016-11-22 21:45:16 +11:00
|
|
|
gl_prog->info.gs.output_primitive !=
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.Geom.OutputType) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "geometry shader defined with conflicting "
|
|
|
|
|
"output types\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-06-01 23:03:34 +08:00
|
|
|
gl_prog->info.gs.output_primitive = (enum mesa_prim)shader->info.Geom.OutputType;
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.Geom.VerticesOut != -1) {
|
2016-11-22 21:45:16 +11:00
|
|
|
if (vertices_out != -1 &&
|
|
|
|
|
vertices_out != shader->info.Geom.VerticesOut) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "geometry shader defined with conflicting "
|
|
|
|
|
"output vertex count (%d and %d)\n",
|
2016-11-22 21:45:16 +11:00
|
|
|
vertices_out, shader->info.Geom.VerticesOut);
|
2016-09-28 16:04:05 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 21:45:16 +11:00
|
|
|
vertices_out = shader->info.Geom.VerticesOut;
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
2014-01-25 02:17:21 -08:00
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.Geom.Invocations != 0) {
|
2016-11-22 21:45:16 +11:00
|
|
|
if (gl_prog->info.gs.invocations != 0 &&
|
|
|
|
|
gl_prog->info.gs.invocations !=
|
|
|
|
|
(unsigned) shader->info.Geom.Invocations) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "geometry shader defined with conflicting "
|
|
|
|
|
"invocation count (%d and %d)\n",
|
2016-11-22 21:45:16 +11:00
|
|
|
gl_prog->info.gs.invocations,
|
2016-09-28 16:04:05 +10:00
|
|
|
shader->info.Geom.Invocations);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-22 21:45:16 +11:00
|
|
|
gl_prog->info.gs.invocations = shader->info.Geom.Invocations;
|
2014-01-25 02:17:21 -08:00
|
|
|
}
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just do the intrastage -> interstage propagation right now,
|
|
|
|
|
* since we already know we're in the right type of shader program
|
|
|
|
|
* for doing it.
|
|
|
|
|
*/
|
2023-06-01 23:03:34 +08:00
|
|
|
if (gl_prog->info.gs.input_primitive == MESA_PRIM_UNKNOWN) {
|
2013-06-12 18:12:40 -07:00
|
|
|
linker_error(prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
"geometry shader didn't declare primitive input type\n");
|
2013-06-12 18:12:40 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-01 23:03:34 +08:00
|
|
|
if (gl_prog->info.gs.output_primitive == MESA_PRIM_UNKNOWN) {
|
2013-06-12 18:12:40 -07:00
|
|
|
linker_error(prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
"geometry shader didn't declare primitive output type\n");
|
2013-06-12 18:12:40 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-22 21:45:16 +11:00
|
|
|
if (vertices_out == -1) {
|
2013-06-12 18:12:40 -07:00
|
|
|
linker_error(prog,
|
2016-09-28 16:04:05 +10:00
|
|
|
"geometry shader didn't declare max_vertices\n");
|
2013-06-12 18:12:40 -07:00
|
|
|
return;
|
2016-11-22 21:45:16 +11:00
|
|
|
} else {
|
|
|
|
|
gl_prog->info.gs.vertices_out = vertices_out;
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
2014-01-25 02:17:21 -08:00
|
|
|
|
2016-11-22 21:45:16 +11:00
|
|
|
if (gl_prog->info.gs.invocations == 0)
|
|
|
|
|
gl_prog->info.gs.invocations = 1;
|
2013-06-12 18:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
2014-01-08 11:59:28 -08:00
|
|
|
|
|
|
|
|
/**
|
2019-03-26 00:04:57 -07:00
|
|
|
* Perform cross-validation of compute shader local_size_{x,y,z} layout and
|
|
|
|
|
* derivative arrangement qualifiers for the attached compute shaders, and
|
|
|
|
|
* propagate them to the linked CS and linked shader program.
|
2014-01-08 11:59:28 -08:00
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
|
2016-11-22 23:31:08 +11:00
|
|
|
struct gl_program *gl_prog,
|
2014-01-08 11:59:28 -08:00
|
|
|
struct gl_shader **shader_list,
|
|
|
|
|
unsigned num_shaders)
|
|
|
|
|
{
|
|
|
|
|
/* This function is called for all shader stages, but it only has an effect
|
|
|
|
|
* for compute shaders.
|
|
|
|
|
*/
|
2016-11-22 23:31:08 +11:00
|
|
|
if (gl_prog->info.stage != MESA_SHADER_COMPUTE)
|
2014-01-08 11:59:28 -08:00
|
|
|
return;
|
|
|
|
|
|
2016-11-22 23:31:08 +11:00
|
|
|
for (int i = 0; i < 3; i++)
|
2021-05-05 12:24:44 -07:00
|
|
|
gl_prog->info.workgroup_size[i] = 0;
|
2016-11-22 23:31:08 +11:00
|
|
|
|
2021-05-05 12:24:44 -07:00
|
|
|
gl_prog->info.workgroup_size_variable = false;
|
2016-11-22 23:31:08 +11:00
|
|
|
|
2019-03-26 00:04:57 -07:00
|
|
|
gl_prog->info.cs.derivative_group = DERIVATIVE_GROUP_NONE;
|
|
|
|
|
|
2014-01-08 11:59:28 -08:00
|
|
|
/* From the ARB_compute_shader spec, in the section describing local size
|
|
|
|
|
* declarations:
|
|
|
|
|
*
|
|
|
|
|
* If multiple compute shaders attached to a single program object
|
|
|
|
|
* declare local work-group size, the declarations must be identical;
|
|
|
|
|
* otherwise a link-time error results. Furthermore, if a program
|
|
|
|
|
* object contains any compute shaders, at least one must contain an
|
|
|
|
|
* input layout qualifier specifying the local work sizes of the
|
|
|
|
|
* program, or a link-time error will occur.
|
|
|
|
|
*/
|
|
|
|
|
for (unsigned sh = 0; sh < num_shaders; sh++) {
|
|
|
|
|
struct gl_shader *shader = shader_list[sh];
|
|
|
|
|
|
2016-06-30 14:44:59 +10:00
|
|
|
if (shader->info.Comp.LocalSize[0] != 0) {
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[0] != 0) {
|
2014-01-08 11:59:28 -08:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[i] !=
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.Comp.LocalSize[i]) {
|
2014-01-08 11:59:28 -08:00
|
|
|
linker_error(prog, "compute shader defined with conflicting "
|
|
|
|
|
"local sizes\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-30 14:44:59 +10:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2021-05-05 12:24:44 -07:00
|
|
|
gl_prog->info.workgroup_size[i] =
|
2016-06-30 14:44:59 +10:00
|
|
|
shader->info.Comp.LocalSize[i];
|
|
|
|
|
}
|
2016-09-06 22:46:42 +02:00
|
|
|
} else if (shader->info.Comp.LocalSizeVariable) {
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[0] != 0) {
|
2016-09-06 22:46:42 +02:00
|
|
|
/* The ARB_compute_variable_group_size spec says:
|
|
|
|
|
*
|
|
|
|
|
* If one compute shader attached to a program declares a
|
|
|
|
|
* variable local group size and a second compute shader
|
|
|
|
|
* attached to the same program declares a fixed local group
|
|
|
|
|
* size, a link-time error results.
|
|
|
|
|
*/
|
|
|
|
|
linker_error(prog, "compute shader defined with both fixed and "
|
|
|
|
|
"variable local group size\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-05 12:24:44 -07:00
|
|
|
gl_prog->info.workgroup_size_variable = true;
|
2014-01-08 11:59:28 -08:00
|
|
|
}
|
2019-03-26 00:04:57 -07:00
|
|
|
|
|
|
|
|
enum gl_derivative_group group = shader->info.Comp.DerivativeGroup;
|
|
|
|
|
if (group != DERIVATIVE_GROUP_NONE) {
|
|
|
|
|
if (gl_prog->info.cs.derivative_group != DERIVATIVE_GROUP_NONE &&
|
|
|
|
|
gl_prog->info.cs.derivative_group != group) {
|
|
|
|
|
linker_error(prog, "compute shader defined with conflicting "
|
|
|
|
|
"derivative groups\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
gl_prog->info.cs.derivative_group = group;
|
|
|
|
|
}
|
2014-01-08 11:59:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just do the intrastage -> interstage propagation right now,
|
|
|
|
|
* since we already know we're in the right type of shader program
|
|
|
|
|
* for doing it.
|
|
|
|
|
*/
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[0] == 0 &&
|
|
|
|
|
!gl_prog->info.workgroup_size_variable) {
|
2016-09-06 22:46:42 +02:00
|
|
|
linker_error(prog, "compute shader must contain a fixed or a variable "
|
|
|
|
|
"local group size\n");
|
2014-01-08 11:59:28 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2019-03-26 00:04:57 -07:00
|
|
|
|
|
|
|
|
if (gl_prog->info.cs.derivative_group == DERIVATIVE_GROUP_QUADS) {
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[0] % 2 != 0) {
|
2019-03-26 00:04:57 -07:00
|
|
|
linker_error(prog, "derivative_group_quadsNV must be used with a "
|
|
|
|
|
"local group size whose first dimension "
|
|
|
|
|
"is a multiple of 2\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-05 12:24:44 -07:00
|
|
|
if (gl_prog->info.workgroup_size[1] % 2 != 0) {
|
2019-03-26 00:04:57 -07:00
|
|
|
linker_error(prog, "derivative_group_quadsNV must be used with a local"
|
|
|
|
|
"group size whose second dimension "
|
|
|
|
|
"is a multiple of 2\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (gl_prog->info.cs.derivative_group == DERIVATIVE_GROUP_LINEAR) {
|
2021-05-05 12:24:44 -07:00
|
|
|
if ((gl_prog->info.workgroup_size[0] *
|
|
|
|
|
gl_prog->info.workgroup_size[1] *
|
|
|
|
|
gl_prog->info.workgroup_size[2]) % 4 != 0) {
|
2019-03-26 00:04:57 -07:00
|
|
|
linker_error(prog, "derivative_group_linearNV must be used with a "
|
|
|
|
|
"local group size whose total number of invocations "
|
|
|
|
|
"is a multiple of 4\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-01-08 11:59:28 -08:00
|
|
|
}
|
|
|
|
|
|
2018-08-28 10:32:18 +03:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
|
2018-10-24 13:28:23 +03:00
|
|
|
ir_variable *var = (ir_variable *) ir;
|
2018-08-28 10:32:18 +03:00
|
|
|
|
|
|
|
|
if (var->data.mode == ir_var_shader_out &&
|
|
|
|
|
!symbols->get_variable(var->name)) {
|
2018-10-24 13:28:23 +03:00
|
|
|
var = var->clone(linked_shader, NULL);
|
2018-08-28 10:32:18 +03:00
|
|
|
symbols->add_variable(var);
|
|
|
|
|
linked_shader->ir->push_head(var);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 11:59:28 -08:00
|
|
|
|
2010-07-09 14:09:34 -07:00
|
|
|
/**
|
|
|
|
|
* Combine a group of shaders for a single stage to generate a linked shader
|
|
|
|
|
*
|
|
|
|
|
* \note
|
|
|
|
|
* If this function is supplied a single shader, it is cloned, and the new
|
|
|
|
|
* shader is returned.
|
|
|
|
|
*/
|
2016-09-15 11:09:34 -07:00
|
|
|
struct gl_linked_shader *
|
2010-11-17 11:03:57 -08:00
|
|
|
link_intrastage_shaders(void *mem_ctx,
|
2016-09-28 16:04:05 +10:00
|
|
|
struct gl_context *ctx,
|
|
|
|
|
struct gl_shader_program *prog,
|
|
|
|
|
struct gl_shader **shader_list,
|
2016-09-15 11:09:34 -07:00
|
|
|
unsigned num_shaders,
|
|
|
|
|
bool allow_missing_main)
|
2010-07-09 14:09:34 -07:00
|
|
|
{
|
2023-09-08 13:36:04 +10:00
|
|
|
bool arb_fragment_coord_conventions_enable = false;
|
2012-04-27 13:52:56 -07:00
|
|
|
|
2010-06-29 18:53:38 -07:00
|
|
|
/* Check that global variables defined in multiple shaders are consistent.
|
|
|
|
|
*/
|
2016-06-27 15:38:51 +10:00
|
|
|
glsl_symbol_table variables;
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
if (shader_list[i] == NULL)
|
2016-09-28 16:04:05 +10:00
|
|
|
continue;
|
2022-01-07 12:37:56 +10:00
|
|
|
cross_validate_globals(&ctx->Const, prog, shader_list[i]->ir, &variables,
|
2018-06-14 11:00:24 +10:00
|
|
|
false);
|
2023-09-08 13:36:04 +10:00
|
|
|
if (shader_list[i]->ARB_fragment_coord_conventions_enable)
|
|
|
|
|
arb_fragment_coord_conventions_enable = true;
|
2016-06-27 15:38:51 +10:00
|
|
|
}
|
|
|
|
|
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
2010-06-29 18:53:38 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
2013-05-20 23:42:49 -07:00
|
|
|
/* Check that interface blocks defined in multiple shaders are consistent.
|
|
|
|
|
*/
|
2013-07-27 11:08:31 -07:00
|
|
|
validate_intrastage_interface_blocks(prog, (const gl_shader **)shader_list,
|
|
|
|
|
num_shaders);
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
2013-05-20 23:42:49 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
2010-06-29 18:53:38 -07:00
|
|
|
/* Check that there is only a single definition of each function signature
|
|
|
|
|
* across all shaders.
|
|
|
|
|
*/
|
|
|
|
|
for (unsigned i = 0; i < (num_shaders - 1); i++) {
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_instruction, node, shader_list[i]->ir) {
|
2016-09-28 16:04:05 +10:00
|
|
|
ir_function *const f = node->as_function();
|
|
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (unsigned j = i + 1; j < num_shaders; j++) {
|
|
|
|
|
ir_function *const other =
|
|
|
|
|
shader_list[j]->symbols->get_function(f->name);
|
|
|
|
|
|
|
|
|
|
/* If the other shader has no function (and therefore no function
|
|
|
|
|
* signatures) with the same name, skip to the next shader.
|
|
|
|
|
*/
|
|
|
|
|
if (other == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
foreach_in_list(ir_function_signature, sig, &f->signatures) {
|
|
|
|
|
if (!sig->is_defined)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ir_function_signature *other_sig =
|
|
|
|
|
other->exact_matching_signature(NULL, &sig->parameters);
|
|
|
|
|
|
|
|
|
|
if (other_sig != NULL && other_sig->is_defined) {
|
|
|
|
|
linker_error(prog, "function `%s' is multiply defined\n",
|
|
|
|
|
f->name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-29 18:53:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the shader that defines main, and make a clone of it.
|
|
|
|
|
*
|
|
|
|
|
* Starting with the clone, search for undefined references. If one is
|
|
|
|
|
* found, find the shader that defines it. Clone the reference and add
|
|
|
|
|
* it to the shader. Repeat until there are no undefined references or
|
|
|
|
|
* until a reference cannot be resolved.
|
|
|
|
|
*/
|
2010-07-09 15:28:22 -07:00
|
|
|
gl_shader *main = NULL;
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
2016-06-30 14:55:40 +10:00
|
|
|
if (_mesa_get_main_function_signature(shader_list[i]->symbols)) {
|
2016-09-28 16:04:05 +10:00
|
|
|
main = shader_list[i];
|
|
|
|
|
break;
|
2010-07-09 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
}
|
2010-06-29 18:53:38 -07:00
|
|
|
|
2016-09-15 11:09:34 -07:00
|
|
|
if (main == NULL && allow_missing_main)
|
|
|
|
|
main = shader_list[0];
|
|
|
|
|
|
2010-07-09 15:28:22 -07:00
|
|
|
if (main == NULL) {
|
2011-07-28 14:04:09 -07:00
|
|
|
linker_error(prog, "%s shader lacks `main'\n",
|
2016-09-28 16:04:05 +10:00
|
|
|
_mesa_shader_stage_to_string(shader_list[0]->Stage));
|
2010-07-09 15:28:22 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-06-29 18:53:38 -07:00
|
|
|
|
2016-11-04 13:51:59 +11:00
|
|
|
gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
|
|
|
|
|
linked->Stage = shader_list[0]->Stage;
|
2016-10-31 23:54:03 +11:00
|
|
|
|
|
|
|
|
/* Create program and attach it to the linked shader */
|
|
|
|
|
struct gl_program *gl_prog =
|
2020-03-31 10:03:55 -04:00
|
|
|
ctx->Driver.NewProgram(ctx, shader_list[0]->Stage, prog->Name, false);
|
2016-11-22 13:19:33 +11:00
|
|
|
if (!gl_prog) {
|
2018-01-25 12:50:12 -07:00
|
|
|
prog->data->LinkStatus = LINKING_FAILURE;
|
2016-10-31 23:54:03 +11:00
|
|
|
_mesa_delete_linked_shader(ctx, linked);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-07 13:31:55 +10:00
|
|
|
_mesa_reference_shader_program_data(&gl_prog->sh.data, prog->data);
|
2016-12-20 21:37:25 +11:00
|
|
|
|
2016-10-31 23:54:03 +11:00
|
|
|
/* Don't use _mesa_reference_program() just take ownership */
|
|
|
|
|
linked->Program = gl_prog;
|
|
|
|
|
|
2010-07-09 14:09:34 -07:00
|
|
|
linked->ir = new(linked) exec_list;
|
2010-11-17 11:03:57 -08:00
|
|
|
clone_ir_list(mem_ctx, linked->ir, main->ir);
|
2010-07-09 14:09:34 -07:00
|
|
|
|
2023-09-08 13:36:04 +10:00
|
|
|
link_fs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders,
|
|
|
|
|
arb_fragment_coord_conventions_enable);
|
2016-11-22 13:10:18 +11:00
|
|
|
link_tcs_out_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
|
2016-11-22 21:14:14 +11:00
|
|
|
link_tes_in_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
|
2016-11-22 21:45:16 +11:00
|
|
|
link_gs_inout_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
|
2016-11-22 23:31:08 +11:00
|
|
|
link_cs_input_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
|
2017-06-22 12:47:57 +02:00
|
|
|
|
|
|
|
|
if (linked->Stage != MESA_SHADER_FRAGMENT)
|
2022-01-07 10:35:02 +10:00
|
|
|
link_xfb_stride_layout_qualifiers(&ctx->Const, prog, shader_list, num_shaders);
|
2017-06-22 12:47:57 +02:00
|
|
|
|
glsl: Silence unused parameter warnings
glsl/ast_type.cpp: In function ‘void merge_bindless_qualifier(YYLTYPE*, _mesa_glsl_parse_state*, const ast_type_qualifier&, const ast_type_qualifier&)’:
glsl/ast_type.cpp:189:35: warning: unused parameter ‘loc’ [-Wunused-parameter]
merge_bindless_qualifier(YYLTYPE *loc,
^~~
glsl/ast_type.cpp:191:52: warning: unused parameter ‘qualifier’ [-Wunused-parameter]
const ast_type_qualifier &qualifier,
^~~~~~~~~
glsl/ast_type.cpp:192:52: warning: unused parameter ‘new_qualifier’ [-Wunused-parameter]
const ast_type_qualifier &new_qualifier)
^~~~~~~~~~~~~
glsl/ir_constant_expression.cpp: In member function ‘virtual ir_constant* ir_rvalue::constant_expression_value(void*, hash_table*)’:
glsl/ir_constant_expression.cpp:512:44: warning: unused parameter ‘mem_ctx’ [-Wunused-parameter]
ir_rvalue::constant_expression_value(void *mem_ctx, struct hash_table *)
^~~~~~~
glsl/ir_constant_expression.cpp: In member function ‘virtual ir_constant* ir_texture::constant_expression_value(void*, hash_table*)’:
glsl/ir_constant_expression.cpp:705:45: warning: unused parameter ‘mem_ctx’ [-Wunused-parameter]
ir_texture::constant_expression_value(void *mem_ctx, struct hash_table *)
^~~~~~~
glsl/ir_constant_expression.cpp: In member function ‘virtual ir_constant* ir_assignment::constant_expression_value(void*, hash_table*)’:
glsl/ir_constant_expression.cpp:851:48: warning: unused parameter ‘mem_ctx’ [-Wunused-parameter]
ir_assignment::constant_expression_value(void *mem_ctx, struct hash_table *)
^~~~~~~
glsl/ir_constant_expression.cpp: In member function ‘virtual ir_constant* ir_constant::constant_expression_value(void*, hash_table*)’:
glsl/ir_constant_expression.cpp:859:46: warning: unused parameter ‘mem_ctx’ [-Wunused-parameter]
ir_constant::constant_expression_value(void *mem_ctx, struct hash_table *)
^~~~~~~
glsl/linker.cpp: In function ‘void link_xfb_stride_layout_qualifiers(gl_context*, gl_shader_program*, gl_linked_shader*, gl_shader**, unsigned int)’:
glsl/linker.cpp:1655:60: warning: unused parameter ‘linked_shader’ [-Wunused-parameter]
struct gl_linked_shader *linked_shader,
^~~~~~~~~~~~~
glsl/linker.cpp: In function ‘void link_bindless_layout_qualifiers(gl_shader_program*, gl_program*, gl_shader**, unsigned int)’:
glsl/linker.cpp:1693:52: warning: unused parameter ‘gl_prog’ [-Wunused-parameter]
struct gl_program *gl_prog,
^~~~~~~
glsl/lower_distance.cpp: In member function ‘virtual void {anonymous}::lower_distance_visitor_counter::handle_rvalue(ir_rvalue**)’:
glsl/lower_distance.cpp:652:59: warning: unused parameter ‘rv’ [-Wunused-parameter]
lower_distance_visitor_counter::handle_rvalue(ir_rvalue **rv)
^~
glsl/opt_array_splitting.cpp: In member function ‘virtual ir_visitor_status {anonymous}::ir_array_reference_visitor::visit_leave(ir_assignment*)’:
glsl/opt_array_splitting.cpp:198:56: warning: unused parameter ‘ir’ [-Wunused-parameter]
ir_array_reference_visitor::visit_leave(ir_assignment *ir)
^~
glsl/glsl_parser_extras.cpp: In function ‘void assign_subroutine_indexes(gl_shader*, _mesa_glsl_parse_state*)’:
glsl/glsl_parser_extras.cpp:1869:45: warning: unused parameter ‘sh’ [-Wunused-parameter]
assign_subroutine_indexes(struct gl_shader *sh,
^~
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Reviewed-by: Elie Tournier <elie.tournier@collabora.com>
2017-09-07 18:40:11 -07:00
|
|
|
link_bindless_layout_qualifiers(prog, shader_list, num_shaders);
|
2013-06-12 18:12:40 -07:00
|
|
|
|
2020-04-10 16:02:09 -04:00
|
|
|
link_layer_viewport_relative_qualifier(prog, gl_prog, shader_list, num_shaders);
|
|
|
|
|
|
2017-03-05 20:28:42 +01:00
|
|
|
populate_symbol_table(linked, shader_list[0]->symbols);
|
2010-07-09 14:09:34 -07:00
|
|
|
|
2014-10-24 16:51:09 +03:00
|
|
|
/* The pointer to the main function in the final linked shader (i.e., the
|
2010-07-12 18:48:50 -07:00
|
|
|
* copy of the original shader that contained the main function).
|
|
|
|
|
*/
|
2014-06-19 12:05:20 -07:00
|
|
|
ir_function_signature *const main_sig =
|
2016-06-27 16:25:00 +10:00
|
|
|
_mesa_get_main_function_signature(linked->symbols);
|
2010-07-12 18:48:50 -07:00
|
|
|
|
|
|
|
|
/* Move any instructions other than variable declarations or function
|
|
|
|
|
* declarations into main.
|
|
|
|
|
*/
|
2016-09-15 11:09:34 -07:00
|
|
|
if (main_sig != NULL) {
|
|
|
|
|
exec_node *insertion_point =
|
2021-11-17 00:46:19 +01:00
|
|
|
move_non_declarations(linked->ir, &main_sig->body.head_sentinel, false,
|
2016-09-15 11:09:34 -07:00
|
|
|
linked);
|
2010-07-19 12:33:54 -07:00
|
|
|
|
2016-09-15 11:09:34 -07:00
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
if (shader_list[i] == main)
|
|
|
|
|
continue;
|
2010-07-19 12:33:54 -07:00
|
|
|
|
2016-09-15 11:09:34 -07:00
|
|
|
insertion_point = move_non_declarations(shader_list[i]->ir,
|
|
|
|
|
insertion_point, true, linked);
|
|
|
|
|
}
|
2010-07-12 18:48:50 -07:00
|
|
|
}
|
|
|
|
|
|
2014-11-11 22:32:27 -08:00
|
|
|
if (!link_function_calls(prog, linked, shader_list, num_shaders)) {
|
2016-06-30 14:55:40 +10:00
|
|
|
_mesa_delete_linked_shader(ctx, linked);
|
2013-08-02 00:35:05 -07:00
|
|
|
return NULL;
|
2010-10-13 15:13:02 -07:00
|
|
|
}
|
2010-07-20 11:29:46 -07:00
|
|
|
|
2018-08-28 10:32:18 +03:00
|
|
|
if (linked->Stage != MESA_SHADER_FRAGMENT)
|
|
|
|
|
link_output_variables(linked, shader_list, num_shaders);
|
|
|
|
|
|
2016-05-25 13:31:41 +10:00
|
|
|
/* 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.
|
|
|
|
|
*/
|
|
|
|
|
array_sizing_visitor v;
|
|
|
|
|
v.run(linked->ir);
|
|
|
|
|
v.fixup_unnamed_interface_types();
|
|
|
|
|
|
2021-07-14 20:39:45 +03:00
|
|
|
/* Now that we know the sizes of all the arrays, we can replace .length()
|
|
|
|
|
* calls with a constant expression.
|
|
|
|
|
*/
|
|
|
|
|
array_length_to_const_visitor len_v;
|
|
|
|
|
len_v.run(linked->ir);
|
|
|
|
|
|
2017-11-08 09:54:22 +11:00
|
|
|
if (!prog->data->LinkStatus) {
|
|
|
|
|
_mesa_delete_linked_shader(ctx, linked);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-05-25 13:31:41 +10:00
|
|
|
|
2011-08-03 15:37:01 -07:00
|
|
|
/* At this point linked should contain all of the linked IR, so
|
|
|
|
|
* validate it to make sure nothing went wrong.
|
|
|
|
|
*/
|
2013-08-02 00:35:05 -07:00
|
|
|
validate_ir_tree(linked->ir);
|
2011-08-03 15:37:01 -07:00
|
|
|
|
2013-07-30 21:13:48 -07:00
|
|
|
/* Set the size of geometry shader input arrays */
|
2014-01-07 10:58:56 -08:00
|
|
|
if (linked->Stage == MESA_SHADER_GEOMETRY) {
|
2016-11-22 21:45:16 +11:00
|
|
|
unsigned num_vertices =
|
2023-08-21 18:09:22 -05:00
|
|
|
mesa_vertices_per_prim(gl_prog->info.gs.input_primitive);
|
2016-07-08 13:29:31 -07:00
|
|
|
array_resize_visitor input_resize_visitor(num_vertices, prog,
|
|
|
|
|
MESA_SHADER_GEOMETRY);
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_instruction, ir, linked->ir) {
|
2013-07-30 21:13:48 -07:00
|
|
|
ir->accept(&input_resize_visitor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 09:15:27 -05:00
|
|
|
/* Set the linked source SHA1. */
|
|
|
|
|
if (num_shaders == 1) {
|
|
|
|
|
memcpy(linked->linked_source_sha1, shader_list[0]->compiled_source_sha1,
|
|
|
|
|
SHA1_DIGEST_LENGTH);
|
|
|
|
|
} else {
|
|
|
|
|
struct mesa_sha1 sha1_ctx;
|
|
|
|
|
_mesa_sha1_init(&sha1_ctx);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_shaders; i++) {
|
|
|
|
|
if (shader_list[i] == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
_mesa_sha1_update(&sha1_ctx, shader_list[i]->compiled_source_sha1,
|
|
|
|
|
SHA1_DIGEST_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
_mesa_sha1_final(&sha1_ctx, linked->linked_source_sha1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-09 14:09:34 -07:00
|
|
|
return linked;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 13:33:14 +12:00
|
|
|
/**
|
|
|
|
|
* Resize tessellation evaluation per-vertex inputs to the size of
|
|
|
|
|
* tessellation control per-vertex outputs.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2022-01-07 10:37:35 +10:00
|
|
|
resize_tes_inputs(const struct gl_constants *consts,
|
2014-09-21 13:33:14 +12:00
|
|
|
struct gl_shader_program *prog)
|
|
|
|
|
{
|
|
|
|
|
if (prog->_LinkedShaders[MESA_SHADER_TESS_EVAL] == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-06-30 14:55:40 +10:00
|
|
|
gl_linked_shader *const tcs = prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
|
|
|
|
|
gl_linked_shader *const tes = prog->_LinkedShaders[MESA_SHADER_TESS_EVAL];
|
2014-09-21 13:33:14 +12:00
|
|
|
|
|
|
|
|
/* If no control shader is present, then the TES inputs are statically
|
|
|
|
|
* sized to MaxPatchVertices; the actual size of the arrays won't be
|
|
|
|
|
* known until draw time.
|
|
|
|
|
*/
|
|
|
|
|
const int num_vertices = tcs
|
2016-11-22 13:10:18 +11:00
|
|
|
? tcs->Program->info.tess.tcs_vertices_out
|
2022-01-07 10:37:35 +10:00
|
|
|
: consts->MaxPatchVertices;
|
2014-09-21 13:33:14 +12:00
|
|
|
|
2016-07-08 13:29:31 -07:00
|
|
|
array_resize_visitor input_resize_visitor(num_vertices, prog,
|
|
|
|
|
MESA_SHADER_TESS_EVAL);
|
2014-09-21 13:33:14 +12:00
|
|
|
foreach_in_list(ir_instruction, ir, tes->ir) {
|
|
|
|
|
ir->accept(&input_resize_visitor);
|
|
|
|
|
}
|
2015-07-28 18:16:37 -07:00
|
|
|
|
2018-01-08 09:45:15 +01:00
|
|
|
if (tcs) {
|
2015-07-28 18:16:37 -07:00
|
|
|
/* Convert the gl_PatchVerticesIn system value into a constant, since
|
|
|
|
|
* the value is known at this point.
|
|
|
|
|
*/
|
|
|
|
|
foreach_in_list(ir_instruction, ir, tes->ir) {
|
|
|
|
|
ir_variable *var = ir->as_variable();
|
|
|
|
|
if (var && var->data.mode == ir_var_system_value &&
|
|
|
|
|
var->data.location == SYSTEM_VALUE_VERTICES_IN) {
|
|
|
|
|
void *mem_ctx = ralloc_parent(var);
|
|
|
|
|
var->data.location = 0;
|
2016-05-26 20:21:58 -07:00
|
|
|
var->data.explicit_location = false;
|
2018-01-08 09:45:15 +01:00
|
|
|
var->data.mode = ir_var_auto;
|
|
|
|
|
var->constant_value = new(mem_ctx) ir_constant(num_vertices);
|
2015-07-28 18:16:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
|
|
|
|
|
2014-04-08 08:45:36 +03:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes explicit location slots to INACTIVE_UNIFORM_EXPLICIT_LOCATION
|
|
|
|
|
* for a variable, checks for overlaps between other uniforms using explicit
|
|
|
|
|
* locations.
|
|
|
|
|
*/
|
2016-02-11 15:00:02 +02:00
|
|
|
static int
|
2014-04-08 08:45:36 +03:00
|
|
|
reserve_explicit_locations(struct gl_shader_program *prog,
|
|
|
|
|
string_to_uint_map *map, ir_variable *var)
|
|
|
|
|
{
|
|
|
|
|
unsigned slots = var->type->uniform_locations();
|
|
|
|
|
unsigned max_loc = var->data.location + slots - 1;
|
2016-02-11 15:00:02 +02:00
|
|
|
unsigned return_value = slots;
|
2014-04-08 08:45:36 +03:00
|
|
|
|
|
|
|
|
/* Resize remap table if locations do not fit in the current one. */
|
|
|
|
|
if (max_loc + 1 > prog->NumUniformRemapTable) {
|
|
|
|
|
prog->UniformRemapTable =
|
|
|
|
|
reralloc(prog, prog->UniformRemapTable,
|
|
|
|
|
gl_uniform_storage *,
|
|
|
|
|
max_loc + 1);
|
|
|
|
|
|
|
|
|
|
if (!prog->UniformRemapTable) {
|
2014-11-18 08:43:35 -07:00
|
|
|
linker_error(prog, "Out of memory during linking.\n");
|
2016-02-11 15:00:02 +02:00
|
|
|
return -1;
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize allocated space. */
|
|
|
|
|
for (unsigned i = prog->NumUniformRemapTable; i < max_loc + 1; i++)
|
|
|
|
|
prog->UniformRemapTable[i] = NULL;
|
|
|
|
|
|
|
|
|
|
prog->NumUniformRemapTable = max_loc + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < slots; i++) {
|
|
|
|
|
unsigned loc = var->data.location + i;
|
|
|
|
|
|
|
|
|
|
/* Check if location is already used. */
|
|
|
|
|
if (prog->UniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) {
|
|
|
|
|
|
|
|
|
|
/* Possibly same uniform from a different stage, this is ok. */
|
|
|
|
|
unsigned hash_loc;
|
2016-02-11 15:00:02 +02:00
|
|
|
if (map->get(hash_loc, var->name) && hash_loc == loc - i) {
|
|
|
|
|
return_value = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-04-08 08:45:36 +03:00
|
|
|
|
|
|
|
|
/* ARB_explicit_uniform_location specification states:
|
|
|
|
|
*
|
|
|
|
|
* "No two default-block uniform variables in the program can have
|
|
|
|
|
* the same location, even if they are unused, otherwise a compiler
|
|
|
|
|
* or linker error will be generated."
|
|
|
|
|
*/
|
|
|
|
|
linker_error(prog,
|
2014-11-13 15:31:44 +00:00
|
|
|
"location qualifier for uniform %s overlaps "
|
2014-11-18 08:43:35 -07:00
|
|
|
"previously used location\n",
|
2014-04-08 08:45:36 +03:00
|
|
|
var->name);
|
2016-02-11 15:00:02 +02:00
|
|
|
return -1;
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize location as inactive before optimization
|
|
|
|
|
* rounds and location assignment.
|
|
|
|
|
*/
|
|
|
|
|
prog->UniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Note, base location used for arrays. */
|
|
|
|
|
map->put(var->data.location, var->name);
|
|
|
|
|
|
2016-02-11 15:00:02 +02:00
|
|
|
return return_value;
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
|
2015-04-20 10:27:36 +10:00
|
|
|
static bool
|
|
|
|
|
reserve_subroutine_explicit_locations(struct gl_shader_program *prog,
|
2016-12-29 08:56:43 +11:00
|
|
|
struct gl_program *p,
|
2015-04-20 10:27:36 +10:00
|
|
|
ir_variable *var)
|
|
|
|
|
{
|
|
|
|
|
unsigned slots = var->type->uniform_locations();
|
|
|
|
|
unsigned max_loc = var->data.location + slots - 1;
|
|
|
|
|
|
|
|
|
|
/* Resize remap table if locations do not fit in the current one. */
|
2016-12-29 08:56:43 +11:00
|
|
|
if (max_loc + 1 > p->sh.NumSubroutineUniformRemapTable) {
|
|
|
|
|
p->sh.SubroutineUniformRemapTable =
|
|
|
|
|
reralloc(p, p->sh.SubroutineUniformRemapTable,
|
2015-04-20 10:27:36 +10:00
|
|
|
gl_uniform_storage *,
|
|
|
|
|
max_loc + 1);
|
|
|
|
|
|
2016-12-29 08:56:43 +11:00
|
|
|
if (!p->sh.SubroutineUniformRemapTable) {
|
2015-04-20 10:27:36 +10:00
|
|
|
linker_error(prog, "Out of memory during linking.\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize allocated space. */
|
2016-12-29 08:56:43 +11:00
|
|
|
for (unsigned i = p->sh.NumSubroutineUniformRemapTable; i < max_loc + 1; i++)
|
|
|
|
|
p->sh.SubroutineUniformRemapTable[i] = NULL;
|
2015-04-20 10:27:36 +10:00
|
|
|
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.NumSubroutineUniformRemapTable = max_loc + 1;
|
2015-04-20 10:27:36 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < slots; i++) {
|
|
|
|
|
unsigned loc = var->data.location + i;
|
|
|
|
|
|
|
|
|
|
/* Check if location is already used. */
|
2016-12-29 08:56:43 +11:00
|
|
|
if (p->sh.SubroutineUniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) {
|
2015-04-20 10:27:36 +10:00
|
|
|
|
|
|
|
|
/* ARB_explicit_uniform_location specification states:
|
|
|
|
|
* "No two subroutine uniform variables can have the same location
|
|
|
|
|
* in the same shader stage, otherwise a compiler or linker error
|
|
|
|
|
* will be generated."
|
|
|
|
|
*/
|
|
|
|
|
linker_error(prog,
|
|
|
|
|
"location qualifier for uniform %s overlaps "
|
|
|
|
|
"previously used location\n",
|
|
|
|
|
var->name);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize location as inactive before optimization
|
|
|
|
|
* rounds and location assignment.
|
|
|
|
|
*/
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.SubroutineUniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION;
|
2015-04-20 10:27:36 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-04-08 08:45:36 +03:00
|
|
|
/**
|
|
|
|
|
* Check and reserve all explicit uniform locations, called before
|
|
|
|
|
* any optimizations happen to handle also inactive uniforms and
|
|
|
|
|
* inactive array elements that may get trimmed away.
|
|
|
|
|
*/
|
2016-12-04 22:47:17 +11:00
|
|
|
static void
|
2022-01-07 12:37:56 +10:00
|
|
|
check_explicit_uniform_locations(const struct gl_extensions *exts,
|
2014-04-08 08:45:36 +03:00
|
|
|
struct gl_shader_program *prog)
|
|
|
|
|
{
|
2016-12-04 22:47:17 +11:00
|
|
|
prog->NumExplicitUniformLocations = 0;
|
|
|
|
|
|
2022-01-07 12:37:56 +10:00
|
|
|
if (!exts->ARB_explicit_uniform_location)
|
2016-12-04 22:47:17 +11:00
|
|
|
return;
|
2014-04-08 08:45:36 +03:00
|
|
|
|
|
|
|
|
/* This map is used to detect if overlapping explicit locations
|
|
|
|
|
* occur with the same uniform (from different stage) or a different one.
|
|
|
|
|
*/
|
|
|
|
|
string_to_uint_map *uniform_map = new string_to_uint_map;
|
|
|
|
|
|
|
|
|
|
if (!uniform_map) {
|
2014-11-18 08:43:35 -07:00
|
|
|
linker_error(prog, "Out of memory during linking.\n");
|
2016-12-04 22:47:17 +11:00
|
|
|
return;
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
|
2016-01-20 22:02:22 +02:00
|
|
|
unsigned entries_total = 0;
|
2016-11-02 14:28:12 +11:00
|
|
|
unsigned mask = prog->data->linked_stages;
|
|
|
|
|
while (mask) {
|
|
|
|
|
const int i = u_bit_scan(&mask);
|
2016-12-29 08:56:43 +11:00
|
|
|
struct gl_program *p = prog->_LinkedShaders[i]->Program;
|
2014-04-08 08:45:36 +03:00
|
|
|
|
2016-12-29 08:56:43 +11:00
|
|
|
foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) {
|
2014-06-24 21:34:05 -07:00
|
|
|
ir_variable *var = node->as_variable();
|
2016-01-08 08:20:25 +02:00
|
|
|
if (!var || var->data.mode != ir_var_uniform)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (var->data.explicit_location) {
|
2016-02-11 15:00:02 +02:00
|
|
|
bool ret = false;
|
2016-01-18 11:13:27 +11:00
|
|
|
if (var->type->without_array()->is_subroutine())
|
2016-12-29 08:56:43 +11:00
|
|
|
ret = reserve_subroutine_explicit_locations(prog, p, var);
|
2016-02-11 15:00:02 +02:00
|
|
|
else {
|
|
|
|
|
int slots = reserve_explicit_locations(prog, uniform_map,
|
|
|
|
|
var);
|
|
|
|
|
if (slots != -1) {
|
|
|
|
|
ret = true;
|
|
|
|
|
entries_total += slots;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-20 10:27:36 +10:00
|
|
|
if (!ret) {
|
2014-09-02 09:54:36 +10:00
|
|
|
delete uniform_map;
|
2016-12-04 22:47:17 +11:00
|
|
|
return;
|
2014-09-02 09:54:36 +10:00
|
|
|
}
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-20 22:02:22 +02:00
|
|
|
|
2018-06-26 16:28:59 +02:00
|
|
|
link_util_update_empty_uniform_locations(prog);
|
2016-02-11 15:00:02 +02:00
|
|
|
|
2014-04-08 08:45:36 +03:00
|
|
|
delete uniform_map;
|
2016-12-04 22:47:17 +11:00
|
|
|
prog->NumExplicitUniformLocations = entries_total;
|
2014-04-08 08:45:36 +03:00
|
|
|
}
|
|
|
|
|
|
2015-08-19 13:36:22 -07:00
|
|
|
static void
|
|
|
|
|
link_assign_subroutine_types(struct gl_shader_program *prog)
|
2015-04-20 10:27:36 +10:00
|
|
|
{
|
2016-11-02 14:28:12 +11:00
|
|
|
unsigned mask = prog->data->linked_stages;
|
|
|
|
|
while (mask) {
|
|
|
|
|
const int i = u_bit_scan(&mask);
|
2016-12-29 08:56:43 +11:00
|
|
|
gl_program *p = prog->_LinkedShaders[i]->Program;
|
2015-04-20 10:27:36 +10:00
|
|
|
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.MaxSubroutineFunctionIndex = 0;
|
|
|
|
|
foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) {
|
2015-04-20 10:27:36 +10:00
|
|
|
ir_function *fn = node->as_function();
|
|
|
|
|
if (!fn)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (fn->is_subroutine)
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.NumSubroutineUniformTypes++;
|
2015-04-20 10:27:36 +10:00
|
|
|
|
|
|
|
|
if (!fn->num_subroutine_types)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-09-28 16:04:05 +10:00
|
|
|
/* these should have been calculated earlier. */
|
|
|
|
|
assert(fn->subroutine_index != -1);
|
2016-12-29 08:56:43 +11:00
|
|
|
if (p->sh.NumSubroutineFunctions + 1 > MAX_SUBROUTINES) {
|
2016-05-17 14:52:38 +10:00
|
|
|
linker_error(prog, "Too many subroutine functions declared.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.SubroutineFunctions = reralloc(p, p->sh.SubroutineFunctions,
|
2015-04-20 10:27:36 +10:00
|
|
|
struct gl_subroutine_function,
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.NumSubroutineFunctions + 1);
|
2021-10-22 19:19:48 -04:00
|
|
|
p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].name.string = ralloc_strdup(p, fn->name);
|
|
|
|
|
resource_name_updated(&p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].name);
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].num_compat_types = fn->num_subroutine_types;
|
|
|
|
|
p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].types =
|
|
|
|
|
ralloc_array(p, const struct glsl_type *,
|
2015-04-20 10:27:36 +10:00
|
|
|
fn->num_subroutine_types);
|
2015-11-09 09:34:40 +11:00
|
|
|
|
|
|
|
|
/* From Section 4.4.4(Subroutine Function Layout Qualifiers) of the
|
|
|
|
|
* GLSL 4.5 spec:
|
|
|
|
|
*
|
|
|
|
|
* "Each subroutine with an index qualifier in the shader must be
|
|
|
|
|
* given a unique index, otherwise a compile or link error will be
|
|
|
|
|
* generated."
|
|
|
|
|
*/
|
2016-12-29 08:56:43 +11:00
|
|
|
for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
|
|
|
|
|
if (p->sh.SubroutineFunctions[j].index != -1 &&
|
|
|
|
|
p->sh.SubroutineFunctions[j].index == fn->subroutine_index) {
|
2015-11-09 09:34:40 +11:00
|
|
|
linker_error(prog, "each subroutine index qualifier in the "
|
|
|
|
|
"shader must be unique\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].index =
|
2015-11-09 09:34:40 +11:00
|
|
|
fn->subroutine_index;
|
|
|
|
|
|
2016-12-29 08:56:43 +11:00
|
|
|
if (fn->subroutine_index > (int)p->sh.MaxSubroutineFunctionIndex)
|
|
|
|
|
p->sh.MaxSubroutineFunctionIndex = fn->subroutine_index;
|
2016-05-17 14:44:47 +10:00
|
|
|
|
2015-04-20 10:27:36 +10:00
|
|
|
for (int j = 0; j < fn->num_subroutine_types; j++)
|
2016-12-29 08:56:43 +11:00
|
|
|
p->sh.SubroutineFunctions[p->sh.NumSubroutineFunctions].types[j] = fn->subroutine_types[j];
|
|
|
|
|
p->sh.NumSubroutineFunctions++;
|
2015-04-20 10:27:36 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-06 09:14:49 +02:00
|
|
|
|
2018-10-03 11:39:04 +03:00
|
|
|
static void
|
|
|
|
|
verify_subroutine_associated_funcs(struct gl_shader_program *prog)
|
|
|
|
|
{
|
|
|
|
|
unsigned mask = prog->data->linked_stages;
|
|
|
|
|
while (mask) {
|
|
|
|
|
const int i = u_bit_scan(&mask);
|
|
|
|
|
gl_program *p = prog->_LinkedShaders[i]->Program;
|
|
|
|
|
glsl_symbol_table *symbols = prog->_LinkedShaders[i]->symbols;
|
|
|
|
|
|
2018-10-10 13:51:28 +03:00
|
|
|
/* Section 6.1.2 (Subroutines) of the GLSL 4.00 spec says:
|
|
|
|
|
*
|
|
|
|
|
* "A program will fail to compile or link if any shader
|
|
|
|
|
* or stage contains two or more functions with the same
|
|
|
|
|
* name if the name is associated with a subroutine type."
|
2018-10-03 11:39:04 +03:00
|
|
|
*/
|
|
|
|
|
for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
|
|
|
|
|
unsigned definitions = 0;
|
2021-10-22 19:19:48 -04:00
|
|
|
char *name = p->sh.SubroutineFunctions[j].name.string;
|
2018-10-03 11:39:04 +03:00
|
|
|
ir_function *fn = symbols->get_function(name);
|
|
|
|
|
|
|
|
|
|
/* Calculate number of function definitions with the same name */
|
|
|
|
|
foreach_in_list(ir_function_signature, sig, &fn->signatures) {
|
|
|
|
|
if (sig->is_defined) {
|
|
|
|
|
if (++definitions > 1) {
|
|
|
|
|
linker_error(prog, "%s shader contains two or more function "
|
|
|
|
|
"definitions with name `%s', which is "
|
|
|
|
|
"associated with a subroutine type.\n",
|
|
|
|
|
_mesa_shader_stage_to_string(i),
|
|
|
|
|
fn->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
void
|
2010-10-12 12:26:10 -04:00
|
|
|
link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
2010-06-17 15:04:20 -07:00
|
|
|
{
|
2022-01-07 10:31:10 +10:00
|
|
|
const struct gl_constants *consts = &ctx->Const;
|
2018-01-25 12:50:12 -07:00
|
|
|
prog->data->LinkStatus = LINKING_SUCCESS; /* All error paths will set this to false */
|
2016-11-07 14:47:18 +11:00
|
|
|
prog->data->Validated = false;
|
2016-01-25 21:56:18 +11:00
|
|
|
|
|
|
|
|
/* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec says:
|
|
|
|
|
*
|
|
|
|
|
* "Linking can fail for a variety of reasons as specified in the
|
|
|
|
|
* OpenGL Shading Language Specification, as well as any of the
|
|
|
|
|
* following reasons:
|
|
|
|
|
*
|
|
|
|
|
* - No shader objects are attached to program."
|
|
|
|
|
*
|
|
|
|
|
* The Compatibility Profile specification does not list the error. In
|
|
|
|
|
* Compatibility Profile missing shader stages are replaced by
|
|
|
|
|
* fixed-function. This applies to the case where all stages are
|
|
|
|
|
* missing.
|
|
|
|
|
*/
|
|
|
|
|
if (prog->NumShaders == 0) {
|
|
|
|
|
if (ctx->API != API_OPENGL_COMPAT)
|
|
|
|
|
linker_error(prog, "no shaders attached to the program\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 16:27:53 +11:00
|
|
|
#ifdef ENABLE_SHADER_CACHE
|
2018-03-13 10:44:39 -07:00
|
|
|
if (shader_cache_read_program_metadata(ctx, prog))
|
2017-01-24 08:39:13 +11:00
|
|
|
return;
|
2017-02-17 16:27:53 +11:00
|
|
|
#endif
|
2017-01-24 08:39:13 +11:00
|
|
|
|
2011-01-21 14:32:31 -08:00
|
|
|
void *mem_ctx = ralloc_context(NULL); // temporary linker context
|
2023-12-18 16:16:18 +11:00
|
|
|
unsigned prev = MESA_SHADER_STAGES;
|
2010-11-17 11:03:57 -08:00
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
/* Separate the shaders into groups based on their type.
|
|
|
|
|
*/
|
2014-01-07 08:56:57 -08:00
|
|
|
struct gl_shader **shader_list[MESA_SHADER_STAGES];
|
|
|
|
|
unsigned num_shaders[MESA_SHADER_STAGES];
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
|
|
|
|
|
shader_list[i] = (struct gl_shader **)
|
|
|
|
|
calloc(prog->NumShaders, sizeof(struct gl_shader *));
|
|
|
|
|
num_shaders[i] = 0;
|
|
|
|
|
}
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2010-07-16 15:51:50 -07:00
|
|
|
unsigned min_version = UINT_MAX;
|
|
|
|
|
unsigned max_version = 0;
|
2010-06-17 15:04:20 -07:00
|
|
|
for (unsigned i = 0; i < prog->NumShaders; i++) {
|
2010-07-16 15:51:50 -07:00
|
|
|
min_version = MIN2(min_version, prog->Shaders[i]->Version);
|
|
|
|
|
max_version = MAX2(max_version, prog->Shaders[i]->Version);
|
|
|
|
|
|
2022-01-07 12:37:56 +10:00
|
|
|
if (!consts->AllowGLSLRelaxedES &&
|
2018-06-14 11:00:24 +10:00
|
|
|
prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) {
|
2016-09-28 16:04:05 +10:00
|
|
|
linker_error(prog, "all shaders must use same shading "
|
|
|
|
|
"language version\n");
|
|
|
|
|
goto done;
|
glsl: Clean up shading language mixing check for GLSL 3.00 ES.
Previously, we prohibited mixing of shading language versions if
min_version == 100 or max_version >= 130. This was technically
correct (since desktop GLSL 1.30 and beyond prohibit mixing of shading
language versions, as does GLSL 1.00 ES), but it was confusing. Also,
we asserted that all shading language versions were between 1.00 and
1.40, which was unnecessary (since the parser already checks shading
language versions) and doesn't work for GLSL 3.00 ES.
This patch changes the code to explicitly check that (a) ES shaders
aren't mixed with desktop shaders, (b) shaders aren't mixed between ES
versions, and (c) shaders aren't mixed between desktop GLSL versions
when at least one shader is GLSL 1.30 or greater. Also, it removes
the unnecessary assertion.
[v2, idr]: Slightly tweak the is_es_prog detection to occur outside the loop
instead of doing something special on the first loop iteration. Suggested by
Ken.
[v3, idr]: s/IsEs(Shader|Prog)/IsES/ Suggested by Ken and Eric.
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> [v1]
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Carl Worth <cworth@cworth.org>
2012-08-02 17:49:44 -07:00
|
|
|
}
|
|
|
|
|
|
2014-01-07 08:56:57 -08:00
|
|
|
gl_shader_stage shader_type = prog->Shaders[i]->Stage;
|
|
|
|
|
shader_list[shader_type][num_shaders[shader_type]] = prog->Shaders[i];
|
|
|
|
|
num_shaders[shader_type]++;
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
2013-10-13 18:01:11 -07:00
|
|
|
/* In desktop GLSL, different shader versions may be linked together. In
|
|
|
|
|
* GLSL ES, all shader versions must be the same.
|
2010-07-16 15:51:50 -07:00
|
|
|
*/
|
2022-01-07 12:37:56 +10:00
|
|
|
if (!consts->AllowGLSLRelaxedES && prog->Shaders[0]->IsES &&
|
2018-06-19 17:52:00 +10:00
|
|
|
min_version != max_version) {
|
2011-07-28 14:04:09 -07:00
|
|
|
linker_error(prog, "all shaders must use same shading "
|
2016-09-28 16:04:05 +10:00
|
|
|
"language version\n");
|
2010-07-16 15:51:50 -07:00
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 15:28:08 +01:00
|
|
|
prog->GLSL_Version = max_version;
|
2016-01-27 15:34:53 +11:00
|
|
|
prog->IsES = prog->Shaders[0]->IsES;
|
2010-07-16 15:51:50 -07:00
|
|
|
|
2014-09-21 13:33:14 +12:00
|
|
|
/* Some shaders have to be linked with some other shaders present.
|
2013-05-24 23:26:54 +02:00
|
|
|
*/
|
2016-01-27 15:42:58 +11:00
|
|
|
if (!prog->SeparateShader) {
|
|
|
|
|
if (num_shaders[MESA_SHADER_GEOMETRY] > 0 &&
|
|
|
|
|
num_shaders[MESA_SHADER_VERTEX] == 0) {
|
|
|
|
|
linker_error(prog, "Geometry shader must be linked with "
|
2016-09-28 16:04:05 +10:00
|
|
|
"vertex shader\n");
|
2016-01-27 15:42:58 +11:00
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (num_shaders[MESA_SHADER_TESS_EVAL] > 0 &&
|
|
|
|
|
num_shaders[MESA_SHADER_VERTEX] == 0) {
|
|
|
|
|
linker_error(prog, "Tessellation evaluation shader must be linked "
|
2016-09-28 16:04:05 +10:00
|
|
|
"with vertex shader\n");
|
2016-01-27 15:42:58 +11:00
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 &&
|
|
|
|
|
num_shaders[MESA_SHADER_VERTEX] == 0) {
|
|
|
|
|
linker_error(prog, "Tessellation control shader must be linked with "
|
2016-09-28 16:04:05 +10:00
|
|
|
"vertex shader\n");
|
2016-01-27 15:42:58 +11:00
|
|
|
goto done;
|
|
|
|
|
}
|
2014-09-21 13:33:14 +12:00
|
|
|
|
2017-02-10 20:56:38 -08:00
|
|
|
/* 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
|
2016-01-27 15:42:58 +11:00
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* More investigation showed that the idea of transform feedback after
|
|
|
|
|
* a tess control shader was dropped, because some hw vendors couldn't
|
|
|
|
|
* support tessellation without a tess eval shader, but the linker
|
|
|
|
|
* section wasn't updated to reflect that.
|
|
|
|
|
*
|
|
|
|
|
* All specifications (ARB_tessellation_shader, GL 4.0-4.5) have this
|
|
|
|
|
* spec bug.
|
|
|
|
|
*
|
|
|
|
|
* Do what's reasonable and always require a tess eval shader if a tess
|
|
|
|
|
* control shader is present.
|
|
|
|
|
*/
|
|
|
|
|
if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 &&
|
|
|
|
|
num_shaders[MESA_SHADER_TESS_EVAL] == 0) {
|
|
|
|
|
linker_error(prog, "Tessellation control shader must be linked with "
|
2016-09-28 16:04:05 +10:00
|
|
|
"tessellation evaluation shader\n");
|
2016-01-27 15:42:58 +11:00
|
|
|
goto done;
|
|
|
|
|
}
|
2017-02-22 17:16:01 -08:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-21 13:33:14 +12:00
|
|
|
}
|
2013-05-24 23:26:54 +02:00
|
|
|
|
2014-01-08 11:40:23 -08:00
|
|
|
/* Compute shaders have additional restrictions. */
|
|
|
|
|
if (num_shaders[MESA_SHADER_COMPUTE] > 0 &&
|
|
|
|
|
num_shaders[MESA_SHADER_COMPUTE] != prog->NumShaders) {
|
|
|
|
|
linker_error(prog, "Compute shaders may not be linked with any other "
|
|
|
|
|
"type of shader\n");
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-16 16:00:07 -07:00
|
|
|
/* Link all shaders for a particular stage and validate the result.
|
|
|
|
|
*/
|
2014-01-07 08:56:57 -08:00
|
|
|
for (int stage = 0; stage < MESA_SHADER_STAGES; stage++) {
|
|
|
|
|
if (num_shaders[stage] > 0) {
|
2016-06-30 14:55:40 +10:00
|
|
|
gl_linked_shader *const sh =
|
2014-01-07 08:56:57 -08:00
|
|
|
link_intrastage_shaders(mem_ctx, ctx, prog, shader_list[stage],
|
2016-09-15 11:09:34 -07:00
|
|
|
num_shaders[stage], false);
|
2010-06-18 17:13:42 -07:00
|
|
|
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus) {
|
2015-05-17 17:56:44 -04:00
|
|
|
if (sh)
|
2016-06-30 14:55:40 +10:00
|
|
|
_mesa_delete_linked_shader(ctx, sh);
|
2014-01-07 08:56:57 -08:00
|
|
|
goto done;
|
2015-05-17 17:56:44 -04:00
|
|
|
}
|
2010-07-09 14:09:34 -07:00
|
|
|
|
2014-01-07 08:56:57 -08:00
|
|
|
switch (stage) {
|
|
|
|
|
case MESA_SHADER_VERTEX:
|
2022-01-07 10:31:10 +10:00
|
|
|
validate_vertex_shader_executable(prog, sh, consts);
|
2014-01-07 08:56:57 -08:00
|
|
|
break;
|
2014-09-09 19:25:02 +12:00
|
|
|
case MESA_SHADER_TESS_CTRL:
|
|
|
|
|
/* nothing to be done */
|
|
|
|
|
break;
|
|
|
|
|
case MESA_SHADER_TESS_EVAL:
|
2022-01-07 10:31:10 +10:00
|
|
|
validate_tess_eval_shader_executable(prog, sh, consts);
|
2014-09-09 19:25:02 +12:00
|
|
|
break;
|
2014-01-07 08:56:57 -08:00
|
|
|
case MESA_SHADER_GEOMETRY:
|
2022-01-07 10:31:10 +10:00
|
|
|
validate_geometry_shader_executable(prog, sh, consts);
|
2014-01-07 08:56:57 -08:00
|
|
|
break;
|
|
|
|
|
case MESA_SHADER_FRAGMENT:
|
|
|
|
|
validate_fragment_shader_executable(prog, sh);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus) {
|
2015-05-17 17:56:44 -04:00
|
|
|
if (sh)
|
2016-06-30 14:55:40 +10:00
|
|
|
_mesa_delete_linked_shader(ctx, sh);
|
2014-01-07 08:56:57 -08:00
|
|
|
goto done;
|
2015-05-17 17:56:44 -04:00
|
|
|
}
|
2010-07-09 14:09:34 -07:00
|
|
|
|
2016-06-30 14:55:40 +10:00
|
|
|
prog->_LinkedShaders[stage] = sh;
|
2016-10-31 21:16:50 +11:00
|
|
|
prog->data->linked_stages |= 1 << stage;
|
2014-01-07 08:56:57 -08:00
|
|
|
}
|
2010-06-18 17:13:42 -07:00
|
|
|
}
|
2010-06-17 15:04:20 -07:00
|
|
|
|
2010-06-23 12:18:21 -07:00
|
|
|
/* Here begins the inter-stage linking phase. Some initial validation is
|
|
|
|
|
* performed, then locations are assigned for uniforms, attributes, and
|
|
|
|
|
* varyings.
|
|
|
|
|
*/
|
2022-01-07 12:37:56 +10:00
|
|
|
cross_validate_uniforms(consts, prog);
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
2013-07-27 11:08:31 -07:00
|
|
|
goto done;
|
2010-10-14 13:28:42 -07:00
|
|
|
|
2022-01-07 12:37:56 +10:00
|
|
|
check_explicit_uniform_locations(&ctx->Extensions, prog);
|
2017-11-08 09:54:22 +11:00
|
|
|
link_assign_subroutine_types(prog);
|
2018-10-03 11:39:04 +03:00
|
|
|
verify_subroutine_associated_funcs(prog);
|
2015-04-20 10:27:36 +10:00
|
|
|
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
2014-04-08 08:45:36 +03:00
|
|
|
goto done;
|
|
|
|
|
|
2022-01-07 10:37:35 +10:00
|
|
|
resize_tes_inputs(consts, prog);
|
2014-09-21 13:33:14 +12:00
|
|
|
|
2013-07-27 11:08:31 -07:00
|
|
|
/* Validate the inputs of each stage with the output of the preceding
|
|
|
|
|
* stage.
|
|
|
|
|
*/
|
2023-12-18 16:16:18 +11:00
|
|
|
for (unsigned i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
|
2013-07-27 11:08:31 -07:00
|
|
|
if (prog->_LinkedShaders[i] == NULL)
|
|
|
|
|
continue;
|
2013-05-20 23:46:16 -07:00
|
|
|
|
2023-12-18 16:16:18 +11:00
|
|
|
if (prev == MESA_SHADER_STAGES) {
|
|
|
|
|
prev = i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
glsl: Fix interstage uniform interface block link error detection.
Previously, we checked for interstage uniform interface block link
errors in validate_interstage_interface_blocks(), which is only called
on pairs of adjacent shader stages. Therefore, we failed to detect
uniform interface block mismatches between non-adjacent shader stages.
Before the introduction of geometry shaders, this wasn't a problem,
because the only supported shader stages were vertex and fragment
shaders, therefore they were always adjacent. However, now that we
allow a program to contain vertex, geometry, and fragment shaders,
that is no longer the case.
Fixes piglit test "skip-stage-uniform-block-array-size-mismatch".
Cc: "10.0" <mesa-stable@lists.freedesktop.org>
v2: Rename validate_interstage_interface_blocks() to
validate_interstage_inout_blocks() to reflect the fact that it no
longer validates uniform blocks.
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
v3: Make validate_interstage_inout_blocks() skip uniform blocks.
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2013-11-15 14:23:45 -08:00
|
|
|
validate_interstage_inout_blocks(prog, prog->_LinkedShaders[prev],
|
|
|
|
|
prog->_LinkedShaders[i]);
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
2013-07-27 11:08:31 -07:00
|
|
|
goto done;
|
2010-10-14 13:28:42 -07:00
|
|
|
|
2013-07-27 11:08:31 -07:00
|
|
|
prev = i;
|
2010-06-18 19:02:10 -07:00
|
|
|
}
|
2010-06-17 15:04:20 -07:00
|
|
|
|
glsl: Fix interstage uniform interface block link error detection.
Previously, we checked for interstage uniform interface block link
errors in validate_interstage_interface_blocks(), which is only called
on pairs of adjacent shader stages. Therefore, we failed to detect
uniform interface block mismatches between non-adjacent shader stages.
Before the introduction of geometry shaders, this wasn't a problem,
because the only supported shader stages were vertex and fragment
shaders, therefore they were always adjacent. However, now that we
allow a program to contain vertex, geometry, and fragment shaders,
that is no longer the case.
Fixes piglit test "skip-stage-uniform-block-array-size-mismatch".
Cc: "10.0" <mesa-stable@lists.freedesktop.org>
v2: Rename validate_interstage_interface_blocks() to
validate_interstage_inout_blocks() to reflect the fact that it no
longer validates uniform blocks.
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
v3: Make validate_interstage_inout_blocks() skip uniform blocks.
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2013-11-15 14:23:45 -08:00
|
|
|
/* Cross-validate uniform blocks between shader stages */
|
2016-06-30 14:55:40 +10:00
|
|
|
validate_interstage_uniform_blocks(prog, prog->_LinkedShaders);
|
2016-11-07 14:47:18 +11:00
|
|
|
if (!prog->data->LinkStatus)
|
glsl: Fix interstage uniform interface block link error detection.
Previously, we checked for interstage uniform interface block link
errors in validate_interstage_interface_blocks(), which is only called
on pairs of adjacent shader stages. Therefore, we failed to detect
uniform interface block mismatches between non-adjacent shader stages.
Before the introduction of geometry shaders, this wasn't a problem,
because the only supported shader stages were vertex and fragment
shaders, therefore they were always adjacent. However, now that we
allow a program to contain vertex, geometry, and fragment shaders,
that is no longer the case.
Fixes piglit test "skip-stage-uniform-block-array-size-mismatch".
Cc: "10.0" <mesa-stable@lists.freedesktop.org>
v2: Rename validate_interstage_interface_blocks() to
validate_interstage_inout_blocks() to reflect the fact that it no
longer validates uniform blocks.
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
v3: Make validate_interstage_inout_blocks() skip uniform blocks.
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2013-11-15 14:23:45 -08:00
|
|
|
goto done;
|
2013-03-10 03:20:03 -07:00
|
|
|
|
2023-02-08 15:28:08 +01:00
|
|
|
if (prog->IsES && prog->GLSL_Version == 100)
|
2018-09-07 15:14:52 +03:00
|
|
|
if (!validate_invariant_builtins(prog,
|
|
|
|
|
prog->_LinkedShaders[MESA_SHADER_VERTEX],
|
|
|
|
|
prog->_LinkedShaders[MESA_SHADER_FRAGMENT]))
|
|
|
|
|
goto done;
|
|
|
|
|
|
2012-05-04 13:08:46 -07:00
|
|
|
/* 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.
|
2012-08-02 17:51:02 -07:00
|
|
|
*
|
|
|
|
|
* This rule also applies to GLSL ES 3.00.
|
2012-05-04 13:08:46 -07:00
|
|
|
*/
|
2016-01-27 15:34:53 +11:00
|
|
|
if (max_version >= (prog->IsES ? 300 : 130)) {
|
2016-06-30 14:55:40 +10:00
|
|
|
struct gl_linked_shader *sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
|
2012-05-04 13:08:46 -07:00
|
|
|
if (sh) {
|
2016-09-28 16:04:05 +10:00
|
|
|
lower_discard_flow(sh->ir);
|
2012-05-04 13:08:46 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 13:02:46 +10:00
|
|
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
|
|
|
|
if (prog->_LinkedShaders[i] == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
2023-12-11 12:35:06 +11:00
|
|
|
struct gl_linked_shader *shader = prog->_LinkedShaders[i];
|
|
|
|
|
exec_list *ir = shader->ir;
|
|
|
|
|
|
2023-12-11 16:17:18 +11:00
|
|
|
detect_recursion_linked(prog, ir);
|
|
|
|
|
if (!prog->data->LinkStatus)
|
|
|
|
|
goto done;
|
|
|
|
|
|
2023-12-11 12:35:06 +11:00
|
|
|
lower_vector_derefs(shader);
|
|
|
|
|
|
|
|
|
|
lower_packing_builtins(ir, ctx->Extensions.ARB_shading_language_packing,
|
|
|
|
|
ctx->Extensions.ARB_gpu_shader5,
|
|
|
|
|
ctx->Const.GLSLHasHalfFloatPacking);
|
|
|
|
|
do_mat_op_to_vec(ir);
|
|
|
|
|
|
|
|
|
|
lower_instructions(ir, ctx->Extensions.ARB_gpu_shader5);
|
|
|
|
|
|
|
|
|
|
do_vec_index_to_cond_assign(ir);
|
2023-06-21 13:02:46 +10:00
|
|
|
}
|
2011-11-08 12:37:19 -08:00
|
|
|
|
2023-12-11 16:17:18 +11:00
|
|
|
/* Check and validate stream emissions in geometry shaders */
|
|
|
|
|
validate_geometry_shader_emissions(consts, prog);
|
|
|
|
|
|
2010-06-17 15:04:20 -07:00
|
|
|
done:
|
2014-01-07 10:11:39 -08:00
|
|
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
2014-01-07 08:56:57 -08:00
|
|
|
free(shader_list[i]);
|
2010-11-17 11:03:57 -08:00
|
|
|
if (prog->_LinkedShaders[i] == NULL)
|
2016-09-28 16:04:05 +10:00
|
|
|
continue;
|
2010-11-17 11:03:57 -08:00
|
|
|
|
2013-11-22 12:37:22 -08:00
|
|
|
/* Do a final validation step to make sure that the IR wasn't
|
|
|
|
|
* invalidated by any modifications performed after intrastage linking.
|
|
|
|
|
*/
|
|
|
|
|
validate_ir_tree(prog->_LinkedShaders[i]->ir);
|
|
|
|
|
|
2010-11-17 11:03:57 -08:00
|
|
|
/* Retain any live IR, but trash the rest. */
|
|
|
|
|
reparent_ir(prog->_LinkedShaders[i]->ir, prog->_LinkedShaders[i]->ir);
|
2011-09-30 14:21:10 -07:00
|
|
|
|
|
|
|
|
/* The symbol table in the linked shaders may contain references to
|
|
|
|
|
* variables that were removed (e.g., unused uniforms). Since it may
|
|
|
|
|
* contain junk, there is no possible valid use. Delete it and set the
|
|
|
|
|
* pointer to NULL.
|
|
|
|
|
*/
|
|
|
|
|
delete prog->_LinkedShaders[i]->symbols;
|
|
|
|
|
prog->_LinkedShaders[i]->symbols = NULL;
|
2010-11-17 11:03:57 -08:00
|
|
|
}
|
|
|
|
|
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_free(mem_ctx);
|
2010-06-17 15:04:20 -07:00
|
|
|
}
|
2021-10-22 19:19:48 -04:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
resource_name_updated(struct gl_resource_name *name)
|
|
|
|
|
{
|
2021-10-22 19:22:53 -04:00
|
|
|
if (name->string) {
|
|
|
|
|
name->length = strlen(name->string);
|
2021-10-22 21:02:42 -04:00
|
|
|
|
|
|
|
|
const char *last_square_bracket = strrchr(name->string, '[');
|
|
|
|
|
if (last_square_bracket) {
|
|
|
|
|
name->last_square_bracket = last_square_bracket - name->string;
|
|
|
|
|
name->suffix_is_zero_square_bracketed =
|
|
|
|
|
strcmp(last_square_bracket, "[0]") == 0;
|
|
|
|
|
} else {
|
|
|
|
|
name->last_square_bracket = -1;
|
|
|
|
|
name->suffix_is_zero_square_bracketed = false;
|
|
|
|
|
}
|
2021-10-22 19:22:53 -04:00
|
|
|
} else {
|
|
|
|
|
name->length = 0;
|
2021-10-22 21:02:42 -04:00
|
|
|
name->last_square_bracket = -1;
|
|
|
|
|
name->suffix_is_zero_square_bracketed = false;
|
2021-10-22 19:22:53 -04:00
|
|
|
}
|
2021-10-22 19:19:48 -04:00
|
|
|
}
|