mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 09:08:10 +02:00
glsl: add gl_nir_linker_size_arrays()
This will size implicitly size arrays during linking, replacing the glsl ir version. Acked-by: Marek Olšák <marek.olsak@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31137>
This commit is contained in:
parent
a235da080e
commit
083b4ffb78
2 changed files with 227 additions and 0 deletions
|
|
@ -34,6 +34,231 @@
|
|||
#include "util/hash_table.h"
|
||||
#include "util/u_string.h"
|
||||
|
||||
/**
|
||||
* Change var->interface_type on a variable that previously had a
|
||||
* different, but compatible, interface_type. This is used during linking
|
||||
* to set the size of arrays in interface blocks.
|
||||
*/
|
||||
static void
|
||||
change_interface_type(nir_variable *var, const struct glsl_type *type)
|
||||
{
|
||||
if (var->max_ifc_array_access != NULL) {
|
||||
/* max_ifc_array_access has already been allocated, so make sure the
|
||||
* new interface has the same number of fields as the old one.
|
||||
*/
|
||||
assert(var->interface_type->length == type->length);
|
||||
}
|
||||
var->interface_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
fixup_type(const struct glsl_type **type, unsigned max_array_access,
|
||||
bool from_ssbo_unsized_array, bool *implicit_sized)
|
||||
{
|
||||
if (!from_ssbo_unsized_array && glsl_type_is_unsized_array(*type)) {
|
||||
*type = glsl_array_type((*type)->fields.array,
|
||||
max_array_access + 1, (*type)->explicit_stride);
|
||||
*implicit_sized = true;
|
||||
assert(*type != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fixup_unnamed_interface_type(const void *key, void *data,
|
||||
UNUSED void *closure)
|
||||
{
|
||||
const struct glsl_type *ifc_type = (const struct glsl_type *) key;
|
||||
nir_variable **interface_vars = (nir_variable **) data;
|
||||
unsigned num_fields = ifc_type->length;
|
||||
glsl_struct_field *fields = malloc(sizeof(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) {
|
||||
free(fields);
|
||||
return;
|
||||
}
|
||||
enum glsl_interface_packing packing =
|
||||
(enum glsl_interface_packing) ifc_type->interface_packing;
|
||||
bool row_major = (bool) ifc_type->interface_row_major;
|
||||
const struct glsl_type *new_ifc_type =
|
||||
glsl_interface_type(fields, num_fields, packing,
|
||||
row_major, glsl_get_type_name(ifc_type));
|
||||
free(fields);
|
||||
for (unsigned i = 0; i < num_fields; i++) {
|
||||
if (interface_vars[i] != NULL)
|
||||
change_interface_type(interface_vars[i], new_ifc_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 struct glsl_type *type,
|
||||
const int *max_ifc_array_access,
|
||||
bool is_ssbo)
|
||||
{
|
||||
unsigned num_fields = type->length;
|
||||
glsl_struct_field *fields = malloc(sizeof(glsl_struct_field) * num_fields); //new glsl_struct_field[num_fields];
|
||||
memcpy(fields, type->fields.structure,
|
||||
num_fields * sizeof(*fields));
|
||||
for (unsigned i = 0; i < num_fields; i++) {
|
||||
bool implicit_sized_array = fields[i].implicit_sized_array;
|
||||
/* 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],
|
||||
true, &implicit_sized_array);
|
||||
else
|
||||
fixup_type(&fields[i].type, max_ifc_array_access[i],
|
||||
false, &implicit_sized_array);
|
||||
fields[i].implicit_sized_array = implicit_sized_array;
|
||||
}
|
||||
enum glsl_interface_packing packing =
|
||||
(enum glsl_interface_packing) type->interface_packing;
|
||||
bool row_major = (bool) type->interface_row_major;
|
||||
const struct glsl_type *new_ifc_type =
|
||||
glsl_interface_type(fields, num_fields,
|
||||
packing, row_major, glsl_get_type_name(type));
|
||||
free(fields);
|
||||
return new_ifc_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 struct glsl_type *elem_type = type->fields.structure[i].type;
|
||||
if (glsl_type_is_unsized_array(elem_type))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const glsl_type *
|
||||
update_interface_members_array(const glsl_type *type,
|
||||
const glsl_type *new_interface_type)
|
||||
{
|
||||
const struct glsl_type *element_type = type->fields.array;
|
||||
if (glsl_type_is_array(element_type)) {
|
||||
const glsl_type *new_array_type =
|
||||
update_interface_members_array(element_type, new_interface_type);
|
||||
return glsl_array_type(new_array_type, type->length,
|
||||
type->explicit_stride);
|
||||
} else {
|
||||
return glsl_array_type(new_interface_type, type->length,
|
||||
type->explicit_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
size_variable_array(void *mem_ctx, nir_variable *var,
|
||||
struct hash_table *unnamed_interfaces)
|
||||
{
|
||||
const struct glsl_type *type_without_array;
|
||||
const struct glsl_type *ifc_type = var->interface_type;
|
||||
bool implicit_sized_array = var->data.implicit_sized_array;
|
||||
|
||||
fixup_type(&var->type, var->data.max_array_access,
|
||||
var->data.from_ssbo_unsized_array,
|
||||
&implicit_sized_array);
|
||||
var->data.implicit_sized_array = implicit_sized_array;
|
||||
type_without_array = glsl_without_array(var->type);
|
||||
if (glsl_type_is_interface(var->type)) {
|
||||
if (interface_contains_unsized_arrays(var->type)) {
|
||||
const struct glsl_type *new_type =
|
||||
resize_interface_members(var->type,
|
||||
var->max_ifc_array_access,
|
||||
var->data.mode == nir_var_mem_ssbo);
|
||||
var->type = new_type;
|
||||
change_interface_type(var, new_type);
|
||||
}
|
||||
} else if (glsl_type_is_interface(type_without_array)) {
|
||||
if (interface_contains_unsized_arrays(type_without_array)) {
|
||||
const struct glsl_type *new_type =
|
||||
resize_interface_members(type_without_array,
|
||||
var->max_ifc_array_access,
|
||||
var->data.mode == nir_var_mem_ssbo);
|
||||
change_interface_type(var, new_type);
|
||||
var->type = update_interface_members_array(var->type, new_type);
|
||||
}
|
||||
} else if (ifc_type) {
|
||||
/* Store a pointer to the variable in the unnamed_interfaces
|
||||
* hashtable.
|
||||
*/
|
||||
struct hash_entry *entry =
|
||||
_mesa_hash_table_search(unnamed_interfaces, ifc_type);
|
||||
|
||||
nir_variable **interface_vars =
|
||||
entry ? (nir_variable **) entry->data : NULL;
|
||||
|
||||
if (interface_vars == NULL) {
|
||||
interface_vars = rzalloc_array(mem_ctx, nir_variable *,
|
||||
ifc_type->length);
|
||||
_mesa_hash_table_insert(unnamed_interfaces, ifc_type,
|
||||
interface_vars);
|
||||
}
|
||||
unsigned index = glsl_get_field_index(ifc_type, var->name);
|
||||
assert(index < ifc_type->length);
|
||||
assert(interface_vars[index] == NULL);
|
||||
interface_vars[index] = var;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gl_nir_linker_size_arrays(nir_shader *shader)
|
||||
{
|
||||
void *mem_ctx = ralloc_context(NULL);
|
||||
|
||||
/**
|
||||
* Hash table from const glsl_type * to an array of nir_variable *'s
|
||||
* pointing to the nir_variables constituting each unnamed interface block.
|
||||
*/
|
||||
struct hash_table *unnamed_interfaces =
|
||||
_mesa_pointer_hash_table_create(NULL);
|
||||
|
||||
nir_foreach_variable_in_shader(var, shader) {
|
||||
size_variable_array(mem_ctx, var, unnamed_interfaces);
|
||||
}
|
||||
|
||||
nir_foreach_function_impl(impl, shader) {
|
||||
nir_foreach_variable_in_list(var, &impl->locals) {
|
||||
size_variable_array(mem_ctx, var, unnamed_interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 nir_variable nodes to point to the new interface
|
||||
* type.
|
||||
*/
|
||||
hash_table_call_foreach(unnamed_interfaces,
|
||||
fixup_unnamed_interface_type, NULL);
|
||||
|
||||
_mesa_hash_table_destroy(unnamed_interfaces, NULL);
|
||||
ralloc_free(mem_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if interface members mismatch and its not allowed by GLSL.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ bool gl_nir_validate_intrastage_arrays(struct gl_shader_program *prog,
|
|||
nir_shader *existing_shader,
|
||||
bool match_precision);
|
||||
|
||||
void gl_nir_linker_size_arrays(nir_shader *shader);
|
||||
|
||||
struct nir_xfb_info *
|
||||
gl_to_nir_xfb_info(struct gl_transform_feedback_info *info, void *mem_ctx);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue