Test shader group handle alignment
authorRicardo Garcia <rgarcia@igalia.com>
Fri, 10 Jun 2022 13:30:13 +0000 (15:30 +0200)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Thu, 16 Jun 2022 20:37:44 +0000 (20:37 +0000)
This commit adds a new test group that verifies the advertised supported
shader group handle alignment in shader binding tables works as
expected.

The new tests create shader binding tables with shader record buffers
that act as padding bytes to achieve the desired alignments. These
shader record buffers are also read from ray tracing shaders and
verified to have the right contents.

New tests:
dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.*

Components: Vulkan
VK-GL-CTS issue: 3298

Change-Id: Id2d4f11ed2fcf56ce30e1a5896d38416cbaf1b82

android/cts/main/vk-master-2022-03-01/ray-tracing-pipeline.txt
android/cts/main/vk-master/ray-tracing-pipeline.txt
external/vulkancts/framework/vulkan/vkRayTracingUtil.cpp
external/vulkancts/framework/vulkan/vkRayTracingUtil.hpp
external/vulkancts/modules/vulkan/ray_tracing/vktRayTracingShaderBindingTableTests.cpp
external/vulkancts/mustpass/main/vk-default/ray-tracing-pipeline.txt

index e757c43..a1dbf57 100644 (file)
@@ -50,6 +50,12 @@ dEQP-VK.ray_tracing_pipeline.trace_rays_cmds_maintenance_1.indirect2_gpu.8_8_8
 dEQP-VK.ray_tracing_pipeline.trace_rays_cmds_maintenance_1.indirect2_gpu.11_1_1
 dEQP-VK.ray_tracing_pipeline.trace_rays_cmds_maintenance_1.indirect2_gpu.11_13_1
 dEQP-VK.ray_tracing_pipeline.trace_rays_cmds_maintenance_1.indirect2_gpu.11_13_5
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_1
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_2
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_4
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_8
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_16
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_32
 dEQP-VK.ray_tracing_pipeline.pipeline_no_null_shaders_flag.gpu.triangles.stride_3.offset_7.use_libs.miss
 dEQP-VK.ray_tracing_pipeline.pipeline_no_null_shaders_flag.gpu.triangles.stride_3.offset_7.use_libs.chit
 dEQP-VK.ray_tracing_pipeline.pipeline_no_null_shaders_flag.gpu.triangles.stride_3.offset_7.use_libs.chit_or_miss
index 24b22cf..215ba83 100644 (file)
@@ -440,6 +440,12 @@ dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.sh
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.1_0
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.2_0
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.3_0_extrabits
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_1
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_2
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_4
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_8
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_16
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_32
 dEQP-VK.ray_tracing_pipeline.procedural_geometry.object_behind_bounding_boxes
 dEQP-VK.ray_tracing_pipeline.procedural_geometry.triangle_in_between
 dEQP-VK.ray_tracing_pipeline.pipeline_no_null_shaders_flag.gpu.triangles.stride_3.offset_7.use_libs.miss
index 7eeaf90..ef84174 100644 (file)
@@ -3275,13 +3275,15 @@ de::MovePtr<BufferWithMemory> RayTracingPipeline::createShaderBindingTable (cons
                                                                                                                                                        const VkDeviceAddress&          opaqueCaptureAddress,
                                                                                                                                                        const deUint32                          shaderBindingTableOffset,
                                                                                                                                                        const deUint32                          shaderRecordSize,
-                                                                                                                                                       const void**                            shaderGroupDataPtrPerGroup)
+                                                                                                                                                       const void**                            shaderGroupDataPtrPerGroup,
+                                                                                                                                                       const bool                                      autoAlignRecords)
 {
        DE_ASSERT(shaderGroupBaseAlignment != 0u);
        DE_ASSERT((shaderBindingTableOffset % shaderGroupBaseAlignment) == 0);
        DE_UNREF(shaderGroupBaseAlignment);
 
-       const deUint32                                                  sbtSize                                                 = shaderBindingTableOffset + groupCount * deAlign32(shaderGroupHandleSize + shaderRecordSize, shaderGroupHandleSize);
+       const auto                                                              totalEntrySize                                  = (autoAlignRecords ? (deAlign32(shaderGroupHandleSize + shaderRecordSize, shaderGroupHandleSize)) : (shaderGroupHandleSize + shaderRecordSize));
+       const deUint32                                                  sbtSize                                                 = shaderBindingTableOffset + groupCount * totalEntrySize;
        const VkBufferUsageFlags                                sbtFlags                                                = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | additionalBufferUsageFlags;
        VkBufferCreateInfo                                              sbtCreateInfo                                   = makeBufferCreateInfo(sbtSize, sbtFlags);
        sbtCreateInfo.flags                                                                                                             |= additionalBufferCreateFlags;
@@ -3310,7 +3312,7 @@ de::MovePtr<BufferWithMemory> RayTracingPipeline::createShaderBindingTable (cons
        for (deUint32 idx = 0; idx < groupCount; ++idx)
        {
                deUint8* shaderSrcPos   = shaderHandles.data() + idx * shaderGroupHandleSize;
-               deUint8* shaderDstPos   = shaderBegin + idx * deAlign32(shaderGroupHandleSize + shaderRecordSize, shaderGroupHandleSize);
+               deUint8* shaderDstPos   = shaderBegin + idx * totalEntrySize;
                deMemcpy(shaderDstPos, shaderSrcPos, shaderGroupHandleSize);
 
                if (shaderGroupDataPtrPerGroup          != nullptr &&
@@ -3369,16 +3371,17 @@ public:
                                                                                                                                                 const VkPhysicalDevice         physicalDevice);
        virtual                                 ~RayTracingPropertiesKHR                                        ();
 
-       virtual deUint32                getShaderGroupHandleSize                                        (void)  { return m_rayTracingPipelineProperties.shaderGroupHandleSize;                                          }
-       virtual deUint32                getMaxRecursionDepth                                            (void)  { return m_rayTracingPipelineProperties.maxRayRecursionDepth;                                           }
-       virtual deUint32                getMaxShaderGroupStride                                         (void)  { return m_rayTracingPipelineProperties.maxShaderGroupStride;                                           }
-       virtual deUint32                getShaderGroupBaseAlignment                                     (void)  { return m_rayTracingPipelineProperties.shaderGroupBaseAlignment;                                       }
-       virtual deUint64                getMaxGeometryCount                                                     (void)  { return m_accelerationStructureProperties.maxGeometryCount;                                            }
-       virtual deUint64                getMaxInstanceCount                                                     (void)  { return m_accelerationStructureProperties.maxInstanceCount;                                            }
-       virtual deUint64                getMaxPrimitiveCount                                            (void)  { return m_accelerationStructureProperties.maxPrimitiveCount;                                           }
-       virtual deUint32                getMaxDescriptorSetAccelerationStructures       (void)  { return m_accelerationStructureProperties.maxDescriptorSetAccelerationStructures;      }
-       deUint32                                getMaxRayDispatchInvocationCount                        (void)  { return m_rayTracingPipelineProperties.maxRayDispatchInvocationCount;                          }
-       deUint32                                getMaxRayHitAttributeSize                                       (void)  { return m_rayTracingPipelineProperties.maxRayHitAttributeSize;                                         }
+       uint32_t                getShaderGroupHandleSize                                        (void)  override { return m_rayTracingPipelineProperties.shaderGroupHandleSize;                                         }
+       uint32_t                getShaderGroupHandleAlignment                           (void)  override { return m_rayTracingPipelineProperties.shaderGroupHandleAlignment;                            }
+       uint32_t                getMaxRecursionDepth                                            (void)  override { return m_rayTracingPipelineProperties.maxRayRecursionDepth;                                          }
+       uint32_t                getMaxShaderGroupStride                                         (void)  override { return m_rayTracingPipelineProperties.maxShaderGroupStride;                                          }
+       uint32_t                getShaderGroupBaseAlignment                                     (void)  override { return m_rayTracingPipelineProperties.shaderGroupBaseAlignment;                                      }
+       uint64_t                getMaxGeometryCount                                                     (void)  override { return m_accelerationStructureProperties.maxGeometryCount;                                           }
+       uint64_t                getMaxInstanceCount                                                     (void)  override { return m_accelerationStructureProperties.maxInstanceCount;                                           }
+       uint64_t                getMaxPrimitiveCount                                            (void)  override { return m_accelerationStructureProperties.maxPrimitiveCount;                                          }
+       uint32_t                getMaxDescriptorSetAccelerationStructures       (void)  override { return m_accelerationStructureProperties.maxDescriptorSetAccelerationStructures;     }
+       uint32_t                getMaxRayDispatchInvocationCount                        (void)  override { return m_rayTracingPipelineProperties.maxRayDispatchInvocationCount;                         }
+       uint32_t                getMaxRayHitAttributeSize                                       (void)  override { return m_rayTracingPipelineProperties.maxRayHitAttributeSize;                                        }
 
 protected:
        VkPhysicalDeviceAccelerationStructurePropertiesKHR      m_accelerationStructureProperties;
index 3569d37..f7b59cf 100644 (file)
@@ -887,7 +887,8 @@ public:
                                                                                                                                                                                         const VkDeviceAddress&                                                                 opaqueCaptureAddress            = 0u,
                                                                                                                                                                                         const deUint32                                                                                 shaderBindingTableOffset        = 0u,
                                                                                                                                                                                         const deUint32                                                                                 shaderRecordSize                        = 0u,
-                                                                                                                                                                                        const void**                                                                                   shaderGroupDataPtrPerGroup      = nullptr);
+                                                                                                                                                                                        const void**                                                                                   shaderGroupDataPtrPerGroup      = nullptr,
+                                                                                                                                                                                        const bool                                                                                             autoAlignRecords                        = true);
        void                                                                                                            setCreateFlags                          (const VkPipelineCreateFlags&                                                   pipelineCreateFlags);
        void                                                                                                            setMaxRecursionDepth            (const deUint32&                                                                                maxRecursionDepth);
        void                                                                                                            setMaxPayloadSize                       (const deUint32&                                                                                maxPayloadSize);
@@ -926,16 +927,17 @@ public:
                                                                                                                                                                 const VkPhysicalDevice         physicalDevice) { DE_UNREF(vki); DE_UNREF(physicalDevice); }
        virtual                                                 ~RayTracingProperties                                           () {}
 
-       virtual deUint32                                getShaderGroupHandleSize                                        (void)  = DE_NULL;
-       virtual deUint32                                getMaxRecursionDepth                                            (void)  = DE_NULL;
-       virtual deUint32                                getMaxShaderGroupStride                                         (void)  = DE_NULL;
-       virtual deUint32                                getShaderGroupBaseAlignment                                     (void)  = DE_NULL;
-       virtual deUint64                                getMaxGeometryCount                                                     (void)  = DE_NULL;
-       virtual deUint64                                getMaxInstanceCount                                                     (void)  = DE_NULL;
-       virtual deUint64                                getMaxPrimitiveCount                                            (void)  = DE_NULL;
-       virtual deUint32                                getMaxDescriptorSetAccelerationStructures       (void)  = DE_NULL;
-       virtual deUint32                                getMaxRayDispatchInvocationCount                        (void)  = DE_NULL;
-       virtual deUint32                                getMaxRayHitAttributeSize                                       (void)  = DE_NULL;
+       virtual uint32_t                                getShaderGroupHandleSize                                        (void)  = 0;
+       virtual uint32_t                                getShaderGroupHandleAlignment                           (void)  = 0;
+       virtual uint32_t                                getMaxRecursionDepth                                            (void)  = 0;
+       virtual uint32_t                                getMaxShaderGroupStride                                         (void)  = 0;
+       virtual uint32_t                                getShaderGroupBaseAlignment                                     (void)  = 0;
+       virtual uint64_t                                getMaxGeometryCount                                                     (void)  = 0;
+       virtual uint64_t                                getMaxInstanceCount                                                     (void)  = 0;
+       virtual uint64_t                                getMaxPrimitiveCount                                            (void)  = 0;
+       virtual uint32_t                                getMaxDescriptorSetAccelerationStructures       (void)  = 0;
+       virtual uint32_t                                getMaxRayDispatchInvocationCount                        (void)  = 0;
+       virtual uint32_t                                getMaxRayHitAttributeSize                                       (void)  = 0;
 };
 
 de::MovePtr<RayTracingProperties> makeRayTracingProperties (const InstanceInterface&   vki,
index d34c222..4d0f3e0 100644 (file)
@@ -985,6 +985,478 @@ tcu::TestStatus ShaderBindingTableIndexingTestInstance::iterate (void)
        return tcu::TestStatus::pass("Pass");
 }
 
+/*
+
+Test the advertised shader group handle alignment requirements work as expected. The tests will prepare shader binding tables using
+shader record buffers for padding and achieving the desired alignments.
+
++-------------------------------------------
+| Shader | Shader    | Aligned |
+| Group  | Record    | Shader  | ...
+| Handle | Buffer    | Group   |
+|        | (padding) | Handle  |
++-------------------------------------------
+
+The number of geometries to try (hence the number of alignments and shader record buffers to try) is 32/align + 1, so 33 in the case
+of align=1, and 2 in the case of align=32. This allows us to test all possible alignment values.
+
+Geometries are triangles put alongside the X axis. The base triangle is:
+
+0,1|      x
+   |     x x
+   |    x  0.5,0.5
+   |   x  x  x
+   |  x       x
+   | xxxxxxxxxxx
+   +-------------
+ 0,0             1,0
+
+A triangle surrounding point (0.5, 0.5), in the [0, 1] range of both the X and Y axis.
+
+As more than one triangle is needed, each triangle is translated one more unit in the X axis, so each triangle is in the [i, i+1]
+range. The Y axis doesn't change, triangles are always in the [0,1] range.
+
+Triangles have Z=5, and one ray is traced per triangle, origin (i+0.5, 0.5, 0) direction (0, 0, 1), where i is gl_LaunchIDEXT.x.
+
+For each geometry, the shader record buffer contents vary depending on the geometry index and the desired alignment (padding).
+
+Alignment      Element Type    Element Count                   Data
+1                      uint8_t                 1                                               0x80 | geometryID
+2                      uint16_t                1                                               0xABC0 | geometryID
+4+                     uint32_t                alignment/4                             For each element: 0xABCDE0F0 | (element << 8) | geometryID
+
+The test will try to verify everything works properly and all shader record buffers can be read with the right values.
+
+ */
+struct ShaderGroupHandleAlignmentParams
+{
+       const uint32_t alignment;
+
+       ShaderGroupHandleAlignmentParams (uint32_t alignment_)
+               : alignment (alignment_)
+       {
+               DE_ASSERT(alignment >= 1u && alignment <= 32u);
+               DE_ASSERT(deIsPowerOfTwo32(static_cast<int>(alignment)));
+       }
+
+       uint32_t geometryCount () const
+       {
+               return (32u / alignment + 1u);
+       }
+
+       uint32_t shaderRecordElementCount () const
+       {
+               return ((alignment <= 4u) ? 1u : (alignment / 4u));
+       }
+
+       std::string glslElementType () const
+       {
+               if (alignment == 1u)
+                       return "uint8_t";
+               if (alignment == 2u)
+                       return "uint16_t";
+               return "uint32_t";
+       }
+
+       std::string glslExtension () const
+       {
+               if (alignment == 1u)
+                       return "GL_EXT_shader_explicit_arithmetic_types_int8";
+               if (alignment == 2u)
+                       return "GL_EXT_shader_explicit_arithmetic_types_int16";
+               return "GL_EXT_shader_explicit_arithmetic_types_int32";
+       }
+
+       std::vector<uint8_t> getRecordData (uint32_t geometryID) const
+       {
+               std::vector<uint8_t> recordData;
+               switch (alignment)
+               {
+               case 1u:
+                       recordData.push_back(static_cast<uint8_t>(0x80u | geometryID));
+                       break;
+               case 2u:
+                       recordData.push_back(uint8_t{0xABu});
+                       recordData.push_back(static_cast<uint8_t>(0xC0u | geometryID));
+                       break;
+               default:
+                       {
+                               const auto elemCount = shaderRecordElementCount();
+                               for (uint32_t i = 0u; i < elemCount; ++i)
+                               {
+                                       recordData.push_back(uint8_t{0xABu});
+                                       recordData.push_back(uint8_t{0xCDu});
+                                       recordData.push_back(static_cast<uint8_t>(0xE0u | i));
+                                       recordData.push_back(static_cast<uint8_t>(0xF0u | geometryID));
+                               }
+                       }
+                       break;
+               }
+               return recordData;
+       }
+};
+
+class ShaderGroupHandleAlignmentCase : public TestCase
+{
+public:
+                                       ShaderGroupHandleAlignmentCase          (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const ShaderGroupHandleAlignmentParams& params)
+                                               : TestCase      (testCtx, name, description)
+                                               , m_params      (params)
+                                               {
+                                               }
+       virtual                 ~ShaderGroupHandleAlignmentCase         (void) {}
+
+       void                    checkSupport                                            (Context& context) const override;
+       void                    initPrograms                                            (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                                          (Context& context) const override;
+
+protected:
+       ShaderGroupHandleAlignmentParams                                        m_params;
+};
+
+class ShaderGroupHandleAlignmentInstance : public TestInstance
+{
+public:
+                                               ShaderGroupHandleAlignmentInstance      (Context& context, const ShaderGroupHandleAlignmentParams& params)
+                                                       : TestInstance  (context)
+                                                       , m_params              (params)
+                                                       {}
+       virtual                         ~ShaderGroupHandleAlignmentInstance     (void) {}
+
+       tcu::TestStatus         iterate                                                         (void) override;
+
+protected:
+       ShaderGroupHandleAlignmentParams                                                        m_params;
+};
+
+void ShaderGroupHandleAlignmentCase::checkSupport (Context& context) const
+{
+       context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
+       context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
+
+       const auto&     vki                             = context.getInstanceInterface();
+       const auto      physicalDevice  = context.getPhysicalDevice();
+       const auto      rtProperties    = makeRayTracingProperties(vki, physicalDevice);
+
+       if (m_params.alignment < rtProperties->getShaderGroupHandleAlignment())
+               TCU_THROW(NotSupportedError, "Required shader group handle alignment not supported");
+
+       switch (m_params.alignment)
+       {
+       case 1u:
+               {
+                       const auto& int8Features = context.getShaderFloat16Int8Features();
+                       if (!int8Features.shaderInt8)
+                               TCU_THROW(NotSupportedError, "shaderInt8 not supported");
+
+                       const auto& int8StorageFeatures = context.get8BitStorageFeatures();
+                       if (!int8StorageFeatures.storageBuffer8BitAccess)
+                               TCU_THROW(NotSupportedError, "storageBuffer8BitAccess not supported");
+               }
+               break;
+
+       case 2u:
+               {
+                       context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT16);
+
+                       const auto& int16StorageFeatures = context.get16BitStorageFeatures();
+                       if (!int16StorageFeatures.storageBuffer16BitAccess)
+                               TCU_THROW(NotSupportedError, "storageBuffer16BitAccess not supported");
+               }
+               break;
+
+       default:
+               break;
+       }
+}
+
+void ShaderGroupHandleAlignmentCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       const ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
+
+       const auto elemType                     = m_params.glslElementType();
+       const auto geometryCount        = m_params.geometryCount();
+       const auto elementCount         = m_params.shaderRecordElementCount();
+       const auto extension            = m_params.glslExtension();
+
+       std::ostringstream descriptors;
+       descriptors
+               << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
+               << "layout(set=0, binding=1, std430) buffer SSBOBlock {\n"
+               << "  " << elemType << " data[" << geometryCount << "][" << elementCount << "];\n"
+               << "} ssbo;\n"
+               ;
+       const auto descriptorsStr = descriptors.str();
+
+       std::ostringstream commonHeader;
+       commonHeader
+               << "#version 460 core\n"
+               << "#extension GL_EXT_ray_tracing : require\n"
+               << "#extension " << extension << " : require\n"
+               ;
+       const auto commontHeaderStr = commonHeader.str();
+
+       std::ostringstream rgen;
+       rgen
+               << commontHeaderStr
+               << "\n"
+               << descriptorsStr
+               << "layout(location=0) rayPayloadEXT vec4 unused;\n"
+               << "\n"
+               << "void main()\n"
+               << "{\n"
+               << "  const uint  rayFlags  = 0;\n"
+               << "  const uint  cullMask  = 0xFF;\n"
+               << "  const float tMin      = 0.0;\n"
+               << "  const float tMax      = 10.0;\n"
+               << "  const vec3  origin    = vec3(float(gl_LaunchIDEXT.x) + 0.5, 0.5, 0.0);\n"
+               << "  const vec3  direction = vec3(0.0, 0.0, 1.0);\n"
+               << "  const uint  sbtOffset = 0;\n"
+               << "  const uint  sbtStride = 1;\n"
+               << "  const uint  missIndex = 0;\n"
+               << "  traceRayEXT(topLevelAS, rayFlags, cullMask, sbtOffset, sbtStride, missIndex, origin, tMin, direction, tMax, 0);\n"
+               << "}\n"
+               ;
+
+       std::ostringstream chit;
+       chit
+               << commontHeaderStr
+               << "\n"
+               << descriptorsStr
+               << "layout(location=0) rayPayloadInEXT vec4 unused;\n"
+               << "layout(shaderRecordEXT, std430) buffer srbBlock {\n"
+               << "  " << elemType << " data[" << elementCount << "];\n"
+               << "} srb;\n"
+               << "\n"
+               << "void main()\n"
+               << "{\n"
+               << "  for (uint i = 0; i < " << elementCount << "; ++i) {\n"
+               << "    ssbo.data[gl_LaunchIDEXT.x][i] = srb.data[i];\n"
+               << "  }\n"
+               << "}\n"
+               ;
+
+       std::ostringstream miss;
+       miss
+               << commontHeaderStr
+               << "\n"
+               << descriptorsStr
+               << "layout(location=0) rayPayloadInEXT vec4 unused;\n"
+               << "\n"
+               << "void main()\n"
+               << "{\n"
+               << "}\n"
+               ;
+
+       programCollection.glslSources.add("rgen") << glu::RaygenSource(rgen.str()) << buildOptions;
+       programCollection.glslSources.add("chit") << glu::ClosestHitSource(chit.str()) << buildOptions;
+       programCollection.glslSources.add("miss") << glu::MissSource(miss.str()) << buildOptions;
+}
+
+TestInstance* ShaderGroupHandleAlignmentCase::createInstance (Context& context) const
+{
+       return new ShaderGroupHandleAlignmentInstance(context, m_params);
+}
+
+tcu::TestStatus ShaderGroupHandleAlignmentInstance::iterate (void)
+{
+       const auto&     vki                     = m_context.getInstanceInterface();
+       const auto      physDev         = m_context.getPhysicalDevice();
+       const auto&     vkd                     = m_context.getDeviceInterface();
+       const auto      device          = m_context.getDevice();
+       auto&           alloc           = m_context.getDefaultAllocator();
+       const auto      qIndex          = m_context.getUniversalQueueFamilyIndex();
+       const auto      queue           = m_context.getUniversalQueue();
+       const auto      stages          = (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR);
+       const auto      geoCount        = m_params.geometryCount();
+       const auto      triangleZ       = 5.0f;
+
+       // Command pool and buffer.
+       const auto cmdPool              = makeCommandPool(vkd, device, qIndex);
+       const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+       const auto cmdBuffer    = cmdBufferPtr.get();
+
+       beginCommandBuffer(vkd, cmdBuffer);
+
+       // Build acceleration structures.
+       auto topLevelAS         = makeTopLevelAccelerationStructure();
+       auto bottomLevelAS      = makeBottomLevelAccelerationStructure();
+
+       // Create the needed amount of geometries (triangles) with the right coordinates.
+       const tcu::Vec3 baseLocation    (0.5f, 0.5f, triangleZ);
+       const float             vertexOffset    = 0.25f; // From base location, to build a triangle around it.
+
+       for (uint32_t i = 0; i < geoCount; ++i)
+       {
+               // Triangle "center" or base location.
+               const tcu::Vec3                                 triangleLocation (baseLocation.x() + static_cast<float>(i), baseLocation.y(), baseLocation.z());
+
+               // Actual triangle.
+               const std::vector<tcu::Vec3>    triangle
+               {
+                       tcu::Vec3(triangleLocation.x() - vertexOffset, triangleLocation.y() - vertexOffset, triangleLocation.z()),
+                       tcu::Vec3(triangleLocation.x() + vertexOffset, triangleLocation.y() - vertexOffset, triangleLocation.z()),
+                       tcu::Vec3(triangleLocation.x(),                triangleLocation.y() + vertexOffset, triangleLocation.z()),
+               };
+
+               bottomLevelAS->addGeometry(triangle, true/*triangles*/);
+       }
+
+       bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
+
+       de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
+       topLevelAS->setInstanceCount(1);
+       topLevelAS->addInstance(blasSharedPtr, identityMatrix3x4, 0u, 0xFF, 0u, VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
+       topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
+
+       // Get some ray tracing properties.
+       uint32_t shaderGroupHandleSize          = 0u;
+       uint32_t shaderGroupBaseAlignment       = 1u;
+       {
+               const auto rayTracingPropertiesKHR      = makeRayTracingProperties(vki, physDev);
+               shaderGroupHandleSize                           = rayTracingPropertiesKHR->getShaderGroupHandleSize();
+               shaderGroupBaseAlignment                        = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
+       }
+
+       // SSBO to copy results over from the shaders.
+       const auto                      shaderRecordSize        = m_params.alignment;
+       const auto                      hitSBTStride            = shaderGroupHandleSize + shaderRecordSize;
+       const auto                      ssboSize                        = static_cast<VkDeviceSize>(geoCount * hitSBTStride);
+       const auto                      ssboInfo                        = makeBufferCreateInfo(ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+       BufferWithMemory        ssbo                            (vkd, device, alloc, ssboInfo, MemoryRequirement::HostVisible);
+       auto&                           ssboAlloc                       = ssbo.getAllocation();
+       void*                           ssboData                        = ssboAlloc.getHostPtr();
+
+       deMemset(ssboData, 0, static_cast<size_t>(ssboSize));
+
+       // Descriptor set layout and pipeline layout.
+       DescriptorSetLayoutBuilder setLayoutBuilder;
+       setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
+       setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
+       const auto setLayout            = setLayoutBuilder.build(vkd, device);
+       const auto pipelineLayout       = makePipelineLayout(vkd, device, setLayout.get());
+
+       // Descriptor pool and set.
+       DescriptorPoolBuilder poolBuilder;
+       poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
+       poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
+       const auto descriptorPool       = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+       const auto descriptorSet        = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
+
+       // Update descriptor set.
+       {
+               const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
+               {
+                       VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
+                       nullptr,
+                       1u,
+                       topLevelAS.get()->getPtr(),
+               };
+
+               const auto ssboDescInfo = makeDescriptorBufferInfo(ssbo.get(), 0ull, ssboSize);
+
+               DescriptorSetUpdateBuilder updateBuilder;
+               updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
+               updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboDescInfo);
+               updateBuilder.update(vkd, device);
+       }
+
+       // Shader modules.
+       auto rgenModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0));
+       auto missModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("miss"), 0));
+       auto chitModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("chit"), 0));
+
+       // Create raytracing pipeline and shader binding tables.
+       Move<VkPipeline>                                pipeline;
+
+       de::MovePtr<BufferWithMemory>   raygenSBT;
+       de::MovePtr<BufferWithMemory>   missSBT;
+       de::MovePtr<BufferWithMemory>   hitSBT;
+       de::MovePtr<BufferWithMemory>   callableSBT;
+
+       VkStridedDeviceAddressRegionKHR raygenSBTRegion         = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+       VkStridedDeviceAddressRegionKHR missSBTRegion           = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+       VkStridedDeviceAddressRegionKHR hitSBTRegion            = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+       VkStridedDeviceAddressRegionKHR callableSBTRegion       = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+
+       // Create shader record buffer data.
+       using DataVec = std::vector<uint8_t>;
+
+       std::vector<DataVec> srbData;
+       for (uint32_t i = 0; i < geoCount; ++i)
+       {
+               srbData.emplace_back(m_params.getRecordData(i));
+       }
+
+       std::vector<const void*> srbDataPtrs;
+       srbDataPtrs.reserve(srbData.size());
+       std::transform(begin(srbData), end(srbData), std::back_inserter(srbDataPtrs), [](const DataVec& data) { return data.data(); });
+
+       // Generate ids for the closest hit and miss shaders according to the test parameters.
+       {
+               const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
+
+               rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, 0u);
+               rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule, 1u);
+
+               for (uint32_t i = 0; i < geoCount; ++i)
+                       rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule, 2u + i);
+
+               pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
+
+               raygenSBT               = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0u, 1u);
+               raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
+
+               missSBT                 = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1u, 1u);
+               missSBTRegion   = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
+
+               hitSBT                  = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 2u, geoCount,
+                                                                                                                                          0u, 0u, MemoryRequirement::Any, 0u, 0u, shaderRecordSize, srbDataPtrs.data(), false/*autoalign*/);
+               hitSBTRegion    = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0), hitSBTStride, hitSBTStride*geoCount);
+       }
+
+       // Trace rays and verify ssbo contents.
+       vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
+       vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
+       vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, geoCount, 1u, 1u);
+       const auto shaderToHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
+       cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT, &shaderToHostBarrier);
+
+       endCommandBuffer(vkd, cmdBuffer);
+       submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+
+       invalidateAlloc(vkd, device, ssboAlloc);
+
+       // Verify SSBO.
+       const auto      ssboDataAsBytes = reinterpret_cast<const uint8_t*>(ssboData);
+       size_t          ssboDataIdx             = 0u;
+       bool            fail                    = false;
+       auto&           log                             = m_context.getTestContext().getLog();
+
+       for (const auto& dataVec : srbData)
+               for (const uint8_t byte : dataVec)
+               {
+                       const uint8_t outputByte = ssboDataAsBytes[ssboDataIdx++];
+                       if (byte != outputByte)
+                       {
+                               std::ostringstream msg;
+                               msg
+                                       << std::hex << std::setfill('0')
+                                       << "Unexpectd output data: "
+                                       << "0x" << std::setw(2) << static_cast<int>(outputByte)
+                                       << " vs "
+                                       << "0x" << std::setw(2) << static_cast<int>(byte)
+                                       ;
+                               log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
+                               fail = true;
+                       }
+               }
+
+       if (fail)
+               return tcu::TestStatus::fail("Unexpected output data found; check log for details");
+       return tcu::TestStatus::pass("Pass");
+}
+
 }      // anonymous
 
 tcu::TestCaseGroup*    createShaderBindingTableTests (tcu::TestContext& testCtx)
@@ -1042,47 +1514,47 @@ tcu::TestCaseGroup*     createShaderBindingTableTests (tcu::TestContext& testCtx)
                                                                                                                                                                                                                                                                : MAX_SBT_RECORD_OFFSET | (~((1u << 4)  - 1)); //< Only 4 least significant bits matter for SBT record offsets
 
                                for (deUint32 sbtRecordOffset = 0; sbtRecordOffset <= maxSbtRecordOffset; ++sbtRecordOffset)
-                               for (deUint32 sbtRecordStride = 0; sbtRecordStride <= maxSbtRecordStride; ++sbtRecordStride)
-                               {
-                                       if ((shaderTestTypes[shaderTestNdx].shaderTestType      != STT_HIT)                             &&
-                                               (sbtRecordStride                                                                == maxSbtRecordStride))
-                                       {
-                                               continue;
-                                       }
-
-                                       TestParams testParams
-                                       {
-                                               CHECKERBOARD_WIDTH,
-                                               CHECKERBOARD_HEIGHT,
-                                               shaderTestTypes[shaderTestNdx].shaderTestType,
-                                               shaderBufferOffsets[sbtOffsetNdx].sbtOffset,
-                                               shaderRecords[shaderRecordNdx].present,
-                                               sbtRecordOffset,
-                                               (sbtRecordOffset == maxSbtRecordOffset) ? maxSbtRecordOffsetWithExtraBits
-                                                                                                                               : sbtRecordOffset,
-                                               //< Only first 4 least significant bits matter for SBT record stride
-                                               sbtRecordStride,
-                                               (sbtRecordStride == maxSbtRecordStride) ? maxSbtRecordStride | (~((1u << 4) - 1))
-                                                                                                                               : sbtRecordStride,
-                                               de::SharedPtr<TestConfiguration>(new CheckerboardConfiguration())
-                                       };
-
-                                       std::stringstream str;
-                                       str << sbtRecordOffset << "_" << sbtRecordStride;
-
-                                       if (testParams.sbtRecordStride != testParams.sbtRecordStridePassedToTraceRay)
+                                       for (deUint32 sbtRecordStride = 0; sbtRecordStride <= maxSbtRecordStride; ++sbtRecordStride)
                                        {
-                                               str << "_extraSBTRecordStrideBits";
+                                               if ((shaderTestTypes[shaderTestNdx].shaderTestType      != STT_HIT)                             &&
+                                                       (sbtRecordStride                                                                == maxSbtRecordStride))
+                                               {
+                                                       continue;
+                                               }
+
+                                               TestParams testParams
+                                               {
+                                                       CHECKERBOARD_WIDTH,
+                                                       CHECKERBOARD_HEIGHT,
+                                                       shaderTestTypes[shaderTestNdx].shaderTestType,
+                                                       shaderBufferOffsets[sbtOffsetNdx].sbtOffset,
+                                                       shaderRecords[shaderRecordNdx].present,
+                                                       sbtRecordOffset,
+                                                       (sbtRecordOffset == maxSbtRecordOffset) ? maxSbtRecordOffsetWithExtraBits
+                                                                                                                                       : sbtRecordOffset,
+                                                       //< Only first 4 least significant bits matter for SBT record stride
+                                                       sbtRecordStride,
+                                                       (sbtRecordStride == maxSbtRecordStride) ? maxSbtRecordStride | (~((1u << 4) - 1))
+                                                                                                                                       : sbtRecordStride,
+                                                       de::SharedPtr<TestConfiguration>(new CheckerboardConfiguration())
+                                               };
+
+                                               std::stringstream str;
+                                               str << sbtRecordOffset << "_" << sbtRecordStride;
+
+                                               if (testParams.sbtRecordStride != testParams.sbtRecordStridePassedToTraceRay)
+                                               {
+                                                       str << "_extraSBTRecordStrideBits";
+                                               }
+
+                                               if (testParams.sbtRecordOffset != testParams.sbtRecordOffsetPassedToTraceRay)
+                                               {
+                                                       str << "_extrabits";
+                                               }
+
+                                               shaderRecordGroup->addChild(new ShaderBindingTableIndexingTestCase(group->getTestContext(), str.str().c_str(), "", testParams));
                                        }
 
-                                       if (testParams.sbtRecordOffset != testParams.sbtRecordOffsetPassedToTraceRay)
-                                       {
-                                               str << "_extrabits";
-                                       }
-
-                                       shaderRecordGroup->addChild(new ShaderBindingTableIndexingTestCase(group->getTestContext(), str.str().c_str(), "", testParams));
-                               }
-
                                sbtOffsetGroup->addChild(shaderRecordGroup.release());
                        }
 
@@ -1092,6 +1564,22 @@ tcu::TestCaseGroup*      createShaderBindingTableTests (tcu::TestContext& testCtx)
                group->addChild(shaderTestGroup.release());
        }
 
+       {
+               const uint32_t                                  kAlignments[]                   = { 1u, 2u, 4u, 8u, 16u, 32u };
+               de::MovePtr<tcu::TestCaseGroup> handleAlignmentGroup    (new tcu::TestCaseGroup(testCtx, "handle_alignment", "Test allowed handle alignments"));
+
+               for (const auto alignment : kAlignments)
+               {
+                       const auto alignStr = std::to_string(alignment);
+                       const auto testName = "alignment_" + alignStr;
+                       const auto testDesc = "Check aligning shader group handles to " + alignStr + " bytes";
+
+                       handleAlignmentGroup->addChild(new ShaderGroupHandleAlignmentCase(testCtx, testName, testDesc, ShaderGroupHandleAlignmentParams{alignment}));
+               }
+
+               group->addChild(handleAlignmentGroup.release());
+       }
+
        return group.release();
 }
 
index ef93a56..9009985 100644 (file)
@@ -440,6 +440,12 @@ dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.sh
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.1_0
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.2_0
 dEQP-VK.ray_tracing_pipeline.shader_binding_table.indexing_call.sbt_offset_16.shaderrecord.3_0_extrabits
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_1
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_2
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_4
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_8
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_16
+dEQP-VK.ray_tracing_pipeline.shader_binding_table.handle_alignment.alignment_32
 dEQP-VK.ray_tracing_pipeline.procedural_geometry.object_behind_bounding_boxes
 dEQP-VK.ray_tracing_pipeline.procedural_geometry.triangle_in_between
 dEQP-VK.ray_tracing_pipeline.pipeline_no_null_shaders_flag.gpu.triangles.stride_3.offset_7.use_libs.miss