glsl: remove now unused GLSL IR block linker

This is now done in the NIR linker instead.

Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26534>
This commit is contained in:
Timothy Arceri
2023-12-06 13:20:48 +11:00
committed by Marge Bot
parent 32f274768e
commit 72ad0db505
6 changed files with 0 additions and 1246 deletions

View File

@@ -1,294 +0,0 @@
/*
* Copyright © 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.
*/
#include "link_uniform_block_active_visitor.h"
#include "program.h"
#include "linker_util.h"
static link_uniform_block_active *
process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
{
const hash_entry *const existing_block =
_mesa_hash_table_search(ht, glsl_get_type_name(var->get_interface_type()));
const glsl_type *const block_type = var->is_interface_instance()
? var->type : var->get_interface_type();
/* If a block with this block-name has not previously been seen, add it.
* If a block with this block-name has been seen, it must be identical to
* the block currently being examined.
*/
if (existing_block == NULL) {
link_uniform_block_active *const b =
rzalloc(mem_ctx, struct link_uniform_block_active);
b->type = block_type;
b->has_instance_name = var->is_interface_instance();
b->is_shader_storage = var->data.mode == ir_var_shader_storage;
if (var->data.explicit_binding) {
b->has_binding = true;
b->binding = var->data.binding;
} else {
b->has_binding = false;
b->binding = 0;
}
_mesa_hash_table_insert(ht, glsl_get_type_name(var->get_interface_type()), (void *) b);
return b;
} else {
link_uniform_block_active *const b =
(link_uniform_block_active *) existing_block->data;
if (b->type != block_type
|| b->has_instance_name != var->is_interface_instance())
return NULL;
else
return b;
}
assert(!"Should not get here.");
return NULL;
}
/* For arrays of arrays this function will give us a middle ground between
* detecting inactive uniform blocks and structuring them in a way that makes
* it easy to calculate the offset for indirect indexing.
*
* For example given the shader:
*
* uniform ArraysOfArraysBlock
* {
* vec4 a;
* } i[3][4][5];
*
* void main()
* {
* vec4 b = i[0][1][1].a;
* gl_Position = i[2][2][3].a + b;
* }
*
* There are only 2 active blocks above but for the sake of indirect indexing
* and not over complicating the code we will end up with a count of 8. Here
* each dimension has 2 different indices counted so we end up with 2*2*2
*/
static struct uniform_block_array_elements **
process_arrays(void *mem_ctx, ir_dereference_array *ir,
struct link_uniform_block_active *block)
{
if (ir) {
struct uniform_block_array_elements **ub_array_ptr =
process_arrays(mem_ctx, ir->array->as_dereference_array(), block);
if (*ub_array_ptr == NULL) {
*ub_array_ptr = rzalloc(mem_ctx, struct uniform_block_array_elements);
(*ub_array_ptr)->ir = ir;
(*ub_array_ptr)->aoa_size =
ir->array->type->arrays_of_arrays_size();
}
struct uniform_block_array_elements *ub_array = *ub_array_ptr;
ir_constant *c = ir->array_index->as_constant();
if (c) {
/* Index is a constant, so mark just that element used, if not
* already.
*/
const unsigned idx = c->get_uint_component(0);
unsigned i;
for (i = 0; i < ub_array->num_array_elements; i++) {
if (ub_array->array_elements[i] == idx)
break;
}
assert(i <= ub_array->num_array_elements);
if (i == ub_array->num_array_elements) {
ub_array->array_elements = reralloc(mem_ctx,
ub_array->array_elements,
unsigned,
ub_array->num_array_elements + 1);
ub_array->array_elements[ub_array->num_array_elements] = idx;
ub_array->num_array_elements++;
}
} else {
/* The array index is not a constant, so mark the entire array used. */
assert(ir->array->type->is_array());
if (ub_array->num_array_elements < ir->array->type->length) {
ub_array->num_array_elements = ir->array->type->length;
ub_array->array_elements = reralloc(mem_ctx,
ub_array->array_elements,
unsigned,
ub_array->num_array_elements);
for (unsigned i = 0; i < ub_array->num_array_elements; i++) {
ub_array->array_elements[i] = i;
}
}
}
return &ub_array->array;
} else {
return &block->array;
}
}
ir_visitor_status
link_uniform_block_active_visitor::visit(ir_variable *var)
{
if (!var->is_in_buffer_block())
return visit_continue;
/* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec says:
*
* "All members of a named uniform block declared with a shared or
* std140 layout qualifier are considered active, even if they are not
* referenced in any shader in the program. The uniform block itself is
* also considered active, even if no member of the block is
* referenced."
*/
if (var->get_interface_type_packing() == GLSL_INTERFACE_PACKING_PACKED)
return visit_continue;
/* Process the block. Bail if there was an error. */
link_uniform_block_active *const b =
process_block(this->mem_ctx, this->ht, var);
if (b == NULL) {
linker_error(this->prog,
"uniform block `%s' has mismatching definitions",
glsl_get_type_name(var->get_interface_type()));
this->success = false;
return visit_stop;
}
assert(b->array == NULL);
assert(b->type != NULL);
assert(!b->type->is_array() || b->has_instance_name);
/* For uniform block arrays declared with a shared or std140 layout
* qualifier, mark all its instances as used.
*/
const glsl_type *type = b->type;
struct uniform_block_array_elements **ub_array = &b->array;
while (type->is_array()) {
assert(b->type->length > 0);
*ub_array = rzalloc(this->mem_ctx, struct uniform_block_array_elements);
(*ub_array)->num_array_elements = type->length;
(*ub_array)->array_elements = reralloc(this->mem_ctx,
(*ub_array)->array_elements,
unsigned,
(*ub_array)->num_array_elements);
(*ub_array)->aoa_size = type->arrays_of_arrays_size();
for (unsigned i = 0; i < (*ub_array)->num_array_elements; i++) {
(*ub_array)->array_elements[i] = i;
}
ub_array = &(*ub_array)->array;
type = type->fields.array;
}
return visit_continue;
}
ir_visitor_status
link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
{
/* cycle through arrays of arrays */
ir_dereference_array *base_ir = ir;
while (base_ir->array->ir_type == ir_type_dereference_array)
base_ir = base_ir->array->as_dereference_array();
ir_dereference_variable *const d =
base_ir->array->as_dereference_variable();
ir_variable *const var = (d == NULL) ? NULL : d->var;
/* If the r-value being dereferenced is not a variable (e.g., a field of a
* structure) or is not a uniform block instance, continue.
*
* WARNING: It is not enough for the variable to be part of uniform block.
* It must represent the entire block. Arrays (or matrices) inside blocks
* that lack an instance name are handled by the ir_dereference_variable
* function.
*/
if (var == NULL
|| !var->is_in_buffer_block()
|| !var->is_interface_instance())
return visit_continue;
/* Process the block. Bail if there was an error. */
link_uniform_block_active *const b =
process_block(this->mem_ctx, this->ht, var);
if (b == NULL) {
linker_error(prog,
"uniform block `%s' has mismatching definitions",
glsl_get_type_name(var->get_interface_type()));
this->success = false;
return visit_stop;
}
/* Block arrays must be declared with an instance name.
*/
assert(b->has_instance_name);
assert(b->type != NULL);
/* If the block array was declared with a shared or std140 layout
* qualifier, all its instances have been already marked as used in
* link_uniform_block_active_visitor::visit(ir_variable *).
*/
if (var->get_interface_type_packing() == GLSL_INTERFACE_PACKING_PACKED) {
b->var = var;
process_arrays(this->mem_ctx, ir, b);
}
return visit_continue_with_parent;
}
ir_visitor_status
link_uniform_block_active_visitor::visit(ir_dereference_variable *ir)
{
ir_variable *var = ir->var;
if (!var->is_in_buffer_block())
return visit_continue;
assert(!var->is_interface_instance() || !var->type->is_array());
/* Process the block. Bail if there was an error. */
link_uniform_block_active *const b =
process_block(this->mem_ctx, this->ht, var);
if (b == NULL) {
linker_error(this->prog,
"uniform block `%s' has mismatching definitions",
glsl_get_type_name(var->get_interface_type()));
this->success = false;
return visit_stop;
}
assert(b->array == NULL);
assert(b->type != NULL);
return visit_continue;
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright © 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.
*/
#ifndef LINK_UNIFORM_BLOCK_ACTIVE_VISITOR_H
#define LINK_UNIFORM_BLOCK_ACTIVE_VISITOR_H
#include "ir.h"
#include "util/hash_table.h"
struct uniform_block_array_elements {
unsigned *array_elements;
unsigned num_array_elements;
/**
* Size of the array before array-trimming optimizations.
*
* Locations are only assigned to active array elements, but the location
* values are calculated as if all elements are active. The total number
* of elements in an array including the elements in arrays of arrays before
* inactive elements are removed is needed to be perform that calculation.
*/
unsigned aoa_size;
ir_dereference_array *ir;
struct uniform_block_array_elements *array;
};
struct link_uniform_block_active {
const glsl_type *type;
ir_variable *var;
struct uniform_block_array_elements *array;
unsigned binding;
bool has_instance_name;
bool has_binding;
bool is_shader_storage;
};
class link_uniform_block_active_visitor : public ir_hierarchical_visitor {
public:
link_uniform_block_active_visitor(void *mem_ctx, struct hash_table *ht,
struct gl_shader_program *prog)
: success(true), prog(prog), ht(ht), mem_ctx(mem_ctx)
{
/* empty */
}
virtual ir_visitor_status visit_enter(ir_dereference_array *);
virtual ir_visitor_status visit(ir_dereference_variable *);
virtual ir_visitor_status visit(ir_variable *);
bool success;
private:
struct gl_shader_program *prog;
struct hash_table *ht;
void *mem_ctx;
};
#endif /* LINK_UNIFORM_BLOCK_ACTIVE_VISITOR_H */

View File

@@ -22,464 +22,7 @@
*/
#include "ir.h"
#include "linker.h"
#include "ir_uniform.h"
#include "link_uniform_block_active_visitor.h"
#include "util/hash_table.h"
#include "util/u_math.h"
#include "program.h"
#include "main/errors.h"
#include "main/shader_types.h"
#include "main/consts_exts.h"
namespace {
class ubo_visitor : public program_resource_visitor {
public:
ubo_visitor(void *mem_ctx, gl_uniform_buffer_variable *variables,
unsigned num_variables, struct gl_shader_program *prog,
bool use_std430_as_default)
: index(0), offset(0), buffer_size(0), variables(variables),
num_variables(num_variables), mem_ctx(mem_ctx),
is_array_instance(false), prog(prog),
use_std430_as_default(use_std430_as_default)
{
/* empty */
}
void process(const glsl_type *type, const char *name)
{
this->offset = 0;
this->buffer_size = 0;
this->is_array_instance = strchr(name, ']') != NULL;
this->program_resource_visitor::process(type, name,
use_std430_as_default);
}
unsigned index;
unsigned offset;
unsigned buffer_size;
gl_uniform_buffer_variable *variables;
unsigned num_variables;
void *mem_ctx;
bool is_array_instance;
struct gl_shader_program *prog;
private:
virtual void enter_record(const glsl_type *type, const char *,
bool row_major,
const enum glsl_interface_packing packing)
{
assert(type->is_struct());
if (packing == GLSL_INTERFACE_PACKING_STD430)
this->offset = align(
this->offset, type->std430_base_alignment(row_major));
else
this->offset = align(
this->offset, type->std140_base_alignment(row_major));
}
virtual void leave_record(const glsl_type *type, const char *,
bool row_major,
const enum glsl_interface_packing packing)
{
assert(type->is_struct());
/* If this is the last field of a structure, apply rule #9. The
* ARB_uniform_buffer_object spec says:
*
* The structure may have padding at the end; the base offset of the
* member following the sub-structure is rounded up to the next
* multiple of the base alignment of the structure.
*/
if (packing == GLSL_INTERFACE_PACKING_STD430)
this->offset = align(
this->offset, type->std430_base_alignment(row_major));
else
this->offset = align(
this->offset, type->std140_base_alignment(row_major));
}
virtual void set_buffer_offset(unsigned offset)
{
this->offset = offset;
}
virtual void visit_field(const glsl_type *type, const char *name,
bool row_major, const glsl_type *,
const enum glsl_interface_packing packing,
bool last_field)
{
assert(this->index < this->num_variables);
gl_uniform_buffer_variable *v = &this->variables[this->index++];
v->Name = ralloc_strdup(mem_ctx, name);
v->Type = type;
v->RowMajor = type->without_array()->is_matrix() && row_major;
if (this->is_array_instance) {
v->IndexName = ralloc_strdup(mem_ctx, name);
char *open_bracket = strchr(v->IndexName, '[');
assert(open_bracket != NULL);
char *close_bracket = strchr(open_bracket, '.') - 1;
assert(close_bracket != NULL);
/* Length of the tail without the ']' but with the NUL.
*/
unsigned len = strlen(close_bracket + 1) + 1;
memmove(open_bracket, close_bracket + 1, len);
} else {
v->IndexName = v->Name;
}
unsigned alignment = 0;
unsigned size = 0;
/* The ARB_program_interface_query spec says:
*
* If the final member of an active shader storage block is array
* with no declared size, the minimum buffer size is computed
* assuming the array was declared as an array with one element.
*
* For that reason, we use the base type of the unsized array to
* calculate its size. We don't need to check if the unsized array is
* the last member of a shader storage block (that check was already
* done by the parser).
*/
const glsl_type *type_for_size = type;
if (type->is_unsized_array()) {
if (!last_field) {
linker_error(prog, "unsized array `%s' definition: "
"only last member of a shader storage block "
"can be defined as unsized array",
name);
}
type_for_size = type->without_array();
}
if (packing == GLSL_INTERFACE_PACKING_STD430) {
alignment = type->std430_base_alignment(v->RowMajor);
size = type_for_size->std430_size(v->RowMajor);
} else {
alignment = type->std140_base_alignment(v->RowMajor);
size = type_for_size->std140_size(v->RowMajor);
}
this->offset = align(this->offset, alignment);
v->Offset = this->offset;
this->offset += size;
/* The ARB_uniform_buffer_object spec says:
*
* For uniform blocks laid out according to [std140] rules, the
* minimum buffer object size returned by the UNIFORM_BLOCK_DATA_SIZE
* query is derived by taking the offset of the last basic machine
* unit consumed by the last uniform of the uniform block (including
* any end-of-array or end-of-structure padding), adding one, and
* rounding up to the next multiple of the base alignment required
* for a vec4.
*/
this->buffer_size = align(this->offset, 16);
}
bool use_std430_as_default;
};
class count_block_size : public program_resource_visitor {
public:
count_block_size() : num_active_uniforms(0)
{
/* empty */
}
unsigned num_active_uniforms;
private:
virtual void visit_field(const glsl_type * /* type */,
const char * /* name */,
bool /* row_major */,
const glsl_type * /* record_type */,
const enum glsl_interface_packing,
bool /* last_field */)
{
this->num_active_uniforms++;
}
};
} /* anonymous namespace */
struct block {
const glsl_type *type;
bool has_instance_name;
};
static void process_block_array_leaf(const char *name, gl_uniform_block *blocks,
ubo_visitor *parcel,
gl_uniform_buffer_variable *variables,
const struct link_uniform_block_active *const b,
unsigned *block_index,
unsigned binding_offset,
unsigned linearized_index,
const struct gl_constants *consts,
struct gl_shader_program *prog);
/**
*
* \param first_index Value of \c block_index for the first element of the
* array.
*/
static void
process_block_array(struct uniform_block_array_elements *ub_array, char **name,
size_t name_length, gl_uniform_block *blocks,
ubo_visitor *parcel, gl_uniform_buffer_variable *variables,
const struct link_uniform_block_active *const b,
unsigned *block_index, unsigned binding_offset,
const struct gl_constants *consts,
struct gl_shader_program *prog,
unsigned first_index)
{
for (unsigned j = 0; j < ub_array->num_array_elements; j++) {
size_t new_length = name_length;
unsigned int element_idx = ub_array->array_elements[j];
/* Append the subscript to the current variable name */
ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", element_idx);
if (ub_array->array) {
unsigned binding_stride = binding_offset + (element_idx *
ub_array->array->aoa_size);
process_block_array(ub_array->array, name, new_length, blocks,
parcel, variables, b, block_index,
binding_stride, consts, prog, first_index);
} else {
process_block_array_leaf(*name, blocks,
parcel, variables, b, block_index,
binding_offset + element_idx,
*block_index - first_index, consts, prog);
}
}
}
static void
process_block_array_leaf(const char *name,
gl_uniform_block *blocks,
ubo_visitor *parcel, gl_uniform_buffer_variable *variables,
const struct link_uniform_block_active *const b,
unsigned *block_index, unsigned binding_offset,
unsigned linearized_index,
const struct gl_constants *consts,
struct gl_shader_program *prog)
{
unsigned i = *block_index;
const glsl_type *type = b->type->without_array();
blocks[i].name.string = ralloc_strdup(blocks, name);
resource_name_updated(&blocks[i].name);
blocks[i].Uniforms = &variables[(*parcel).index];
/* The ARB_shading_language_420pack spec says:
*
* If the binding identifier is used with a uniform block instanced as
* an array then the first element of the array takes the specified
* block binding and each subsequent element takes the next consecutive
* uniform block binding point.
*/
blocks[i].Binding = (b->has_binding) ? b->binding + binding_offset : 0;
blocks[i].UniformBufferSize = 0;
blocks[i]._Packing = glsl_interface_packing(type->interface_packing);
blocks[i]._RowMajor = type->get_interface_row_major();
blocks[i].linearized_array_index = linearized_index;
parcel->process(type, b->has_instance_name ? blocks[i].name.string : "");
blocks[i].UniformBufferSize = parcel->buffer_size;
/* Check SSBO size is lower than maximum supported size for SSBO */
if (b->is_shader_storage &&
parcel->buffer_size > consts->MaxShaderStorageBlockSize) {
linker_error(prog, "shader storage block `%s' has size %d, "
"which is larger than the maximum allowed (%d)",
glsl_get_type_name(b->type),
parcel->buffer_size,
consts->MaxShaderStorageBlockSize);
}
blocks[i].NumUniforms =
(unsigned)(ptrdiff_t)(&variables[parcel->index] - blocks[i].Uniforms);
*block_index = *block_index + 1;
}
/* This function resizes the array types of the block so that later we can use
* this new size to correctly calculate the offest for indirect indexing.
*/
static const glsl_type *
resize_block_array(const glsl_type *type,
struct uniform_block_array_elements *ub_array)
{
if (type->is_array()) {
struct uniform_block_array_elements *child_array =
type->fields.array->is_array() ? ub_array->array : NULL;
const glsl_type *new_child_type =
resize_block_array(type->fields.array, child_array);
const glsl_type *new_type =
glsl_type::get_array_instance(new_child_type,
ub_array->num_array_elements);
ub_array->ir->array->type = new_type;
return new_type;
} else {
return type;
}
}
static void
create_buffer_blocks(void *mem_ctx, const struct gl_constants *consts,
struct gl_shader_program *prog,
struct gl_uniform_block **out_blks, unsigned num_blocks,
struct hash_table *block_hash, unsigned num_variables,
bool create_ubo_blocks)
{
if (num_blocks == 0) {
assert(num_variables == 0);
return;
}
assert(num_variables != 0);
/* Allocate storage to hold all of the information related to uniform
* blocks that can be queried through the API.
*/
struct gl_uniform_block *blocks =
rzalloc_array(mem_ctx, gl_uniform_block, num_blocks);
gl_uniform_buffer_variable *variables =
ralloc_array(blocks, gl_uniform_buffer_variable, num_variables);
/* Add each variable from each uniform block to the API tracking
* structures.
*/
ubo_visitor parcel(blocks, variables, num_variables, prog,
consts->UseSTD430AsDefaultPacking);
unsigned i = 0;
hash_table_foreach (block_hash, entry) {
const struct link_uniform_block_active *const b =
(const struct link_uniform_block_active *) entry->data;
const glsl_type *block_type = b->type;
if ((create_ubo_blocks && !b->is_shader_storage) ||
(!create_ubo_blocks && b->is_shader_storage)) {
if (b->array != NULL) {
char *name = ralloc_strdup(NULL,
glsl_get_type_name(block_type->without_array()));
size_t name_length = strlen(name);
assert(b->has_instance_name);
process_block_array(b->array, &name, name_length, blocks, &parcel,
variables, b, &i, 0, consts, prog,
i);
ralloc_free(name);
} else {
process_block_array_leaf(glsl_get_type_name(block_type), blocks, &parcel,
variables, b, &i, 0,
0, consts, prog);
}
}
}
*out_blks = blocks;
assert(parcel.index == num_variables);
}
void
link_uniform_blocks(void *mem_ctx,
const struct gl_constants *consts,
struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_uniform_block **ubo_blocks,
unsigned *num_ubo_blocks,
struct gl_uniform_block **ssbo_blocks,
unsigned *num_ssbo_blocks)
{
/* This hash table will track all of the uniform blocks that have been
* encountered. Since blocks with the same block-name must be the same,
* the hash is organized by block-name.
*/
struct hash_table *block_hash =
_mesa_hash_table_create(mem_ctx, _mesa_hash_string,
_mesa_key_string_equal);
if (block_hash == NULL) {
_mesa_error_no_memory(__func__);
linker_error(prog, "out of memory\n");
return;
}
/* Determine which uniform blocks are active. */
link_uniform_block_active_visitor v(mem_ctx, block_hash, prog);
visit_list_elements(&v, shader->ir);
/* Count the number of active uniform blocks. Count the total number of
* active slots in those uniform blocks.
*/
unsigned num_ubo_variables = 0;
unsigned num_ssbo_variables = 0;
count_block_size block_size;
hash_table_foreach (block_hash, entry) {
struct link_uniform_block_active *const b =
(struct link_uniform_block_active *) entry->data;
assert((b->array != NULL) == b->type->is_array());
if (b->array != NULL &&
(b->type->without_array()->interface_packing ==
GLSL_INTERFACE_PACKING_PACKED)) {
b->type = resize_block_array(b->type, b->array);
b->var->type = b->type;
b->var->data.max_array_access = b->type->length - 1;
}
block_size.num_active_uniforms = 0;
block_size.process(b->type->without_array(), "",
consts->UseSTD430AsDefaultPacking);
if (b->array != NULL) {
unsigned aoa_size = b->type->arrays_of_arrays_size();
if (b->is_shader_storage) {
*num_ssbo_blocks += aoa_size;
num_ssbo_variables += aoa_size * block_size.num_active_uniforms;
} else {
*num_ubo_blocks += aoa_size;
num_ubo_variables += aoa_size * block_size.num_active_uniforms;
}
} else {
if (b->is_shader_storage) {
(*num_ssbo_blocks)++;
num_ssbo_variables += block_size.num_active_uniforms;
} else {
(*num_ubo_blocks)++;
num_ubo_variables += block_size.num_active_uniforms;
}
}
}
create_buffer_blocks(mem_ctx, consts, prog, ubo_blocks, *num_ubo_blocks,
block_hash, num_ubo_variables, true);
create_buffer_blocks(mem_ctx, consts, prog, ssbo_blocks, *num_ssbo_blocks,
block_hash, num_ssbo_variables, false);
_mesa_hash_table_destroy(block_hash, NULL);
}
static bool
link_uniform_blocks_are_compatible(const gl_uniform_block *a,

View File

@@ -1,284 +0,0 @@
/*
* Copyright © 2011 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.
*/
#include "ir.h"
#include "linker.h"
#include "ir_uniform.h"
#include "glsl_symbol_table.h"
#include "program.h"
#include "string_to_uint_map.h"
#include "ir_array_refcount.h"
#include "main/shader_types.h"
#include "main/consts_exts.h"
#include "util/strndup.h"
#include "util/u_math.h"
/**
* \file link_uniforms.cpp
* Assign locations for GLSL uniforms.
*
* \author Ian Romanick <ian.d.romanick@intel.com>
*/
void
program_resource_visitor::process(const glsl_type *type, const char *name,
bool use_std430_as_default)
{
assert(type->without_array()->is_struct()
|| type->without_array()->is_interface());
unsigned record_array_count = 1;
char *name_copy = ralloc_strdup(NULL, name);
enum glsl_interface_packing packing =
type->get_internal_ifc_packing(use_std430_as_default);
recursion(type, &name_copy, strlen(name), false, NULL, packing, false,
record_array_count, NULL);
ralloc_free(name_copy);
}
void
program_resource_visitor::process(ir_variable *var, bool use_std430_as_default)
{
const glsl_type *t =
var->data.from_named_ifc_block ? var->get_interface_type() : var->type;
process(var, t, use_std430_as_default);
}
void
program_resource_visitor::process(ir_variable *var, const glsl_type *var_type,
bool use_std430_as_default)
{
unsigned record_array_count = 1;
const bool row_major =
var->data.matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR;
enum glsl_interface_packing packing = var->get_interface_type() ?
var->get_interface_type()->
get_internal_ifc_packing(use_std430_as_default) :
var->type->get_internal_ifc_packing(use_std430_as_default);
const glsl_type *t = var_type;
const glsl_type *t_without_array = t->without_array();
/* false is always passed for the row_major parameter to the other
* processing functions because no information is available to do
* otherwise. See the warning in linker.h.
*/
if (t_without_array->is_struct() ||
(t->is_array() && t->fields.array->is_array())) {
char *name = ralloc_strdup(NULL, var->name);
recursion(var->type, &name, strlen(name), row_major, NULL, packing,
false, record_array_count, NULL);
ralloc_free(name);
} else if (t_without_array->is_interface()) {
char *name = ralloc_strdup(NULL, glsl_get_type_name(t_without_array));
const glsl_struct_field *ifc_member = var->data.from_named_ifc_block ?
&t_without_array->
fields.structure[t_without_array->field_index(var->name)] : NULL;
recursion(t, &name, strlen(name), row_major, NULL, packing,
false, record_array_count, ifc_member);
ralloc_free(name);
} else {
this->set_record_array_count(record_array_count);
this->visit_field(t, var->name, row_major, NULL, packing, false);
}
}
void
program_resource_visitor::recursion(const glsl_type *t, char **name,
size_t name_length, bool row_major,
const glsl_type *record_type,
const enum glsl_interface_packing packing,
bool last_field,
unsigned record_array_count,
const glsl_struct_field *named_ifc_member)
{
/* Records need to have each field processed individually.
*
* Arrays of records need to have each array element processed
* individually, then each field of the resulting array elements processed
* individually.
*/
if (t->is_interface() && named_ifc_member) {
ralloc_asprintf_rewrite_tail(name, &name_length, ".%s",
named_ifc_member->name);
recursion(named_ifc_member->type, name, name_length, row_major, NULL,
packing, false, record_array_count, NULL);
} else if (t->is_struct() || t->is_interface()) {
if (record_type == NULL && t->is_struct())
record_type = t;
if (t->is_struct())
this->enter_record(t, *name, row_major, packing);
for (unsigned i = 0; i < t->length; i++) {
const char *field = t->fields.structure[i].name;
size_t new_length = name_length;
if (t->is_interface() && t->fields.structure[i].offset != -1)
this->set_buffer_offset(t->fields.structure[i].offset);
/* Append '.field' to the current variable name. */
if (name_length == 0) {
ralloc_asprintf_rewrite_tail(name, &new_length, "%s", field);
} else {
ralloc_asprintf_rewrite_tail(name, &new_length, ".%s", field);
}
/* The layout of structures at the top level of the block is set
* during parsing. For matrices contained in multiple levels of
* structures in the block, the inner structures have no layout.
* These cases must potentially inherit the layout from the outer
* levels.
*/
bool field_row_major = row_major;
const enum glsl_matrix_layout matrix_layout =
glsl_matrix_layout(t->fields.structure[i].matrix_layout);
if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
field_row_major = true;
} else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
field_row_major = false;
}
recursion(t->fields.structure[i].type, name, new_length,
field_row_major,
record_type,
packing,
(i + 1) == t->length, record_array_count, NULL);
/* Only the first leaf-field of the record gets called with the
* record type pointer.
*/
record_type = NULL;
}
if (t->is_struct()) {
(*name)[name_length] = '\0';
this->leave_record(t, *name, row_major, packing);
}
} else if (t->without_array()->is_struct() ||
t->without_array()->is_interface() ||
(t->is_array() && t->fields.array->is_array())) {
if (record_type == NULL && t->fields.array->is_struct())
record_type = t->fields.array;
unsigned length = t->length;
/* Shader storage block unsized arrays: add subscript [0] to variable
* names.
*/
if (t->is_unsized_array())
length = 1;
record_array_count *= length;
for (unsigned i = 0; i < length; i++) {
size_t new_length = name_length;
/* Append the subscript to the current variable name */
ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i);
recursion(t->fields.array, name, new_length, row_major,
record_type,
packing,
(i + 1) == t->length, record_array_count,
named_ifc_member);
/* Only the first leaf-field of the record gets called with the
* record type pointer.
*/
record_type = NULL;
}
} else {
this->set_record_array_count(record_array_count);
this->visit_field(t, *name, row_major, record_type, packing, last_field);
}
}
void
program_resource_visitor::enter_record(const glsl_type *, const char *, bool,
const enum glsl_interface_packing)
{
}
void
program_resource_visitor::leave_record(const glsl_type *, const char *, bool,
const enum glsl_interface_packing)
{
}
void
program_resource_visitor::set_buffer_offset(unsigned)
{
}
void
program_resource_visitor::set_record_array_count(unsigned)
{
}
unsigned
link_calculate_matrix_stride(const glsl_type *matrix, bool row_major,
enum glsl_interface_packing packing)
{
const unsigned N = matrix->is_double() ? 8 : 4;
const unsigned items =
row_major ? matrix->matrix_columns : matrix->vector_elements;
assert(items <= 4);
/* Matrix stride for std430 mat2xY matrices are not rounded up to
* vec4 size.
*
* Section 7.6.2.2 "Standard Uniform Block Layout" of the OpenGL 4.3 spec
* says:
*
* 2. If the member is a two- or four-component vector with components
* consuming N basic machine units, the base alignment is 2N or 4N,
* respectively.
* ...
* 4. If the member is an array of scalars or vectors, the base
* alignment and array stride are set to match the base alignment of
* a single array element, according to rules (1), (2), and (3), and
* rounded up to the base alignment of a vec4.
* ...
* 7. If the member is a row-major matrix with C columns and R rows, the
* matrix is stored identically to an array of R row vectors with C
* components each, according to rule (4).
* ...
*
* When using the std430 storage layout, shader storage blocks will be
* laid out in buffer storage identically to uniform and shader storage
* blocks using the std140 layout, except that the base alignment and
* stride of arrays of scalars and vectors in rule 4 and of structures
* in rule 9 are not rounded up a multiple of the base alignment of a
* vec4.
*/
return packing == GLSL_INTERFACE_PACKING_STD430
? (items < 3 ? items * N : align(items * N, 16))
: align(items * N, 16);
}

View File

@@ -41,16 +41,6 @@ link_cross_validate_uniform_block(void *mem_ctx,
unsigned int *num_linked_blocks,
struct gl_uniform_block *new_block);
extern void
link_uniform_blocks(void *mem_ctx,
const struct gl_constants *consts,
struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_uniform_block **ubo_blocks,
unsigned *num_ubo_blocks,
struct gl_uniform_block **ssbo_blocks,
unsigned *num_ssbo_blocks);
bool
validate_intrastage_arrays(struct gl_shader_program *prog,
ir_variable *const var,
@@ -79,120 +69,4 @@ link_intrastage_shaders(void *mem_ctx,
unsigned num_shaders,
bool allow_missing_main);
extern unsigned
link_calculate_matrix_stride(const glsl_type *matrix, bool row_major,
enum glsl_interface_packing packing);
/**
* Class for processing all of the leaf fields of a variable that corresponds
* to a program resource.
*
* The leaf fields are all the parts of the variable that the application
* could query using \c glGetProgramResourceIndex (or that could be returned
* by \c glGetProgramResourceName).
*
* Classes my derive from this class to implement specific functionality.
* This class only provides the mechanism to iterate over the leaves. Derived
* classes must implement \c ::visit_field and may override \c ::process.
*/
class program_resource_visitor {
public:
/**
* Begin processing a variable
*
* Classes that overload this function should call \c ::process from the
* base class to start the recursive processing of the variable.
*
* \param var The variable that is to be processed
*
* Calls \c ::visit_field for each leaf of the variable.
*
* \warning
* When processing a uniform block, this entry should only be used in cases
* where the row / column ordering of matrices in the block does not
* matter. For example, enumerating the names of members of the block, but
* not for determining the offsets of members.
*/
void process(ir_variable *var, bool use_std430_as_default);
/**
* Begin processing a variable
*
* Classes that overload this function should call \c ::process from the
* base class to start the recursive processing of the variable.
*
* \param var The variable that is to be processed
* \param var_type The glsl_type reference of the variable
*
* Calls \c ::visit_field for each leaf of the variable.
*
* \warning
* When processing a uniform block, this entry should only be used in cases
* where the row / column ordering of matrices in the block does not
* matter. For example, enumerating the names of members of the block, but
* not for determining the offsets of members.
*/
void process(ir_variable *var, const glsl_type *var_type,
bool use_std430_as_default);
/**
* Begin processing a variable of a structured type.
*
* This flavor of \c process should be used to handle structured types
* (i.e., structures, interfaces, or arrays there of) that need special
* name handling. A common usage is to handle cases where the block name
* (instead of the instance name) is used for an interface block.
*
* \param type Type that is to be processed, associated with \c name
* \param name Base name of the structured variable being processed
*
* \note
* \c type must be \c GLSL_TYPE_RECORD, \c GLSL_TYPE_INTERFACE, or an array
* there of.
*/
void process(const glsl_type *type, const char *name,
bool use_std430_as_default);
protected:
/**
* Method invoked for each leaf of the variable
*
* \param type Type of the field.
* \param name Fully qualified name of the field.
* \param row_major For a matrix type, is it stored row-major.
* \param record_type Type of the record containing the field.
* \param last_field Set if \c name is the last field of the structure
* containing it. This will always be false for items
* not contained in a structure or interface block.
*/
virtual void visit_field(const glsl_type *type, const char *name,
bool row_major, const glsl_type *record_type,
const enum glsl_interface_packing packing,
bool last_field) = 0;
virtual void enter_record(const glsl_type *type, const char *name,
bool row_major, const enum glsl_interface_packing packing);
virtual void leave_record(const glsl_type *type, const char *name,
bool row_major, const enum glsl_interface_packing packing);
virtual void set_buffer_offset(unsigned offset);
virtual void set_record_array_count(unsigned record_array_count);
private:
/**
* \param name_length Length of the current name \b not including the
* terminating \c NUL character.
* \param last_field Set if \c name is the last field of the structure
* containing it. This will always be false for items
* not contained in a structure or interface block.
*/
void recursion(const glsl_type *t, char **name, size_t name_length,
bool row_major, const glsl_type *record_type,
const enum glsl_interface_packing packing,
bool last_field, unsigned record_array_count,
const glsl_struct_field *named_ifc_member);
};
#endif /* GLSL_LINKER_H */

View File

@@ -190,9 +190,6 @@ files_libglsl = files(
'linker_util.cpp',
'link_functions.cpp',
'link_interface_blocks.cpp',
'link_uniforms.cpp',
'link_uniform_block_active_visitor.cpp',
'link_uniform_block_active_visitor.h',
'link_uniform_blocks.cpp',
'list.h',
'lower_builtins.cpp',