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];
}
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
*/
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
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:
(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);
}
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);
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");
/* 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 |
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);