1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 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 Build Large Shader Set tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingBuildIndirectTests.hpp"
25 
26 #include "vkDefs.hpp"
27 
28 #include "vktTestCase.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkTypeUtil.hpp"
36 
37 #include "vkRayTracingUtil.hpp"
38 
39 namespace vkt
40 {
41 namespace RayTracing
42 {
43 namespace
44 {
45 using namespace vk;
46 using namespace std;
47 
48 static const VkFlags	ALL_RAY_TRACING_STAGES	= VK_SHADER_STAGE_RAYGEN_BIT_KHR
49 												| VK_SHADER_STAGE_ANY_HIT_BIT_KHR
50 												| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
51 												| VK_SHADER_STAGE_MISS_BIT_KHR
52 												| VK_SHADER_STAGE_INTERSECTION_BIT_KHR
53 												| VK_SHADER_STAGE_CALLABLE_BIT_KHR;
54 
55 struct CaseDef
56 {
57 	deUint32	width;
58 	deUint32	height;
59 	deUint32	depth;
60 	deUint32	squaresGroupCount;
61 	deUint32	geometriesGroupCount;
62 	deUint32	instancesGroupCount;
63 };
64 
65 enum ShaderGroups
66 {
67 	FIRST_GROUP		= 0,
68 	RAYGEN_GROUP	= FIRST_GROUP,
69 	MISS_GROUP,
70 	HIT_GROUP,
71 	GROUP_COUNT
72 };
73 
74 const deUint32 HIT				= 1;
75 const deUint32 MISS				= 2;
76 const deUint32 HIT_MISS_PATTERN	= 7;
77 
getShaderGroupSize(const InstanceInterface& vki, const VkPhysicalDevice physicalDevice)78 deUint32 getShaderGroupSize (const InstanceInterface&	vki,
79 							 const VkPhysicalDevice		physicalDevice)
80 {
81 	de::MovePtr<RayTracingProperties>	rayTracingPropertiesKHR;
82 
83 	rayTracingPropertiesKHR	= makeRayTracingProperties(vki, physicalDevice);
84 
85 	return rayTracingPropertiesKHR->getShaderGroupHandleSize();
86 }
87 
getShaderGroupBaseAlignment(const InstanceInterface& vki, const VkPhysicalDevice physicalDevice)88 deUint32 getShaderGroupBaseAlignment (const InstanceInterface&	vki,
89 									  const VkPhysicalDevice	physicalDevice)
90 {
91 	de::MovePtr<RayTracingProperties>	rayTracingPropertiesKHR;
92 
93 	rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
94 
95 	return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
96 }
97 
makePipeline(const DeviceInterface& vkd, const VkDevice device, vk::BinaryCollection& collection, de::MovePtr<RayTracingPipeline>& rayTracingPipeline, VkPipelineLayout pipelineLayout, const std::string& shaderName)98 Move<VkPipeline> makePipeline (const DeviceInterface&			vkd,
99 							   const VkDevice					device,
100 							   vk::BinaryCollection&			collection,
101 							   de::MovePtr<RayTracingPipeline>&	rayTracingPipeline,
102 							   VkPipelineLayout					pipelineLayout,
103 							   const std::string&				shaderName)
104 {
105 	Move<VkShaderModule>	raygenShader	= createShaderModule(vkd, device, collection.get(shaderName), 0);
106 
107 	rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, raygenShader, 0);
108 
109 	Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
110 
111 	return pipeline;
112 }
113 
makePipeline(const DeviceInterface& vkd, const VkDevice device, vk::BinaryCollection& collection, de::MovePtr<RayTracingPipeline>& rayTracingPipeline, VkPipelineLayout pipelineLayout, const deUint32 raygenGroup, const deUint32 missGroup, const deUint32 hitGroup)114 Move<VkPipeline> makePipeline (const DeviceInterface&			vkd,
115 							   const VkDevice					device,
116 							   vk::BinaryCollection&			collection,
117 							   de::MovePtr<RayTracingPipeline>&	rayTracingPipeline,
118 							   VkPipelineLayout					pipelineLayout,
119 							   const deUint32					raygenGroup,
120 							   const deUint32					missGroup,
121 							   const deUint32					hitGroup)
122 {
123 	Move<VkShaderModule>	raygenShader		= createShaderModule(vkd, device, collection.get("rgen"), 0);
124 	Move<VkShaderModule>	hitShader			= createShaderModule(vkd, device, collection.get("chit"), 0);
125 	Move<VkShaderModule>	missShader			= createShaderModule(vkd, device, collection.get("miss"), 0);
126 
127 	rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,		raygenShader,		raygenGroup);
128 	rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,	hitShader,			hitGroup);
129 	rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,			missShader,			missGroup);
130 
131 	Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
132 
133 	return pipeline;
134 }
135 
136 
makeImageCreateInfo(deUint32 width, deUint32 height, deUint32 depth, VkFormat format)137 VkImageCreateInfo makeImageCreateInfo (deUint32 width, deUint32 height, deUint32 depth, VkFormat format)
138 {
139 	const VkImageUsageFlags	usage			= VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
140 	const VkImageCreateInfo	imageCreateInfo	=
141 	{
142 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType;
143 		DE_NULL,								// const void*				pNext;
144 		(VkImageCreateFlags)0u,					// VkImageCreateFlags		flags;
145 		VK_IMAGE_TYPE_3D,						// VkImageType				imageType;
146 		format,									// VkFormat					format;
147 		makeExtent3D(width, height, depth),		// VkExtent3D				extent;
148 		1u,										// deUint32					mipLevels;
149 		1u,										// deUint32					arrayLayers;
150 		VK_SAMPLE_COUNT_1_BIT,					// VkSampleCountFlagBits	samples;
151 		VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling			tiling;
152 		usage,									// VkImageUsageFlags		usage;
153 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
154 		0u,										// deUint32					queueFamilyIndexCount;
155 		DE_NULL,								// const deUint32*			pQueueFamilyIndices;
156 		VK_IMAGE_LAYOUT_UNDEFINED				// VkImageLayout			initialLayout;
157 	};
158 
159 	return imageCreateInfo;
160 }
161 
162 class RayTracingBuildIndirectTestInstance : public TestInstance
163 {
164 public:
165 													RayTracingBuildIndirectTestInstance		(Context& context, const CaseDef& data);
166 													~RayTracingBuildIndirectTestInstance	(void);
167 	tcu::TestStatus									iterate									(void);
168 
169 protected:
170 	void											checkSupportInInstance					(void) const;
171 	de::MovePtr<BufferWithMemory>					prepareBuffer							(VkDeviceSize										bufferSizeBytes,
172 																							 const std::string&									shaderName);
173 	de::MovePtr<BufferWithMemory>					runTest									(const VkBuffer										indirectBottomAccelerationStructure,
174 																							 const VkBuffer										indirectTopAccelerationStructure);
175 	de::SharedPtr<TopLevelAccelerationStructure>	initTopAccelerationStructure			(VkCommandBuffer									cmdBuffer,
176 																							 de::SharedPtr<BottomLevelAccelerationStructure>&	bottomLevelAccelerationStructure,
177 																							 const VkBuffer										indirectBuffer,
178 																							 const VkDeviceSize									indirectBufferOffset,
179 																							 const deUint32										indirectBufferStride);
180 	de::SharedPtr<BottomLevelAccelerationStructure>	initBottomAccelerationStructure			(VkCommandBuffer									cmdBuffer,
181 																							 const VkBuffer										indirectBuffer,
182 																							 const VkDeviceSize									indirectBufferOffset,
183 																							 const deUint32										indirectBufferStride);
184 	VkBuffer										initIndirectTopAccelerationStructure	(void);
185 	VkBuffer										initIndirectBottomAccelerationStructure	(void);
186 
187 private:
188 	CaseDef											m_data;
189 	de::MovePtr<BufferWithMemory>					m_indirectAccelerationStructureBottom;
190 	de::MovePtr<BufferWithMemory>					m_indirectAccelerationStructureTop;
191 };
192 
RayTracingBuildIndirectTestInstance(Context& context, const CaseDef& data)193 RayTracingBuildIndirectTestInstance::RayTracingBuildIndirectTestInstance (Context& context, const CaseDef& data)
194 	: vkt::TestInstance						(context)
195 	, m_data								(data)
196 	, m_indirectAccelerationStructureBottom	()
197 	, m_indirectAccelerationStructureTop	()
198 {
199 }
200 
~RayTracingBuildIndirectTestInstance(void)201 RayTracingBuildIndirectTestInstance::~RayTracingBuildIndirectTestInstance (void)
202 {
203 }
204 
205 class RayTracingTestCase : public TestCase
206 {
207 	public:
208 							RayTracingTestCase	(tcu::TestContext& context, const char* name, const char* desc, const CaseDef data);
209 							~RayTracingTestCase	(void);
210 
211 	virtual	void			initPrograms		(SourceCollections& programCollection) const;
212 	virtual TestInstance*	createInstance		(Context& context) const;
213 	virtual void			checkSupport		(Context& context) const;
214 
215 private:
216 	CaseDef					m_data;
217 };
218 
RayTracingTestCase(tcu::TestContext& context, const char* name, const char* desc, const CaseDef data)219 RayTracingTestCase::RayTracingTestCase (tcu::TestContext& context, const char* name, const char* desc, const CaseDef data)
220 	: vkt::TestCase	(context, name, desc)
221 	, m_data		(data)
222 {
223 	DE_ASSERT((m_data.width * m_data.height * m_data.depth) == (m_data.squaresGroupCount * m_data.geometriesGroupCount * m_data.instancesGroupCount));
224 }
225 
~RayTracingTestCase(void)226 RayTracingTestCase::~RayTracingTestCase	(void)
227 {
228 }
229 
checkSupport(Context& context) const230 void RayTracingTestCase::checkSupport(Context& context) const
231 {
232 	const VkPhysicalDeviceAccelerationStructureFeaturesKHR&	accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
233 	if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE)
234 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
235 
236 	const VkPhysicalDeviceRayTracingPipelineFeaturesKHR&	rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures();
237 	if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE)
238 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
239 
240 	if (accelerationStructureFeaturesKHR.accelerationStructureIndirectBuild == DE_FALSE)
241 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureIndirectBuild");
242 }
243 
initPrograms(SourceCollections& programCollection) const244 void RayTracingTestCase::initPrograms (SourceCollections& programCollection) const
245 {
246 	const vk::ShaderBuildOptions	buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
247 	{
248 		std::stringstream css;
249 		css <<
250 			"#version 460 core\n"
251 			"#extension GL_EXT_ray_tracing : require\n"
252 			"layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
253 			"{\n"
254 			"  uvec4 accelerationStructureBuildOffsetInfoKHR[" << m_data.depth << "];\n"
255 			"} b_out;\n"
256 			"\n"
257 			"void main()\n"
258 			"{\n"
259 			"  for (uint i = 0; i < " << m_data.depth << "; i++)\n"
260 			"  {\n"
261 			"    uint primitiveCount  = " << m_data.width * m_data.height << "u;\n"
262 			"    uint primitiveOffset = " << m_data.width * m_data.height * 3u * sizeof(tcu::Vec3) << "u * i;\n"
263 			"    uint firstVertex     = " << 0 << "u;\n"
264 			"    uint transformOffset = " << 0 << "u;\n"
265 			"\n"
266 			"    b_out.accelerationStructureBuildOffsetInfoKHR[i] = uvec4(primitiveCount, primitiveOffset, firstVertex, transformOffset);\n"
267 			"  }\n"
268 			"}\n";
269 
270 		programCollection.glslSources.add("wr-asb") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
271 	}
272 
273 	{
274 		std::stringstream css;
275 		css <<
276 			"#version 460 core\n"
277 			"#extension GL_EXT_ray_tracing : require\n"
278 			"layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
279 			"{\n"
280 			"  uvec4 accelerationStructureBuildOffsetInfoKHR;\n"
281 			"} b_out;\n"
282 			"\n"
283 			"void main()\n"
284 			"{\n"
285 			"  uint primitiveCount  = " << m_data.instancesGroupCount << "u;\n"
286 			"  uint primitiveOffset = " << 0 << "u;\n"
287 			"  uint firstVertex     = " << 0 << "u;\n"
288 			"  uint transformOffset = " << 0 << "u;\n"
289 			"\n"
290 			"  b_out.accelerationStructureBuildOffsetInfoKHR = uvec4(primitiveCount, primitiveOffset, firstVertex, transformOffset);\n"
291 			"}\n";
292 
293 		programCollection.glslSources.add("wr-ast") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
294 	}
295 
296 	{
297 		std::stringstream css;
298 		css <<
299 			"#version 460 core\n"
300 			"#extension GL_EXT_ray_tracing : require\n"
301 			"layout(location = 0) rayPayloadEXT vec3 hitValue;\n"
302 			"layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
303 			"\n"
304 			"void main()\n"
305 			"{\n"
306 			"  uint  rayFlags = 0;\n"
307 			"  uint  cullMask = 0xFF;\n"
308 			"  float tmin     = 0.0;\n"
309 			"  float tmax     = 9.0;\n"
310 			"  float x        = (float(gl_LaunchIDEXT.x) + 0.5f) / float(gl_LaunchSizeEXT.x);\n"
311 			"  float y        = (float(gl_LaunchIDEXT.y) + 0.5f) / float(gl_LaunchSizeEXT.y);\n"
312 			"  float z        = (float(gl_LaunchIDEXT.z) + 0.5f) / float(gl_LaunchSizeEXT.z);\n"
313 			"  vec3  origin   = vec3(x, y, z);\n"
314 			"  vec3  direct   = vec3(0.0, 0.0, -1.0);\n"
315 			"  traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
316 			"}\n";
317 
318 		programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
319 	}
320 
321 	{
322 		std::stringstream css;
323 		css <<
324 			"#version 460 core\n"
325 			"#extension GL_EXT_ray_tracing : require\n"
326 			"layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
327 			"hitAttributeEXT vec3 attribs;\n"
328 			"layout(set = 0, binding = 0, r32ui) uniform uimage3D result;\n"
329 			"void main()\n"
330 			"{\n"
331 			"  uvec4 color = uvec4(" << HIT << ",0,0,1);\n"
332 			"  imageStore(result, ivec3(gl_LaunchIDEXT.xyz), color);\n"
333 			"}\n";
334 
335 		programCollection.glslSources.add("chit") << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
336 	}
337 
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 dummyPayload { vec4 dummy; };\n"
344 			"layout(set = 0, binding = 0, r32ui) uniform uimage3D result;\n"
345 			"void main()\n"
346 			"{\n"
347 			"  uvec4 color = uvec4(" << MISS << ",0,0,1);\n"
348 			"  imageStore(result, ivec3(gl_LaunchIDEXT.xyz), color);\n"
349 			"}\n";
350 
351 		programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
352 	}
353 }
354 
createInstance(Context& context) const355 TestInstance* RayTracingTestCase::createInstance (Context& context) const
356 {
357 	return new RayTracingBuildIndirectTestInstance(context, m_data);
358 }
359 
initTopAccelerationStructure(VkCommandBuffer cmdBuffer, de::SharedPtr<BottomLevelAccelerationStructure>& bottomLevelAccelerationStructure, const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset, const deUint32 indirectBufferStride)360 de::SharedPtr<TopLevelAccelerationStructure> RayTracingBuildIndirectTestInstance::initTopAccelerationStructure (VkCommandBuffer										cmdBuffer,
361 																												de::SharedPtr<BottomLevelAccelerationStructure>&	bottomLevelAccelerationStructure,
362 																												const VkBuffer										indirectBuffer,
363 																												const VkDeviceSize									indirectBufferOffset,
364 																												const deUint32										indirectBufferStride)
365 {
366 	const DeviceInterface&						vkd			= m_context.getDeviceInterface();
367 	const VkDevice								device		= m_context.getDevice();
368 	Allocator&									allocator	= m_context.getDefaultAllocator();
369 	de::MovePtr<TopLevelAccelerationStructure>	result		= makeTopLevelAccelerationStructure();
370 
371 	result->setInstanceCount(1);
372 	result->addInstance(bottomLevelAccelerationStructure);
373 	result->setIndirectBuildParameters(indirectBuffer, indirectBufferOffset, indirectBufferStride);
374 
375 	result->createAndBuild(vkd, device, cmdBuffer, allocator);
376 
377 	return de::SharedPtr<TopLevelAccelerationStructure>(result.release());
378 }
379 
initBottomAccelerationStructure(VkCommandBuffer cmdBuffer, const VkBuffer indirectBuffer, const VkDeviceSize indirectBufferOffset, const deUint32 indirectBufferStride)380 de::SharedPtr<BottomLevelAccelerationStructure> RayTracingBuildIndirectTestInstance::initBottomAccelerationStructure (VkCommandBuffer		cmdBuffer,
381 																													  const VkBuffer		indirectBuffer,
382 																													  const VkDeviceSize	indirectBufferOffset,
383 																													  const deUint32		indirectBufferStride)
384 {
385 	const DeviceInterface&							vkd			= m_context.getDeviceInterface();
386 	const VkDevice									device		= m_context.getDevice();
387 	Allocator&										allocator	= m_context.getDefaultAllocator();
388 	de::MovePtr<BottomLevelAccelerationStructure>	result		= makeBottomLevelAccelerationStructure();
389 
390 	result->setGeometryCount(m_data.geometriesGroupCount);
391 	result->setIndirectBuildParameters(indirectBuffer, indirectBufferOffset, indirectBufferStride);
392 
393 	for (size_t geometryNdx = 0; geometryNdx < m_data.geometriesGroupCount; ++geometryNdx)
394 	{
395 		std::vector<tcu::Vec3>	geometryData;
396 
397 		geometryData.reserve(m_data.squaresGroupCount * 3u);
398 
399 		tcu::UVec2	startPos	= tcu::UVec2(0u, 0u);
400 
401 		for (size_t squareNdx = 0; squareNdx < m_data.squaresGroupCount; ++squareNdx)
402 		{
403 			const deUint32	n	= m_data.width * startPos.y() + startPos.x();
404 			const float		x0	= float(startPos.x() + 0) / float(m_data.width);
405 			const float		y0	= float(startPos.y() + 0) / float(m_data.height);
406 			const float		x1	= float(startPos.x() + 1) / float(m_data.width);
407 			const float		y1	= float(startPos.y() + 1) / float(m_data.height);
408 			const float		xm	= (x0 + x1) / 2.0f;
409 			const float		ym	= (y0 + y1) / 2.0f;
410 			const float		z	= (n % HIT_MISS_PATTERN == 0) ? +1.0f : (float(geometryNdx) + 0.25f) / float(m_data.geometriesGroupCount);
411 
412 			geometryData.push_back(tcu::Vec3(x0, y0, z));
413 			geometryData.push_back(tcu::Vec3(xm, y1, z));
414 			geometryData.push_back(tcu::Vec3(x1, ym, z));
415 
416 			startPos.y() = (n + 1) / m_data.width;
417 			startPos.x() = (n + 1) % m_data.width;
418 		}
419 
420 		result->addGeometry(geometryData, true);
421 	}
422 
423 	result->createAndBuild(vkd, device, cmdBuffer, allocator);
424 
425 	return de::SharedPtr<BottomLevelAccelerationStructure>(result.release());
426 }
427 
prepareBuffer(VkDeviceSize bufferSizeBytes, const std::string& shaderName)428 de::MovePtr<BufferWithMemory> RayTracingBuildIndirectTestInstance::prepareBuffer (VkDeviceSize			bufferSizeBytes,
429 																				  const std::string&	shaderName)
430 {
431 	const InstanceInterface&			vki									= m_context.getInstanceInterface();
432 	const DeviceInterface&				vkd									= m_context.getDeviceInterface();
433 	const VkDevice						device								= m_context.getDevice();
434 	const VkPhysicalDevice				physicalDevice						= m_context.getPhysicalDevice();
435 	const deUint32						queueFamilyIndex					= m_context.getUniversalQueueFamilyIndex();
436 	const VkQueue						queue								= m_context.getUniversalQueue();
437 	Allocator&							allocator							= m_context.getDefaultAllocator();
438 	const deUint32						shaderGroupHandleSize				= getShaderGroupSize(vki, physicalDevice);
439 	const deUint32						shaderGroupBaseAlignment			= getShaderGroupBaseAlignment(vki, physicalDevice);
440 
441 	const VkBufferCreateInfo			bufferCreateInfo					= makeBufferCreateInfo(bufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
442 	de::MovePtr<BufferWithMemory>		buffer								= de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress));
443 
444 	const Move<VkDescriptorSetLayout>	descriptorSetLayout					= DescriptorSetLayoutBuilder()
445 																					.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ALL_RAY_TRACING_STAGES)
446 																					.build(vkd, device);
447 	const Move<VkDescriptorPool>		descriptorPool						= DescriptorPoolBuilder()
448 																					.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
449 																					.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
450 	const Move<VkDescriptorSet>			descriptorSet						= makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
451 	const Move<VkPipelineLayout>		pipelineLayout						= makePipelineLayout(vkd, device, descriptorSetLayout.get());
452 	const Move<VkCommandPool>			cmdPool								= createCommandPool(vkd, device, 0, queueFamilyIndex);
453 	const Move<VkCommandBuffer>			cmdBuffer							= allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
454 
455 	const vk::VkDescriptorBufferInfo	descriptorBufferInfo				= makeDescriptorBufferInfo(**buffer, 0ull, bufferSizeBytes);
456 
457 	de::MovePtr<RayTracingPipeline>		rayTracingPipeline					= de::newMovePtr<RayTracingPipeline>();
458 	const Move<VkPipeline>				pipeline							= makePipeline(vkd, device, m_context.getBinaryCollection(), rayTracingPipeline, *pipelineLayout, shaderName);
459 	const de::MovePtr<BufferWithMemory>	shaderBindingTable					= rayTracingPipeline->createShaderBindingTable(vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
460 	const VkStridedDeviceAddressRegionKHR	raygenShaderBindingTableRegion		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, shaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
461 	const VkStridedDeviceAddressRegionKHR	missShaderBindingTableRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
462 	const VkStridedDeviceAddressRegionKHR	hitShaderBindingTableRegion			= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
463 	const VkStridedDeviceAddressRegionKHR	callableShaderBindingTableRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
464 
465 	beginCommandBuffer(vkd, *cmdBuffer, 0u);
466 	{
467 		DescriptorSetUpdateBuilder()
468 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
469 			.update(vkd, device);
470 
471 		vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
472 
473 		vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
474 
475 		cmdTraceRays(vkd,
476 			*cmdBuffer,
477 			&raygenShaderBindingTableRegion,
478 			&missShaderBindingTableRegion,
479 			&hitShaderBindingTableRegion,
480 			&callableShaderBindingTableRegion,
481 			1u, 1u, 1u);
482 	}
483 	endCommandBuffer(vkd, *cmdBuffer);
484 
485 	submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
486 
487 	return buffer;
488 }
489 
490 
runTest(const VkBuffer indirectBottomAccelerationStructure, const VkBuffer indirectTopAccelerationStructure)491 de::MovePtr<BufferWithMemory> RayTracingBuildIndirectTestInstance::runTest (const VkBuffer	indirectBottomAccelerationStructure,
492 																			const VkBuffer	indirectTopAccelerationStructure)
493 {
494 	const InstanceInterface&			vki									= m_context.getInstanceInterface();
495 	const DeviceInterface&				vkd									= m_context.getDeviceInterface();
496 	const VkDevice						device								= m_context.getDevice();
497 	const VkPhysicalDevice				physicalDevice						= m_context.getPhysicalDevice();
498 	const deUint32						queueFamilyIndex					= m_context.getUniversalQueueFamilyIndex();
499 	const VkQueue						queue								= m_context.getUniversalQueue();
500 	Allocator&							allocator							= m_context.getDefaultAllocator();
501 	const VkFormat						format								= VK_FORMAT_R32_UINT;
502 	const deUint32						pixelCount							= m_data.width * m_data.height * m_data.depth;
503 	const deUint32						shaderGroupHandleSize				= getShaderGroupSize(vki, physicalDevice);
504 	const deUint32						shaderGroupBaseAlignment			= getShaderGroupBaseAlignment(vki, physicalDevice);
505 
506 	const Move<VkDescriptorSetLayout>	descriptorSetLayout					= DescriptorSetLayoutBuilder()
507 																					.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
508 																					.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
509 																					.build(vkd, device);
510 	const Move<VkDescriptorPool>		descriptorPool						= DescriptorPoolBuilder()
511 																					.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
512 																					.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
513 																					.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
514 	const Move<VkDescriptorSet>			descriptorSet						= makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
515 	const Move<VkPipelineLayout>		pipelineLayout						= makePipelineLayout(vkd, device, descriptorSetLayout.get());
516 	const Move<VkCommandPool>			cmdPool								= createCommandPool(vkd, device, 0, queueFamilyIndex);
517 	const Move<VkCommandBuffer>			cmdBuffer							= allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
518 
519 	de::MovePtr<RayTracingPipeline>		rayTracingPipeline					= de::newMovePtr<RayTracingPipeline>();
520 	const Move<VkPipeline>				pipeline							= makePipeline(vkd, device, m_context.getBinaryCollection(), rayTracingPipeline, *pipelineLayout, RAYGEN_GROUP, MISS_GROUP, HIT_GROUP);
521 	const de::MovePtr<BufferWithMemory>	raygenShaderBindingTable			= rayTracingPipeline->createShaderBindingTable(vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, RAYGEN_GROUP, 1u);
522 	const de::MovePtr<BufferWithMemory>	missShaderBindingTable				= rayTracingPipeline->createShaderBindingTable(vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, MISS_GROUP, 1u);
523 	const de::MovePtr<BufferWithMemory>	hitShaderBindingTable				= rayTracingPipeline->createShaderBindingTable(vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, HIT_GROUP, 1u);
524 	const VkStridedDeviceAddressRegionKHR	raygenShaderBindingTableRegion		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
525 	const VkStridedDeviceAddressRegionKHR	missShaderBindingTableRegion		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
526 	const VkStridedDeviceAddressRegionKHR	hitShaderBindingTableRegion			= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
527 	const VkStridedDeviceAddressRegionKHR	callableShaderBindingTableRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
528 
529 	const VkImageCreateInfo				imageCreateInfo						= makeImageCreateInfo(m_data.width, m_data.height, m_data.depth, format);
530 	const VkImageSubresourceRange		imageSubresourceRange				= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
531 	const de::MovePtr<ImageWithMemory>	image								= de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
532 	const Move<VkImageView>				imageView							= makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_3D, format, imageSubresourceRange);
533 
534 	const VkBufferCreateInfo			bufferCreateInfo					= makeBufferCreateInfo(pixelCount * sizeof(deUint32), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
535 	const VkImageSubresourceLayers		bufferImageSubresourceLayers		= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
536 	const VkBufferImageCopy				bufferImageRegion					= makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, m_data.depth), bufferImageSubresourceLayers);
537 	de::MovePtr<BufferWithMemory>		buffer								= de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
538 
539 	const VkDescriptorImageInfo			descriptorImageInfo					= makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
540 
541 	const VkImageMemoryBarrier			preImageBarrier						= makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
542 																				VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
543 																				**image, imageSubresourceRange);
544 	const VkImageMemoryBarrier			postImageBarrier					= makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
545 																				VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
546 																				**image, imageSubresourceRange);
547 	const VkMemoryBarrier				postTraceMemoryBarrier				= makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
548 	const VkMemoryBarrier				postCopyMemoryBarrier				= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
549 	const VkClearValue					clearValue							= makeClearValueColorU32(5u, 5u, 5u, 255u);
550 	const deUint32						indirectAccelerationStructureStride	= sizeof(VkAccelerationStructureBuildRangeInfoKHR);
551 
552 	de::SharedPtr<BottomLevelAccelerationStructure>	bottomLevelAccelerationStructure;
553 	de::SharedPtr<TopLevelAccelerationStructure>	topLevelAccelerationStructure;
554 
555 	beginCommandBuffer(vkd, *cmdBuffer, 0u);
556 	{
557 		cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
558 		vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &imageSubresourceRange);
559 		cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
560 
561 		bottomLevelAccelerationStructure	= initBottomAccelerationStructure(*cmdBuffer, indirectBottomAccelerationStructure, 0, indirectAccelerationStructureStride);
562 		topLevelAccelerationStructure		= initTopAccelerationStructure(*cmdBuffer, bottomLevelAccelerationStructure, indirectTopAccelerationStructure, 0, indirectAccelerationStructureStride);
563 
564 		const TopLevelAccelerationStructure*			topLevelAccelerationStructurePtr		= topLevelAccelerationStructure.get();
565 		VkWriteDescriptorSetAccelerationStructureKHR	accelerationStructureWriteDescriptorSet	=
566 		{
567 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,	//  VkStructureType						sType;
568 			DE_NULL,															//  const void*							pNext;
569 			1u,																	//  deUint32							accelerationStructureCount;
570 			topLevelAccelerationStructurePtr->getPtr(),							//  const VkAccelerationStructureKHR*	pAccelerationStructures;
571 		};
572 
573 		DescriptorSetUpdateBuilder()
574 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
575 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
576 			.update(vkd, device);
577 
578 		vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
579 
580 		vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
581 
582 		cmdTraceRays(vkd,
583 			*cmdBuffer,
584 			&raygenShaderBindingTableRegion,
585 			&missShaderBindingTableRegion,
586 			&hitShaderBindingTableRegion,
587 			&callableShaderBindingTableRegion,
588 			m_data.width, m_data.height, m_data.depth);
589 
590 		cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
591 
592 		vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **buffer, 1u, &bufferImageRegion);
593 
594 		cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier);
595 	}
596 	endCommandBuffer(vkd, *cmdBuffer);
597 
598 	submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
599 
600 	invalidateMappedMemoryRange(vkd, device, buffer->getAllocation().getMemory(), buffer->getAllocation().getOffset(), pixelCount * sizeof(deUint32));
601 
602 	return buffer;
603 }
604 
checkSupportInInstance(void) const605 void RayTracingBuildIndirectTestInstance::checkSupportInInstance (void) const
606 {
607 	const InstanceInterface&			vki						= m_context.getInstanceInterface();
608 	const VkPhysicalDevice				physicalDevice			= m_context.getPhysicalDevice();
609 	de::MovePtr<RayTracingProperties>	rayTracingProperties	= makeRayTracingProperties(vki, physicalDevice);
610 
611 	if (rayTracingProperties->getMaxPrimitiveCount() < m_data.squaresGroupCount)
612 		TCU_THROW(NotSupportedError, "Triangles required more than supported");
613 
614 	if (rayTracingProperties->getMaxGeometryCount() < m_data.geometriesGroupCount)
615 		TCU_THROW(NotSupportedError, "Geometries required more than supported");
616 
617 	if (rayTracingProperties->getMaxInstanceCount() < m_data.instancesGroupCount)
618 		TCU_THROW(NotSupportedError, "Instances required more than supported");
619 }
620 
initIndirectTopAccelerationStructure(void)621 VkBuffer	RayTracingBuildIndirectTestInstance::initIndirectTopAccelerationStructure (void)
622 {
623 	VkBuffer result	= DE_NULL;
624 
625 	m_indirectAccelerationStructureTop	= prepareBuffer(sizeof(VkAccelerationStructureBuildRangeInfoKHR), "wr-ast");
626 	result								= **m_indirectAccelerationStructureTop;
627 
628 	return result;
629 }
630 
initIndirectBottomAccelerationStructure(void)631 VkBuffer	RayTracingBuildIndirectTestInstance::initIndirectBottomAccelerationStructure (void)
632 {
633 	VkBuffer result	= DE_NULL;
634 
635 	m_indirectAccelerationStructureBottom	= prepareBuffer(sizeof(VkAccelerationStructureBuildRangeInfoKHR) * m_data.geometriesGroupCount, "wr-asb");
636 	result									= **m_indirectAccelerationStructureBottom;
637 
638 	return result;
639 }
640 
iterate(void)641 tcu::TestStatus RayTracingBuildIndirectTestInstance::iterate (void)
642 {
643 	checkSupportInInstance();
644 
645 	const VkBuffer						indirectAccelerationStructureBottom	= initIndirectBottomAccelerationStructure();
646 	const VkBuffer						indirectAccelerationStructureTop	= initIndirectTopAccelerationStructure();
647 	const de::MovePtr<BufferWithMemory>	buffer								= runTest(indirectAccelerationStructureBottom, indirectAccelerationStructureTop);
648 	const deUint32*						bufferPtr							= (deUint32*)buffer->getAllocation().getHostPtr();
649 	deUint32							failures							= 0;
650 
651 	for (deUint32 z = 0; z < m_data.depth; ++z)
652 	{
653 		const deUint32*	bufferPtrLevel	= &bufferPtr[z * m_data.height * m_data.width];
654 
655 		for (deUint32 y = 0; y < m_data.height; ++y)
656 		for (deUint32 x = 0; x < m_data.width; ++x)
657 		{
658 			const deUint32	n				= m_data.width * y + x;
659 			const deUint32	expectedValue	= (n % HIT_MISS_PATTERN == 0) ? MISS : HIT;
660 
661 			if (bufferPtrLevel[n] != expectedValue)
662 				failures++;
663 		}
664 	}
665 
666 	if (failures == 0)
667 		return tcu::TestStatus::pass("Pass");
668 	else
669 		return tcu::TestStatus::fail("failures=" + de::toString(failures));
670 }
671 
672 }	// anonymous
673 
createBuildIndirectTests(tcu::TestContext& testCtx)674 tcu::TestCaseGroup*	createBuildIndirectTests (tcu::TestContext& testCtx)
675 {
676 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "indirect", "Build acceleration structure indirect ray tracing tests"));
677 
678 	const deUint32	width					= 512u;
679 	const deUint32	height					= 128u;
680 	const deUint32	depth					= 4u;
681 	const deUint32	largestGroup			= width * height;
682 	const deUint32	squaresGroupCount		= largestGroup;
683 	const deUint32	geometriesGroupCount	= depth;
684 	const deUint32	instancesGroupCount		= 1;
685 	const CaseDef	caseDef					=
686 	{
687 		width,
688 		height,
689 		depth,
690 		squaresGroupCount,
691 		geometriesGroupCount,
692 		instancesGroupCount,
693 	};
694 	const std::string	testName			= "build_structure";
695 
696 	group->addChild(new RayTracingTestCase(testCtx, testName.c_str(), "", caseDef));
697 
698 	return group.release();
699 }
700 
701 }	// RayTracing
702 }	// vkt
703