Mesa (master): zink: rework ssbo indexing and binding
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Thu Jan 28 14:41:40 UTC 2021
Module: Mesa
Branch: master
Commit: b0847a43245c6efdd17ad4bd03ef52c72167fa65
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=b0847a43245c6efdd17ad4bd03ef52c72167fa65
Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date: Fri Aug 7 19:16:01 2020 -0400
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 at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8628>
---
.../drivers/zink/nir_to_spirv/nir_to_spirv.c | 111 +++++++++++----------
src/gallium/drivers/zink/zink_compiler.c | 29 ++++--
2 files changed, 78 insertions(+), 62 deletions(-)
diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
index 4ea5d0ec80c..d6cf1a255ac 100644
--- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
+++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
@@ -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");
diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c
index 12823382b61..55e49c72185 100644
--- a/src/gallium/drivers/zink/zink_compiler.c
+++ b/src/gallium/drivers/zink/zink_compiler.c
@@ -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);
More information about the mesa-commit
mailing list