Commit 5ebf5473 authored by Jordan Justen's avatar Jordan Justen

glsl linker: remove interface block instance names

Convert interface blocks with instance names into flat
interface blocks without an instance name.
Signed-off-by: default avatarJordan Justen <jordan.l.justen@intel.com>
Reviewed-by: default avatarKenneth Graunke <kenneth@whitecape.org>
parent b24eeb07
......@@ -63,6 +63,7 @@ LIBGLSL_FILES = \
$(GLSL_SRCDIR)/lower_mat_op_to_vec.cpp \
$(GLSL_SRCDIR)/lower_noise.cpp \
$(GLSL_SRCDIR)/lower_packed_varyings.cpp \
$(GLSL_SRCDIR)/lower_named_interface_blocks.cpp \
$(GLSL_SRCDIR)/lower_packing_builtins.cpp \
$(GLSL_SRCDIR)/lower_texture_projection.cpp \
$(GLSL_SRCDIR)/lower_variable_index_to_cond_assign.cpp \
......
......@@ -110,6 +110,7 @@ void lower_packed_varyings(void *mem_ctx, unsigned location_base,
unsigned locations_used, ir_variable_mode mode,
gl_shader *shader);
bool lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index);
void lower_named_interface_blocks(void *mem_ctx, gl_shader *shader);
bool optimize_redundant_jumps(exec_list *instructions);
bool optimize_split_arrays(exec_list *instructions, bool linked);
......
......@@ -1733,6 +1733,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->LinkStatus = true;
}
for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] != NULL)
lower_named_interface_blocks(mem_ctx, prog->_LinkedShaders[i]);
}
/* 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.
......
/*
* Copyright (c) 2013 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 lower_named_interface_blocks.cpp
*
* This lowering pass converts all interface blocks with instance names
* into interface blocks without an instance name.
*
* For example, the following shader:
*
* out block {
* float block_var;
* } inst_name;
*
* main()
* {
* inst_name.block_var = 0.0;
* }
*
* Is rewritten to:
*
* out block {
* float block_var;
* };
*
* main()
* {
* block_var = 0.0;
* }
*
* This takes place after the shader code has already been verified with
* the interface name in place.
*
* The linking phase will use the interface block name rather than the
* interface's instance name when linking interfaces.
*
* This modification to the ir allows our currently existing dead code
* elimination to work with interface blocks without changes.
*/
#include "glsl_symbol_table.h"
#include "ir.h"
#include "ir_optimization.h"
#include "ir_rvalue_visitor.h"
#include "program/hash_table.h"
class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
{
public:
void * const mem_ctx;
hash_table *interface_namespace;
flatten_named_interface_blocks_declarations(void *mem_ctx)
: mem_ctx(mem_ctx)
{
}
void run(exec_list *instructions);
virtual ir_visitor_status visit_leave(ir_assignment *);
virtual void handle_rvalue(ir_rvalue **rvalue);
};
void
flatten_named_interface_blocks_declarations::run(exec_list *instructions)
{
interface_namespace = hash_table_ctor(0, hash_table_string_hash,
hash_table_string_compare);
/* First pass: adjust instance block variables with an instance name
* to not have an instance name.
*
* The interface block variables are stored in the interface_namespace
* hash table so they can be used in the second pass.
*/
foreach_list_safe(node, instructions) {
ir_variable *var = ((ir_instruction *) node)->as_variable();
if (!var || !var->is_interface_instance())
continue;
/* It should be possible to handle uniforms during this pass,
* but, this will require changes to the other uniform block
* support code.
*/
if (var->mode == ir_var_uniform)
continue;
const glsl_type *const t = var->type;
exec_node *insert_pos = var;
char *iface_field_name;
for (unsigned i = 0; i < t->length; i++) {
iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", t->name,
t->fields.structure[i].name);
ir_variable *found_var =
(ir_variable *) hash_table_find(interface_namespace,
iface_field_name);
if (!found_var) {
ir_variable *new_var =
new(mem_ctx) ir_variable(t->fields.structure[i].type,
ralloc_strdup(mem_ctx, t->fields.structure[i].name),
(ir_variable_mode) var->mode);
new_var->interface_type = t;
hash_table_insert(interface_namespace, new_var,
iface_field_name);
insert_pos->insert_after(new_var);
insert_pos = new_var;
}
}
var->remove();
}
/* Second pass: visit all ir_dereference_record instances, and if they
* reference an interface block, then flatten the refererence out.
*/
visit_list_elements(this, instructions);
hash_table_dtor(interface_namespace);
interface_namespace = NULL;
}
ir_visitor_status
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
{
ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
if (lhs_rec) {
ir_rvalue *lhs_rec_tmp = lhs_rec;
handle_rvalue(&lhs_rec_tmp);
if (lhs_rec_tmp != lhs_rec) {
ir->set_lhs(lhs_rec_tmp);
}
}
return rvalue_visit(ir);
}
void
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
{
if (*rvalue == NULL)
return;
ir_dereference_record *ir = (*rvalue)->as_dereference_record();
if (ir == NULL)
return;
ir_variable *var = ir->variable_referenced();
if (!var->is_interface_instance())
return;
/* It should be possible to handle uniforms during this pass,
* but, this will require changes to the other uniform block
* support code.
*/
if (var->mode == ir_var_uniform)
return;
if (var->interface_type != NULL) {
char *iface_field_name =
ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
ir->field);
/* Find the variable in the set of flattened interface blocks */
ir_variable *found_var =
(ir_variable *) hash_table_find(interface_namespace,
iface_field_name);
assert(found_var);
ir_dereference_variable *deref_var =
new(mem_ctx) ir_dereference_variable(found_var);
*rvalue = deref_var;
}
}
void
lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
{
flatten_named_interface_blocks_declarations v_decl(mem_ctx);
v_decl.run(shader->ir);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment