spirv: Make push constants an offset-based pointer
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 22 Mar 2018 15:50:34 +0000 (08:50 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Sat, 23 Jun 2018 03:15:57 +0000 (20:15 -0700)
Push constants have been a weird edge-case for a while in that they have
explitic offsets but we've been internally building access chains for
them.  This mostly works but it means that passing pointers to push
constants through as function arguments is broken.  The easy thing to do
for now is to just treat them like UBOs or SSBOs only without a block
index.  This does loose a bit of information since we no longer have an
accurate access range and any indirect access will look like it could
read the whole block.  Unfortunately, there's not much we can do about
that.  Once NIR derefs get a bit more powerful, we can plumb these
through as derefs and be able to reason about them again.

Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Acked-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/compiler/spirv/spirv_to_nir.c
src/compiler/spirv/vtn_variables.c

index ab624866fb41443f22128c83eddcd56136ae07fc..fb62f3035a97b3911ead4dd4f6470048f7b8b6a7 100644 (file)
@@ -1182,6 +1182,13 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
          val->type->type = glsl_vector_type(GLSL_TYPE_UINT, 2);
       }
 
+      if (storage_class == SpvStorageClassPushConstant) {
+         /* These can actually be stored to nir_variables and used as SSA
+          * values so they need a real glsl_type.
+          */
+         val->type->type = glsl_uint_type();
+      }
+
       if (storage_class == SpvStorageClassWorkgroup &&
           b->options->lower_workgroup_access_to_offsets) {
          uint32_t size, align;
index 09d61803d1b0d87ef25a84c7d9933b6d07421a7e..ee2bbfe799a771cedfd3fd45c780c9babb01da16 100644 (file)
@@ -64,6 +64,7 @@ vtn_pointer_uses_ssa_offset(struct vtn_builder *b,
 {
    return ptr->mode == vtn_variable_mode_ubo ||
           ptr->mode == vtn_variable_mode_ssbo ||
+          ptr->mode == vtn_variable_mode_push_constant ||
           (ptr->mode == vtn_variable_mode_workgroup &&
            b->options->lower_workgroup_access_to_offsets);
 }
@@ -269,6 +270,12 @@ vtn_ssa_offset_pointer_dereference(struct vtn_builder *b,
          }
 
          offset = nir_imm_int(&b->nb, base->var->shared_location);
+      } else if (base->mode == vtn_variable_mode_push_constant) {
+         /* Push constants neither need nor have a block index */
+         vtn_assert(!block_index);
+
+         /* Start off with at the start of the push constant block. */
+         offset = nir_imm_int(&b->nb, 0);
       } else {
          /* The code above should have ensured a block_index when needed. */
          vtn_assert(block_index);
@@ -661,31 +668,6 @@ vtn_type_block_size(struct vtn_builder *b, struct vtn_type *type)
    }
 }
 
-static void
-vtn_access_chain_get_offset_size(struct vtn_builder *b,
-                                 struct vtn_access_chain *chain,
-                                 struct vtn_type *type,
-                                 unsigned *access_offset,
-                                 unsigned *access_size)
-{
-   *access_offset = 0;
-
-   for (unsigned i = 0; i < chain->length; i++) {
-      if (chain->link[i].mode != vtn_access_mode_literal)
-         break;
-
-      if (glsl_type_is_struct(type->type)) {
-         *access_offset += type->offsets[chain->link[i].id];
-         type = type->members[chain->link[i].id];
-      } else {
-         *access_offset += type->stride * chain->link[i].id;
-         type = type->array_element;
-      }
-   }
-
-   *access_size = vtn_type_block_size(b, type);
-}
-
 static void
 _vtn_load_store_tail(struct vtn_builder *b, nir_intrinsic_op op, bool load,
                      nir_ssa_def *index, nir_ssa_def *offset,
@@ -882,8 +864,7 @@ vtn_block_load(struct vtn_builder *b, struct vtn_pointer *src)
       break;
    case vtn_variable_mode_push_constant:
       op = nir_intrinsic_load_push_constant;
-      vtn_access_chain_get_offset_size(b, src->chain, src->var->type,
-                                       &access_offset, &access_size);
+      access_size = b->shader->num_uniforms;
       break;
    case vtn_variable_mode_workgroup:
       op = nir_intrinsic_load_shared;
@@ -1661,7 +1642,8 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
       ptr->offset = nir_channel(&b->nb, ssa, 1);
    } else {
       vtn_assert(ssa->num_components == 1);
-      vtn_assert(ptr->mode == vtn_variable_mode_workgroup);
+      vtn_assert(ptr->mode == vtn_variable_mode_workgroup ||
+                 ptr->mode == vtn_variable_mode_push_constant);
       ptr->block_index = NULL;
       ptr->offset = ssa;
    }