#include "glsl_symbol_table.h"
#include "linker.h"
#include "main/macros.h"
+#include "main/mtypes.h"
#include "util/hash_table.h"
+#include "util/u_string.h"
namespace {
bool
intrastage_match(ir_variable *a,
ir_variable *b,
- struct gl_shader_program *prog)
+ struct gl_shader_program *prog,
+ bool match_precision)
{
/* Types must match. */
if (a->get_interface_type() != b->get_interface_type()) {
return false;
}
+ bool type_match = (match_precision ?
+ a->type == b->type :
+ a->type->compare_no_precision(b->type));
+
/* If a block is an array then it must match across the shader.
* Unsized arrays are also processed and matched agaist sized arrays.
*/
- if (b->type != a->type && (b->type->is_array() || a->type->is_array()) &&
+ if (!type_match && (b->type->is_array() || a->type->is_array()) &&
(b->is_interface_instance() || a->is_interface_instance()) &&
- !validate_intrastage_arrays(prog, b, a))
+ !validate_intrastage_arrays(prog, b, a, match_precision))
return false;
return true;
public:
interface_block_definitions()
: mem_ctx(ralloc_context(NULL)),
- ht(_mesa_hash_table_create(NULL, _mesa_key_hash_string,
+ ht(_mesa_hash_table_create(NULL, _mesa_hash_string,
_mesa_key_string_equal))
{
}
* it into the appropriate data structure.
*/
definitions->store(var);
- } else if (!intrastage_match(prev_def, var, prog)) {
+ } else if (!intrastage_match(prev_def, var, prog,
+ true /* match_precision */)) {
linker_error(prog, "definitions of interface block `%s' do not"
" match\n", iface_type->name);
return;
return;
}
+ /* Desktop OpenGL requires redeclaration of the built-in interfaces for
+ * SSO programs. Passes above implement following rules:
+ *
+ * From Section 7.4 (Program Pipeline Objects) of the OpenGL 4.6 Core
+ * spec:
+ *
+ * "To use any built-in input or output in the gl_PerVertex and
+ * gl_PerFragment blocks in separable program objects, shader code
+ * must redeclare those blocks prior to use. A separable program
+ * will fail to link if:
+ *
+ * it contains multiple shaders of a single type with different
+ * redeclarations of these built-in input and output blocks; or
+ *
+ * any shader uses a built-in block member not found in the
+ * redeclaration of that block."
+ *
+ * ARB_separate_shader_objects issues section (issue #28) states that
+ * redeclaration is not required for GLSL shaders using #version 140 or
+ * earlier (since interface blocks are not possible with older versions).
+ *
+ * From Section 7.4.1 (Shader Interface Matching) of the OpenGL ES 3.1
+ * spec:
+ *
+ * "Built-in inputs or outputs do not affect interface matching."
+ *
+ * GL_OES_shader_io_blocks adds following:
+ *
+ * "When using any built-in input or output in the gl_PerVertex block
+ * in separable program objects, shader code may redeclare that block
+ * prior to use. If the shader does not redeclare the block, the
+ * intrinsically declared definition of that block will be used."
+ */
+
/* Add output interfaces from the producer to the symbol table. */
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *var = node->as_variable();
if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
continue;
+ /* Built-in interface redeclaration check. */
+ if (prog->SeparateShader && !prog->IsES && prog->data->Version >= 150 &&
+ var->data.how_declared == ir_var_declared_implicitly &&
+ var->data.used && !producer_iface) {
+ linker_error(prog, "missing output builtin block %s redeclaration "
+ "in separable shader program",
+ var->get_interface_type()->name);
+ return;
+ }
+
definitions.store(var);
}
ir_variable *producer_def = definitions.lookup(var);
+ /* Built-in interface redeclaration check. */
+ if (prog->SeparateShader && !prog->IsES && prog->data->Version >= 150 &&
+ var->data.how_declared == ir_var_declared_implicitly &&
+ var->data.used && !producer_iface) {
+ linker_error(prog, "missing input builtin block %s redeclaration "
+ "in separable shader program",
+ var->get_interface_type()->name);
+ return;
+ }
+
/* The producer doesn't generate this input: fail to link. Skip built-in
* 'gl_in[]' since that may not be present if the producer does not
* write to any of the pre-defined outputs (e.g. if the vertex shader
* does not write to gl_Position, etc), which is allowed and results in
* undefined behavior.
+ *
+ * From Section 4.3.4 (Inputs) of the GLSL 1.50 spec:
+ *
+ * "Only the input variables that are actually read need to be written
+ * by the previous stage; it is allowed to have superfluous
+ * declarations of input variables."
*/
if (producer_def == NULL &&
- !is_builtin_gl_in_block(var, consumer->Stage)) {
+ !is_builtin_gl_in_block(var, consumer->Stage) && var->data.used) {
linker_error(prog, "Input block `%s' is not an output of "
"the previous stage\n", var->get_interface_type()->name);
return;
* uniform matchin rules (for uniforms, it is as though all
* shaders are in the same shader stage).
*/
- if (!intrastage_match(old_def, var, prog)) {
+ if (!intrastage_match(old_def, var, prog, false /* precision */)) {
linker_error(prog, "definitions of uniform block `%s' do not "
"match\n", var->get_interface_type()->name);
return;