spirv: Add support for SPV_EXT_physical_storage_buffer
authorJason Ekstrand <jason.ekstrand@intel.com>
Sat, 19 Jan 2019 16:23:28 +0000 (10:23 -0600)
committerJason Ekstrand <jason.ekstrand@intel.com>
Sat, 26 Jan 2019 19:41:50 +0000 (13:41 -0600)
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/compiler/shader_info.h
src/compiler/spirv/nir_spirv.h
src/compiler/spirv/spirv_to_nir.c
src/compiler/spirv/vtn_private.h
src/compiler/spirv/vtn_variables.c

index 7af36a66d1338bb7d4552561f13fb8c66a00441a..c3dbe764961085aa3190efc7a9c04c9cca312019 100644 (file)
@@ -51,6 +51,7 @@ struct spirv_supported_capabilities {
    bool kernel;
    bool min_lod;
    bool multiview;
+   bool physical_storage_buffer_address;
    bool post_depth_coverage;
    bool runtime_descriptor_array;
    bool shader_viewport_index_layer;
index 7e7db373a3a018599a83bd47d0831c7b88ae095d..35b30660e296f338c8a09a1798b743c0235c622e 100644 (file)
@@ -67,6 +67,7 @@ struct spirv_to_nir_options {
    /* Storage types for various kinds of pointers. */
    const struct glsl_type *ubo_ptr_type;
    const struct glsl_type *ssbo_ptr_type;
+   const struct glsl_type *phys_ssbo_ptr_type;
    const struct glsl_type *push_const_ptr_type;
    const struct glsl_type *shared_ptr_type;
 
index 022a90eff7eb1b9852df6d6345a2057b8b1ff342..9bfe58059199d0d1324f30e73ced462706068443 100644 (file)
@@ -1308,6 +1308,9 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
          case SpvStorageClassStorageBuffer:
             val->type->type = b->options->ssbo_ptr_type;
             break;
+         case SpvStorageClassPhysicalStorageBufferEXT:
+            val->type->type = b->options->phys_ssbo_ptr_type;
+            break;
          case SpvStorageClassPushConstant:
             val->type->type = b->options->push_const_ptr_type;
             break;
@@ -3718,6 +3721,10 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
          spv_check_supported(post_depth_coverage, cap);
          break;
 
+      case SpvCapabilityPhysicalStorageBufferAddressesEXT:
+         spv_check_supported(physical_storage_buffer_address, cap);
+         break;
+
       default:
          vtn_fail("Unhandled capability");
       }
@@ -3729,7 +3736,10 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpMemoryModel:
-      vtn_assert(w[1] == SpvAddressingModelLogical);
+      vtn_assert(w[1] == SpvAddressingModelLogical ||
+                 (b->options &&
+                  b->options->caps.physical_storage_buffer_address &&
+                  w[1] == SpvAddressingModelPhysicalStorageBuffer64EXT));
       vtn_assert(w[2] == SpvMemoryModelSimple ||
                  w[2] == SpvMemoryModelGLSL450);
       break;
index 3a5c5f32224b73649ae52614c365b17b083b68ad..cba2bd665fa5673fff4d80f4fa40f04f48904efc 100644 (file)
@@ -417,6 +417,7 @@ enum vtn_variable_mode {
    vtn_variable_mode_uniform,
    vtn_variable_mode_ubo,
    vtn_variable_mode_ssbo,
+   vtn_variable_mode_phys_ssbo,
    vtn_variable_mode_push_constant,
    vtn_variable_mode_workgroup,
    vtn_variable_mode_cross_workgroup,
index 4f7e2a15af92b9b47777c5fb00b29412bb326342..b1ac0b99784f0794ab94c32849e83815174202ff 100644 (file)
@@ -62,6 +62,7 @@ vtn_pointer_is_external_block(struct vtn_builder *b,
 {
    return ptr->mode == vtn_variable_mode_ssbo ||
           ptr->mode == vtn_variable_mode_ubo ||
+          ptr->mode == vtn_variable_mode_phys_ssbo ||
           ptr->mode == vtn_variable_mode_push_constant ||
           (ptr->mode == vtn_variable_mode_workgroup &&
            b->options->lower_workgroup_access_to_offsets);
@@ -1521,6 +1522,11 @@ apply_var_decoration(struct vtn_builder *b,
       /* HLSL semantic decorations can safely be ignored by the driver. */
       break;
 
+   case SpvDecorationRestrictPointerEXT:
+   case SpvDecorationAliasedPointerEXT:
+      /* TODO: We should actually plumb alias information through NIR. */
+      break;
+
    default:
       vtn_fail("Unhandled decoration");
    }
@@ -1682,6 +1688,10 @@ vtn_storage_class_to_mode(struct vtn_builder *b,
       mode = vtn_variable_mode_ssbo;
       nir_mode = nir_var_mem_ssbo;
       break;
+   case SpvStorageClassPhysicalStorageBufferEXT:
+      mode = vtn_variable_mode_phys_ssbo;
+      nir_mode = nir_var_mem_global;
+      break;
    case SpvStorageClassUniformConstant:
       mode = vtn_variable_mode_uniform;
       nir_mode = nir_var_uniform;
@@ -1760,13 +1770,23 @@ vtn_pointer_to_ssa(struct vtn_builder *b, struct vtn_pointer *ptr)
       }
    } else {
       if (vtn_pointer_is_external_block(b, ptr) &&
-          vtn_type_contains_block(b, ptr->type)) {
+          vtn_type_contains_block(b, ptr->type) &&
+          ptr->mode != vtn_variable_mode_phys_ssbo) {
          const unsigned bit_size = glsl_get_bit_size(ptr->ptr_type->type);
          const unsigned num_components =
             glsl_get_vector_elements(ptr->ptr_type->type);
 
          /* In this case, we're looking for a block index and not an actual
           * deref.
+          *
+          * For PhysicalStorageBufferEXT pointers, we don't have a block index
+          * at all because we get the pointer directly from the client.  This
+          * assumes that there will never be a SSBO binding variable using the
+          * PhysicalStorageBufferEXT storage class.  This assumption appears
+          * to be correct according to the Vulkan spec because the table,
+          * "Shader Resource and Storage Class Correspondence," the only the
+          * Uniform storage class with BufferBlock or the StorageBuffer
+          * storage class with Block can be used.
           */
          if (!ptr->block_index) {
             /* If we don't have a block_index then we must be a pointer to the
@@ -1843,7 +1863,8 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
          assert(ssa->bit_size == 32 && ssa->num_components == 1);
          ptr->deref = nir_build_deref_cast(&b->nb, ssa, nir_mode,
                                            glsl_get_bare_type(deref_type), 0);
-      } else if (vtn_type_contains_block(b, ptr->type)) {
+      } else if (vtn_type_contains_block(b, ptr->type) &&
+                 ptr->mode != vtn_variable_mode_phys_ssbo) {
          /* This is a pointer to somewhere in an array of blocks, not a
           * pointer to somewhere inside the block.  We squashed it into a
           * random vector type before so just pick off the first channel and
@@ -1853,6 +1874,15 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
       } else {
          /* This is a pointer to something internal or a pointer inside a
           * block.  It's just a regular cast.
+          *
+          * For PhysicalStorageBufferEXT pointers, we don't have a block index
+          * at all because we get the pointer directly from the client.  This
+          * assumes that there will never be a SSBO binding variable using the
+          * PhysicalStorageBufferEXT storage class.  This assumption appears
+          * to be correct according to the Vulkan spec because the table,
+          * "Shader Resource and Storage Class Correspondence," the only the
+          * Uniform storage class with BufferBlock or the StorageBuffer
+          * storage class with Block can be used.
           */
          ptr->deref = nir_build_deref_cast(&b->nb, ssa, nir_mode,
                                            ptr_type->deref->type,
@@ -1933,6 +1963,12 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
    case vtn_variable_mode_push_constant:
       b->shader->num_uniforms = vtn_type_block_size(b, type);
       break;
+
+   case vtn_variable_mode_phys_ssbo:
+      vtn_fail("Cannot create a variable with the "
+               "PhysicalStorageBufferEXT storage class");
+      break;
+
    default:
       /* No tallying is needed */
       break;
@@ -2087,6 +2123,9 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
    case vtn_variable_mode_cross_workgroup:
       /* These don't need actual variables. */
       break;
+
+   case vtn_variable_mode_phys_ssbo:
+      unreachable("Should have been caught before");
    }
 
    if (initializer) {