spirv: Use value_id_bound to set initial memory allocated

Don't rely on the current default (which is 2048 bytes) buffer size for
blocks -- which ends up being too small for most shaders.  Since we
already rely on value_id_bound to allocate an array of vtn_value, use
that to estimate a better value.

In addition to space for the array, we approximate the extra size of
extra data structures with the size of vtn_ssa_value, and skip it to the
next size (double it) to cover the CFG related allocations.  This
results in only single system allocation necessary to back the temporary
data for the majority of the shaders.

Parsing code was slightly reordered so we can validate and read the
value_id_bound before the temporary allocator is created.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25279>
This commit is contained in:
Caio Oliveira 2023-12-23 09:13:41 -08:00 committed by Marge Bot
parent d5b4b7356e
commit 0b5abf2512

View file

@ -6697,15 +6697,6 @@ vtn_create_builder(const uint32_t *words, size_t word_count,
/* Initialize the vtn_builder object */
struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
/* Allocate all the data that can be dropped after parsing using
* a cheaper allocation strategy.
*/
b->lin_ctx = linear_context(b);
struct spirv_to_nir_options *dup_options =
vtn_alloc(b, struct spirv_to_nir_options);
*dup_options = *options;
b->spirv = words;
b->spirv_word_count = word_count;
b->file = NULL;
@ -6714,7 +6705,6 @@ vtn_create_builder(const uint32_t *words, size_t word_count,
list_inithead(&b->functions);
b->entry_point_stage = stage;
b->entry_point_name = entry_point_name;
b->options = dup_options;
/*
* Handle the SPIR-V header (first 5 dwords).
@ -6737,6 +6727,33 @@ vtn_create_builder(const uint32_t *words, size_t word_count,
b->generator_id = words[2] >> 16;
uint16_t generator_version = words[2];
unsigned value_id_bound = words[3];
if (words[4] != 0) {
vtn_err("words[4] was %u, want 0", words[4]);
goto fail;
}
b->value_id_bound = value_id_bound;
/* Allocate all the data that can be dropped after parsing using
* a cheaper allocation strategy. Use the value_id_bound and the
* size of the common internal structs to approximate a good
* buffer_size.
*/
const linear_opts lin_opts = {
.min_buffer_size = 2 * value_id_bound * (sizeof(struct vtn_value) +
sizeof(struct vtn_ssa_value)),
};
b->lin_ctx = linear_context_with_opts(b, &lin_opts);
struct spirv_to_nir_options *dup_options =
vtn_alloc(b, struct spirv_to_nir_options);
*dup_options = *options;
b->options = dup_options;
b->values = vtn_zalloc_array(b, struct vtn_value, value_id_bound);
/* In GLSLang commit 8297936dd6eb3, their handling of barrier() was fixed
* to provide correct memory semantics on compute shader barrier()
* commands. Prior to that, we need to fix them up ourselves. This
@ -6780,16 +6797,6 @@ vtn_create_builder(const uint32_t *words, size_t word_count,
(b->generator_id == vtn_generator_clay_shader_compiler &&
generator_version < 18);
/* words[2] == generator magic */
unsigned value_id_bound = words[3];
if (words[4] != 0) {
vtn_err("words[4] was %u, want 0", words[4]);
goto fail;
}
b->value_id_bound = value_id_bound;
b->values = vtn_zalloc_array(b, struct vtn_value, value_id_bound);
if (b->options->environment == NIR_SPIRV_VULKAN && b->version < 0x10400)
b->vars_used_indirectly = _mesa_pointer_set_create(b);