zink: rework ssbo indexing and binding
this is actually crazy, but there's no other way to do it from the variable. ideally, nir would have a separate type for atomic counters to simplify this and then also stop mangling binding/block index during lower_buffers Reviewed-by: Dave Airlie <airlied@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8628>
This commit is contained in:
parent
deeafe47b6
commit
b0847a4324
|
@ -45,6 +45,8 @@ struct ntv_context {
|
|||
size_t num_ubos;
|
||||
|
||||
SpvId ssbos[PIPE_MAX_SHADER_BUFFERS];
|
||||
uint32_t ssbo_mask;
|
||||
uint32_t num_ssbos;
|
||||
SpvId image_types[PIPE_MAX_SAMPLERS];
|
||||
SpvId images[PIPE_MAX_SAMPLERS];
|
||||
SpvId sampler_types[PIPE_MAX_SAMPLERS];
|
||||
|
@ -813,47 +815,7 @@ emit_image(struct ntv_context *ctx, struct nir_variable *var)
|
|||
}
|
||||
|
||||
static void
|
||||
emit_ssbo(struct ntv_context *ctx, struct nir_variable *var)
|
||||
{
|
||||
SpvId vec4_type = get_uvec_type(ctx, 32, 4);
|
||||
SpvId array_type = spirv_builder_type_runtime_array(&ctx->builder, vec4_type);
|
||||
spirv_builder_emit_array_stride(&ctx->builder, array_type, 16);
|
||||
|
||||
SpvId struct_type = spirv_builder_type_struct(&ctx->builder, &array_type, 1);
|
||||
if (var->name) {
|
||||
char struct_name[100];
|
||||
snprintf(struct_name, sizeof(struct_name), "struct_%s", var->name);
|
||||
spirv_builder_emit_name(&ctx->builder, struct_type, struct_name);
|
||||
}
|
||||
|
||||
spirv_builder_emit_decoration(&ctx->builder, struct_type,
|
||||
SpvDecorationBlock);
|
||||
spirv_builder_emit_member_offset(&ctx->builder, struct_type, 0, 0);
|
||||
|
||||
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
|
||||
SpvStorageClassStorageBuffer,
|
||||
struct_type);
|
||||
|
||||
SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
|
||||
SpvStorageClassStorageBuffer);
|
||||
if (var->name) {
|
||||
char struct_name[100];
|
||||
snprintf(struct_name, sizeof(struct_name), "%s", var->name);
|
||||
spirv_builder_emit_name(&ctx->builder, var_id, var->name);
|
||||
}
|
||||
|
||||
assert(var->data.binding < ARRAY_SIZE(ctx->ssbos));
|
||||
ctx->ssbos[var->data.binding] = var_id;
|
||||
|
||||
spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0);
|
||||
int binding = zink_binding(ctx->stage,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
var->data.binding);
|
||||
spirv_builder_emit_binding(&ctx->builder, var_id, binding);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
|
||||
emit_bo(struct ntv_context *ctx, struct nir_variable *var)
|
||||
{
|
||||
bool is_ubo_array = glsl_type_is_array(var->type) && glsl_type_is_interface(glsl_without_array(var->type));
|
||||
/* variables accessed inside a uniform block will get merged into a big
|
||||
|
@ -861,12 +823,18 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
|
|||
*/
|
||||
if (var->data.location && !is_ubo_array && var->type != var->interface_type)
|
||||
return;
|
||||
bool ssbo = var->data.mode == nir_var_mem_ssbo;
|
||||
|
||||
uint32_t size = glsl_count_attribute_slots(var->interface_type, false);
|
||||
SpvId array_type;
|
||||
SpvId vec4_type = get_uvec_type(ctx, 32, 4);
|
||||
SpvId array_length = emit_uint_const(ctx, 32, size);
|
||||
SpvId array_type = spirv_builder_type_array(&ctx->builder, vec4_type,
|
||||
if (glsl_type_is_unsized_array(var->type))
|
||||
array_type = spirv_builder_type_runtime_array(&ctx->builder, vec4_type);
|
||||
else {
|
||||
uint32_t size = glsl_count_attribute_slots(var->interface_type, false);
|
||||
SpvId array_length = emit_uint_const(ctx, 32, size);
|
||||
array_type = spirv_builder_type_array(&ctx->builder, vec4_type,
|
||||
array_length);
|
||||
}
|
||||
spirv_builder_emit_array_stride(&ctx->builder, array_type, 16);
|
||||
|
||||
// wrap UBO-array in a struct
|
||||
|
@ -882,7 +850,7 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
|
|||
spirv_builder_emit_member_offset(&ctx->builder, struct_type, 0, 0);
|
||||
|
||||
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
|
||||
SpvStorageClassUniform,
|
||||
ssbo ? SpvStorageClassStorageBuffer : SpvStorageClassUniform,
|
||||
struct_type);
|
||||
|
||||
/* if this is a ubo array, create a binding point for each array member:
|
||||
|
@ -893,21 +861,57 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
|
|||
|
||||
(also it's just easier)
|
||||
*/
|
||||
for (unsigned i = 0; i < (is_ubo_array ? glsl_get_aoa_size(var->type) : 1); i++) {
|
||||
unsigned size = is_ubo_array ? glsl_get_aoa_size(var->type) : 1;
|
||||
int base = -1;
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
|
||||
SpvStorageClassUniform);
|
||||
ssbo ? SpvStorageClassStorageBuffer : SpvStorageClassUniform);
|
||||
if (var->name) {
|
||||
char struct_name[100];
|
||||
snprintf(struct_name, sizeof(struct_name), "%s[%u]", var->name, i);
|
||||
spirv_builder_emit_name(&ctx->builder, var_id, var->name);
|
||||
}
|
||||
|
||||
assert(ctx->num_ubos < ARRAY_SIZE(ctx->ubos));
|
||||
ctx->ubos[ctx->num_ubos++] = var_id;
|
||||
if (ssbo) {
|
||||
unsigned ssbo_idx = 0;
|
||||
if (!is_ubo_array && var->data.explicit_binding &&
|
||||
(glsl_type_is_unsized_array(var->type) || glsl_get_length(var->interface_type) == 1)) {
|
||||
/* - block ssbos get their binding broken in gl_nir_lower_buffers,
|
||||
* but also they're totally indistinguishable from lowered counter buffers which have valid bindings
|
||||
*
|
||||
* hopefully this is a counter or some other non-block variable, but if not then we're probably fucked
|
||||
*/
|
||||
ssbo_idx = var->data.binding;
|
||||
} else if (base >= 0)
|
||||
/* we're indexing into a ssbo array and already have the base index */
|
||||
ssbo_idx = base + i;
|
||||
else {
|
||||
if (ctx->ssbo_mask & 1) {
|
||||
/* 0 index is used, iterate through the used blocks until we find the first unused one */
|
||||
for (unsigned j = 1; j < ctx->num_ssbos; j++)
|
||||
if (!(ctx->ssbo_mask & (1 << j))) {
|
||||
/* we're iterating forward through the blocks, so the first available one should be
|
||||
* what we're looking for
|
||||
*/
|
||||
base = ssbo_idx = j;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
/* we're iterating forward through the ssbos, so always assign 0 first */
|
||||
base = ssbo_idx = 0;
|
||||
assert(ssbo_idx < ctx->num_ssbos);
|
||||
}
|
||||
assert(!ctx->ssbos[ssbo_idx]);
|
||||
ctx->ssbos[ssbo_idx] = var_id;
|
||||
ctx->ssbo_mask |= 1 << ssbo_idx;
|
||||
} else {
|
||||
assert(ctx->num_ubos < ARRAY_SIZE(ctx->ubos));
|
||||
ctx->ubos[ctx->num_ubos++] = var_id;
|
||||
}
|
||||
|
||||
spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0);
|
||||
int binding = zink_binding(ctx->stage,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
ssbo ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
var->data.binding + i);
|
||||
spirv_builder_emit_binding(&ctx->builder, var_id, binding);
|
||||
}
|
||||
|
@ -916,10 +920,8 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
|
|||
static void
|
||||
emit_uniform(struct ntv_context *ctx, struct nir_variable *var)
|
||||
{
|
||||
if (var->data.mode == nir_var_mem_ubo)
|
||||
emit_ubo(ctx, var);
|
||||
else if (var->data.mode == nir_var_mem_ssbo)
|
||||
emit_ssbo(ctx, var);
|
||||
if (var->data.mode == nir_var_mem_ubo || var->data.mode == nir_var_mem_ssbo)
|
||||
emit_bo(ctx, var);
|
||||
else {
|
||||
assert(var->data.mode == nir_var_uniform);
|
||||
const struct glsl_type *type = glsl_without_array(var->type);
|
||||
|
@ -3231,6 +3233,7 @@ nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info,
|
|||
|
||||
ctx.stage = s->info.stage;
|
||||
ctx.so_info = so_info;
|
||||
ctx.num_ssbos = s->info.num_ssbos;
|
||||
ctx.shader_slot_map = shader_slot_map;
|
||||
ctx.shader_slots_reserved = *shader_slots_reserved;
|
||||
ctx.GLSL_std_450 = spirv_builder_import(&ctx.builder, "GLSL.std.450");
|
||||
|
|
|
@ -463,6 +463,7 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir,
|
|||
/* need to set up var->data.binding for UBOs, which means we need to start at
|
||||
* the "first" UBO, which is at the end of the list
|
||||
*/
|
||||
int ssbo_array_index = 0;
|
||||
foreach_list_typed_reverse(nir_variable, var, node, &nir->variables) {
|
||||
if (_nir_shader_variable_has_mode(var, nir_var_uniform |
|
||||
nir_var_mem_ubo |
|
||||
|
@ -493,14 +494,26 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir,
|
|||
ret->num_bindings++;
|
||||
}
|
||||
} else if (var->data.mode == nir_var_mem_ssbo) {
|
||||
int binding = zink_binding(nir->info.stage,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
var->data.binding);
|
||||
ret->bindings[ret->num_bindings].index = var->data.binding;
|
||||
ret->bindings[ret->num_bindings].binding = binding;
|
||||
ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
ret->bindings[ret->num_bindings].size = 1;
|
||||
ret->num_bindings++;
|
||||
/* same-ish mechanics as ubos */
|
||||
bool bo_array = glsl_type_is_array(var->type) && glsl_type_is_interface(glsl_without_array(var->type));
|
||||
if (var->data.location && !bo_array)
|
||||
continue;
|
||||
if (!var->data.explicit_binding) {
|
||||
var->data.binding = ssbo_array_index;
|
||||
}
|
||||
for (unsigned i = 0; i < (bo_array ? glsl_get_aoa_size(var->type) : 1); i++) {
|
||||
int binding = zink_binding(nir->info.stage,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
var->data.binding + i);
|
||||
if (strcmp(glsl_get_type_name(var->interface_type), "counters"))
|
||||
ret->bindings[ret->num_bindings].index = ssbo_array_index++;
|
||||
else
|
||||
ret->bindings[ret->num_bindings].index = var->data.binding;
|
||||
ret->bindings[ret->num_bindings].binding = binding;
|
||||
ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
ret->bindings[ret->num_bindings].size = 1;
|
||||
ret->num_bindings++;
|
||||
}
|
||||
} else {
|
||||
assert(var->data.mode == nir_var_uniform);
|
||||
const struct glsl_type *type = glsl_without_array(var->type);
|
||||
|
|
Loading…
Reference in New Issue