diff --git a/src/compiler/glsl/ir.h b/src/compiler/glsl/ir.h index d6abd843813..c9280aef438 100644 --- a/src/compiler/glsl/ir.h +++ b/src/compiler/glsl/ir.h @@ -2513,10 +2513,6 @@ _mesa_glsl_initialize_variables(exec_list *instructions, extern void reparent_ir(exec_list *list, void *mem_ctx); -extern void -do_set_program_inouts(exec_list *instructions, struct gl_program *prog, - gl_shader_stage shader_stage); - extern char * prototype_string(const glsl_type *return_type, const char *name, exec_list *parameters); diff --git a/src/compiler/glsl/ir_set_program_inouts.cpp b/src/compiler/glsl/ir_set_program_inouts.cpp deleted file mode 100644 index d280344cbe0..00000000000 --- a/src/compiler/glsl/ir_set_program_inouts.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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 ir_set_program_inouts.cpp - * - * Sets the inputs_read and outputs_written of Mesa programs. - * - * Mesa programs (gl_program, not gl_shader_program) have a set of - * flags indicating which varyings are read and written. Computing - * which are actually read from some sort of backend code can be - * tricky when variable array indexing involved. So this pass - * provides support for setting inputs_read and outputs_written right - * from the GLSL IR. - */ - -#include "ir.h" -#include "ir_visitor.h" -#include "compiler/glsl_types.h" -#include "main/shader_types.h" - -namespace { - -class ir_set_program_inouts_visitor : public ir_hierarchical_visitor { -public: - ir_set_program_inouts_visitor(struct gl_program *prog, - gl_shader_stage shader_stage) - { - this->prog = prog; - this->shader_stage = shader_stage; - } - ~ir_set_program_inouts_visitor() - { - } - - virtual ir_visitor_status visit_enter(ir_dereference_array *); - virtual ir_visitor_status visit_enter(ir_function_signature *); - virtual ir_visitor_status visit_enter(ir_discard *); - virtual ir_visitor_status visit_enter(ir_texture *); - virtual ir_visitor_status visit(ir_dereference_variable *); - -private: - void mark_whole_variable(ir_variable *var); - bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index); - - struct gl_program *prog; - gl_shader_stage shader_stage; -}; - -} /* anonymous namespace */ - -static inline bool -is_shader_inout(ir_variable *var) -{ - return var->data.mode == ir_var_shader_in || - var->data.mode == ir_var_shader_out || - var->data.mode == ir_var_system_value; -} - -static void -mark(struct gl_program *prog, ir_variable *var, int offset, int len, - gl_shader_stage stage) -{ - /* As of GLSL 1.20, varyings can only be floats, floating-point - * vectors or matrices, or arrays of them. For Mesa programs using - * inputs_read/outputs_written, everything but matrices uses one - * slot, while matrices use a slot per column. Presumably - * something doing a more clever packing would use something other - * than inputs_read/outputs_written. - */ - - for (int i = 0; i < len; i++) { - assert(var->data.location != -1); - - int idx = var->data.location + offset + i; - bool is_patch_generic = var->data.patch && - idx != VARYING_SLOT_TESS_LEVEL_INNER && - idx != VARYING_SLOT_TESS_LEVEL_OUTER && - idx != VARYING_SLOT_BOUNDING_BOX0 && - idx != VARYING_SLOT_BOUNDING_BOX1; - GLbitfield64 bitfield; - - if (is_patch_generic) { - assert(idx >= VARYING_SLOT_PATCH0 && idx < VARYING_SLOT_TESS_MAX); - bitfield = BITFIELD64_BIT(idx - VARYING_SLOT_PATCH0); - } - else { - assert(idx < VARYING_SLOT_MAX); - bitfield = BITFIELD64_BIT(idx); - } - - if (var->data.mode == ir_var_shader_in) { - if (is_patch_generic) - prog->info.patch_inputs_read |= bitfield; - else - prog->info.inputs_read |= bitfield; - - /* double inputs read is only for vertex inputs */ - if (stage == MESA_SHADER_VERTEX && - var->type->without_array()->is_dual_slot()) - prog->DualSlotInputs |= bitfield; - - if (stage == MESA_SHADER_FRAGMENT) { - prog->info.fs.uses_sample_qualifier |= var->data.sample; - } - } else if (var->data.mode == ir_var_system_value) { - BITSET_SET(prog->info.system_values_read, idx); - } else { - assert(var->data.mode == ir_var_shader_out); - if (is_patch_generic) { - prog->info.patch_outputs_written |= bitfield; - } else if (!var->data.read_only) { - prog->info.outputs_written |= bitfield; - if (var->data.index > 0) - prog->SecondaryOutputsWritten |= bitfield; - } - - if (var->data.fb_fetch_output) - prog->info.outputs_read |= bitfield; - } - } -} - -/** - * Mark an entire variable as used. Caller must ensure that the variable - * represents a shader input or output. - */ -void -ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var) -{ - const glsl_type *type = var->type; - bool is_vertex_input = false; - if (this->shader_stage == MESA_SHADER_GEOMETRY && - var->data.mode == ir_var_shader_in && type->is_array()) { - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_CTRL && - var->data.mode == ir_var_shader_in) { - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_CTRL && - var->data.mode == ir_var_shader_out && !var->data.patch) { - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_EVAL && - var->data.mode == ir_var_shader_in && !var->data.patch) { - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_VERTEX && - var->data.mode == ir_var_shader_in) - is_vertex_input = true; - - mark(this->prog, var, 0, type->count_attribute_slots(is_vertex_input), - this->shader_stage); -} - -/* Default handler: Mark all the locations in the variable as used. */ -ir_visitor_status -ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) -{ - if (!is_shader_inout(ir->var)) - return visit_continue; - - mark_whole_variable(ir->var); - - return visit_continue; -} - -/** - * Try to mark a portion of the given variable as used. Caller must ensure - * that the variable represents a shader input or output which can be indexed - * into in array fashion (an array or matrix). For the purpose of geometry - * shader inputs (which are always arrays*), this means that the array element - * must be something that can be indexed into in array fashion. - * - * *Except gl_PrimitiveIDIn, as noted below. - * - * For tessellation control shaders all inputs and non-patch outputs are - * arrays. For tessellation evaluation shaders non-patch inputs are arrays. - * - * If the index can't be interpreted as a constant, or some other problem - * occurs, then nothing will be marked and false will be returned. - */ -bool -ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var, - ir_rvalue *index) -{ - const glsl_type *type = var->type; - - if (this->shader_stage == MESA_SHADER_GEOMETRY && - var->data.mode == ir_var_shader_in) { - /* The only geometry shader input that is not an array is - * gl_PrimitiveIDIn, and in that case, this code will never be reached, - * because gl_PrimitiveIDIn can't be indexed into in array fashion. - */ - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_CTRL && - var->data.mode == ir_var_shader_in) { - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_CTRL && - var->data.mode == ir_var_shader_out && !var->data.patch) { - assert(type->is_array()); - type = type->fields.array; - } - - if (this->shader_stage == MESA_SHADER_TESS_EVAL && - var->data.mode == ir_var_shader_in && !var->data.patch) { - assert(type->is_array()); - type = type->fields.array; - } - - /* TODO: implement proper arrays of arrays support - * for now let the caller mark whole variable as used. - */ - if (type->is_array() && type->fields.array->is_array()) - return false; - - /* The code below only handles: - * - * - Indexing into matrices - * - Indexing into arrays of (matrices, vectors, or scalars) - * - * All other possibilities are either prohibited by GLSL (vertex inputs and - * fragment outputs can't be structs) or should have been eliminated by - * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into - * vectors, and lower_packed_varyings() gets rid of structs that occur in - * varyings). - * - * However, we don't use varying packing in all cases - tessellation - * shaders bypass it. This means we'll see varying structs and arrays - * of structs here. For now, we just give up so the caller marks the - * entire variable as used. - */ - if (!(type->is_matrix() || - (type->is_array() && - (type->fields.array->is_numeric() || - type->fields.array->is_boolean())))) { - - /* If we don't know how to handle this case, give up and let the - * caller mark the whole variable as used. - */ - return false; - } - - ir_constant *index_as_constant = index->as_constant(); - if (!index_as_constant) - return false; - - unsigned elem_width; - unsigned num_elems; - if (type->is_array()) { - num_elems = type->length; - if (type->fields.array->is_matrix()) - elem_width = type->fields.array->matrix_columns; - else - elem_width = 1; - } else { - num_elems = type->matrix_columns; - elem_width = 1; - } - - if (index_as_constant->value.u[0] >= num_elems) { - /* Constant index outside the bounds of the matrix/array. This could - * arise as a result of constant folding of a legal GLSL program. - * - * Even though the spec says that indexing outside the bounds of a - * matrix/array results in undefined behaviour, we don't want to pass - * out-of-range values to mark() (since this could result in slots that - * don't exist being marked as used), so just let the caller mark the - * whole variable as used. - */ - return false; - } - - /* double element width for double types that takes two slots */ - if (this->shader_stage != MESA_SHADER_VERTEX || - var->data.mode != ir_var_shader_in) { - if (type->without_array()->is_dual_slot()) - elem_width *= 2; - } - - mark(this->prog, var, index_as_constant->value.u[0] * elem_width, - elem_width, this->shader_stage); - return true; -} - -static bool -is_multiple_vertices(gl_shader_stage stage, ir_variable *var) -{ - if (var->data.patch) - return false; - - if (var->data.mode == ir_var_shader_in) - return stage == MESA_SHADER_GEOMETRY || - stage == MESA_SHADER_TESS_CTRL || - stage == MESA_SHADER_TESS_EVAL; - if (var->data.mode == ir_var_shader_out) - return stage == MESA_SHADER_TESS_CTRL; - - return false; -} - -ir_visitor_status -ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) -{ - /* Note: for geometry shader inputs, lower_named_interface_blocks may - * create 2D arrays, so we need to be able to handle those. 2D arrays - * shouldn't be able to crop up for any other reason. - */ - if (ir_dereference_array * const inner_array = - ir->array->as_dereference_array()) { - /* ir => foo[i][j] - * inner_array => foo[i] - */ - if (ir_dereference_variable * const deref_var = - inner_array->array->as_dereference_variable()) { - if (is_multiple_vertices(this->shader_stage, deref_var->var)) { - /* foo is a geometry or tessellation shader input, so i is - * the vertex, and j the part of the input we're accessing. - */ - if (try_mark_partial_variable(deref_var->var, ir->array_index)) - { - /* We've now taken care of foo and j, but i might contain a - * subexpression that accesses shader inputs. So manually - * visit i and then continue with the parent. - */ - inner_array->array_index->accept(this); - return visit_continue_with_parent; - } - } - } - } else if (ir_dereference_variable * const deref_var = - ir->array->as_dereference_variable()) { - /* ir => foo[i], where foo is a variable. */ - if (is_multiple_vertices(this->shader_stage, deref_var->var)) { - /* foo is a geometry or tessellation shader input, so i is - * the vertex, and we're accessing the entire input. - */ - mark_whole_variable(deref_var->var); - /* We've now taken care of foo, but i might contain a subexpression - * that accesses shader inputs. So manually visit i and then - * continue with the parent. - */ - ir->array_index->accept(this); - return visit_continue_with_parent; - } else if (is_shader_inout(deref_var->var)) { - /* foo is a shader input/output, but not a geometry shader input, - * so i is the part of the input we're accessing. - */ - if (try_mark_partial_variable(deref_var->var, ir->array_index)) - return visit_continue_with_parent; - } - } - - /* The expression is something we don't recognize. Just visit its - * subexpressions. - */ - return visit_continue; -} - -ir_visitor_status -ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir) -{ - /* We don't want to descend into the function parameters and - * consider them as shader inputs or outputs. - */ - visit_list_elements(this, &ir->body); - return visit_continue_with_parent; -} - -ir_visitor_status -ir_set_program_inouts_visitor::visit_enter(ir_discard *) -{ - /* discards are only allowed in fragment shaders. */ - assert(this->shader_stage == MESA_SHADER_FRAGMENT); - - prog->info.fs.uses_discard = true; - - return visit_continue; -} - -ir_visitor_status -ir_set_program_inouts_visitor::visit_enter(ir_texture *ir) -{ - if (ir->op == ir_tg4) - prog->info.uses_texture_gather = true; - return visit_continue; -} - -void -do_set_program_inouts(exec_list *instructions, struct gl_program *prog, - gl_shader_stage shader_stage) -{ - ir_set_program_inouts_visitor v(prog, shader_stage); - - prog->info.inputs_read = 0; - prog->info.outputs_written = 0; - prog->SecondaryOutputsWritten = 0; - prog->info.outputs_read = 0; - prog->info.patch_inputs_read = 0; - prog->info.patch_outputs_written = 0; - BITSET_ZERO(prog->info.system_values_read); - if (shader_stage == MESA_SHADER_FRAGMENT) { - prog->info.fs.uses_sample_qualifier = false; - prog->info.fs.uses_discard = false; - } - visit_list_elements(&v, instructions); -} diff --git a/src/compiler/glsl/meson.build b/src/compiler/glsl/meson.build index de73301a9e4..de87ef6f1b7 100644 --- a/src/compiler/glsl/meson.build +++ b/src/compiler/glsl/meson.build @@ -135,7 +135,6 @@ files_libglsl = files( 'ir_reader.h', 'ir_rvalue_visitor.cpp', 'ir_rvalue_visitor.h', - 'ir_set_program_inouts.cpp', 'ir_uniform.h', 'ir_validate.cpp', 'ir_variable_refcount.cpp',