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 <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8155>
This commit is contained in:
Mike Blumenkrantz 2020-07-28 14:50:45 -04:00 committed by Marge Bot
parent 1a7b7b17ad
commit 9c18491e41
5 changed files with 100 additions and 99 deletions

View file

@ -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);

View file

@ -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++;
}
}
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;