1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Ray Tracing Shader Binding Table tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingShaderBindingTableTests.hpp"
25 
26 #include "vkDefs.hpp"
27 
28 #include "vktTestCase.hpp"
29 #include "vktTestGroupUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "deRandom.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuImageCompare.hpp"
43 
44 #include "vkRayTracingUtil.hpp"
45 
46 namespace vkt
47 {
48 namespace RayTracing
49 {
50 namespace
51 {
52 using namespace vk;
53 using namespace vkt;
54 
55 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
56                                               VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
57                                               VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
58 
59 enum ShaderTestType
60 {
61     STT_HIT   = 0,
62     STT_MISS  = 1,
63     STT_CALL  = 2,
64     STT_COUNT = 3
65 };
66 
67 const uint32_t CHECKERBOARD_WIDTH  = 8;
68 const uint32_t CHECKERBOARD_HEIGHT = 8;
69 const uint32_t HIT_GEOMETRY_COUNT  = 3;
70 const uint32_t HIT_INSTANCE_COUNT  = 1 + CHECKERBOARD_WIDTH * CHECKERBOARD_HEIGHT / (2 * HIT_GEOMETRY_COUNT);
71 
72 const uint32_t MAX_SBT_RECORD_OFFSET     = 3;
73 const uint32_t MAX_HIT_SBT_RECORD_STRIDE = HIT_GEOMETRY_COUNT + 1;
74 const uint32_t SBT_RANDOM_SEED           = 1410;
75 
76 struct TestParams;
77 
78 class TestConfiguration
79 {
80 public:
~TestConfiguration()81     virtual ~TestConfiguration()
82     {
83     }
84 
85     virtual std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures(
86         Context &context, TestParams &testParams) = 0;
87     virtual de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure(
88         Context &context, TestParams &testParams,
89         std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)    = 0;
90     virtual de::MovePtr<BufferWithMemory> initUniformBuffer(Context &context, TestParams &testParams)       = 0;
91     virtual void initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
92                                        TestParams &testParams)                                              = 0;
93     virtual void initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
94                                          TestParams &testParams, VkPipeline pipeline, uint32_t shaderGroupHandleSize,
95                                          uint32_t shaderGroupBaseAlignment,
96                                          de::MovePtr<BufferWithMemory> &raygenShaderBindingTable,
97                                          de::MovePtr<BufferWithMemory> &hitShaderBindingTable,
98                                          de::MovePtr<BufferWithMemory> &missShaderBindingTable,
99                                          de::MovePtr<BufferWithMemory> &callableShaderBindingTable,
100                                          VkStridedDeviceAddressRegionKHR &raygenShaderBindingTableRegion,
101                                          VkStridedDeviceAddressRegionKHR &hitShaderBindingTableRegion,
102                                          VkStridedDeviceAddressRegionKHR &missShaderBindingTableRegion,
103                                          VkStridedDeviceAddressRegionKHR &callableShaderBindingTableRegion) = 0;
104     virtual bool verifyImage(BufferWithMemory *resultBuffer, Context &context, TestParams &testParams)      = 0;
105     virtual VkFormat getResultImageFormat()                                                                 = 0;
106     virtual size_t getResultImageFormatSize()                                                               = 0;
107     virtual VkClearValue getClearValue()                                                                    = 0;
108 };
109 
110 struct TestParams
111 {
112     uint32_t width;
113     uint32_t height;
114     ShaderTestType shaderTestType;
115     uint32_t sbtOffset;
116     bool shaderRecordPresent;
117     uint32_t sbtRecordOffset;
118     uint32_t sbtRecordOffsetPassedToTraceRay;
119     uint32_t sbtRecordStride;
120     uint32_t sbtRecordStridePassedToTraceRay;
121     de::SharedPtr<TestConfiguration> testConfiguration;
122 };
123 
getShaderCounts()124 std::vector<uint32_t> getShaderCounts()
125 {
126     std::vector<uint32_t> shaderCount(STT_COUNT);
127     shaderCount[STT_HIT] =
128         HIT_INSTANCE_COUNT + HIT_GEOMETRY_COUNT * MAX_HIT_SBT_RECORD_STRIDE + MAX_SBT_RECORD_OFFSET + 1;
129     shaderCount[STT_MISS] = MAX_SBT_RECORD_OFFSET + HIT_INSTANCE_COUNT + 1;
130     shaderCount[STT_CALL] = MAX_SBT_RECORD_OFFSET + HIT_INSTANCE_COUNT + 1;
131     return shaderCount;
132 }
133 
getShaderGroupHandleSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)134 uint32_t getShaderGroupHandleSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
135 {
136     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
137 
138     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
139     return rayTracingPropertiesKHR->getShaderGroupHandleSize();
140 }
141 
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)142 uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
143 {
144     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
145 
146     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
147     return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
148 }
149 
makeImageCreateInfo(uint32_t width,uint32_t height,VkFormat format)150 VkImageCreateInfo makeImageCreateInfo(uint32_t width, uint32_t height, VkFormat format)
151 {
152     const VkImageCreateInfo imageCreateInfo = {
153         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
154         DE_NULL,                             // const void* pNext;
155         (VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
156         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
157         format,                              // VkFormat format;
158         makeExtent3D(width, height, 1),      // VkExtent3D extent;
159         1u,                                  // uint32_t mipLevels;
160         1u,                                  // uint32_t arrayLayers;
161         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
162         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
163         VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
164             VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
165         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
166         0u,                                  // uint32_t queueFamilyIndexCount;
167         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
168         VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
169     };
170 
171     return imageCreateInfo;
172 }
173 
174 class CheckerboardConfiguration : public TestConfiguration
175 {
176 public:
177     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures(
178         Context &context, TestParams &testParams) override;
179     de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure(
180         Context &context, TestParams &testParams,
181         std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures) override;
182     de::MovePtr<BufferWithMemory> initUniformBuffer(Context &context, TestParams &testParams) override;
183     void initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
184                                TestParams &testParams) override;
185     void initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
186                                  TestParams &testParams, VkPipeline pipeline, uint32_t shaderGroupHandleSize,
187                                  uint32_t shaderGroupBaseAlignment,
188                                  de::MovePtr<BufferWithMemory> &raygenShaderBindingTable,
189                                  de::MovePtr<BufferWithMemory> &hitShaderBindingTable,
190                                  de::MovePtr<BufferWithMemory> &missShaderBindingTable,
191                                  de::MovePtr<BufferWithMemory> &callableShaderBindingTable,
192                                  VkStridedDeviceAddressRegionKHR &raygenShaderBindingTableRegion,
193                                  VkStridedDeviceAddressRegionKHR &hitShaderBindingTableRegion,
194                                  VkStridedDeviceAddressRegionKHR &missShaderBindingTableRegion,
195                                  VkStridedDeviceAddressRegionKHR &callableShaderBindingTableRegion) override;
196     bool verifyImage(BufferWithMemory *resultBuffer, Context &context, TestParams &testParams) override;
197     VkFormat getResultImageFormat() override;
198     size_t getResultImageFormatSize() override;
199     VkClearValue getClearValue() override;
200 };
201 
202 std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> CheckerboardConfiguration::
initBottomAccelerationStructures(Context & context,TestParams & testParams)203     initBottomAccelerationStructures(Context &context, TestParams &testParams)
204 {
205     DE_UNREF(context);
206 
207     std::vector<tcu::Vec3> corners;
208     for (uint32_t y = 0; y < testParams.height; ++y)
209         for (uint32_t x = 0; x < testParams.width; ++x)
210         {
211             if (((x + y) % 2) == 0)
212                 continue;
213             corners.push_back(tcu::Vec3((float)x, (float)y, 0.0f));
214         }
215 
216     de::Random rnd(SBT_RANDOM_SEED);
217     rnd.shuffle(begin(corners), end(corners));
218 
219     tcu::Vec3 v0(0.0, 1.0, 0.0);
220     tcu::Vec3 v1(0.0, 0.0, 0.0);
221     tcu::Vec3 v2(1.0, 1.0, 0.0);
222     tcu::Vec3 v3(1.0, 0.0, 0.0);
223     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> result;
224 
225     for (size_t cornerNdx = 0; cornerNdx < corners.size(); cornerNdx += HIT_GEOMETRY_COUNT)
226     {
227         de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure =
228             makeBottomLevelAccelerationStructure();
229         size_t geometryCount = std::min(corners.size() - cornerNdx, size_t(HIT_GEOMETRY_COUNT));
230         bottomLevelAccelerationStructure->setGeometryCount(geometryCount);
231         for (size_t idx = cornerNdx; idx < cornerNdx + geometryCount; ++idx)
232         {
233             de::SharedPtr<RaytracedGeometryBase> geometry = makeRaytracedGeometry(
234                 VK_GEOMETRY_TYPE_TRIANGLES_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR);
235             geometry->addVertex(corners[idx] + v0);
236             geometry->addVertex(corners[idx] + v1);
237             geometry->addVertex(corners[idx] + v2);
238             geometry->addVertex(corners[idx] + v2);
239             geometry->addVertex(corners[idx] + v1);
240             geometry->addVertex(corners[idx] + v3);
241             bottomLevelAccelerationStructure->addGeometry(geometry);
242         }
243         result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
244     }
245     return result;
246 }
247 
initTopAccelerationStructure(Context & context,TestParams & testParams,std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> & bottomLevelAccelerationStructures)248 de::MovePtr<TopLevelAccelerationStructure> CheckerboardConfiguration::initTopAccelerationStructure(
249     Context &context, TestParams &testParams,
250     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)
251 {
252     DE_UNREF(context);
253     DE_UNREF(testParams);
254 
255     de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
256     uint32_t instanceCount                            = uint32_t(bottomLevelAccelerationStructures.size());
257     result->setInstanceCount(instanceCount);
258 
259     VkTransformMatrixKHR identityMatrix = {
260         {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}};
261     for (uint32_t i = 0; i < instanceCount; ++i)
262         result->addInstance(bottomLevelAccelerationStructures[i], identityMatrix, 0u, 0xFF,
263                             (testParams.shaderTestType == STT_MISS) ? 0 : i);
264 
265     return result;
266 }
267 
initUniformBuffer(Context & context,TestParams & testParams)268 de::MovePtr<BufferWithMemory> CheckerboardConfiguration::initUniformBuffer(Context &context, TestParams &testParams)
269 {
270     const DeviceInterface &vkd = context.getDeviceInterface();
271     const VkDevice device      = context.getDevice();
272     Allocator &allocator       = context.getDefaultAllocator();
273 
274     const VkBufferCreateInfo uniformBufferCreateInfo =
275         makeBufferCreateInfo(sizeof(tcu::UVec4), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
276     de::MovePtr<BufferWithMemory> uniformBuffer = de::MovePtr<BufferWithMemory>(
277         new BufferWithMemory(vkd, device, allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
278     tcu::UVec4 uniformValue; // x = sbtRecordOffset, y = sbtRecordStride, z = missIndex
279     switch (testParams.shaderTestType)
280     {
281     case STT_HIT:
282     {
283         uniformValue = tcu::UVec4(testParams.sbtRecordOffsetPassedToTraceRay, testParams.sbtRecordStride, 0, 0);
284         break;
285     }
286     case STT_MISS:
287     {
288         uniformValue = tcu::UVec4(0, 0, testParams.sbtRecordOffsetPassedToTraceRay, 0);
289         break;
290     }
291     case STT_CALL:
292     {
293         uniformValue = tcu::UVec4(testParams.sbtRecordOffsetPassedToTraceRay, testParams.sbtRecordStride, 0, 0);
294         break;
295     }
296     default:
297         TCU_THROW(InternalError, "Wrong shader test type");
298     }
299     deMemcpy(uniformBuffer->getAllocation().getHostPtr(), &uniformValue, sizeof(tcu::UVec4));
300     flushMappedMemoryRange(vkd, device, uniformBuffer->getAllocation().getMemory(),
301                            uniformBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE);
302 
303     return uniformBuffer;
304 }
305 
initRayTracingShaders(de::MovePtr<RayTracingPipeline> & rayTracingPipeline,Context & context,TestParams & testParams)306 void CheckerboardConfiguration::initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
307                                                       Context &context, TestParams &testParams)
308 {
309     const DeviceInterface &vkd = context.getDeviceInterface();
310     const VkDevice device      = context.getDevice();
311 
312     std::vector<uint32_t> shaderCount = getShaderCounts();
313 
314     switch (testParams.shaderTestType)
315     {
316     case STT_HIT:
317     {
318         if (testParams.shaderRecordPresent)
319         {
320             // shaders: rgen, chit_shaderRecord (N times), miss_0
321             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
322                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
323                                           0);
324             for (uint32_t idx = 0; idx < shaderCount[STT_HIT]; ++idx)
325                 rayTracingPipeline->addShader(
326                     VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
327                     createShaderModule(vkd, device, context.getBinaryCollection().get("chit_shaderRecord"), 0),
328                     1 + idx);
329             rayTracingPipeline->addShader(
330                 VK_SHADER_STAGE_MISS_BIT_KHR,
331                 createShaderModule(vkd, device, context.getBinaryCollection().get("miss_0"), 0),
332                 1 + shaderCount[STT_HIT]);
333         }
334         else
335         {
336             // shaders: rgen, chit_0 .. chit_N, miss_0
337             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
338                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
339                                           0);
340             for (uint32_t idx = 0; idx < shaderCount[STT_HIT]; ++idx)
341             {
342                 std::stringstream csname;
343                 csname << "chit_" << idx;
344                 rayTracingPipeline->addShader(
345                     VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
346                     createShaderModule(vkd, device, context.getBinaryCollection().get(csname.str()), 0), 1 + idx);
347             }
348             rayTracingPipeline->addShader(
349                 VK_SHADER_STAGE_MISS_BIT_KHR,
350                 createShaderModule(vkd, device, context.getBinaryCollection().get("miss_0"), 0),
351                 1 + shaderCount[STT_HIT]);
352         }
353         rayTracingPipeline->setMaxPayloadSize(16u);
354         break;
355     }
356     case STT_MISS:
357     {
358         if (testParams.shaderRecordPresent)
359         {
360             // shaders: rgen, chit_0, miss_shaderRecord ( N times )
361             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
362                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
363                                           0);
364             rayTracingPipeline->addShader(
365                 VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
366                 createShaderModule(vkd, device, context.getBinaryCollection().get("chit_0"), 0), 1);
367             for (uint32_t idx = 0; idx < shaderCount[STT_MISS]; ++idx)
368                 rayTracingPipeline->addShader(
369                     VK_SHADER_STAGE_MISS_BIT_KHR,
370                     createShaderModule(vkd, device, context.getBinaryCollection().get("miss_shaderRecord"), 0),
371                     2 + idx);
372         }
373         else
374         {
375             // shaders: rgen, chit_0, miss_0 .. miss_N
376             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
377                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
378                                           0);
379             rayTracingPipeline->addShader(
380                 VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
381                 createShaderModule(vkd, device, context.getBinaryCollection().get("chit_0"), 0), 1);
382             for (uint32_t idx = 0; idx < shaderCount[STT_MISS]; ++idx)
383             {
384                 std::stringstream csname;
385                 csname << "miss_" << idx;
386                 rayTracingPipeline->addShader(
387                     VK_SHADER_STAGE_MISS_BIT_KHR,
388                     createShaderModule(vkd, device, context.getBinaryCollection().get(csname.str()), 0), 2 + idx);
389             }
390         }
391         rayTracingPipeline->setMaxPayloadSize(16u);
392         break;
393     }
394     case STT_CALL:
395     {
396         if (testParams.shaderRecordPresent)
397         {
398             // shaders: rgen, chit_call_0 .. chit_call_N, miss_0, call_shaderRecord ( N times )
399             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
400                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
401                                           0);
402             for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
403             {
404                 std::stringstream csname;
405                 csname << "chit_call_" << idx;
406                 rayTracingPipeline->addShader(
407                     VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
408                     createShaderModule(vkd, device, context.getBinaryCollection().get(csname.str()), 0), 1 + idx);
409             }
410             rayTracingPipeline->addShader(
411                 VK_SHADER_STAGE_MISS_BIT_KHR,
412                 createShaderModule(vkd, device, context.getBinaryCollection().get("miss_0"), 0),
413                 1 + shaderCount[STT_CALL]);
414             for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
415                 rayTracingPipeline->addShader(
416                     VK_SHADER_STAGE_CALLABLE_BIT_KHR,
417                     createShaderModule(vkd, device, context.getBinaryCollection().get("call_shaderRecord"), 0),
418                     2 + shaderCount[STT_CALL] + idx);
419         }
420         else
421         {
422             // shaders: rgen, chit_call_0 .. chit_call_N, miss_0, call_0 .. call_N
423             rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
424                                           createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0),
425                                           0);
426             for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
427             {
428                 std::stringstream csname;
429                 csname << "chit_call_" << idx;
430                 rayTracingPipeline->addShader(
431                     VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
432                     createShaderModule(vkd, device, context.getBinaryCollection().get(csname.str()), 0), 1 + idx);
433             }
434             rayTracingPipeline->addShader(
435                 VK_SHADER_STAGE_MISS_BIT_KHR,
436                 createShaderModule(vkd, device, context.getBinaryCollection().get("miss_0"), 0),
437                 1 + shaderCount[STT_CALL]);
438             for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
439             {
440                 std::stringstream csname;
441                 csname << "call_" << idx;
442                 rayTracingPipeline->addShader(
443                     VK_SHADER_STAGE_CALLABLE_BIT_KHR,
444                     createShaderModule(vkd, device, context.getBinaryCollection().get(csname.str()), 0),
445                     2 + shaderCount[STT_CALL] + idx);
446             }
447         }
448         rayTracingPipeline->setMaxPayloadSize(16u);
449         break;
450     }
451     default:
452         TCU_THROW(InternalError, "Wrong shader test type");
453     }
454 }
455 
initShaderBindingTables(de::MovePtr<RayTracingPipeline> & rayTracingPipeline,Context & context,TestParams & testParams,VkPipeline pipeline,uint32_t shaderGroupHandleSize,uint32_t shaderGroupBaseAlignment,de::MovePtr<BufferWithMemory> & raygenShaderBindingTable,de::MovePtr<BufferWithMemory> & hitShaderBindingTable,de::MovePtr<BufferWithMemory> & missShaderBindingTable,de::MovePtr<BufferWithMemory> & callableShaderBindingTable,VkStridedDeviceAddressRegionKHR & raygenShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & hitShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & missShaderBindingTableRegion,VkStridedDeviceAddressRegionKHR & callableShaderBindingTableRegion)456 void CheckerboardConfiguration::initShaderBindingTables(
457     de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context, TestParams &testParams, VkPipeline pipeline,
458     uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment,
459     de::MovePtr<BufferWithMemory> &raygenShaderBindingTable, de::MovePtr<BufferWithMemory> &hitShaderBindingTable,
460     de::MovePtr<BufferWithMemory> &missShaderBindingTable, de::MovePtr<BufferWithMemory> &callableShaderBindingTable,
461     VkStridedDeviceAddressRegionKHR &raygenShaderBindingTableRegion,
462     VkStridedDeviceAddressRegionKHR &hitShaderBindingTableRegion,
463     VkStridedDeviceAddressRegionKHR &missShaderBindingTableRegion,
464     VkStridedDeviceAddressRegionKHR &callableShaderBindingTableRegion)
465 {
466     const DeviceInterface &vkd = context.getDeviceInterface();
467     const VkDevice device      = context.getDevice();
468     Allocator &allocator       = context.getDefaultAllocator();
469 
470     std::vector<uint32_t> shaderCount = getShaderCounts();
471 
472     // shaderBindingTableOffset must be multiple of shaderGroupBaseAlignment
473     uint32_t shaderBindingTableOffset = testParams.sbtOffset * shaderGroupBaseAlignment;
474 
475     // ShaderRecordKHR size must be multiple of shaderGroupHandleSize
476     uint32_t shaderRecordAlignedSize =
477         deAlign32(shaderGroupHandleSize + uint32_t(sizeof(tcu::UVec4)), shaderGroupHandleSize);
478     switch (testParams.shaderTestType)
479     {
480     case STT_HIT:
481     {
482         raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
483             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
484         if (testParams.shaderRecordPresent)
485             hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
486                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1,
487                 shaderCount[STT_HIT], 0u, 0u, MemoryRequirement::Any, 0u, shaderBindingTableOffset, sizeof(tcu::UVec4));
488         else
489             hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
490                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1,
491                 shaderCount[STT_HIT], 0u, 0u, MemoryRequirement::Any, 0u, shaderBindingTableOffset);
492         missShaderBindingTable =
493             rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize,
494                                                          shaderGroupBaseAlignment, 1 + shaderCount[STT_HIT], 1);
495 
496         raygenShaderBindingTableRegion =
497             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
498                                               shaderGroupHandleSize, shaderGroupHandleSize);
499         if (testParams.shaderRecordPresent)
500             hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
501                 getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), shaderBindingTableOffset),
502                 shaderRecordAlignedSize, shaderCount[STT_HIT] * shaderRecordAlignedSize);
503         else
504             hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
505                 getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), shaderBindingTableOffset),
506                 shaderGroupHandleSize, shaderCount[STT_HIT] * shaderGroupHandleSize);
507         missShaderBindingTableRegion =
508             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0),
509                                               shaderGroupHandleSize, shaderGroupHandleSize);
510         callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
511 
512         // fill ShaderRecordKHR data
513         if (testParams.shaderRecordPresent)
514         {
515             uint8_t *hitAddressBegin =
516                 (uint8_t *)hitShaderBindingTable->getAllocation().getHostPtr() + shaderBindingTableOffset;
517 
518             for (size_t idx = 0; idx < shaderCount[STT_HIT]; ++idx)
519             {
520                 uint8_t *shaderRecordAddress =
521                     hitAddressBegin + idx * shaderRecordAlignedSize + size_t(shaderGroupHandleSize);
522                 tcu::UVec4 shaderRecord(uint32_t(idx), 0, 0, 0);
523                 deMemcpy(shaderRecordAddress, &shaderRecord, sizeof(tcu::UVec4));
524             }
525 
526             flushMappedMemoryRange(vkd, device, hitShaderBindingTable->getAllocation().getMemory(),
527                                    hitShaderBindingTable->getAllocation().getOffset(), VK_WHOLE_SIZE);
528         }
529         break;
530     }
531     case STT_MISS:
532     {
533         raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
534             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
535         hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
536             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
537         if (testParams.shaderRecordPresent)
538             missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
539                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 2,
540                 shaderCount[STT_MISS], 0u, 0u, MemoryRequirement::Any, 0u, shaderBindingTableOffset,
541                 sizeof(tcu::UVec4));
542         else
543             missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
544                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 2,
545                 shaderCount[STT_MISS], 0u, 0u, MemoryRequirement::Any, 0u, shaderBindingTableOffset);
546 
547         raygenShaderBindingTableRegion =
548             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
549                                               shaderGroupHandleSize, shaderGroupHandleSize);
550         hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
551             getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0), 0, shaderGroupHandleSize);
552         if (testParams.shaderRecordPresent)
553             missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
554                 getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), shaderBindingTableOffset),
555                 shaderRecordAlignedSize, shaderCount[STT_MISS] * shaderRecordAlignedSize);
556         else
557             missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
558                 getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), shaderBindingTableOffset),
559                 shaderGroupHandleSize, shaderCount[STT_MISS] * shaderGroupHandleSize);
560         callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
561 
562         if (testParams.shaderRecordPresent)
563         {
564             uint8_t *missAddressBegin =
565                 (uint8_t *)missShaderBindingTable->getAllocation().getHostPtr() + shaderBindingTableOffset;
566 
567             for (size_t idx = 0; idx < shaderCount[STT_MISS]; ++idx)
568             {
569                 uint8_t *shaderRecordAddress =
570                     missAddressBegin + idx * shaderRecordAlignedSize + size_t(shaderGroupHandleSize);
571                 tcu::UVec4 shaderRecord(uint32_t(idx), 0, 0, 0);
572                 deMemcpy(shaderRecordAddress, &shaderRecord, sizeof(tcu::UVec4));
573             }
574 
575             flushMappedMemoryRange(vkd, device, missShaderBindingTable->getAllocation().getMemory(),
576                                    missShaderBindingTable->getAllocation().getOffset(), VK_WHOLE_SIZE);
577         }
578         break;
579     }
580     case STT_CALL:
581     {
582         raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
583             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
584         hitShaderBindingTable =
585             rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize,
586                                                          shaderGroupBaseAlignment, 1, shaderCount[STT_CALL]);
587         missShaderBindingTable =
588             rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize,
589                                                          shaderGroupBaseAlignment, 1 + shaderCount[STT_CALL], 1);
590         if (testParams.shaderRecordPresent)
591             callableShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
592                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment,
593                 2 + shaderCount[STT_CALL], shaderCount[STT_CALL], 0u, 0u, MemoryRequirement::Any, 0u,
594                 shaderBindingTableOffset, sizeof(tcu::UVec4));
595         else
596             callableShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
597                 vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment,
598                 2 + shaderCount[STT_CALL], shaderCount[STT_CALL], 0u, 0u, MemoryRequirement::Any, 0u,
599                 shaderBindingTableOffset);
600 
601         raygenShaderBindingTableRegion =
602             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
603                                               shaderGroupHandleSize, shaderGroupHandleSize);
604         hitShaderBindingTableRegion =
605             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0),
606                                               shaderGroupHandleSize, shaderCount[STT_CALL] * shaderGroupHandleSize);
607         missShaderBindingTableRegion =
608             makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0),
609                                               shaderGroupHandleSize, shaderGroupHandleSize);
610         if (testParams.shaderRecordPresent)
611             callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
612                 getBufferDeviceAddress(vkd, device, callableShaderBindingTable->get(), shaderBindingTableOffset),
613                 shaderRecordAlignedSize, shaderCount[STT_CALL] * shaderRecordAlignedSize);
614         else
615             callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
616                 getBufferDeviceAddress(vkd, device, callableShaderBindingTable->get(), shaderBindingTableOffset),
617                 shaderGroupHandleSize, shaderCount[STT_CALL] * shaderGroupHandleSize);
618 
619         if (testParams.shaderRecordPresent)
620         {
621             uint8_t *callAddressBegin =
622                 (uint8_t *)callableShaderBindingTable->getAllocation().getHostPtr() + shaderBindingTableOffset;
623 
624             for (size_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
625             {
626                 uint8_t *shaderRecordAddress =
627                     callAddressBegin + idx * shaderRecordAlignedSize + size_t(shaderGroupHandleSize);
628                 tcu::UVec4 shaderRecord(uint32_t(idx), 0, 0, 0);
629                 deMemcpy(shaderRecordAddress, &shaderRecord, sizeof(tcu::UVec4));
630             }
631             flushMappedMemoryRange(vkd, device, callableShaderBindingTable->getAllocation().getMemory(),
632                                    callableShaderBindingTable->getAllocation().getOffset(), VK_WHOLE_SIZE);
633         }
634         break;
635     }
636     default:
637         TCU_THROW(InternalError, "Wrong shader test type");
638     }
639 }
640 
verifyImage(BufferWithMemory * resultBuffer,Context & context,TestParams & testParams)641 bool CheckerboardConfiguration::verifyImage(BufferWithMemory *resultBuffer, Context &context, TestParams &testParams)
642 {
643     // create result image
644     tcu::TextureFormat imageFormat = vk::mapVkFormat(getResultImageFormat());
645     tcu::ConstPixelBufferAccess resultAccess(imageFormat, testParams.width, testParams.height, 1,
646                                              resultBuffer->getAllocation().getHostPtr());
647 
648     // recreate geometry indices and instance offsets
649     std::vector<tcu::UVec4> corners;
650     for (uint32_t y = 0; y < testParams.height; ++y)
651         for (uint32_t x = 0; x < testParams.width; ++x)
652         {
653             if (((x + y) % 2) == 0)
654                 continue;
655             corners.push_back(tcu::UVec4(x, y, 0, 0));
656         }
657     de::Random rnd(SBT_RANDOM_SEED);
658     rnd.shuffle(begin(corners), end(corners));
659 
660     uint32_t instanceOffset = 0;
661     for (size_t cornerNdx = 0; cornerNdx < corners.size(); cornerNdx += HIT_GEOMETRY_COUNT, ++instanceOffset)
662     {
663         size_t geometryCount   = std::min(corners.size() - cornerNdx, size_t(HIT_GEOMETRY_COUNT));
664         uint32_t geometryIndex = 0;
665         for (size_t idx = cornerNdx; idx < cornerNdx + geometryCount; ++idx, ++geometryIndex)
666         {
667             corners[idx].z() = instanceOffset;
668             corners[idx].w() = geometryIndex;
669         }
670     }
671 
672     std::vector<uint32_t> reference(testParams.width * testParams.height);
673     tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 1, reference.data());
674     // clear image with miss values
675     tcu::UVec4 missValue((testParams.shaderTestType == STT_MISS) ? testParams.sbtRecordOffset : 0, 0, 0, 0);
676     tcu::clear(referenceAccess, missValue);
677 
678     // for each pixel - set its color to proper value
679     for (const auto &pixel : corners)
680     {
681         uint32_t shaderIndex;
682         switch (testParams.shaderTestType)
683         {
684         case STT_HIT:
685         {
686             shaderIndex = testParams.sbtRecordOffset + pixel.z() + pixel.w() * testParams.sbtRecordStride;
687             break;
688         }
689         case STT_MISS:
690         {
691             shaderIndex = 0; // pixel.z();
692             break;
693         }
694         case STT_CALL:
695         {
696             shaderIndex = testParams.sbtRecordOffset + pixel.z() + pixel.w() * testParams.sbtRecordStride;
697             break;
698         }
699         default:
700             TCU_THROW(InternalError, "Wrong shader test type");
701         }
702 
703         referenceAccess.setPixel(tcu::UVec4(shaderIndex, 0, 0, 0), pixel.x(), pixel.y());
704     }
705 
706     // compare result and reference
707     return tcu::intThresholdCompare(context.getTestContext().getLog(), "Result comparison", "", referenceAccess,
708                                     resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
709 }
710 
getResultImageFormat()711 VkFormat CheckerboardConfiguration::getResultImageFormat()
712 {
713     return VK_FORMAT_R32_UINT;
714 }
715 
getResultImageFormatSize()716 size_t CheckerboardConfiguration::getResultImageFormatSize()
717 {
718     return sizeof(uint32_t);
719 }
720 
getClearValue()721 VkClearValue CheckerboardConfiguration::getClearValue()
722 {
723     return makeClearValueColorU32(0xFF, 0u, 0u, 0u);
724 }
725 
726 class ShaderBindingTableIndexingTestCase : public TestCase
727 {
728 public:
729     ShaderBindingTableIndexingTestCase(tcu::TestContext &context, const char *name, const TestParams data);
730     ~ShaderBindingTableIndexingTestCase(void);
731 
732     virtual void checkSupport(Context &context) const;
733     virtual void initPrograms(SourceCollections &programCollection) const;
734     virtual TestInstance *createInstance(Context &context) const;
735 
736 private:
737     TestParams m_data;
738 };
739 
740 class ShaderBindingTableIndexingTestInstance : public TestInstance
741 {
742 public:
743     ShaderBindingTableIndexingTestInstance(Context &context, const TestParams &data);
744     ~ShaderBindingTableIndexingTestInstance(void);
745     tcu::TestStatus iterate(void);
746 
747 protected:
748     de::MovePtr<BufferWithMemory> runTest();
749 
750 private:
751     TestParams m_data;
752 };
753 
ShaderBindingTableIndexingTestCase(tcu::TestContext & context,const char * name,const TestParams data)754 ShaderBindingTableIndexingTestCase::ShaderBindingTableIndexingTestCase(tcu::TestContext &context, const char *name,
755                                                                        const TestParams data)
756     : vkt::TestCase(context, name)
757     , m_data(data)
758 {
759 }
760 
~ShaderBindingTableIndexingTestCase(void)761 ShaderBindingTableIndexingTestCase::~ShaderBindingTableIndexingTestCase(void)
762 {
763 }
764 
checkSupport(Context & context) const765 void ShaderBindingTableIndexingTestCase::checkSupport(Context &context) const
766 {
767     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
768     context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
769 
770     const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
771         context.getRayTracingPipelineFeatures();
772     if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
773         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
774 
775     const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
776         context.getAccelerationStructureFeatures();
777     if (accelerationStructureFeaturesKHR.accelerationStructure == false)
778         TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
779                              "VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
780 }
781 
initPrograms(SourceCollections & programCollection) const782 void ShaderBindingTableIndexingTestCase::initPrograms(SourceCollections &programCollection) const
783 {
784     const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
785 
786     std::vector<uint32_t> shaderCount = getShaderCounts();
787 
788     {
789         std::stringstream css;
790         css << "#version 460 core\n"
791                "#extension GL_EXT_ray_tracing : require\n"
792                "layout(location = 0) rayPayloadEXT uvec4 hitValue;\n"
793                "layout(r32ui, set = 0, binding = 0) uniform uimage2D result;\n"
794                "layout(set = 0, binding = 1) uniform TraceRaysParamsUBO\n"
795                "{\n"
796                "    uvec4 trParams; // x = sbtRecordOffset, y = sbtRecordStride, z = missIndex\n"
797                "};\n"
798                "layout(set = 0, binding = 2) uniform accelerationStructureEXT topLevelAS;\n"
799                "\n"
800                "void main()\n"
801                "{\n"
802                "  float tmin     = 0.0;\n"
803                "  float tmax     = 1.0;\n"
804                "  vec3  origin   = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 0.5f);\n"
805                "  vec3  direct   = vec3(0.0, 0.0, -1.0);\n"
806                "  hitValue       = uvec4(0,0,0,0);\n"
807                "  traceRayEXT(topLevelAS, 0, 0xFF, trParams.x, trParams.y, trParams.z, origin, tmin, direct, tmax, "
808                "0);\n"
809                "  imageStore(result, ivec2(gl_LaunchIDEXT.xy), hitValue);\n"
810                "}\n";
811         programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
812     }
813 
814     for (uint32_t idx = 0; idx < shaderCount[STT_HIT]; ++idx)
815     {
816         std::stringstream css;
817         css << "#version 460 core\n"
818                "#extension GL_EXT_ray_tracing : require\n"
819                "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
820                "void main()\n"
821                "{\n"
822                "  hitValue = uvec4("
823             << idx
824             << ",0,0,1);\n"
825                "}\n";
826         std::stringstream csname;
827         csname << "chit_" << idx;
828 
829         programCollection.glslSources.add(csname.str())
830             << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
831     }
832 
833     {
834         std::stringstream css;
835         css << "#version 460 core\n"
836                "#extension GL_EXT_ray_tracing : require\n"
837                "layout(shaderRecordEXT) buffer block\n"
838                "{\n"
839                "  uvec4 info;\n"
840                "};\n"
841                "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
842                "void main()\n"
843                "{\n"
844                "  hitValue = info;\n"
845                "}\n";
846         programCollection.glslSources.add("chit_shaderRecord")
847             << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
848     }
849 
850     for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
851     {
852         std::stringstream css;
853         css << "#version 460 core\n"
854                "#extension GL_EXT_ray_tracing : require\n"
855                "layout(location = 0) callableDataEXT uvec4 value;\n"
856                "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
857                "void main()\n"
858                "{\n"
859                "  executeCallableEXT("
860             << idx
861             << ", 0);\n"
862                "  hitValue = value;\n"
863                "}\n";
864         std::stringstream csname;
865         csname << "chit_call_" << idx;
866 
867         programCollection.glslSources.add(csname.str())
868             << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
869     }
870 
871     for (uint32_t idx = 0; idx < shaderCount[STT_MISS]; ++idx)
872     {
873         std::stringstream css;
874         css << "#version 460 core\n"
875                "#extension GL_EXT_ray_tracing : require\n"
876                "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
877                "void main()\n"
878                "{\n"
879                "  hitValue = uvec4("
880             << idx
881             << ",0,0,1);\n"
882                "}\n";
883         std::stringstream csname;
884         csname << "miss_" << idx;
885 
886         programCollection.glslSources.add(csname.str())
887             << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
888     }
889 
890     {
891         std::stringstream css;
892         css << "#version 460 core\n"
893                "#extension GL_EXT_ray_tracing : require\n"
894                "layout(shaderRecordEXT) buffer block\n"
895                "{\n"
896                "  uvec4 info;\n"
897                "};\n"
898                "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
899                "void main()\n"
900                "{\n"
901                "  hitValue = info;\n"
902                "}\n";
903 
904         programCollection.glslSources.add("miss_shaderRecord")
905             << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
906     }
907 
908     for (uint32_t idx = 0; idx < shaderCount[STT_CALL]; ++idx)
909     {
910         std::stringstream css;
911         css << "#version 460 core\n"
912                "#extension GL_EXT_ray_tracing : require\n"
913                "layout(location = 0) callableDataInEXT uvec4 result;\n"
914                "void main()\n"
915                "{\n"
916                "  result = uvec4("
917             << idx
918             << ",0,0,1);\n"
919                "}\n";
920         std::stringstream csname;
921         csname << "call_" << idx;
922 
923         programCollection.glslSources.add(csname.str())
924             << glu::CallableSource(updateRayTracingGLSL(css.str())) << buildOptions;
925     }
926 
927     {
928         std::stringstream css;
929         css << "#version 460 core\n"
930                "#extension GL_EXT_ray_tracing : require\n"
931                "layout(shaderRecordEXT) buffer block\n"
932                "{\n"
933                "  uvec4 info;\n"
934                "};\n"
935                "layout(location = 0) callableDataInEXT uvec4 result;\n"
936                "void main()\n"
937                "{\n"
938                "  result = info;\n"
939                "}\n";
940 
941         programCollection.glslSources.add("call_shaderRecord")
942             << glu::CallableSource(updateRayTracingGLSL(css.str())) << buildOptions;
943     }
944 }
945 
createInstance(Context & context) const946 TestInstance *ShaderBindingTableIndexingTestCase::createInstance(Context &context) const
947 {
948     return new ShaderBindingTableIndexingTestInstance(context, m_data);
949 }
950 
ShaderBindingTableIndexingTestInstance(Context & context,const TestParams & data)951 ShaderBindingTableIndexingTestInstance::ShaderBindingTableIndexingTestInstance(Context &context, const TestParams &data)
952     : vkt::TestInstance(context)
953     , m_data(data)
954 {
955 }
956 
~ShaderBindingTableIndexingTestInstance(void)957 ShaderBindingTableIndexingTestInstance::~ShaderBindingTableIndexingTestInstance(void)
958 {
959 }
960 
runTest()961 de::MovePtr<BufferWithMemory> ShaderBindingTableIndexingTestInstance::runTest()
962 {
963     const InstanceInterface &vki          = m_context.getInstanceInterface();
964     const DeviceInterface &vkd            = m_context.getDeviceInterface();
965     const VkDevice device                 = m_context.getDevice();
966     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
967     const uint32_t queueFamilyIndex       = m_context.getUniversalQueueFamilyIndex();
968     const VkQueue queue                   = m_context.getUniversalQueue();
969     Allocator &allocator                  = m_context.getDefaultAllocator();
970     const uint32_t pixelCount             = m_data.width * m_data.height * 1;
971 
972     const Move<VkDescriptorSetLayout> descriptorSetLayout =
973         DescriptorSetLayoutBuilder()
974             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
975             .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, ALL_RAY_TRACING_STAGES)
976             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
977             .build(vkd, device);
978     const Move<VkDescriptorPool> descriptorPool =
979         DescriptorPoolBuilder()
980             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
981             .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
982             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
983             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
984     const Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
985     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
986 
987     de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
988     m_data.testConfiguration->initRayTracingShaders(rayTracingPipeline, m_context, m_data);
989     Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, *pipelineLayout);
990 
991     de::MovePtr<BufferWithMemory> raygenShaderBindingTable;
992     de::MovePtr<BufferWithMemory> hitShaderBindingTable;
993     de::MovePtr<BufferWithMemory> missShaderBindingTable;
994     de::MovePtr<BufferWithMemory> callableShaderBindingTable;
995     VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion;
996     VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion;
997     VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion;
998     VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion;
999     m_data.testConfiguration->initShaderBindingTables(
1000         rayTracingPipeline, m_context, m_data, *pipeline, getShaderGroupHandleSize(vki, physicalDevice),
1001         getShaderGroupBaseAlignment(vki, physicalDevice), raygenShaderBindingTable, hitShaderBindingTable,
1002         missShaderBindingTable, callableShaderBindingTable, raygenShaderBindingTableRegion, hitShaderBindingTableRegion,
1003         missShaderBindingTableRegion, callableShaderBindingTableRegion);
1004 
1005     const VkFormat imageFormat              = m_data.testConfiguration->getResultImageFormat();
1006     const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, imageFormat);
1007     const VkImageSubresourceRange imageSubresourceRange =
1008         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1009     const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(
1010         new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
1011     const Move<VkImageView> imageView =
1012         makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, imageFormat, imageSubresourceRange);
1013 
1014     const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(
1015         pixelCount * m_data.testConfiguration->getResultImageFormatSize(), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1016     const VkImageSubresourceLayers resultBufferImageSubresourceLayers =
1017         makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
1018     const VkBufferImageCopy resultBufferImageRegion =
1019         makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, 1), resultBufferImageSubresourceLayers);
1020     de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(
1021         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
1022 
1023     const VkDescriptorImageInfo descriptorImageInfo =
1024         makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
1025 
1026     const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
1027     const Move<VkCommandBuffer> cmdBuffer =
1028         allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1029 
1030     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructures;
1031     de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
1032     de::MovePtr<BufferWithMemory> uniformBuffer;
1033 
1034     beginCommandBuffer(vkd, *cmdBuffer, 0u);
1035     {
1036         const VkImageMemoryBarrier preImageBarrier =
1037             makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1038                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **image, imageSubresourceRange);
1039         cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1040                                       VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
1041 
1042         const VkClearValue clearValue = m_data.testConfiguration->getClearValue();
1043         vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1,
1044                                &imageSubresourceRange);
1045 
1046         const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(
1047             VK_ACCESS_TRANSFER_WRITE_BIT,
1048             VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
1049             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, **image, imageSubresourceRange);
1050         cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
1051                                       VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
1052 
1053         bottomLevelAccelerationStructures =
1054             m_data.testConfiguration->initBottomAccelerationStructures(m_context, m_data);
1055         for (auto &blas : bottomLevelAccelerationStructures)
1056             blas->createAndBuild(vkd, device, *cmdBuffer, allocator);
1057         topLevelAccelerationStructure = m_data.testConfiguration->initTopAccelerationStructure(
1058             m_context, m_data, bottomLevelAccelerationStructures);
1059         topLevelAccelerationStructure->createAndBuild(vkd, device, *cmdBuffer, allocator);
1060 
1061         uniformBuffer = m_data.testConfiguration->initUniformBuffer(m_context, m_data);
1062         VkDescriptorBufferInfo uniformBufferInfo =
1063             makeDescriptorBufferInfo(uniformBuffer->get(), 0ull, sizeof(tcu::UVec4));
1064 
1065         const TopLevelAccelerationStructure *topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
1066         VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
1067             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, //  VkStructureType sType;
1068             DE_NULL,                                                           //  const void* pNext;
1069             1u,                                                                //  uint32_t accelerationStructureCount;
1070             topLevelAccelerationStructurePtr->getPtr(), //  const VkAccelerationStructureKHR* pAccelerationStructures;
1071         };
1072 
1073         DescriptorSetUpdateBuilder()
1074             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1075                          VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1076             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
1077                          VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufferInfo)
1078             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u),
1079                          VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
1080             .update(vkd, device);
1081 
1082         vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
1083                                   &descriptorSet.get(), 0, DE_NULL);
1084 
1085         vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
1086 
1087         cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
1088                      &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, m_data.width, m_data.height, 1);
1089 
1090         const VkMemoryBarrier postTraceMemoryBarrier =
1091             makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
1092         const VkMemoryBarrier postCopyMemoryBarrier =
1093             makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1094         cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
1095                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
1096 
1097         vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u,
1098                                  &resultBufferImageRegion);
1099 
1100         cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
1101                                  &postCopyMemoryBarrier);
1102     }
1103     endCommandBuffer(vkd, *cmdBuffer);
1104 
1105     submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
1106 
1107     invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(),
1108                                 resultBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE);
1109 
1110     return resultBuffer;
1111 }
1112 
iterate(void)1113 tcu::TestStatus ShaderBindingTableIndexingTestInstance::iterate(void)
1114 {
1115     // run test using arrays of pointers
1116     const de::MovePtr<BufferWithMemory> buffer = runTest();
1117 
1118     if (!m_data.testConfiguration->verifyImage(buffer.get(), m_context, m_data))
1119         return tcu::TestStatus::fail("Fail");
1120     return tcu::TestStatus::pass("Pass");
1121 }
1122 
1123 /*
1124 
1125 Test the advertised shader group handle alignment requirements work as expected. The tests will prepare shader binding tables using
1126 shader record buffers for padding and achieving the desired alignments.
1127 
1128 +-------------------------------------------
1129 | Shader | Shader    | Aligned |
1130 | Group  | Record    | Shader  | ...
1131 | Handle | Buffer    | Group   |
1132 |        | (padding) | Handle  |
1133 +-------------------------------------------
1134 
1135 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
1136 of align=1, and 2 in the case of align=32. This allows us to test all possible alignment values.
1137 
1138 Geometries are triangles put alongside the X axis. The base triangle is:
1139 
1140 0,1|      x
1141    |     x x
1142    |    x  0.5,0.5
1143    |   x  x  x
1144    |  x       x
1145    | xxxxxxxxxxx
1146    +-------------
1147  0,0             1,0
1148 
1149 A triangle surrounding point (0.5, 0.5), in the [0, 1] range of both the X and Y axis.
1150 
1151 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]
1152 range. The Y axis doesn't change, triangles are always in the [0,1] range.
1153 
1154 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.
1155 
1156 For each geometry, the shader record buffer contents vary depending on the geometry index and the desired alignment (padding).
1157 
1158 Alignment    Element Type    Element Count            Data
1159 1            uint8_t            1                        0x80 | geometryID
1160 2            uint16_t        1                        0xABC0 | geometryID
1161 4+            uint32_t        alignment/4                For each element: 0xABCDE0F0 | (element << 8) | geometryID
1162 
1163 The test will try to verify everything works properly and all shader record buffers can be read with the right values.
1164 
1165  */
1166 struct ShaderGroupHandleAlignmentParams
1167 {
1168     const uint32_t alignment;
1169 
ShaderGroupHandleAlignmentParamsvkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1170     ShaderGroupHandleAlignmentParams(uint32_t alignment_) : alignment(alignment_)
1171     {
1172         DE_ASSERT(alignment >= 1u && alignment <= 32u);
1173         DE_ASSERT(deIsPowerOfTwo32(static_cast<int>(alignment)));
1174     }
1175 
geometryCountvkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1176     uint32_t geometryCount() const
1177     {
1178         return (32u / alignment + 1u);
1179     }
1180 
shaderRecordElementCountvkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1181     uint32_t shaderRecordElementCount() const
1182     {
1183         return ((alignment <= 4u) ? 1u : (alignment / 4u));
1184     }
1185 
glslElementTypevkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1186     std::string glslElementType() const
1187     {
1188         if (alignment == 1u)
1189             return "uint8_t";
1190         if (alignment == 2u)
1191             return "uint16_t";
1192         return "uint32_t";
1193     }
1194 
glslExtensionvkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1195     std::string glslExtension() const
1196     {
1197         if (alignment == 1u)
1198             return "GL_EXT_shader_explicit_arithmetic_types_int8";
1199         if (alignment == 2u)
1200             return "GL_EXT_shader_explicit_arithmetic_types_int16";
1201         return "GL_EXT_shader_explicit_arithmetic_types_int32";
1202     }
1203 
getRecordDatavkt::RayTracing::__anon5f05db0d0111::ShaderGroupHandleAlignmentParams1204     std::vector<uint8_t> getRecordData(uint32_t geometryID) const
1205     {
1206         std::vector<uint8_t> recordData;
1207         switch (alignment)
1208         {
1209         case 1u:
1210             recordData.push_back(static_cast<uint8_t>(0x80u | geometryID));
1211             break;
1212         case 2u:
1213             recordData.push_back(uint8_t{0xABu});
1214             recordData.push_back(static_cast<uint8_t>(0xC0u | geometryID));
1215             break;
1216         default:
1217         {
1218             const auto elemCount = shaderRecordElementCount();
1219             for (uint32_t i = 0u; i < elemCount; ++i)
1220             {
1221                 recordData.push_back(uint8_t{0xABu});
1222                 recordData.push_back(uint8_t{0xCDu});
1223                 recordData.push_back(static_cast<uint8_t>(0xE0u | i));
1224                 recordData.push_back(static_cast<uint8_t>(0xF0u | geometryID));
1225             }
1226         }
1227         break;
1228         }
1229         return recordData;
1230     }
1231 };
1232 
1233 class ShaderGroupHandleAlignmentCase : public TestCase
1234 {
1235 public:
ShaderGroupHandleAlignmentCase(tcu::TestContext & testCtx,const std::string & name,const ShaderGroupHandleAlignmentParams & params)1236     ShaderGroupHandleAlignmentCase(tcu::TestContext &testCtx, const std::string &name,
1237                                    const ShaderGroupHandleAlignmentParams &params)
1238         : TestCase(testCtx, name)
1239         , m_params(params)
1240     {
1241     }
~ShaderGroupHandleAlignmentCase(void)1242     virtual ~ShaderGroupHandleAlignmentCase(void)
1243     {
1244     }
1245 
1246     void checkSupport(Context &context) const override;
1247     void initPrograms(vk::SourceCollections &programCollection) const override;
1248     TestInstance *createInstance(Context &context) const override;
1249 
1250 protected:
1251     ShaderGroupHandleAlignmentParams m_params;
1252 };
1253 
1254 class ShaderGroupHandleAlignmentInstance : public TestInstance
1255 {
1256 public:
ShaderGroupHandleAlignmentInstance(Context & context,const ShaderGroupHandleAlignmentParams & params)1257     ShaderGroupHandleAlignmentInstance(Context &context, const ShaderGroupHandleAlignmentParams &params)
1258         : TestInstance(context)
1259         , m_params(params)
1260     {
1261     }
~ShaderGroupHandleAlignmentInstance(void)1262     virtual ~ShaderGroupHandleAlignmentInstance(void)
1263     {
1264     }
1265 
1266     tcu::TestStatus iterate(void) override;
1267 
1268 protected:
1269     ShaderGroupHandleAlignmentParams m_params;
1270 };
1271 
checkSupport(Context & context) const1272 void ShaderGroupHandleAlignmentCase::checkSupport(Context &context) const
1273 {
1274     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
1275     context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
1276 
1277     const auto &vki           = context.getInstanceInterface();
1278     const auto physicalDevice = context.getPhysicalDevice();
1279     const auto rtProperties   = makeRayTracingProperties(vki, physicalDevice);
1280 
1281     if (m_params.alignment < rtProperties->getShaderGroupHandleAlignment())
1282         TCU_THROW(NotSupportedError, "Required shader group handle alignment not supported");
1283 
1284     switch (m_params.alignment)
1285     {
1286     case 1u:
1287     {
1288         const auto &int8Features = context.getShaderFloat16Int8Features();
1289         if (!int8Features.shaderInt8)
1290             TCU_THROW(NotSupportedError, "shaderInt8 not supported");
1291 
1292         const auto &int8StorageFeatures = context.get8BitStorageFeatures();
1293         if (!int8StorageFeatures.storageBuffer8BitAccess)
1294             TCU_THROW(NotSupportedError, "storageBuffer8BitAccess not supported");
1295     }
1296     break;
1297 
1298     case 2u:
1299     {
1300         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT16);
1301 
1302         const auto &int16StorageFeatures = context.get16BitStorageFeatures();
1303         if (!int16StorageFeatures.storageBuffer16BitAccess)
1304             TCU_THROW(NotSupportedError, "storageBuffer16BitAccess not supported");
1305     }
1306     break;
1307 
1308     default:
1309         break;
1310     }
1311 }
1312 
initPrograms(vk::SourceCollections & programCollection) const1313 void ShaderGroupHandleAlignmentCase::initPrograms(vk::SourceCollections &programCollection) const
1314 {
1315     const ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
1316 
1317     const auto elemType      = m_params.glslElementType();
1318     const auto geometryCount = m_params.geometryCount();
1319     const auto elementCount  = m_params.shaderRecordElementCount();
1320     const auto extension     = m_params.glslExtension();
1321 
1322     std::ostringstream descriptors;
1323     descriptors << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
1324                 << "layout(set=0, binding=1, std430) buffer SSBOBlock {\n"
1325                 << "  " << elemType << " data[" << geometryCount << "][" << elementCount << "];\n"
1326                 << "} ssbo;\n";
1327     const auto descriptorsStr = descriptors.str();
1328 
1329     std::ostringstream commonHeader;
1330     commonHeader << "#version 460 core\n"
1331                  << "#extension GL_EXT_ray_tracing : require\n"
1332                  << "#extension " << extension << " : require\n";
1333     const auto commontHeaderStr = commonHeader.str();
1334 
1335     std::ostringstream rgen;
1336     rgen << commontHeaderStr << "\n"
1337          << descriptorsStr << "layout(location=0) rayPayloadEXT vec4 unused;\n"
1338          << "\n"
1339          << "void main()\n"
1340          << "{\n"
1341          << "  const uint  rayFlags  = 0;\n"
1342          << "  const uint  cullMask  = 0xFF;\n"
1343          << "  const float tMin      = 0.0;\n"
1344          << "  const float tMax      = 10.0;\n"
1345          << "  const vec3  origin    = vec3(float(gl_LaunchIDEXT.x) + 0.5, 0.5, 0.0);\n"
1346          << "  const vec3  direction = vec3(0.0, 0.0, 1.0);\n"
1347          << "  const uint  sbtOffset = 0;\n"
1348          << "  const uint  sbtStride = 1;\n"
1349          << "  const uint  missIndex = 0;\n"
1350          << "  traceRayEXT(topLevelAS, rayFlags, cullMask, sbtOffset, sbtStride, missIndex, origin, tMin, direction, "
1351             "tMax, 0);\n"
1352          << "}\n";
1353 
1354     std::ostringstream chit;
1355     chit << commontHeaderStr << "\n"
1356          << descriptorsStr << "layout(location=0) rayPayloadInEXT vec4 unused;\n"
1357          << "layout(shaderRecordEXT, std430) buffer srbBlock {\n"
1358          << "  " << elemType << " data[" << elementCount << "];\n"
1359          << "} srb;\n"
1360          << "\n"
1361          << "void main()\n"
1362          << "{\n"
1363          << "  for (uint i = 0; i < " << elementCount << "; ++i) {\n"
1364          << "    ssbo.data[gl_LaunchIDEXT.x][i] = srb.data[i];\n"
1365          << "  }\n"
1366          << "}\n";
1367 
1368     std::ostringstream miss;
1369     miss << commontHeaderStr << "\n"
1370          << descriptorsStr << "layout(location=0) rayPayloadInEXT vec4 unused;\n"
1371          << "\n"
1372          << "void main()\n"
1373          << "{\n"
1374          << "}\n";
1375 
1376     programCollection.glslSources.add("rgen") << glu::RaygenSource(rgen.str()) << buildOptions;
1377     programCollection.glslSources.add("chit") << glu::ClosestHitSource(chit.str()) << buildOptions;
1378     programCollection.glslSources.add("miss") << glu::MissSource(miss.str()) << buildOptions;
1379 }
1380 
createInstance(Context & context) const1381 TestInstance *ShaderGroupHandleAlignmentCase::createInstance(Context &context) const
1382 {
1383     return new ShaderGroupHandleAlignmentInstance(context, m_params);
1384 }
1385 
iterate(void)1386 tcu::TestStatus ShaderGroupHandleAlignmentInstance::iterate(void)
1387 {
1388     const auto &vki    = m_context.getInstanceInterface();
1389     const auto physDev = m_context.getPhysicalDevice();
1390     const auto &vkd    = m_context.getDeviceInterface();
1391     const auto device  = m_context.getDevice();
1392     auto &alloc        = m_context.getDefaultAllocator();
1393     const auto qIndex  = m_context.getUniversalQueueFamilyIndex();
1394     const auto queue   = m_context.getUniversalQueue();
1395     const auto stages =
1396         (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR);
1397     const auto geoCount  = m_params.geometryCount();
1398     const auto triangleZ = 5.0f;
1399 
1400     // Command pool and buffer.
1401     const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
1402     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1403     const auto cmdBuffer    = cmdBufferPtr.get();
1404 
1405     beginCommandBuffer(vkd, cmdBuffer);
1406 
1407     // Build acceleration structures.
1408     auto topLevelAS    = makeTopLevelAccelerationStructure();
1409     auto bottomLevelAS = makeBottomLevelAccelerationStructure();
1410 
1411     // Create the needed amount of geometries (triangles) with the right coordinates.
1412     const tcu::Vec3 baseLocation(0.5f, 0.5f, triangleZ);
1413     const float vertexOffset = 0.25f; // From base location, to build a triangle around it.
1414 
1415     for (uint32_t i = 0; i < geoCount; ++i)
1416     {
1417         // Triangle "center" or base location.
1418         const tcu::Vec3 triangleLocation(baseLocation.x() + static_cast<float>(i), baseLocation.y(), baseLocation.z());
1419 
1420         // Actual triangle.
1421         const std::vector<tcu::Vec3> triangle{
1422             tcu::Vec3(triangleLocation.x() - vertexOffset, triangleLocation.y() - vertexOffset, triangleLocation.z()),
1423             tcu::Vec3(triangleLocation.x() + vertexOffset, triangleLocation.y() - vertexOffset, triangleLocation.z()),
1424             tcu::Vec3(triangleLocation.x(), triangleLocation.y() + vertexOffset, triangleLocation.z()),
1425         };
1426 
1427         bottomLevelAS->addGeometry(triangle, true /*triangles*/);
1428     }
1429 
1430     bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
1431 
1432     de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr(bottomLevelAS.release());
1433     topLevelAS->setInstanceCount(1);
1434     topLevelAS->addInstance(blasSharedPtr, identityMatrix3x4, 0u, 0xFF, 0u,
1435                             VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
1436     topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
1437 
1438     // Get some ray tracing properties.
1439     uint32_t shaderGroupHandleSize    = 0u;
1440     uint32_t shaderGroupBaseAlignment = 1u;
1441     {
1442         const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physDev);
1443         shaderGroupHandleSize              = rayTracingPropertiesKHR->getShaderGroupHandleSize();
1444         shaderGroupBaseAlignment           = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
1445     }
1446 
1447     // SSBO to copy results over from the shaders.
1448     const auto shaderRecordSize = m_params.alignment;
1449     const auto hitSBTStride     = shaderGroupHandleSize + shaderRecordSize;
1450     const auto ssboSize         = static_cast<VkDeviceSize>(geoCount * hitSBTStride);
1451     const auto ssboInfo         = makeBufferCreateInfo(ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1452     BufferWithMemory ssbo(vkd, device, alloc, ssboInfo, MemoryRequirement::HostVisible);
1453     auto &ssboAlloc = ssbo.getAllocation();
1454     void *ssboData  = ssboAlloc.getHostPtr();
1455 
1456     deMemset(ssboData, 0, static_cast<size_t>(ssboSize));
1457 
1458     // Descriptor set layout and pipeline layout.
1459     DescriptorSetLayoutBuilder setLayoutBuilder;
1460     setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
1461     setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
1462     const auto setLayout      = setLayoutBuilder.build(vkd, device);
1463     const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
1464 
1465     // Descriptor pool and set.
1466     DescriptorPoolBuilder poolBuilder;
1467     poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
1468     poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
1469     const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1470     const auto descriptorSet  = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
1471 
1472     // Update descriptor set.
1473     {
1474         const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo = {
1475             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
1476             nullptr,
1477             1u,
1478             topLevelAS.get()->getPtr(),
1479         };
1480 
1481         const auto ssboDescInfo = makeDescriptorBufferInfo(ssbo.get(), 0ull, ssboSize);
1482 
1483         DescriptorSetUpdateBuilder updateBuilder;
1484         updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u),
1485                                   VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
1486         updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u),
1487                                   VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboDescInfo);
1488         updateBuilder.update(vkd, device);
1489     }
1490 
1491     // Shader modules.
1492     auto rgenModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0));
1493     auto missModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("miss"), 0));
1494     auto chitModule = makeVkSharedPtr(createShaderModule(vkd, device, m_context.getBinaryCollection().get("chit"), 0));
1495 
1496     // Create raytracing pipeline and shader binding tables.
1497     Move<VkPipeline> pipeline;
1498 
1499     de::MovePtr<BufferWithMemory> raygenSBT;
1500     de::MovePtr<BufferWithMemory> missSBT;
1501     de::MovePtr<BufferWithMemory> hitSBT;
1502     de::MovePtr<BufferWithMemory> callableSBT;
1503 
1504     VkStridedDeviceAddressRegionKHR raygenSBTRegion   = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1505     VkStridedDeviceAddressRegionKHR missSBTRegion     = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1506     VkStridedDeviceAddressRegionKHR hitSBTRegion      = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1507     VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1508 
1509     // Create shader record buffer data.
1510     using DataVec = std::vector<uint8_t>;
1511 
1512     std::vector<DataVec> srbData;
1513     for (uint32_t i = 0; i < geoCount; ++i)
1514     {
1515         srbData.emplace_back(m_params.getRecordData(i));
1516     }
1517 
1518     std::vector<const void *> srbDataPtrs;
1519     srbDataPtrs.reserve(srbData.size());
1520     std::transform(begin(srbData), end(srbData), std::back_inserter(srbDataPtrs),
1521                    [](const DataVec &data) { return data.data(); });
1522 
1523     // Generate ids for the closest hit and miss shaders according to the test parameters.
1524     {
1525         const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1526 
1527         rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, 0u);
1528         rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule, 1u);
1529 
1530         for (uint32_t i = 0; i < geoCount; ++i)
1531             rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule, 2u + i);
1532 
1533         pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
1534 
1535         raygenSBT = rayTracingPipeline->createShaderBindingTable(
1536             vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0u, 1u);
1537         raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0),
1538                                                             shaderGroupHandleSize, shaderGroupHandleSize);
1539 
1540         missSBT       = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc,
1541                                                                      shaderGroupHandleSize, shaderGroupBaseAlignment, 1u, 1u);
1542         missSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0),
1543                                                           shaderGroupHandleSize, shaderGroupHandleSize);
1544 
1545         hitSBT = rayTracingPipeline->createShaderBindingTable(
1546             vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 2u, geoCount, 0u, 0u,
1547             MemoryRequirement::Any, 0u, 0u, shaderRecordSize, srbDataPtrs.data(), false /*autoalign*/);
1548         hitSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0),
1549                                                          hitSBTStride, hitSBTStride * geoCount);
1550     }
1551 
1552     // Trace rays and verify ssbo contents.
1553     vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
1554     vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u,
1555                               &descriptorSet.get(), 0u, nullptr);
1556     vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, geoCount, 1u,
1557                         1u);
1558     const auto shaderToHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1559     cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT,
1560                              &shaderToHostBarrier);
1561 
1562     endCommandBuffer(vkd, cmdBuffer);
1563     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1564 
1565     invalidateAlloc(vkd, device, ssboAlloc);
1566 
1567     // Verify SSBO.
1568     const auto ssboDataAsBytes = reinterpret_cast<const uint8_t *>(ssboData);
1569     size_t ssboDataIdx         = 0u;
1570     bool fail                  = false;
1571     auto &log                  = m_context.getTestContext().getLog();
1572 
1573     for (const auto &dataVec : srbData)
1574         for (const uint8_t byte : dataVec)
1575         {
1576             const uint8_t outputByte = ssboDataAsBytes[ssboDataIdx++];
1577             if (byte != outputByte)
1578             {
1579                 std::ostringstream msg;
1580                 msg << std::hex << std::setfill('0') << "Unexpectd output data: "
1581                     << "0x" << std::setw(2) << static_cast<int>(outputByte) << " vs "
1582                     << "0x" << std::setw(2) << static_cast<int>(byte);
1583                 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1584                 fail = true;
1585             }
1586         }
1587 
1588     if (fail)
1589         return tcu::TestStatus::fail("Unexpected output data found; check log for details");
1590     return tcu::TestStatus::pass("Pass");
1591 }
1592 
1593 } // namespace
1594 
createShaderBindingTableTests(tcu::TestContext & testCtx)1595 tcu::TestCaseGroup *createShaderBindingTableTests(tcu::TestContext &testCtx)
1596 {
1597     // Tests veryfying shader binding tables
1598     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_binding_table"));
1599 
1600     struct ShaderTestTypeData
1601     {
1602         ShaderTestType shaderTestType;
1603         const char *name;
1604     } shaderTestTypes[] = {
1605         {STT_HIT, "indexing_hit"},
1606         {STT_MISS, "indexing_miss"},
1607         {STT_CALL, "indexing_call"},
1608     };
1609 
1610     struct ShaderBufferOffsetData
1611     {
1612         uint32_t sbtOffset;
1613         const char *name;
1614     } shaderBufferOffsets[] = {
1615         {0u, "sbt_offset_0"},
1616         {4u, "sbt_offset_4"},
1617         {7u, "sbt_offset_7"},
1618         {16u, "sbt_offset_16"},
1619     };
1620 
1621     struct ShaderRecordData
1622     {
1623         bool present;
1624         const char *name;
1625     } shaderRecords[] = {
1626         {false, "no_shaderrecord"},
1627         {true, "shaderrecord"},
1628     };
1629 
1630     for (size_t shaderTestNdx = 0; shaderTestNdx < DE_LENGTH_OF_ARRAY(shaderTestTypes); ++shaderTestNdx)
1631     {
1632         de::MovePtr<tcu::TestCaseGroup> shaderTestGroup(
1633             new tcu::TestCaseGroup(group->getTestContext(), shaderTestTypes[shaderTestNdx].name));
1634 
1635         for (size_t sbtOffsetNdx = 0; sbtOffsetNdx < DE_LENGTH_OF_ARRAY(shaderBufferOffsets); ++sbtOffsetNdx)
1636         {
1637             de::MovePtr<tcu::TestCaseGroup> sbtOffsetGroup(
1638                 new tcu::TestCaseGroup(group->getTestContext(), shaderBufferOffsets[sbtOffsetNdx].name));
1639 
1640             for (size_t shaderRecordNdx = 0; shaderRecordNdx < DE_LENGTH_OF_ARRAY(shaderRecords); ++shaderRecordNdx)
1641             {
1642                 de::MovePtr<tcu::TestCaseGroup> shaderRecordGroup(
1643                     new tcu::TestCaseGroup(group->getTestContext(), shaderRecords[shaderRecordNdx].name));
1644 
1645                 uint32_t maxSbtRecordStride =
1646                     (shaderTestTypes[shaderTestNdx].shaderTestType == STT_HIT) ? MAX_HIT_SBT_RECORD_STRIDE + 1 : 1;
1647                 uint32_t maxSbtRecordOffset = MAX_SBT_RECORD_OFFSET;
1648                 const uint32_t maxSbtRecordOffsetWithExtraBits =
1649                     (shaderTestTypes[shaderTestNdx].shaderTestType == STT_MISS) ?
1650                         MAX_SBT_RECORD_OFFSET |
1651                             (~((1u << 16) - 1)) //< Only 16 least significant bits matter for miss indices
1652                         :
1653                         MAX_SBT_RECORD_OFFSET |
1654                             (~((1u << 4) - 1)); //< Only 4 least significant bits matter for SBT record offsets
1655 
1656                 for (uint32_t sbtRecordOffset = 0; sbtRecordOffset <= maxSbtRecordOffset; ++sbtRecordOffset)
1657                     for (uint32_t sbtRecordStride = 0; sbtRecordStride <= maxSbtRecordStride; ++sbtRecordStride)
1658                     {
1659                         if ((shaderTestTypes[shaderTestNdx].shaderTestType != STT_HIT) &&
1660                             (sbtRecordStride == maxSbtRecordStride))
1661                         {
1662                             continue;
1663                         }
1664 
1665                         TestParams testParams{
1666                             CHECKERBOARD_WIDTH, CHECKERBOARD_HEIGHT, shaderTestTypes[shaderTestNdx].shaderTestType,
1667                             shaderBufferOffsets[sbtOffsetNdx].sbtOffset, shaderRecords[shaderRecordNdx].present,
1668                             sbtRecordOffset,
1669                             (sbtRecordOffset == maxSbtRecordOffset) ? maxSbtRecordOffsetWithExtraBits : sbtRecordOffset,
1670                             //< Only first 4 least significant bits matter for SBT record stride
1671                             sbtRecordStride,
1672                             (sbtRecordStride == maxSbtRecordStride) ? maxSbtRecordStride | (~((1u << 4) - 1)) :
1673                                                                       sbtRecordStride,
1674                             de::SharedPtr<TestConfiguration>(new CheckerboardConfiguration())};
1675 
1676                         std::stringstream str;
1677                         str << sbtRecordOffset << "_" << sbtRecordStride;
1678 
1679                         if (testParams.sbtRecordStride != testParams.sbtRecordStridePassedToTraceRay)
1680                         {
1681                             str << "_extraSBTRecordStrideBits";
1682                         }
1683 
1684                         if (testParams.sbtRecordOffset != testParams.sbtRecordOffsetPassedToTraceRay)
1685                         {
1686                             str << "_extrabits";
1687                         }
1688 
1689                         shaderRecordGroup->addChild(new ShaderBindingTableIndexingTestCase(
1690                             group->getTestContext(), str.str().c_str(), testParams));
1691                     }
1692 
1693                 sbtOffsetGroup->addChild(shaderRecordGroup.release());
1694             }
1695 
1696             shaderTestGroup->addChild(sbtOffsetGroup.release());
1697         }
1698 
1699         group->addChild(shaderTestGroup.release());
1700     }
1701 
1702     {
1703         const uint32_t kAlignments[] = {1u, 2u, 4u, 8u, 16u, 32u};
1704         // Test allowed handle alignments
1705         de::MovePtr<tcu::TestCaseGroup> handleAlignmentGroup(new tcu::TestCaseGroup(testCtx, "handle_alignment"));
1706 
1707         for (const auto alignment : kAlignments)
1708         {
1709             const auto alignStr = std::to_string(alignment);
1710             const auto testName = "alignment_" + alignStr;
1711             // Check aligning shader group handles
1712             handleAlignmentGroup->addChild(
1713                 new ShaderGroupHandleAlignmentCase(testCtx, testName, ShaderGroupHandleAlignmentParams{alignment}));
1714         }
1715 
1716         group->addChild(handleAlignmentGroup.release());
1717     }
1718 
1719     return group.release();
1720 }
1721 
1722 } // namespace RayTracing
1723 
1724 } // namespace vkt
1725