Mesa (master): zink: add alternate ubo loader in ntv

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Dec 1 18:31:37 UTC 2020


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

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Fri Jun 26 15:53:30 2020 -0400

zink: add alternate ubo loader in ntv

This is a loader that handles more cases than the current vec4-based
loader, that is a bit easier to extend to more features.

Reviewed-by: Erik Faye-Lund <erik.faye-lund at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7858>

---

 .../drivers/zink/nir_to_spirv/nir_to_spirv.c       | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)

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 b2021694c19..d990bdc9af6 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
@@ -1525,6 +1525,94 @@ emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
    store_ssa_def(ctx, &load_const->def, constant);
 }
 
+static void
+emit_load_ubo(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+   ASSERTED nir_const_value *const_block_index = nir_src_as_const_value(intr->src[0]);
+   assert(const_block_index); // no dynamic indexing for now
+
+   SpvId uint_type = get_uvec_type(ctx, 32, 1);
+   SpvId one = emit_uint_const(ctx, 32, 1);
+
+   /* number of components being loaded */
+   unsigned num_components = nir_dest_num_components(intr->dest);
+   SpvId constituents[num_components];
+   SpvId result;
+
+   /* destination type for the load */
+   SpvId type = get_dest_uvec_type(ctx, &intr->dest);
+   /* an id of the array stride in bytes */
+   SpvId vec4_size = emit_uint_const(ctx, 32, sizeof(uint32_t) * 4);
+   /* an id of an array member in bytes */
+   SpvId uint_size = emit_uint_const(ctx, 32, sizeof(uint32_t));
+
+   /* we grab a single array member at a time, so it's a pointer to a uint */
+   SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
+                                                   SpvStorageClassUniform,
+                                                   uint_type);
+
+   /* our generated uniform has a memory layout like
+    *
+    * struct {
+    *    vec4 base[array_size];
+    * };
+    *
+    * where 'array_size' is set as though every member of the ubo takes up a vec4,
+    * even if it's only a vec2 or a float.
+    *
+    * first, access 'base'
+    */
+   SpvId member = emit_uint_const(ctx, 32, 0);
+   /* this is the offset (in bytes) that we're accessing:
+    * it may be a const value or it may be dynamic in the shader
+    */
+   SpvId offset = get_src(ctx, &intr->src[1]);
+   /* convert offset to an array index for 'base' to determine which vec4 to access */
+   SpvId vec_offset = emit_binop(ctx, SpvOpUDiv, uint_type, offset, vec4_size);
+   /* use the remainder to calculate the byte offset in the vec, which tells us the member
+    * that we're going to access
+    */
+   SpvId vec_member_offset = emit_binop(ctx, SpvOpUDiv, uint_type,
+                                        emit_binop(ctx, SpvOpUMod, uint_type, offset, vec4_size),
+                                        uint_size);
+   /* OpAccessChain takes an array of indices that drill into a hierarchy based on the type:
+    * index 0 is accessing 'base'
+    * index 1 is accessing 'base[index 1]'
+    * index 2 is accessing 'base[index 1][index 2]'
+    *
+    * we must perform the access this way in case src[1] is dynamic because there's
+    * no other spirv method for using an id to access a member of a composite, as
+    * (composite|vector)_extract both take literals
+    */
+   for (unsigned i = 0; i < num_components; i++) {
+      SpvId indices[3] = { member, vec_offset, vec_member_offset };
+      SpvId ptr = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
+                                                  ctx->ubos[const_block_index->u32], indices,
+                                                  ARRAY_SIZE(indices));
+      /* load a single value into the constituents array */
+      constituents[i] = spirv_builder_emit_load(&ctx->builder, uint_type, ptr);
+      /* increment to the next vec4 member index for the next load */
+      vec_member_offset = emit_binop(ctx, SpvOpIAdd, uint_type, vec_member_offset, one);
+   }
+
+   /* if loading more than 1 value, reassemble the results into the desired type,
+    * otherwise just use the loaded result
+    */
+   if (num_components > 1) {
+      result = spirv_builder_emit_composite_construct(&ctx->builder,
+                                                      type,
+                                                      constituents,
+                                                      num_components);
+   } else
+      result = constituents[0];
+
+   /* explicitly convert to a bool vector if the destination type is a bool */
+   if (nir_dest_bit_size(intr->dest) == 1)
+      result = uvec_to_bvec(ctx, result, num_components);
+
+   store_dest(ctx, &intr->dest, result, nir_type_uint);
+}
+
 static void
 emit_load_ubo_vec4(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
@@ -1721,6 +1809,10 @@ static void
 emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
    switch (intr->intrinsic) {
+   case nir_intrinsic_load_ubo:
+      emit_load_ubo(ctx, intr);
+      break;
+
    case nir_intrinsic_load_ubo_vec4:
       emit_load_ubo_vec4(ctx, intr);
       break;



More information about the mesa-commit mailing list