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 Pipeline Library Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRayTracingPipelineLibraryTests.hpp"
25
26 #include <list>
27 #include <vector>
28
29 #include "vkDefs.hpp"
30
31 #include "vktTestCase.hpp"
32 #include "vktTestGroupUtil.hpp"
33 #include "vktCustomInstancesDevices.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkObjUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38 #include "vkBufferWithMemory.hpp"
39 #include "vkImageWithMemory.hpp"
40 #include "vkTypeUtil.hpp"
41
42 #include "vkRayTracingUtil.hpp"
43
44 #include "tcuCommandLine.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
56 | VK_SHADER_STAGE_ANY_HIT_BIT_KHR
57 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
58 | VK_SHADER_STAGE_MISS_BIT_KHR
59 | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
60 | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
61
62 static const deUint32 RTPL_DEFAULT_SIZE = 8u;
63 static const deUint32 RTPL_MAX_CHIT_SHADER_COUNT = 16;
64
65 struct LibraryConfiguration
66 {
67 deInt32 pipelineShaders;
68 std::vector<tcu::IVec2> pipelineLibraries; // IVec2 = ( parentID, shaderCount )
69 };
70
71 struct TestParams
72 {
73 LibraryConfiguration libraryConfiguration;
74 bool multithreadedCompilation;
75 bool pipelinesCreatedUsingDHO;
76 deUint32 width;
77 deUint32 height;
78 };
79
getShaderGroupSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)80 deUint32 getShaderGroupSize (const InstanceInterface& vki,
81 const VkPhysicalDevice physicalDevice)
82 {
83 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
84
85 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
86 return rayTracingPropertiesKHR->getShaderGroupHandleSize();
87 }
88
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)89 deUint32 getShaderGroupBaseAlignment (const InstanceInterface& vki,
90 const VkPhysicalDevice physicalDevice)
91 {
92 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
93
94 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
95 return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
96 }
97
makeImageCreateInfo(deUint32 width,deUint32 height,VkFormat format)98 VkImageCreateInfo makeImageCreateInfo (deUint32 width, deUint32 height, VkFormat format)
99 {
100 const VkImageCreateInfo imageCreateInfo =
101 {
102 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
103 DE_NULL, // const void* pNext;
104 (VkImageCreateFlags)0u, // VkImageCreateFlags flags;
105 VK_IMAGE_TYPE_2D, // VkImageType imageType;
106 format, // VkFormat format;
107 makeExtent3D(width, height, 1), // VkExtent3D extent;
108 1u, // deUint32 mipLevels;
109 1u, // deUint32 arrayLayers;
110 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
111 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
112 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
113 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
114 0u, // deUint32 queueFamilyIndexCount;
115 DE_NULL, // const deUint32* pQueueFamilyIndices;
116 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
117 };
118
119 return imageCreateInfo;
120 }
121
122 class RayTracingPipelineLibraryTestCase : public TestCase
123 {
124 public:
125 RayTracingPipelineLibraryTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams data);
126 ~RayTracingPipelineLibraryTestCase (void);
127
128 virtual void checkSupport (Context& context) const;
129 virtual void initPrograms (SourceCollections& programCollection) const;
130 virtual TestInstance* createInstance (Context& context) const;
131 private:
132 TestParams m_data;
133 };
134
135 struct DeviceTestFeatures
136 {
137 VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures;
138 VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures;
139 VkPhysicalDeviceBufferDeviceAddressFeaturesKHR deviceAddressFeatures;
140 VkPhysicalDeviceFeatures2 deviceFeatures;
141
linkStructuresvkt::RayTracing::__anonc13c59a90111::DeviceTestFeatures142 void linkStructures ()
143 {
144 rayTracingPipelineFeatures.pNext = nullptr;
145 accelerationStructureFeatures.pNext = &rayTracingPipelineFeatures;
146 deviceAddressFeatures.pNext = &accelerationStructureFeatures;
147 deviceFeatures.pNext = &deviceAddressFeatures;
148 }
149
DeviceTestFeaturesvkt::RayTracing::__anonc13c59a90111::DeviceTestFeatures150 DeviceTestFeatures (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
151 {
152 rayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
153 accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
154 deviceAddressFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
155 deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
156
157 linkStructures();
158 vki.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures);
159 }
160 };
161
162 struct DeviceHelper
163 {
164 Move<VkDevice> device;
165 de::MovePtr<DeviceDriver> vkd;
166 deUint32 queueFamilyIndex;
167 VkQueue queue;
168 de::MovePtr<SimpleAllocator> allocator;
169
DeviceHelpervkt::RayTracing::__anonc13c59a90111::DeviceHelper170 DeviceHelper (Context& context)
171 {
172 const auto& vkp = context.getPlatformInterface();
173 const auto& vki = context.getInstanceInterface();
174 const auto instance = context.getInstance();
175 const auto physicalDevice = context.getPhysicalDevice();
176 const auto queuePriority = 1.0f;
177
178 // Queue index first.
179 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
180
181 // Get device features (these have already been checked in the test case).
182 DeviceTestFeatures features(vki, physicalDevice);
183 features.linkStructures();
184
185 // Make sure robust buffer access is disabled as in the default device.
186 features.deviceFeatures.features.robustBufferAccess = VK_FALSE;
187
188 const VkDeviceQueueCreateInfo queueInfo =
189 {
190 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
191 nullptr, // const void* pNext;
192 0u, // VkDeviceQueueCreateFlags flags;
193 queueFamilyIndex, // deUint32 queueFamilyIndex;
194 1u, // deUint32 queueCount;
195 &queuePriority, // const float* pQueuePriorities;
196 };
197
198 // Required extensions.
199 std::vector<const char*> requiredExtensions;
200 requiredExtensions.push_back("VK_KHR_ray_tracing_pipeline");
201 requiredExtensions.push_back("VK_KHR_pipeline_library");
202 requiredExtensions.push_back("VK_KHR_acceleration_structure");
203 requiredExtensions.push_back("VK_KHR_deferred_host_operations");
204 requiredExtensions.push_back("VK_KHR_buffer_device_address");
205 requiredExtensions.push_back("VK_EXT_descriptor_indexing");
206 requiredExtensions.push_back("VK_KHR_spirv_1_4");
207 requiredExtensions.push_back("VK_KHR_shader_float_controls");
208
209 const VkDeviceCreateInfo createInfo =
210 {
211 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
212 features.deviceFeatures.pNext, // const void* pNext;
213 0u, // VkDeviceCreateFlags flags;
214 1u, // deUint32 queueCreateInfoCount;
215 &queueInfo, // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
216 0u, // deUint32 enabledLayerCount;
217 nullptr, // const char* const* ppEnabledLayerNames;
218 static_cast<deUint32>(requiredExtensions.size()), // deUint32 enabledExtensionCount;
219 requiredExtensions.data(), // const char* const* ppEnabledExtensionNames;
220 &features.deviceFeatures.features, // const VkPhysicalDeviceFeatures* pEnabledFeatures;
221 };
222
223 // Create custom device and related objects.
224 device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &createInfo);
225 vkd = de::MovePtr<DeviceDriver>(new DeviceDriver(vkp, instance, device.get()));
226 queue = getDeviceQueue(*vkd, *device, queueFamilyIndex, 0u);
227 allocator = de::MovePtr<SimpleAllocator>(new SimpleAllocator(*vkd, device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
228 }
229 };
230
231 class RayTracingPipelineLibraryTestInstance : public TestInstance
232 {
233 public:
234 RayTracingPipelineLibraryTestInstance (Context& context, const TestParams& data);
235 ~RayTracingPipelineLibraryTestInstance (void);
236 tcu::TestStatus iterate (void);
237
238 protected:
239 std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures (DeviceHelper& deviceHelper, VkCommandBuffer cmdBuffer);
240 de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure (DeviceHelper& deviceHelper, VkCommandBuffer cmdBuffer,
241 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures);
242 de::MovePtr<BufferWithMemory> runTest (DeviceHelper& deviceHelper);
243 private:
244 TestParams m_data;
245 };
246
247
RayTracingPipelineLibraryTestCase(tcu::TestContext & context,const char * name,const char * desc,const TestParams data)248 RayTracingPipelineLibraryTestCase::RayTracingPipelineLibraryTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams data)
249 : vkt::TestCase (context, name, desc)
250 , m_data (data)
251 {
252 }
253
~RayTracingPipelineLibraryTestCase(void)254 RayTracingPipelineLibraryTestCase::~RayTracingPipelineLibraryTestCase (void)
255 {
256 }
257
checkSupport(Context & context) const258 void RayTracingPipelineLibraryTestCase::checkSupport(Context& context) const
259 {
260 const auto& vki = context.getInstanceInterface();
261 const auto physicalDevice = context.getPhysicalDevice();
262 const auto supportedExtensions = enumerateDeviceExtensionProperties(vki, physicalDevice, nullptr);
263
264 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_ray_tracing_pipeline")))
265 TCU_THROW(NotSupportedError, "VK_KHR_ray_tracing_pipeline not supported");
266
267 // VK_KHR_pipeline_library must be supported if the ray tracing pipeline extension is supported, which it should be at this point.
268 // If it's not supported, this is considered a failure.
269 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_pipeline_library")))
270 TCU_FAIL("VK_KHR_pipeline_library not supported but VK_KHR_ray_tracing_pipeline supported");
271
272 // VK_KHR_acceleration_structure is required by VK_KHR_ray_tracing_pipeline.
273 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_acceleration_structure")))
274 TCU_FAIL("VK_KHR_acceleration_structure not supported but VK_KHR_ray_tracing_pipeline supported");
275
276 // VK_KHR_deferred_host_operations is required by VK_KHR_acceleration_structure.
277 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_deferred_host_operations")))
278 TCU_FAIL("VK_KHR_deferred_host_operations not supported but VK_KHR_acceleration_structure supported");
279
280 // The same for VK_KHR_buffer_device_address.
281 if (!isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_buffer_device_address")))
282 TCU_FAIL("VK_KHR_buffer_device_address not supported but VK_KHR_acceleration_structure supported");
283
284 // Get and check needed features.
285 DeviceTestFeatures testFeatures (vki, physicalDevice);
286
287 if (!testFeatures.rayTracingPipelineFeatures.rayTracingPipeline)
288 TCU_THROW(NotSupportedError, "Ray tracing pipelines not supported");
289
290 if (!testFeatures.accelerationStructureFeatures.accelerationStructure)
291 TCU_THROW(NotSupportedError, "Acceleration structures not supported");
292
293 if (!testFeatures.deviceAddressFeatures.bufferDeviceAddress)
294 TCU_FAIL("Acceleration structures supported but bufferDeviceAddress not supported");
295 }
296
initPrograms(SourceCollections & programCollection) const297 void RayTracingPipelineLibraryTestCase::initPrograms (SourceCollections& programCollection) const
298 {
299 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
300
301 {
302 std::stringstream css;
303 css <<
304 "#version 460 core\n"
305 "#extension GL_EXT_ray_tracing : require\n"
306 "layout(location = 0) rayPayloadEXT uvec4 hitValue;\n"
307 "layout(r32ui, set = 0, binding = 0) uniform uimage2D result;\n"
308 "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
309 "\n"
310 "void main()\n"
311 "{\n"
312 " float tmin = 0.0;\n"
313 " float tmax = 1.0;\n"
314 " vec3 origin = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, float(gl_LaunchIDEXT.z + 0.5f));\n"
315 " vec3 direct = vec3(0.0, 0.0, -1.0);\n"
316 " hitValue = uvec4(" << RTPL_MAX_CHIT_SHADER_COUNT+1 << ",0,0,0);\n"
317 " traceRayEXT(topLevelAS, 0, 0xFF, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
318 " imageStore(result, ivec2(gl_LaunchIDEXT.xy), hitValue);\n"
319 "}\n";
320 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
321 }
322
323 {
324 std::stringstream css;
325 css <<
326 "#version 460 core\n"
327 "#extension GL_EXT_ray_tracing : require\n"
328 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
329 "void main()\n"
330 "{\n"
331 " hitValue = uvec4("<< RTPL_MAX_CHIT_SHADER_COUNT <<",0,0,1);\n"
332 "}\n";
333
334 programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
335 }
336
337 for(deUint32 i=0; i<RTPL_MAX_CHIT_SHADER_COUNT; ++i)
338 {
339 std::stringstream css;
340 css <<
341 "#version 460 core\n"
342 "#extension GL_EXT_ray_tracing : require\n"
343 "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
344 "void main()\n"
345 "{\n"
346 " hitValue = uvec4(" << i << ",0,0,1);\n"
347 "}\n";
348 std::stringstream csname;
349 csname << "chit" << i;
350 programCollection.glslSources.add(csname.str()) << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
351 }
352 }
353
createInstance(Context & context) const354 TestInstance* RayTracingPipelineLibraryTestCase::createInstance (Context& context) const
355 {
356 return new RayTracingPipelineLibraryTestInstance(context, m_data);
357 }
358
RayTracingPipelineLibraryTestInstance(Context & context,const TestParams & data)359 RayTracingPipelineLibraryTestInstance::RayTracingPipelineLibraryTestInstance (Context& context, const TestParams& data)
360 : vkt::TestInstance (context)
361 , m_data (data)
362 {
363 }
364
~RayTracingPipelineLibraryTestInstance(void)365 RayTracingPipelineLibraryTestInstance::~RayTracingPipelineLibraryTestInstance (void)
366 {
367 }
368
initBottomAccelerationStructures(DeviceHelper & deviceHelper,VkCommandBuffer cmdBuffer)369 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > RayTracingPipelineLibraryTestInstance::initBottomAccelerationStructures (DeviceHelper& deviceHelper, VkCommandBuffer cmdBuffer)
370 {
371 const auto& vkd = *deviceHelper.vkd;
372 const auto device = deviceHelper.device.get();
373 auto& allocator = *deviceHelper.allocator;
374 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > result;
375
376 tcu::Vec3 v0(0.0, 1.0, 0.0);
377 tcu::Vec3 v1(0.0, 0.0, 0.0);
378 tcu::Vec3 v2(1.0, 1.0, 0.0);
379 tcu::Vec3 v3(1.0, 0.0, 0.0);
380
381 for (deUint32 y = 0; y < m_data.height; ++y)
382 for (deUint32 x = 0; x < m_data.width; ++x)
383 {
384 // let's build a 3D chessboard of geometries
385 if (((x + y) % 2) == 0)
386 continue;
387 tcu::Vec3 xyz((float)x, (float)y, 0.0f);
388 std::vector<tcu::Vec3> geometryData;
389
390 de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
391 bottomLevelAccelerationStructure->setGeometryCount(1u);
392
393 geometryData.push_back(xyz + v0);
394 geometryData.push_back(xyz + v1);
395 geometryData.push_back(xyz + v2);
396 geometryData.push_back(xyz + v2);
397 geometryData.push_back(xyz + v1);
398 geometryData.push_back(xyz + v3);
399
400 bottomLevelAccelerationStructure->addGeometry(geometryData, true);
401 bottomLevelAccelerationStructure->createAndBuild(vkd, device, cmdBuffer, allocator);
402 result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
403 }
404
405 return result;
406 }
407
initTopAccelerationStructure(DeviceHelper & deviceHelper,VkCommandBuffer cmdBuffer,std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> & bottomLevelAccelerationStructures)408 de::MovePtr<TopLevelAccelerationStructure> RayTracingPipelineLibraryTestInstance::initTopAccelerationStructure (DeviceHelper& deviceHelper, VkCommandBuffer cmdBuffer,
409 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures)
410 {
411 const auto& vkd = *deviceHelper.vkd;
412 const auto device = deviceHelper.device.get();
413 auto& allocator = *deviceHelper.allocator;
414
415 deUint32 instanceCount = m_data.width * m_data.height / 2;
416
417 de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
418 result->setInstanceCount(instanceCount);
419
420 deUint32 currentInstanceIndex = 0;
421 deUint32 numShadersUsed = m_data.libraryConfiguration.pipelineShaders;
422 for (auto it = begin(m_data.libraryConfiguration.pipelineLibraries), eit = end(m_data.libraryConfiguration.pipelineLibraries); it != eit; ++it)
423 numShadersUsed += it->y();
424
425 for (deUint32 y = 0; y < m_data.height; ++y)
426 for (deUint32 x = 0; x < m_data.width; ++x)
427 {
428 if (((x + y) % 2) == 0)
429 continue;
430 const VkTransformMatrixKHR identityMatrix =
431 {
432 { // float matrix[3][4];
433 { 1.0f, 0.0f, 0.0f, 0.0f },
434 { 0.0f, 1.0f, 0.0f, 0.0f },
435 { 0.0f, 0.0f, 1.0f, 0.0f },
436 }
437 };
438
439 result->addInstance(bottomLevelAccelerationStructures[currentInstanceIndex], identityMatrix, 0, 0xFF, currentInstanceIndex % numShadersUsed, 0U);
440 currentInstanceIndex++;
441 }
442 result->createAndBuild(vkd, device, cmdBuffer, allocator);
443
444 return result;
445 }
446
compileShaders(DeviceHelper & deviceHelper,Context & context,de::SharedPtr<de::MovePtr<RayTracingPipeline>> & pipeline,const std::vector<std::tuple<std::string,VkShaderStageFlagBits>> & shaderData)447 void compileShaders (DeviceHelper& deviceHelper, Context& context, de::SharedPtr<de::MovePtr<RayTracingPipeline>>& pipeline, const std::vector<std::tuple<std::string, VkShaderStageFlagBits>>& shaderData)
448 {
449 const auto& vkd = *deviceHelper.vkd;
450 const auto device = deviceHelper.device.get();
451
452 for (deUint32 i=0; i< shaderData.size(); ++i)
453 {
454 std::string shaderName;
455 VkShaderStageFlagBits shaderStage;
456 std::tie(shaderName, shaderStage) = shaderData[i];
457 pipeline->get()->addShader(shaderStage, createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName), 0), i);
458 }
459 }
460
461 struct CompileShadersMultithreadData
462 {
463 DeviceHelper& deviceHelper;
464 Context& context;
465 de::SharedPtr<de::MovePtr<RayTracingPipeline>>& pipeline;
466 const std::vector<std::tuple<std::string, VkShaderStageFlagBits>>& shaderData;
467 };
468
compileShadersThread(void * param)469 void compileShadersThread (void* param)
470 {
471 CompileShadersMultithreadData* csmd = (CompileShadersMultithreadData*)param;
472 compileShaders(csmd->deviceHelper, csmd->context, csmd->pipeline, csmd->shaderData);
473 }
474
runTest(DeviceHelper & deviceHelper)475 de::MovePtr<BufferWithMemory> RayTracingPipelineLibraryTestInstance::runTest (DeviceHelper& deviceHelper)
476 {
477 const InstanceInterface& vki = m_context.getInstanceInterface();
478 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
479 const auto& vkd = *deviceHelper.vkd;
480 const auto device = deviceHelper.device.get();
481 const auto queueFamilyIndex = deviceHelper.queueFamilyIndex;
482 const auto queue = deviceHelper.queue;
483 auto& allocator = *deviceHelper.allocator;
484 const deUint32 pixelCount = m_data.height * m_data.width;
485 const deUint32 shaderGroupHandleSize = getShaderGroupSize(vki, physicalDevice);
486 const deUint32 shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
487
488 const Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder()
489 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
490 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
491 .build(vkd, device);
492 const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
493 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
494 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
495 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
496 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
497 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
498
499 // sort pipeline library configurations ( including main pipeline )
500 std::vector<std::tuple<int, deUint32, deUint32>> libraryList;
501 {
502 // push main pipeline on the list
503 deUint32 shaderOffset = 0U;
504 libraryList.push_back(std::make_tuple(-1, shaderOffset, m_data.libraryConfiguration.pipelineShaders));
505 shaderOffset += m_data.libraryConfiguration.pipelineShaders;
506
507 for (size_t i = 0; i < m_data.libraryConfiguration.pipelineLibraries.size(); ++i)
508 {
509 int parentIndex = m_data.libraryConfiguration.pipelineLibraries[i].x();
510 deUint32 shaderCount = deUint32(m_data.libraryConfiguration.pipelineLibraries[i].y());
511 if (parentIndex < 0 || parentIndex >= int(libraryList.size()) )
512 TCU_THROW(InternalError, "Wrong library tree definition");
513 libraryList.push_back(std::make_tuple(parentIndex, shaderOffset, shaderCount));
514 shaderOffset += shaderCount;
515 }
516 }
517
518 // create pipeline libraries
519 std::vector<de::SharedPtr<de::MovePtr<RayTracingPipeline>>> pipelineLibraries(libraryList.size());
520 std::vector<std::vector<std::tuple<std::string, VkShaderStageFlagBits>>> pipelineShaders(libraryList.size());
521 for (size_t idx=0; idx < libraryList.size(); ++idx)
522 {
523 int parentIndex;
524 deUint32 shaderCount, shaderOffset;
525 std::tie(parentIndex, shaderOffset, shaderCount) = libraryList[idx];
526
527 // create pipeline objects
528 de::SharedPtr<de::MovePtr<RayTracingPipeline>> pipeline = makeVkSharedPtr(de::MovePtr<RayTracingPipeline>(new RayTracingPipeline));
529
530 (*pipeline)->setDeferredOperation(m_data.pipelinesCreatedUsingDHO);
531
532 // all pipelines are pipeline libraries, except for the main pipeline
533 if(idx>0)
534 pipeline->get()->setCreateFlags(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR);
535 pipeline->get()->setMaxPayloadSize(16U); // because rayPayloadInEXT is uvec4 ( = 16 bytes ) for all chit shaders
536 pipelineLibraries[idx] = pipeline;
537
538 // prepare all shader names for all pipelines
539 if (idx == 0)
540 {
541 pipelineShaders[0].push_back(std::make_tuple( "rgen", VK_SHADER_STAGE_RAYGEN_BIT_KHR ));
542 pipelineShaders[0].push_back(std::make_tuple( "miss", VK_SHADER_STAGE_MISS_BIT_KHR ));
543 }
544 for ( deUint32 i=0; i < shaderCount; ++i)
545 {
546 std::stringstream csname;
547 csname << "chit" << shaderOffset + i;
548 pipelineShaders[idx].push_back(std::make_tuple( csname.str(), VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ));
549 }
550 }
551 // singlethreaded / multithreaded compilation of all shaders
552 if (m_data.multithreadedCompilation)
553 {
554 std::vector<CompileShadersMultithreadData> csmds;
555 for (deUint32 i = 0; i < pipelineLibraries.size(); ++i)
556 csmds.push_back(CompileShadersMultithreadData{ deviceHelper, m_context, pipelineLibraries[i], pipelineShaders[i] });
557
558 std::vector<deThread> threads;
559 for (deUint32 i = 0; i < csmds.size(); ++i)
560 threads.push_back(deThread_create(compileShadersThread, (void*)&csmds[i], DE_NULL));
561
562 for (deUint32 i = 0; i < threads.size(); ++i)
563 {
564 deThread_join(threads[i]);
565 deThread_destroy(threads[i]);
566 }
567 }
568 else // m_data.multithreadedCompilation == false
569 {
570 for (deUint32 i = 0; i < pipelineLibraries.size(); ++i)
571 compileShaders(deviceHelper, m_context, pipelineLibraries[i], pipelineShaders[i]);
572 }
573
574 // connect libraries into a tree structure
575 for (size_t idx = 0; idx < libraryList.size(); ++idx)
576 {
577 int parentIndex;
578 deUint32 shaderCount, shaderOffset;
579 std::tie(parentIndex, shaderCount, shaderOffset) = libraryList[idx];
580 if (parentIndex != -1)
581 pipelineLibraries[parentIndex]->get()->addLibrary(pipelineLibraries[idx]);
582 }
583
584 // build main pipeline and all pipeline libraries that it depends on
585 std::vector<de::SharedPtr<Move<VkPipeline>>> pipelines = pipelineLibraries[0]->get()->createPipelineWithLibraries(vkd, device, *pipelineLayout);
586 DE_ASSERT(pipelines.size() > 0);
587 VkPipeline pipeline = pipelines[0]->get();
588
589 deUint32 numShadersUsed = m_data.libraryConfiguration.pipelineShaders;
590 for (auto it = begin(m_data.libraryConfiguration.pipelineLibraries), eit = end(m_data.libraryConfiguration.pipelineLibraries); it != eit; ++it)
591 numShadersUsed += it->y();
592
593 // build shader binding tables
594 const de::MovePtr<BufferWithMemory> raygenShaderBindingTable = pipelineLibraries[0]->get()->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1 );
595 const de::MovePtr<BufferWithMemory> missShaderBindingTable = pipelineLibraries[0]->get()->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1 );
596 const de::MovePtr<BufferWithMemory> hitShaderBindingTable = pipelineLibraries[0]->get()->createShaderBindingTable(vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 2, numShadersUsed);
597 const VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
598 const VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
599 const VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0), shaderGroupHandleSize, numShadersUsed * shaderGroupHandleSize);
600 const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
601
602 const VkFormat imageFormat = VK_FORMAT_R32_UINT;
603 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, imageFormat);
604 const VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
605 const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
606 const Move<VkImageView> imageView = makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, imageFormat, imageSubresourceRange);
607
608 const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(pixelCount*sizeof(deUint32), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
609 const VkImageSubresourceLayers resultBufferImageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
610 const VkBufferImageCopy resultBufferImageRegion = makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, 1), resultBufferImageSubresourceLayers);
611 de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
612
613 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
614
615 const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
616 const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
617
618 std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > bottomLevelAccelerationStructures;
619 de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
620
621 beginCommandBuffer(vkd, *cmdBuffer, 0u);
622 {
623 const VkImageMemoryBarrier preImageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
624 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
625 **image, imageSubresourceRange);
626 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
627
628 const VkClearValue clearValue = makeClearValueColorU32(0xFF, 0u, 0u, 0u);
629 vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &imageSubresourceRange);
630
631 const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
632 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
633 **image, imageSubresourceRange);
634 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
635
636 bottomLevelAccelerationStructures = initBottomAccelerationStructures(deviceHelper, *cmdBuffer);
637 topLevelAccelerationStructure = initTopAccelerationStructure(deviceHelper, *cmdBuffer, bottomLevelAccelerationStructures);
638
639 const TopLevelAccelerationStructure* topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
640 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet =
641 {
642 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
643 DE_NULL, // const void* pNext;
644 1u, // deUint32 accelerationStructureCount;
645 topLevelAccelerationStructurePtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
646 };
647
648 DescriptorSetUpdateBuilder()
649 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
650 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
651 .update(vkd, device);
652
653 vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
654
655 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
656
657 cmdTraceRays(vkd,
658 *cmdBuffer,
659 &raygenShaderBindingTableRegion,
660 &missShaderBindingTableRegion,
661 &hitShaderBindingTableRegion,
662 &callableShaderBindingTableRegion,
663 m_data.width, m_data.height, 1);
664
665 const VkMemoryBarrier postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
666 const VkMemoryBarrier postCopyMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
667 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
668
669 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u, &resultBufferImageRegion);
670
671 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier);
672 }
673 endCommandBuffer(vkd, *cmdBuffer);
674
675 submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
676
677 invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE);
678
679 return resultBuffer;
680 }
681
iterate(void)682 tcu::TestStatus RayTracingPipelineLibraryTestInstance::iterate (void)
683 {
684 // run test using arrays of pointers
685 DeviceHelper deviceHelper(m_context);
686 const de::MovePtr<BufferWithMemory> buffer = runTest(deviceHelper);
687 const deUint32* bufferPtr = (deUint32*)buffer->getAllocation().getHostPtr();
688
689 deUint32 failures = 0;
690 deUint32 pos = 0;
691 deUint32 shaderIdx = 0;
692 deUint32 numShadersUsed = m_data.libraryConfiguration.pipelineShaders;
693 for (auto it = begin(m_data.libraryConfiguration.pipelineLibraries), eit = end(m_data.libraryConfiguration.pipelineLibraries); it != eit; ++it)
694 numShadersUsed += it->y();
695
696 // verify results
697 for (deUint32 y = 0; y < m_data.height; ++y)
698 for (deUint32 x = 0; x < m_data.width; ++x)
699 {
700 deUint32 expectedResult;
701 if ((x + y) % 2)
702 {
703 expectedResult = shaderIdx % numShadersUsed;
704 ++shaderIdx;
705 }
706 else
707 expectedResult = RTPL_MAX_CHIT_SHADER_COUNT;
708
709 if (bufferPtr[pos] != expectedResult)
710 failures++;
711 ++pos;
712 }
713
714 if (failures == 0)
715 return tcu::TestStatus::pass("Pass");
716 else
717 return tcu::TestStatus::fail("Fail (failures=" + de::toString(failures) + ")");
718 }
719
720 } // anonymous
721
addPipelineLibraryConfigurationsTests(tcu::TestCaseGroup * group)722 void addPipelineLibraryConfigurationsTests (tcu::TestCaseGroup* group)
723 {
724 struct ThreadData
725 {
726 bool multithreaded;
727 bool pipelinesCreatedUsingDHO;
728 const char* name;
729 } threadData[] =
730 {
731 { false, false, "singlethreaded_compilation" },
732 { true, false, "multithreaded_compilation" },
733 { true, true, "multithreaded_compilation_dho" },
734 };
735
736 struct LibraryConfigurationData
737 {
738 LibraryConfiguration libraryConfiguration;
739 const char* name;
740 } libraryConfigurationData[] =
741 {
742 { {0, { { 0, 1 } } }, "s0_l1" }, // 0 shaders in a main pipeline. 1 pipeline library with 1 shader
743 { {1, { { 0, 1 } } }, "s1_l1" }, // 1 shader in a main pipeline. 1 pipeline library with 1 shader
744 { {0, { { 0, 1 }, { 0, 1 } } }, "s0_l11" }, // 0 shaders in a main pipeline. 2 pipeline libraries with 1 shader each
745 { {3, { { 0, 1 }, { 0, 1 } } }, "s3_l11" }, // 3 shaders in a main pipeline. 2 pipeline libraries with 1 shader each
746 { {0, { { 0, 2 }, { 0, 3 } } }, "s0_l23" }, // 0 shaders in a main pipeline. 2 pipeline libraries with 2 and 3 shaders respectively
747 { {2, { { 0, 2 }, { 0, 3 } } }, "s2_l23" }, // 2 shaders in a main pipeline. 2 pipeline libraries with 2 and 3 shaders respectively
748 { {0, { { 0, 1 }, { 1, 1 } } }, "s0_l1_l1" }, // 0 shaders in a main pipeline. 2 pipeline libraries with 1 shader each. Second library is a child of a first library
749 { {1, { { 0, 1 }, { 1, 1 } } }, "s1_l1_l1" }, // 1 shader in a main pipeline. 2 pipeline libraries with 1 shader each. Second library is a child of a first library
750 { {0, { { 0, 2 }, { 1, 3 } } }, "s0_l2_l3" }, // 0 shaders in a main pipeline. 2 pipeline libraries with 2 and 3 shaders respectively. Second library is a child of a first library
751 { {3, { { 0, 2 }, { 1, 3 } } }, "s3_l2_l3" }, // 3 shaders in a main pipeline. 2 pipeline libraries with 2 and 3 shaders respectively. Second library is a child of a first library
752 { {3, { { 0, 2 }, { 0, 3 }, { 0, 2 } } }, "s3_l232" }, // 3 shaders in a main pipeline. 3 pipeline libraries with 2, 3 and 2 shaders respectively.
753 { {3, { { 0, 2 }, { 1, 2 }, { 1, 2 }, { 0, 2 } } }, "s3_l22_l22" }, // 3 shaders in a main pipeline. 4 pipeline libraries with 2 shaders each. Second and third library is a child of a first library
754 };
755
756 for (size_t threadNdx = 0; threadNdx < DE_LENGTH_OF_ARRAY(threadData); ++threadNdx)
757 {
758 de::MovePtr<tcu::TestCaseGroup> threadGroup(new tcu::TestCaseGroup(group->getTestContext(), threadData[threadNdx].name, ""));
759
760 for (size_t libConfigNdx = 0; libConfigNdx < DE_LENGTH_OF_ARRAY(libraryConfigurationData); ++libConfigNdx)
761 {
762 TestParams testParams
763 {
764 libraryConfigurationData[libConfigNdx].libraryConfiguration,
765 threadData[threadNdx].multithreaded,
766 threadData[threadNdx].pipelinesCreatedUsingDHO,
767 RTPL_DEFAULT_SIZE,
768 RTPL_DEFAULT_SIZE
769 };
770 threadGroup->addChild(new RayTracingPipelineLibraryTestCase(group->getTestContext(), libraryConfigurationData[libConfigNdx].name, "", testParams));
771 }
772 group->addChild(threadGroup.release());
773 }
774 }
775
createPipelineLibraryTests(tcu::TestContext & testCtx)776 tcu::TestCaseGroup* createPipelineLibraryTests(tcu::TestContext& testCtx)
777 {
778 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "pipeline_library", "Tests verifying pipeline libraries"));
779
780 addTestGroup(group.get(), "configurations", "Test different configurations of pipeline libraries", addPipelineLibraryConfigurationsTests);
781
782 return group.release();
783 }
784
785 } // RayTracing
786
787 } // vkt
788