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 ¶ms)
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 ¶ms)
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