Mesa (master): zink: handle dynamic sampler array indexing for arb_gpu_shader5

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jan 4 15:10:13 UTC 2021


Module: Mesa
Branch: master
Commit: 9c18491e4104a2d31992fb0e1304136b21e8e463
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=9c18491e4104a2d31992fb0e1304136b21e8e463

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Tue Jul 28 14:50:45 2020 -0400

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 at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8155>

---

 .../drivers/zink/nir_to_spirv/nir_to_spirv.c       | 115 +++++++++++----------
 src/gallium/drivers/zink/zink_compiler.c           |  29 ++----
 src/gallium/drivers/zink/zink_compiler.h           |   1 +
 src/gallium/drivers/zink/zink_draw.c               |  58 ++++++-----
 src/gallium/drivers/zink/zink_program.c            |   2 +-
 5 files changed, 103 insertions(+), 102 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);
-
-         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);
-         }
+   SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
+                                         SpvStorageClassUniformConstant);
 
-         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;
-
-         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);
-   }
+   if (var->name)
+      spirv_builder_emit_name(&ctx->builder, var_id, var->name);
+
+   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(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);
-
-            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];
+            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];
+                  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;



More information about the mesa-commit mailing list