• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Test procedural geometry with complex bouding box sets
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingProceduralGeometryTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26 #include "vkDefs.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestGroupUtil.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 #include "vkImageUtil.hpp"
37 #include "vkRayTracingUtil.hpp"
38 #include "tcuVectorUtil.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuCommandLine.hpp"
43 #include "tcuFloat.hpp"
44 
45 namespace vkt
46 {
47 namespace RayTracing
48 {
49 namespace
50 {
51 using namespace vk;
52 using namespace vkt;
53 
54 static const VkFlags	ALL_RAY_TRACING_STAGES	= VK_SHADER_STAGE_RAYGEN_BIT_KHR
55 												| VK_SHADER_STAGE_ANY_HIT_BIT_KHR
56 												| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
57 												| VK_SHADER_STAGE_MISS_BIT_KHR
58 												| VK_SHADER_STAGE_INTERSECTION_BIT_KHR
59 												| VK_SHADER_STAGE_CALLABLE_BIT_KHR;
60 
61 enum class TestType
62 {
63 	OBJECT_BEHIND_BOUNDING_BOX = 0,
64 	TRIANGLE_IN_BETWEEN
65 };
66 
67 struct DeviceHelper
68 {
69 	Move<VkDevice>					device;
70 	de::MovePtr<DeviceDriver>		vkd;
71 	deUint32						queueFamilyIndex;
72 	VkQueue							queue;
73 	de::MovePtr<SimpleAllocator>	allocator;
74 
DeviceHelpervkt::RayTracing::__anoneeddae980111::DeviceHelper75 	DeviceHelper (Context& context)
76 	{
77 		const auto&	vkp					= context.getPlatformInterface();
78 		const auto&	vki					= context.getInstanceInterface();
79 		const auto	instance			= context.getInstance();
80 		const auto	physicalDevice		= context.getPhysicalDevice();
81 
82 		queueFamilyIndex = context.getUniversalQueueFamilyIndex();
83 
84 		// Get device features (these have to be checked in the test case)
85 		VkPhysicalDeviceRayTracingPipelineFeaturesKHR		rayTracingPipelineFeatures		= initVulkanStructure();
86 		VkPhysicalDeviceAccelerationStructureFeaturesKHR	accelerationStructureFeatures	= initVulkanStructure(&rayTracingPipelineFeatures);
87 		VkPhysicalDeviceBufferDeviceAddressFeaturesKHR		deviceAddressFeatures			= initVulkanStructure(&accelerationStructureFeatures);
88 		VkPhysicalDeviceFeatures2							deviceFeatures					= initVulkanStructure(&deviceAddressFeatures);
89 
90 		vki.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures);
91 
92 		// Make sure robust buffer access is disabled as in the default device
93 		deviceFeatures.features.robustBufferAccess = VK_FALSE;
94 
95 		const auto queuePriority = 1.0f;
96 		const VkDeviceQueueCreateInfo queueInfo
97 		{
98 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,			//	VkStructureType					sType;
99 			nullptr,											//	const void*						pNext;
100 			0u,													//	VkDeviceQueueCreateFlags		flags;
101 			queueFamilyIndex,									//	deUint32						queueFamilyIndex;
102 			1u,													//	deUint32						queueCount;
103 			&queuePriority,										//	const float*					pQueuePriorities;
104 		};
105 
106 		// Required extensions - create device with VK_KHR_ray_tracing_pipeline but
107 		// without VK_KHR_pipeline_library to also test that that combination works
108 		std::vector<const char*> requiredExtensions
109 		{
110 			"VK_KHR_ray_tracing_pipeline",
111 			"VK_KHR_acceleration_structure",
112 			"VK_KHR_deferred_host_operations",
113 			"VK_KHR_buffer_device_address",
114 			"VK_EXT_descriptor_indexing",
115 			"VK_KHR_spirv_1_4",
116 			"VK_KHR_shader_float_controls"
117 		};
118 
119 		const VkDeviceCreateInfo createInfo
120 		{
121 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,				//	VkStructureType					sType;
122 			deviceFeatures.pNext,								//	const void*						pNext;
123 			0u,													//	VkDeviceCreateFlags				flags;
124 			1u,													//	deUint32						queueCreateInfoCount;
125 			&queueInfo,											//	const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
126 			0u,													//	deUint32						enabledLayerCount;
127 			nullptr,											//	const char* const*				ppEnabledLayerNames;
128 			static_cast<deUint32>(requiredExtensions.size()),	//	deUint32						enabledExtensionCount;
129 			requiredExtensions.data(),							//	const char* const*				ppEnabledExtensionNames;
130 			&deviceFeatures.features,							//	const VkPhysicalDeviceFeatures*	pEnabledFeatures;
131 		};
132 
133 		// Create custom device and related objects
134 		device		= createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &createInfo);
135 		vkd			= de::MovePtr<DeviceDriver>(new DeviceDriver(vkp, instance, device.get()));
136 		queue		= getDeviceQueue(*vkd, *device, queueFamilyIndex, 0u);
137 		allocator	= de::MovePtr<SimpleAllocator>(new SimpleAllocator(*vkd, device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
138 	}
139 };
140 
141 class RayTracingProceduralGeometryTestBase : public TestInstance
142 {
143 public:
144 
145 	RayTracingProceduralGeometryTestBase	(Context& context);
146 	~RayTracingProceduralGeometryTestBase	(void) = default;
147 
148 	tcu::TestStatus iterate					(void) override;
149 
150 protected:
151 
152 	virtual void setupRayTracingPipeline() = 0;
153 	virtual void setupAccelerationStructures() = 0;
154 
155 private:
156 
157 	VkWriteDescriptorSetAccelerationStructureKHR	makeASWriteDescriptorSet	(const VkAccelerationStructureKHR* pAccelerationStructure);
158 	void											clearBuffer					(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize);
159 
160 protected:
161 
162 	DeviceHelper													m_customDevice;
163 	de::MovePtr<RayTracingPipeline>									m_rayTracingPipeline;
164 	Move<VkPipelineLayout>											m_pipelineLayout;
165 	Move<VkPipeline>												m_pipeline;
166 	de::MovePtr<BufferWithMemory>									m_rgenShaderBT;
167 	de::MovePtr<BufferWithMemory>									m_chitShaderBT;
168 	de::MovePtr<BufferWithMemory>									m_missShaderBT;
169 
170 	Move<VkDescriptorSetLayout>										m_descriptorSetLayout;
171 	Move<VkCommandPool>												m_cmdPool;
172 	Move<VkCommandBuffer>											m_cmdBuffer;
173 
174 	std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >	m_blasVect;
175 	de::SharedPtr<TopLevelAccelerationStructure>					m_referenceTLAS;
176 	de::SharedPtr<TopLevelAccelerationStructure>					m_resultTLAS;
177 };
178 
RayTracingProceduralGeometryTestBase(Context & context)179 RayTracingProceduralGeometryTestBase::RayTracingProceduralGeometryTestBase(Context& context)
180 	: vkt::TestInstance	(context)
181 	, m_customDevice	(context)
182 	, m_referenceTLAS	(makeTopLevelAccelerationStructure().release())
183 	, m_resultTLAS		(makeTopLevelAccelerationStructure().release())
184 {
185 }
186 
iterate(void)187 tcu::TestStatus RayTracingProceduralGeometryTestBase::iterate(void)
188 {
189 	const DeviceInterface&	vkd					= *m_customDevice.vkd;
190 	const VkDevice			device				= *m_customDevice.device;
191 	const deUint32			queueFamilyIndex	= m_customDevice.queueFamilyIndex;
192 	const VkQueue			queue				= m_customDevice.queue;
193 	Allocator&				allocator			= *m_customDevice.allocator;
194 	const deUint32			sgHandleSize		= m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
195 	const deUint32			imageSize			= 64u;
196 
197 	const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
198 		.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 2u)
199 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
200 		.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
201 
202 	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
203 		.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)	// as with single/four aabb's
204 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ALL_RAY_TRACING_STAGES)				// ssbo with result/reference values
205 		.build(vkd, device);
206 
207 	const Move<VkDescriptorSet>			referenceDescriptorSet	= makeDescriptorSet(vkd, device, *descriptorPool, *m_descriptorSetLayout);
208 	const Move<VkDescriptorSet>			resultDescriptorSet		= makeDescriptorSet(vkd, device, *descriptorPool, *m_descriptorSetLayout);
209 
210 	const VkDeviceSize					resultBufferSize		= imageSize * imageSize * sizeof(int);
211 	const VkBufferCreateInfo			resultBufferCreateInfo	= makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
212 	de::SharedPtr<BufferWithMemory>		referenceBuffer			= de::SharedPtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
213 	de::SharedPtr<BufferWithMemory>		resultBuffer			= de::SharedPtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
214 
215 	m_rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
216 
217 	setupRayTracingPipeline();
218 
219 	const VkStridedDeviceAddressRegionKHR	rgenSBTR		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, m_rgenShaderBT->get(), 0), sgHandleSize, sgHandleSize);
220 	const VkStridedDeviceAddressRegionKHR	chitSBTR		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, m_chitShaderBT->get(), 0), sgHandleSize, sgHandleSize);
221 	const VkStridedDeviceAddressRegionKHR	missSBTR		= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, m_missShaderBT->get(), 0), sgHandleSize, sgHandleSize);
222 	const VkStridedDeviceAddressRegionKHR	callableSBTR	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
223 
224 	m_cmdPool	= createCommandPool(vkd, device, 0, queueFamilyIndex);
225 	m_cmdBuffer	= allocateCommandBuffer(vkd, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
226 
227 	// clear result and reference buffers
228 	clearBuffer(resultBuffer, resultBufferSize);
229 	clearBuffer(referenceBuffer, resultBufferSize);
230 
231 	beginCommandBuffer(vkd, *m_cmdBuffer, 0u);
232 	{
233 		setupAccelerationStructures();
234 
235 		// update descriptor sets
236 		{
237 			typedef DescriptorSetUpdateBuilder::Location DSL;
238 
239 			const VkWriteDescriptorSetAccelerationStructureKHR	referenceAS		= makeASWriteDescriptorSet(m_referenceTLAS->getPtr());
240 			const VkDescriptorBufferInfo						referenceSSBO	= makeDescriptorBufferInfo(**referenceBuffer, 0u, VK_WHOLE_SIZE);
241 			DescriptorSetUpdateBuilder()
242 				.writeSingle(*referenceDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &referenceAS)
243 				.writeSingle(*referenceDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &referenceSSBO)
244 				.update(vkd, device);
245 
246 			const VkWriteDescriptorSetAccelerationStructureKHR	resultAS	= makeASWriteDescriptorSet(m_resultTLAS->getPtr());
247 			const VkDescriptorBufferInfo						resultSSBO	= makeDescriptorBufferInfo(**resultBuffer, 0u, VK_WHOLE_SIZE);
248 			DescriptorSetUpdateBuilder()
249 				.writeSingle(*resultDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &resultAS)
250 				.writeSingle(*resultDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultSSBO)
251 				.update(vkd, device);
252 		}
253 
254 		// wait for data transfers
255 		const VkMemoryBarrier bufferUploadBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
256 		cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &bufferUploadBarrier, 1u);
257 
258 		// wait for as build
259 		const VkMemoryBarrier asBuildBarrier = makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR);
260 		cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &asBuildBarrier, 1u);
261 
262 		vkd.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipeline);
263 
264 		// generate reference
265 		vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipelineLayout, 0, 1, &referenceDescriptorSet.get(), 0, DE_NULL);
266 		cmdTraceRays(vkd, *m_cmdBuffer, &rgenSBTR, &missSBTR, &chitSBTR, &callableSBTR, imageSize, imageSize, 1);
267 
268 		// generate result
269 		vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipelineLayout, 0, 1, &resultDescriptorSet.get(), 0, DE_NULL);
270 		cmdTraceRays(vkd, *m_cmdBuffer, &rgenSBTR, &missSBTR, &chitSBTR, &callableSBTR, imageSize, imageSize, 1);
271 
272 		const VkMemoryBarrier postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
273 		cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
274 	}
275 	endCommandBuffer(vkd, *m_cmdBuffer);
276 
277 	submitCommandsAndWait(vkd, device, queue, m_cmdBuffer.get());
278 
279 	// verify result buffer
280 	auto referenceAllocation = referenceBuffer->getAllocation();
281 	invalidateMappedMemoryRange(vkd, device, referenceAllocation.getMemory(), referenceAllocation.getOffset(), resultBufferSize);
282 
283 	auto resultAllocation = resultBuffer->getAllocation();
284 	invalidateMappedMemoryRange(vkd, device, resultAllocation.getMemory(), resultAllocation.getOffset(), resultBufferSize);
285 
286 	tcu::TextureFormat		imageFormat		(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
287 	tcu::PixelBufferAccess	referenceAccess	(imageFormat, imageSize, imageSize, 1, referenceAllocation.getHostPtr());
288 	tcu::PixelBufferAccess	resultAccess	(imageFormat, imageSize, imageSize, 1, resultAllocation.getHostPtr());
289 
290 	if (tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Result comparison", "", referenceAccess, resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_EVERYTHING))
291 		return tcu::TestStatus::pass("Pass");
292 	return tcu::TestStatus::fail("Fail");
293 }
294 
makeASWriteDescriptorSet(const VkAccelerationStructureKHR * pAccelerationStructure)295 VkWriteDescriptorSetAccelerationStructureKHR RayTracingProceduralGeometryTestBase::makeASWriteDescriptorSet(const VkAccelerationStructureKHR* pAccelerationStructure)
296 {
297 	return
298 	{
299 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,	// VkStructureType						sType
300 		DE_NULL,															// const void*							pNext
301 		1u,																	// deUint32								accelerationStructureCount
302 		pAccelerationStructure												// const VkAccelerationStructureKHR*	pAccelerationStructures
303 	};
304 }
305 
clearBuffer(de::SharedPtr<BufferWithMemory> buffer,VkDeviceSize bufferSize)306 void RayTracingProceduralGeometryTestBase::clearBuffer(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize)
307 {
308 	const DeviceInterface&	vkd				= *m_customDevice.vkd;
309 	const VkDevice			device			= *m_customDevice.device;
310 	auto&					bufferAlloc		= buffer->getAllocation();
311 	void*					bufferPtr		= bufferAlloc.getHostPtr();
312 
313 	deMemset(bufferPtr, 1, static_cast<size_t>(bufferSize));
314 	vk::flushAlloc(vkd, device, bufferAlloc);
315 }
316 
317 class ObjectBehindBoundingBoxInstance : public RayTracingProceduralGeometryTestBase
318 {
319 public:
320 
321 	ObjectBehindBoundingBoxInstance(Context& context);
322 
323 	void setupRayTracingPipeline() override;
324 	void setupAccelerationStructures() override;
325 };
326 
ObjectBehindBoundingBoxInstance(Context & context)327 ObjectBehindBoundingBoxInstance::ObjectBehindBoundingBoxInstance(Context& context)
328 	: RayTracingProceduralGeometryTestBase(context)
329 {
330 }
331 
setupRayTracingPipeline()332 void ObjectBehindBoundingBoxInstance::setupRayTracingPipeline()
333 {
334 	const DeviceInterface&	vkd				= *m_customDevice.vkd;
335 	const VkDevice			device			= *m_customDevice.device;
336 	Allocator&				allocator		= *m_customDevice.allocator;
337 	vk::BinaryCollection&	bc				= m_context.getBinaryCollection();
338 	const deUint32			sgHandleSize	= m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
339 	const deUint32			sgBaseAlignment	= m_context.getRayTracingPipelineProperties().shaderGroupBaseAlignment;
340 
341 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,			createShaderModule(vkd, device, bc.get("rgen"), 0), 0);
342 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,	createShaderModule(vkd, device, bc.get("isec"), 0), 1);
343 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,	createShaderModule(vkd, device, bc.get("chit"), 0), 1);
344 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,			createShaderModule(vkd, device, bc.get("miss"), 0), 2);
345 
346 	m_pipelineLayout	= makePipelineLayout(vkd, device, m_descriptorSetLayout.get());
347 	m_pipeline			= m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
348 	m_rgenShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 0, 1);
349 	m_chitShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 1, 1);
350 	m_missShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 2, 1);
351 }
352 
setupAccelerationStructures()353 void ObjectBehindBoundingBoxInstance::setupAccelerationStructures()
354 {
355 	const DeviceInterface&	vkd			= *m_customDevice.vkd;
356 	const VkDevice			device		= *m_customDevice.device;
357 	Allocator&				allocator	= *m_customDevice.allocator;
358 
359 	// build reference acceleration structure - single aabb big enough to fit whole procedural geometry
360 	de::SharedPtr<BottomLevelAccelerationStructure> referenceBLAS(makeBottomLevelAccelerationStructure().release());
361 	referenceBLAS->setGeometryData(
362 		{
363 			{  0.0,  0.0, -64.0 },
364 			{ 64.0, 64.0, -16.0 },
365 		},
366 		false,
367 		0
368 		);
369 	referenceBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
370 	m_blasVect.push_back(referenceBLAS);
371 
372 	m_referenceTLAS->setInstanceCount(1);
373 	m_referenceTLAS->addInstance(m_blasVect.back());
374 	m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
375 
376 	// build result acceleration structure - wall of 4 aabb's and generated object is actualy behind it (as it is just 1.0 unit thick)
377 	de::SharedPtr<BottomLevelAccelerationStructure> resultBLAS(makeBottomLevelAccelerationStructure().release());
378 	resultBLAS->setGeometryData(
379 		{
380 			{  0.0,  0.0, 0.0 },	// |  |
381 			{ 32.0, 32.0, 1.0 },	// |* |
382 			{ 32.0,  0.0, 0.0 },	//    |  |
383 			{ 64.0, 32.0, 1.0 },	//    | *|
384 			{  0.0, 32.0, 0.0 },	// |* |
385 			{ 32.0, 64.0, 1.0 },	// |  |
386 			{ 32.0, 32.0, 0.0 },	//    | *|
387 			{ 64.0, 64.0, 1.0 },	//    |  |
388 		},
389 		false,
390 		0
391 		);
392 	resultBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
393 	m_blasVect.push_back(resultBLAS);
394 
395 	m_resultTLAS->setInstanceCount(1);
396 	m_resultTLAS->addInstance(m_blasVect.back());
397 	m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
398 }
399 
400 class TriangleInBeteenInstance : public RayTracingProceduralGeometryTestBase
401 {
402 public:
403 
404 	TriangleInBeteenInstance(Context& context);
405 
406 	void setupRayTracingPipeline() override;
407 	void setupAccelerationStructures() override;
408 };
409 
TriangleInBeteenInstance(Context & context)410 TriangleInBeteenInstance::TriangleInBeteenInstance(Context& context)
411 	: RayTracingProceduralGeometryTestBase(context)
412 {
413 }
414 
setupRayTracingPipeline()415 void TriangleInBeteenInstance::setupRayTracingPipeline()
416 {
417 	const DeviceInterface&	vkd				= *m_customDevice.vkd;
418 	const VkDevice			device			= *m_customDevice.device;
419 	Allocator&				allocator		= *m_customDevice.allocator;
420 	vk::BinaryCollection&	bc				= m_context.getBinaryCollection();
421 	const deUint32			sgHandleSize	= m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
422 	const deUint32			sgBaseAlignment = m_context.getRayTracingPipelineProperties().shaderGroupBaseAlignment;
423 
424 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,			createShaderModule(vkd, device, bc.get("rgen"), 0), 0);
425 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,	createShaderModule(vkd, device, bc.get("isec"), 0), 1);
426 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,	createShaderModule(vkd, device, bc.get("chit"), 0), 1);
427 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,	createShaderModule(vkd, device, bc.get("chit_triangle"), 0), 2);
428 	m_rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,			createShaderModule(vkd, device, bc.get("miss"), 0), 3);
429 
430 	m_pipelineLayout	= makePipelineLayout(vkd, device, m_descriptorSetLayout.get());
431 	m_pipeline			= m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
432 	m_rgenShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 0, 1);
433 	m_chitShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 1, 2);
434 	m_missShaderBT		= m_rayTracingPipeline->createShaderBindingTable(vkd, device, *m_pipeline, allocator, sgHandleSize, sgBaseAlignment, 3, 1);
435 }
436 
setupAccelerationStructures()437 void TriangleInBeteenInstance::setupAccelerationStructures()
438 {
439 	const DeviceInterface&	vkd			= *m_customDevice.vkd;
440 	const VkDevice			device		= *m_customDevice.device;
441 	Allocator&				allocator	= *m_customDevice.allocator;
442 
443 	de::SharedPtr<BottomLevelAccelerationStructure> triangleBLAS(makeBottomLevelAccelerationStructure().release());
444 	triangleBLAS->setGeometryData(
445 		{
446 			{ 16.0, 16.0, -8.0 },
447 			{ 56.0, 32.0, -8.0 },
448 			{ 32.0, 48.0, -8.0 },
449 		},
450 		true,
451 		VK_GEOMETRY_OPAQUE_BIT_KHR
452 		);
453 	triangleBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
454 	m_blasVect.push_back(triangleBLAS);
455 
456 	de::SharedPtr<BottomLevelAccelerationStructure> fullElipsoidBLAS(makeBottomLevelAccelerationStructure().release());
457 	fullElipsoidBLAS->setGeometryData(
458 		{
459 			{  0.0,  0.0, -64.0 },
460 			{ 64.0, 64.0, -16.0 },
461 		},
462 		false,
463 		0
464 		);
465 	fullElipsoidBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
466 	m_blasVect.push_back(fullElipsoidBLAS);
467 
468 	// build reference acceleration structure - triangle and a single aabb big enough to fit whole procedural geometry
469 	m_referenceTLAS->setInstanceCount(2);
470 	m_referenceTLAS->addInstance(fullElipsoidBLAS);
471 	m_referenceTLAS->addInstance(triangleBLAS);
472 	m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
473 
474 	de::SharedPtr<BottomLevelAccelerationStructure> elipsoidWallBLAS(makeBottomLevelAccelerationStructure().release());
475 	elipsoidWallBLAS->setGeometryData(
476 		{
477 			{  0.0,  0.0, 0.0 },	// |*  |
478 			{ 20.0, 64.0, 1.0 },
479 			{ 20.0,  0.0, 0.0 },	// | * |
480 			{ 44.0, 64.0, 1.0 },
481 			{ 44.0,  0.0, 0.0 },	// |  *|
482 			{ 64.0, 64.0, 1.0 },
483 		},
484 		false,
485 		0
486 		);
487 	elipsoidWallBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
488 	m_blasVect.push_back(elipsoidWallBLAS);
489 
490 	// build result acceleration structure - triangle and a three aabb's (they are in front of triangle but generate intersections behind it)
491 	m_resultTLAS->setInstanceCount(2);
492 	m_resultTLAS->addInstance(elipsoidWallBLAS);
493 	m_resultTLAS->addInstance(triangleBLAS);
494 	m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
495 }
496 
497 class RayTracingProceduralGeometryTestCase : public TestCase
498 {
499 public:
500 	RayTracingProceduralGeometryTestCase		(tcu::TestContext& context, const char* name, TestType testType);
501 	~RayTracingProceduralGeometryTestCase		(void) = default;
502 
503 	void				checkSupport			(Context& context) const override;
504 	void				initPrograms			(SourceCollections& programCollection) const override;
505 	TestInstance*		createInstance			(Context& context) const override;
506 
507 protected:
508 	TestType m_testType;
509 };
510 
RayTracingProceduralGeometryTestCase(tcu::TestContext & context,const char * name,TestType testType)511 RayTracingProceduralGeometryTestCase::RayTracingProceduralGeometryTestCase(tcu::TestContext& context, const char* name, TestType testType)
512 	: TestCase		(context, name, "")
513 	, m_testType	(testType)
514 {
515 }
516 
checkSupport(Context & context) const517 void RayTracingProceduralGeometryTestCase::checkSupport(Context& context) const
518 {
519 	context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
520 	context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
521 
522 	if (!context.getRayTracingPipelineFeatures().rayTracingPipeline)
523 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
524 
525 	if (!context.getAccelerationStructureFeatures().accelerationStructure)
526 		TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
527 }
528 
initPrograms(SourceCollections & programCollection) const529 void RayTracingProceduralGeometryTestCase::initPrograms(SourceCollections& programCollection) const
530 {
531 	const vk::ShaderBuildOptions glslBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
532 
533 	std::string rgenSource =
534 		"#version 460 core\n"
535 		"#extension GL_EXT_ray_tracing : require\n"
536 		"layout(location = 0) rayPayloadEXT int payload;\n"
537 
538 		"layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;\n"
539 		"layout(set = 0, binding = 1, std430) writeonly buffer Result {\n"
540 		"    int value[];\n"
541 		"} result;\n"
542 
543 		"void main()\n"
544 		"{\n"
545 		"  float tmin        = 0.0;\n"
546 		"  float tmax        = 50.0;\n"
547 		"  vec3  origin      = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 2.0);\n"
548 		"  vec3  direction   = vec3(0.0,0.0,-1.0);\n"
549 		"  uint  resultIndex = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x;\n"
550 
551 		"  traceRayEXT(tlas, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, 0, 0, 0, origin, tmin, direction, tmax, 0);\n"
552 		// to be able to display result in cherry this is interpreated as r8g8b8a8 during verification
553 		// we are using only red but we need to add alpha (note: r and a may be swapped depending on endianness)
554 		"  result.value[resultIndex] = payload + 0xFF000000;\n"
555 		"};\n";
556 	programCollection.glslSources.add("rgen") << glu::RaygenSource(rgenSource) << glslBuildOptions;
557 
558 	std::string isecSource =
559 		"#version 460 core\n"
560 		"#extension GL_EXT_ray_tracing : require\n"
561 
562 		"void main()\n"
563 		"{\n"
564 		// note: same elipsoid center and radii are also defined in chit shader
565 		"  vec3 center = vec3(32.0, 32.0, -30.0);\n"
566 		"  vec3 radii  = vec3(30.0, 15.0, 5.0);\n"
567 
568 		// simplify to ray sphere intersection
569 		"  vec3  eliDir = gl_WorldRayOriginEXT - center;\n"
570 		"  vec3  eliS   = eliDir / radii;\n"
571 		"  vec3  rayS   = gl_WorldRayDirectionEXT / radii;\n"
572 
573 		"  float a = dot(rayS, rayS);\n"
574 		"  float b = dot(eliS, rayS);\n"
575 		"  float c = dot(eliS, eliS);\n"
576 		"  float h = b * b - a * (c - 1.0);\n"
577 		"  if (h < 0.0)\n"
578 		"    return;\n"
579 		"  reportIntersectionEXT((-b - sqrt(h)) / a, 0);\n"
580 		"}\n";
581 	programCollection.glslSources.add("isec") << glu::IntersectionSource(isecSource) << glslBuildOptions;
582 
583 	std::string chitSource =
584 		"#version 460 core\n"
585 		"#extension GL_EXT_ray_tracing : require\n"
586 		"layout(location = 0) rayPayloadInEXT int payload;\n"
587 		"\n"
588 		"void main()\n"
589 		"{\n"
590 		// note: same elipsoid center and radii are also defined in chit shader
591 		"  vec3 center    = vec3(32.0, 32.0, -30.0);\n"
592 		"  vec3 radii     = vec3(30.0, 15.0, 5.0);\n"
593 		"  vec3 lightDir  = normalize(vec3(0.0, 0.0, 1.0));\n"
594 		"  vec3 hitPos    = gl_WorldRayOriginEXT + gl_HitTEXT * gl_WorldRayDirectionEXT;\n"
595 		"  vec3 hitNormal = normalize((hitPos - center) / radii);\n"
596 
597 		"  payload = 50 + int(200.0 * clamp(dot(hitNormal, lightDir), 0.0, 1.0));\n"
598 		"}\n";
599 	programCollection.glslSources.add("chit") << glu::ClosestHitSource(chitSource) << glslBuildOptions;
600 
601 	if (m_testType == TestType::TRIANGLE_IN_BETWEEN)
602 	{
603 		std::string chitTriangleSource =
604 			"#version 460 core\n"
605 			"#extension GL_EXT_ray_tracing : require\n"
606 			"layout(location = 0) rayPayloadInEXT int payload;\n"
607 			"\n"
608 			"void main()\n"
609 			"{\n"
610 			"  payload = 250;\n"
611 			"}\n";
612 		programCollection.glslSources.add("chit_triangle") << glu::ClosestHitSource(chitTriangleSource) << glslBuildOptions;
613 	}
614 
615 	std::string missSource =
616 		"#version 460 core\n"
617 		"#extension GL_EXT_ray_tracing : require\n"
618 		"layout(location = 0) rayPayloadInEXT int payload;\n"
619 		"void main()\n"
620 		"{\n"
621 		"  payload = 30;\n"
622 		"}\n";
623 	programCollection.glslSources.add("miss") << glu::MissSource(missSource) << glslBuildOptions;
624 }
625 
createInstance(Context & context) const626 TestInstance* RayTracingProceduralGeometryTestCase::createInstance(Context& context) const
627 {
628 	if (m_testType == TestType::TRIANGLE_IN_BETWEEN)
629 		return new TriangleInBeteenInstance(context);
630 
631 	// TestType::OBJECT_BEHIND_BOUNDING_BOX
632 	return new ObjectBehindBoundingBoxInstance(context);
633 }
634 
635 }	// anonymous
636 
createProceduralGeometryTests(tcu::TestContext & testCtx)637 tcu::TestCaseGroup*	createProceduralGeometryTests(tcu::TestContext& testCtx)
638 {
639 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "procedural_geometry", "Test procedural geometry with complex bouding box sets"));
640 
641 	group->addChild(new RayTracingProceduralGeometryTestCase(testCtx, "object_behind_bounding_boxes",	TestType::OBJECT_BEHIND_BOUNDING_BOX));
642 	group->addChild(new RayTracingProceduralGeometryTestCase(testCtx, "triangle_in_between",			TestType::TRIANGLE_IN_BETWEEN));
643 
644 	return group.release();
645 }
646 
647 }	// RayTracing
648 
649 }	// vkt
650