From 9c18491e4104a2d31992fb0e1304136b21e8e463 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Tue, 28 Jul 2020 14:50:45 -0400 Subject: [PATCH] zink: handle dynamic sampler array indexing for arb_gpu_shader5 this requires that arrays of samplers be declared as single variables with a single binding point, which is then propagated through to the descriptor set updates constant sampler array indexing is now un-lowered during access so we can construct an access chain for both constant and dynamic offset paths Reviewed-by: Erik Faye-Lund Part-of: --- .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 111 ++++++++++-------- src/gallium/drivers/zink/zink_compiler.c | 29 ++--- src/gallium/drivers/zink/zink_compiler.h | 1 + src/gallium/drivers/zink/zink_draw.c | 56 +++++---- src/gallium/drivers/zink/zink_program.c | 2 +- 5 files changed, 100 insertions(+), 99 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 f7501d316bb..4c1af8192bb 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,7 @@ struct ntv_context { size_t num_ubos; SpvId image_types[PIPE_MAX_SAMPLERS]; SpvId samplers[PIPE_MAX_SAMPLERS]; + unsigned char sampler_array_sizes[PIPE_MAX_SAMPLERS]; unsigned samplers_used : PIPE_MAX_SAMPLERS; SpvId entry_ifaces[PIPE_MAX_SHADER_INPUTS * 4 + PIPE_MAX_SHADER_OUTPUTS * 4]; size_t num_entry_ifaces; @@ -582,58 +583,36 @@ emit_sampler(struct ntv_context *ctx, struct nir_variable *var) SpvId sampled_type = spirv_builder_type_sampled_image(&ctx->builder, image_type); + + int index = var->data.binding; + assert(!(ctx->samplers_used & (1 << index))); + assert(!ctx->image_types[index]); + + if (glsl_type_is_array(var->type)) { + sampled_type = spirv_builder_type_array(&ctx->builder, sampled_type, + emit_uint_const(ctx, 32, glsl_get_aoa_size(var->type))); + spirv_builder_emit_array_stride(&ctx->builder, sampled_type, sizeof(void*)); + ctx->sampler_array_sizes[index] = glsl_get_aoa_size(var->type); + } SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder, SpvStorageClassUniformConstant, sampled_type); - if (glsl_type_is_array(var->type)) { - /* ARB_arrays_of_arrays from GLSL 1.30 allows nesting of arrays, so we just - * use the total array size if we encounter a nested array - */ - unsigned size = glsl_get_aoa_size(var->type); - for (int i = 0; i < size; ++i) { - SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type, - SpvStorageClassUniformConstant); + SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type, + SpvStorageClassUniformConstant); - if (var->name) { - char element_name[100]; - snprintf(element_name, sizeof(element_name), "%s_%d", var->name, i); - spirv_builder_emit_name(&ctx->builder, var_id, var->name); - } + if (var->name) + spirv_builder_emit_name(&ctx->builder, var_id, var->name); - int index = var->data.binding + i; - assert(!(ctx->samplers_used & (1 << index))); - assert(!ctx->image_types[index]); - ctx->image_types[index] = image_type; - ctx->samplers[index] = var_id; - ctx->samplers_used |= 1 << index; + ctx->image_types[index] = image_type; + ctx->samplers[index] = var_id; + ctx->samplers_used |= 1 << index; - spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0); - int binding = zink_binding(ctx->stage, - zink_sampler_type(glsl_without_array(var->type)), - var->data.binding + i); - spirv_builder_emit_binding(&ctx->builder, var_id, binding); - } - } else { - SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type, - SpvStorageClassUniformConstant); - - if (var->name) - spirv_builder_emit_name(&ctx->builder, var_id, var->name); - - int index = var->data.binding; - assert(!(ctx->samplers_used & (1 << index))); - assert(!ctx->image_types[index]); - ctx->image_types[index] = image_type; - ctx->samplers[index] = var_id; - ctx->samplers_used |= 1 << index; - - spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0); - int binding = zink_binding(ctx->stage, - zink_sampler_type(var->type), - var->data.binding); - spirv_builder_emit_binding(&ctx->builder, var_id, binding); - } + spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0); + int binding = zink_binding(ctx->stage, + zink_sampler_type(type), + var->data.binding); + spirv_builder_emit_binding(&ctx->builder, var_id, binding); } static void @@ -2153,7 +2132,7 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) assert(tex->texture_index == tex->sampler_index); SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0, dx = 0, dy = 0, - offset = 0, sample = 0; + offset = 0, sample = 0, tex_offset = 0; unsigned coord_components = 0, coord_bitsize = 0, offset_components = 0; for (unsigned i = 0; i < tex->num_srcs; i++) { switch (tex->src[i].src_type) { @@ -2216,6 +2195,14 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) assert(dy != 0); break; + case nir_tex_src_texture_offset: + tex_offset = get_src_int(ctx, &tex->src[i].src); + break; + + case nir_tex_src_sampler_offset: + /* don't care */ + break; + default: fprintf(stderr, "texture source: %d\n", tex->src[i].src_type); unreachable("unknown texture source"); @@ -2227,13 +2214,35 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) assert(lod != 0); } - SpvId image_type = ctx->image_types[tex->texture_index]; + unsigned texture_index = tex->texture_index; + if (!tex_offset) { + /* convert constant index back to base + offset */ + unsigned last_sampler = util_last_bit(ctx->samplers_used); + for (unsigned i = 0; i < last_sampler; i++) { + if (!ctx->sampler_array_sizes[i]) { + if (i == texture_index) + /* this is a non-array sampler, so we don't need an access chain */ + break; + } else if (texture_index <= i + ctx->sampler_array_sizes[i] - 1) { + /* this is the first member of a sampler array */ + tex_offset = emit_uint_const(ctx, 32, texture_index - i); + texture_index = i; + break; + } + } + } + SpvId image_type = ctx->image_types[texture_index]; + assert(image_type); SpvId sampled_type = spirv_builder_type_sampled_image(&ctx->builder, image_type); - - assert(ctx->samplers_used & (1u << tex->texture_index)); - SpvId load = spirv_builder_emit_load(&ctx->builder, sampled_type, - ctx->samplers[tex->texture_index]); + assert(sampled_type); + assert(ctx->samplers_used & (1u << texture_index)); + SpvId sampler_id = ctx->samplers[texture_index]; + if (tex_offset) { + SpvId ptr = spirv_builder_type_pointer(&ctx->builder, SpvStorageClassUniformConstant, sampled_type); + sampler_id = spirv_builder_emit_access_chain(&ctx->builder, ptr, sampler_id, &tex_offset, 1); + } + SpvId load = spirv_builder_emit_load(&ctx->builder, sampled_type, sampler_id); SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type); diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index 5e2516e6194..76e5ed590e7 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -452,37 +452,24 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, ret->bindings[ret->num_bindings].index = ubo_index++; ret->bindings[ret->num_bindings].binding = binding; ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ret->bindings[ret->num_bindings].size = 1; ret->num_bindings++; } else { assert(var->data.mode == nir_var_uniform); - if (glsl_type_is_sampler(var->type)) { - VkDescriptorType vktype = zink_sampler_type(var->type); + const struct glsl_type *type = glsl_without_array(var->type); + if (glsl_type_is_sampler(type)) { + VkDescriptorType vktype = zink_sampler_type(type); int binding = zink_binding(nir->info.stage, vktype, 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 = vktype; + if (glsl_type_is_array(var->type)) + ret->bindings[ret->num_bindings].size = glsl_get_aoa_size(var->type); + else + ret->bindings[ret->num_bindings].size = 1; ret->num_bindings++; - } else if (glsl_type_is_array(var->type)) { - /* need to unroll possible arrays of arrays before checking type - * in order to handle ARB_arrays_of_arrays extension - */ - const struct glsl_type *type = glsl_without_array(var->type); - if (!glsl_type_is_sampler(type)) - continue; - VkDescriptorType vktype = zink_sampler_type(type); - - unsigned size = glsl_get_aoa_size(var->type); - for (int i = 0; i < size; ++i) { - int binding = zink_binding(nir->info.stage, - vktype, - var->data.binding + i); - ret->bindings[ret->num_bindings].index = var->data.binding + i; - ret->bindings[ret->num_bindings].binding = binding; - ret->bindings[ret->num_bindings].type = vktype; - ret->num_bindings++; - } } } } diff --git a/src/gallium/drivers/zink/zink_compiler.h b/src/gallium/drivers/zink/zink_compiler.h index 379595876e6..5e3d8002c1e 100644 --- a/src/gallium/drivers/zink/zink_compiler.h +++ b/src/gallium/drivers/zink/zink_compiler.h @@ -68,6 +68,7 @@ struct zink_shader { int index; int binding; VkDescriptorType type; + unsigned char size; } bindings[PIPE_MAX_CONSTANT_BUFFERS + PIPE_MAX_SHADER_SAMPLER_VIEWS]; size_t num_bindings; struct set *programs; diff --git a/src/gallium/drivers/zink/zink_draw.c b/src/gallium/drivers/zink/zink_draw.c index 5d8297f7072..9f5bddbf301 100644 --- a/src/gallium/drivers/zink/zink_draw.c +++ b/src/gallium/drivers/zink/zink_draw.c @@ -337,35 +337,39 @@ zink_draw_vbo(struct pipe_context *pctx, wds[num_wds].pBufferInfo = buffer_infos + num_buffer_info; ++num_buffer_info; } else { - struct pipe_sampler_view *psampler_view = ctx->image_views[i][index]; - struct zink_sampler_view *sampler_view = zink_sampler_view(psampler_view); + for (unsigned k = 0; k < shader->bindings[j].size; k++) { + struct pipe_sampler_view *psampler_view = ctx->image_views[i][index + k]; + struct zink_sampler_view *sampler_view = zink_sampler_view(psampler_view); - struct zink_resource *res = psampler_view ? zink_resource(psampler_view->texture) : NULL; - write_desc_resources[num_wds] = res; - if (!res) { - /* if we're hitting this assert often, we can probably just throw a junk buffer in since - * the results of this codepath are undefined in ARB_texture_buffer_object spec - */ - assert(screen->info.rb2_feats.nullDescriptor); - if (shader->bindings[j].type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) - wds[num_wds].pTexelBufferView = &buffer_view[0]; + struct zink_resource *res = psampler_view ? zink_resource(psampler_view->texture) : NULL; + write_desc_resources[num_wds] = res; + if (!res) { + /* if we're hitting this assert often, we can probably just throw a junk buffer in since + * the results of this codepath are undefined in ARB_texture_buffer_object spec + */ + assert(screen->info.rb2_feats.nullDescriptor); + if (shader->bindings[j].type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) + wds[num_wds].pTexelBufferView = &buffer_view[0]; + else { + image_infos[num_image_info].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_infos[num_image_info].imageView = VK_NULL_HANDLE; + image_infos[num_image_info].sampler = ctx->samplers[i][index + k]; + if (!k) + wds[num_wds].pImageInfo = image_infos + num_image_info; + ++num_image_info; + } + } else if (res->base.target == PIPE_BUFFER) + wds[num_wds].pTexelBufferView = &sampler_view->buffer_view; else { - image_infos[num_image_info].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_infos[num_image_info].imageView = VK_NULL_HANDLE; - image_infos[num_image_info].sampler = ctx->samplers[i][index]; - wds[num_wds].pImageInfo = image_infos + num_image_info; + if (res->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + transitions[num_transitions++] = res; + image_infos[num_image_info].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_infos[num_image_info].imageView = sampler_view->image_view; + image_infos[num_image_info].sampler = ctx->samplers[i][index + k]; + if (!k) + wds[num_wds].pImageInfo = image_infos + num_image_info; ++num_image_info; } - } else if (res->base.target == PIPE_BUFFER) - wds[num_wds].pTexelBufferView = &sampler_view->buffer_view; - else { - if (res->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - transitions[num_transitions++] = res; - image_infos[num_image_info].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_infos[num_image_info].imageView = sampler_view->image_view; - image_infos[num_image_info].sampler = ctx->samplers[i][index]; - wds[num_wds].pImageInfo = image_infos + num_image_info; - ++num_image_info; } } @@ -373,7 +377,7 @@ zink_draw_vbo(struct pipe_context *pctx, wds[num_wds].pNext = NULL; wds[num_wds].dstBinding = shader->bindings[j].binding; wds[num_wds].dstArrayElement = 0; - wds[num_wds].descriptorCount = 1; + wds[num_wds].descriptorCount = shader->bindings[j].size; wds[num_wds].descriptorType = shader->bindings[j].type; ++num_wds; } diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index cd58980f5db..3ab700d71fd 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -116,7 +116,7 @@ create_desc_set_layout(VkDevice dev, assert(num_bindings < ARRAY_SIZE(bindings)); bindings[num_bindings].binding = shader->bindings[j].binding; bindings[num_bindings].descriptorType = shader->bindings[j].type; - bindings[num_bindings].descriptorCount = 1; + bindings[num_bindings].descriptorCount = shader->bindings[j].size; bindings[num_bindings].stageFlags = stage_flags; bindings[num_bindings].pImmutableSamplers = NULL; ++num_bindings;