1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 NVIDIA Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Ray Tracing Opacity Micromap Tests
23  *//*--------------------------------------------------------------------*/
24 
25 
26 #include "vktRayTracingOpacityMicromapTests.hpp"
27 #include "vktTestCase.hpp"
28 
29 #include "vkRayTracingUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 
37 #include "deUniquePtr.hpp"
38 #include "deRandom.hpp"
39 
40 #include <sstream>
41 #include <vector>
42 #include <iostream>
43 
44 namespace vkt
45 {
46 namespace RayTracing
47 {
48 
49 namespace
50 {
51 
52 using namespace vk;
53 
54 enum TestFlagBits
55 {
56 	TEST_FLAG_BIT_FORCE_OPAQUE_INSTANCE				= 1U << 0,
57 	TEST_FLAG_BIT_FORCE_OPAQUE_RAY_FLAG				= 1U << 1,
58 	TEST_FLAG_BIT_DISABLE_OPACITY_MICROMAP_INSTANCE	= 1U << 2,
59 	TEST_FLAG_BIT_FORCE_2_STATE_INSTANCE			= 1U << 3,
60 	TEST_FLAG_BIT_FORCE_2_STATE_RAY_FLAG			= 1U << 4,
61 	TEST_FLAG_BIT_LAST								= 1U << 5,
62 };
63 
64 std::vector<std::string> testFlagBitNames =
65 {
66 	"force_opaque_instance",
67 	"force_opaque_ray_flag",
68 	"disable_opacity_micromap_instance",
69 	"force_2_state_instance",
70 	"force_2_state_ray_flag",
71 };
72 
73 struct TestParams
74 {
75 	bool					useSpecialIndex;
76 	deUint32				testFlagMask;
77 	deUint32				subdivisionLevel; // Must be 0 for useSpecialIndex
78 	deUint32				mode; // Special index value if useSpecialIndex, 2 or 4 for number of states otherwise
79 	deUint32				seed;
80 };
81 
82 class OpacityMicromapCase : public TestCase
83 {
84 public:
85 	OpacityMicromapCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~OpacityMicromapCase(void)86 	virtual					~OpacityMicromapCase(void) {}
87 
88 	virtual void			checkSupport(Context& context) const;
89 	virtual void			initPrograms(vk::SourceCollections& programCollection) const;
90 	virtual TestInstance* createInstance(Context& context) const;
91 
92 protected:
93 	TestParams				m_params;
94 };
95 
96 class OpacityMicromapInstance : public TestInstance
97 {
98 public:
99 	OpacityMicromapInstance(Context& context, const TestParams& params);
~OpacityMicromapInstance(void)100 	virtual						~OpacityMicromapInstance(void) {}
101 
102 	virtual tcu::TestStatus		iterate(void);
103 
104 protected:
105 	TestParams					m_params;
106 };
107 
OpacityMicromapCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)108 OpacityMicromapCase::OpacityMicromapCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
109 	: TestCase	(testCtx, name, description)
110 	, m_params	(params)
111 {}
112 
checkSupport(Context& context) const113 void OpacityMicromapCase::checkSupport (Context& context) const
114 {
115 	context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
116 	context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
117 	context.requireDeviceFunctionality("VK_EXT_opacity_micromap");
118 
119 	const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
120 	if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE)
121 		TCU_THROW(TestError, "VK_KHR_ray_query requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
122 
123 	const VkPhysicalDeviceOpacityMicromapFeaturesEXT& opacityMicromapFeaturesEXT = context.getOpacityMicromapFeaturesEXT();
124 	if (opacityMicromapFeaturesEXT.micromap == DE_FALSE)
125 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceOpacityMicromapFeaturesEXT.micromap");
126 
127 	const VkPhysicalDeviceOpacityMicromapPropertiesEXT& opacityMicromapPropertiesEXT = context.getOpacityMicromapPropertiesEXT();
128 
129 	if (!m_params.useSpecialIndex)
130 	{
131 		switch (m_params.mode)
132 		{
133 		case 2:
134 			if (m_params.subdivisionLevel > opacityMicromapPropertiesEXT.maxOpacity2StateSubdivisionLevel)
135 				TCU_THROW(NotSupportedError, "Requires a higher supported 2 state subdivision level");
136 			break;
137 		case 4:
138 			if (m_params.subdivisionLevel > opacityMicromapPropertiesEXT.maxOpacity4StateSubdivisionLevel)
139 				TCU_THROW(NotSupportedError, "Requires a higher supported 4 state subdivision level");
140 			break;
141 		default:
142 			DE_ASSERT(false);
143 			break;
144 		}
145 	}
146 }
147 
levelToSubtriangles(deUint32 level)148 static deUint32 levelToSubtriangles(deUint32 level)
149 {
150 	return 1 << (2 * level);
151 }
152 
153 
initPrograms(vk::SourceCollections& programCollection) const154 void OpacityMicromapCase::initPrograms (vk::SourceCollections& programCollection) const
155 {
156 	const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
157 
158 	deUint32 numRays = levelToSubtriangles(m_params.subdivisionLevel);
159 
160 	std::ostringstream layoutDecls;
161 	layoutDecls
162 		<< "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
163 		<< "layout(set=0, binding=1, std430) buffer RayOrigins {\n"
164 		<< "  vec4 values[" << numRays << "];\n"
165 		<< "} origins;\n"
166 		<< "layout(set=0, binding=2, std430) buffer OutputModes {\n"
167 		<< "  uint values[" << numRays << "];\n"
168 		<< "} modes;\n"
169 		;
170 	const auto layoutDeclsStr = layoutDecls.str();
171 
172 	std::string flagsString = (m_params.testFlagMask & TEST_FLAG_BIT_FORCE_OPAQUE_RAY_FLAG) ? "gl_RayFlagsOpaqueEXT" : "gl_RayFlagsNoneEXT";
173 
174 	if (m_params.testFlagMask & TEST_FLAG_BIT_FORCE_2_STATE_RAY_FLAG)
175 		flagsString += " | gl_RayFlagsForceOpacityMicromap2StateEXT";
176 
177 	std::ostringstream rgen;
178 	rgen
179 		<< "#version 460 core\n"
180 		<< "#extension GL_EXT_ray_tracing : require\n"
181 		<< "#extension GL_EXT_opacity_micromap : require\n"
182 		<< "\n"
183 		<< "layout(location=0) rayPayloadEXT uint value;\n"
184 		<< "\n"
185 		<< layoutDeclsStr
186 		<< "\n"
187 		<< "void main()\n"
188 		<< "{\n"
189 		<< "  const uint  cullMask  = 0xFF;\n"
190 		<< "  const vec3  origin    = origins.values[gl_LaunchIDEXT.x].xyz;\n"
191 		<< "  const vec3  direction = vec3(0.0, 0.0, -1.0);\n"
192 		<< "  const float tMin      = 0.0;\n"
193 		<< "  const float tMax      = 2.0;\n"
194 		<< "  value                 = 0xFFFFFFFF;\n"
195 		<< "  traceRayEXT(topLevelAS, " << flagsString << ", cullMask, 0, 0, 0, origin, tMin, direction, tMax, 0);\n"
196 		<< "  modes.values[gl_LaunchIDEXT.x] = value;\n"
197 		<< "}\n"
198 		;
199 
200 	std::ostringstream ah;
201 	ah
202 		<< "#version 460 core\n"
203 		<< "#extension GL_EXT_ray_tracing : require\n"
204 		<< "\n"
205 		<< layoutDeclsStr
206 		<< "\n"
207 		<< "layout(location=0) rayPayloadInEXT uint value;\n"
208 		<< "\n"
209 		<< "void main()\n"
210 		<< "{\n"
211 		<< "  value = 1;\n"
212 		<< "  terminateRayEXT;\n"
213 		<< "}\n"
214 		;
215 
216 	std::ostringstream ch;
217 	ch
218 		<< "#version 460 core\n"
219 		<< "#extension GL_EXT_ray_tracing : require\n"
220 		<< "\n"
221 		<< layoutDeclsStr
222 		<< "\n"
223 		<< "layout(location=0) rayPayloadInEXT uint value;\n"
224 		<< "\n"
225 		<< "void main()\n"
226 		<< "{\n"
227 		<< "  if (value != 1) {\n" // If we didn't already run AH mark as CH
228 		<< "    value = 2;\n"
229 		<< "  }\n"
230 		<< "}\n"
231 		;
232 
233 	std::ostringstream miss;
234 	miss
235 		<< "#version 460 core\n"
236 		<< "#extension GL_EXT_ray_tracing : require\n"
237 		<< layoutDeclsStr
238 		<< "\n"
239 		<< "layout(location=0) rayPayloadInEXT uint value;\n"
240 		<< "\n"
241 		<< "void main()\n"
242 		<< "{\n"
243 		<< "  value = 0;\n"
244 		<< "}\n";
245 
246 	programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
247 	programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions;
248 	programCollection.glslSources.add("ah") << glu::AnyHitSource(updateRayTracingGLSL(ah.str())) << buildOptions;
249 	programCollection.glslSources.add("ch") << glu::ClosestHitSource(updateRayTracingGLSL(ch.str())) << buildOptions;
250 }
251 
createInstance(Context& context) const252 TestInstance* OpacityMicromapCase::createInstance (Context& context) const
253 {
254 	return new OpacityMicromapInstance(context, m_params);
255 }
256 
OpacityMicromapInstance(Context& context, const TestParams& params)257 OpacityMicromapInstance::OpacityMicromapInstance (Context& context, const TestParams& params)
258 	: TestInstance	(context)
259 	, m_params		(params)
260 {}
261 
calcSubtriangleCentroid(const deUint32 index, const deUint32 subdivisionLevel)262 tcu::Vec2 calcSubtriangleCentroid(const deUint32 index, const deUint32 subdivisionLevel)
263 {
264 	if (subdivisionLevel == 0) {
265 		return tcu::Vec2(1.0f / 3.0f, 1.0f / 3.0f);
266 	}
267 
268 	deUint32 d = index;
269 
270 	d = ((d >> 1) & 0x22222222u) | ((d << 1) & 0x44444444u) | (d & 0x99999999u);
271 	d = ((d >> 2) & 0x0c0c0c0cu) | ((d << 2) & 0x30303030u) | (d & 0xc3c3c3c3u);
272 	d = ((d >> 4) & 0x00f000f0u) | ((d << 4) & 0x0f000f00u) | (d & 0xf00ff00fu);
273 	d = ((d >> 8) & 0x0000ff00u) | ((d << 8) & 0x00ff0000u) | (d & 0xff0000ffu);
274 
275 	deUint32 f = (d & 0xffffu) | ((d << 16) & ~d);
276 
277 	f ^= (f >> 1) & 0x7fff7fffu;
278 	f ^= (f >> 2) & 0x3fff3fffu;
279 	f ^= (f >> 4) & 0x0fff0fffu;
280 	f ^= (f >> 8) & 0x00ff00ffu;
281 
282 	deUint32 t = (f ^ d) >> 16;
283 
284 	deUint32 iu = ((f & ~t) | (d & ~t) | (~d & ~f & t)) & 0xffffu;
285 	deUint32 iv = ((f >> 16) ^ d) & 0xffffu;
286 	deUint32 iw = ((~f & ~t) | (d & ~t) | (~d & f & t)) & ((1 << subdivisionLevel) - 1);
287 
288 	const float scale = 1.0f / float(1 << subdivisionLevel);
289 
290 	float u = (1.0f / 3.0f) * scale;
291 	float v = (1.0f / 3.0f) * scale;
292 
293 	// we need to only look at "subdivisionLevel" bits
294 	iu = iu & ((1 << subdivisionLevel) - 1);
295 	iv = iv & ((1 << subdivisionLevel) - 1);
296 	iw = iw & ((1 << subdivisionLevel) - 1);
297 
298 	bool upright = (iu & 1) ^ (iv & 1) ^ (iw & 1);
299 	if (!upright)
300 	{
301 		iu = iu + 1;
302 		iv = iv + 1;
303 	}
304 
305 	if (upright)
306 	{
307 		return tcu::Vec2(
308 			u + (float)iu * scale,
309 			v + (float)iv * scale
310 		);
311 	} else
312 	{
313 		return tcu::Vec2(
314 			(float)iu * scale - u,
315 			(float)iv * scale - v
316 		);
317 	}
318 }
319 
iterate(void)320 tcu::TestStatus OpacityMicromapInstance::iterate (void)
321 {
322 	const auto&	vki		= m_context.getInstanceInterface();
323 	const auto	physDev	= m_context.getPhysicalDevice();
324 	const auto&	vkd		= m_context.getDeviceInterface();
325 	const auto	device	= m_context.getDevice();
326 	auto&		alloc	= m_context.getDefaultAllocator();
327 	const auto	qIndex	= m_context.getUniversalQueueFamilyIndex();
328 	const auto	queue	= m_context.getUniversalQueue();
329 	const auto	stages	= VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
330 
331 	// Command pool and buffer.
332 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
333 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
334 	const auto cmdBuffer	= cmdBufferPtr.get();
335 
336 	beginCommandBuffer(vkd, cmdBuffer);
337 
338 	// Build acceleration structures.
339 	auto topLevelAS		= makeTopLevelAccelerationStructure();
340 	auto bottomLevelAS	= makeBottomLevelAccelerationStructure();
341 
342 	deUint32 numSubtriangles = levelToSubtriangles(m_params.subdivisionLevel);
343 	deUint32 opacityMicromapBytes = (m_params.mode == 2) ? (numSubtriangles + 3) / 4 : (numSubtriangles + 1) / 2;
344 
345 	// Generate random micromap data
346 	std::vector<deUint8> opacityMicromapData;
347 
348 	de::Random rnd(m_params.seed);
349 
350 	while (opacityMicromapData.size() < opacityMicromapBytes) {
351 		opacityMicromapData.push_back(rnd.getUint8());
352 	}
353 
354 	// Build a micromap (ignore infrastructure for now)
355 	// Create the buffer with the mask and index data
356 	// Allocate a fairly conservative bound for now
357 	const auto micromapDataBufferSize = static_cast<VkDeviceSize>(1024 + opacityMicromapBytes);
358 	const auto micromapDataBufferCreateInfo = makeBufferCreateInfo(micromapDataBufferSize,
359 		VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
360 	BufferWithMemory micromapDataBuffer(vkd, device, alloc, micromapDataBufferCreateInfo, MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress);
361 	auto& micromapDataBufferAlloc = micromapDataBuffer.getAllocation();
362 	void* micromapDataBufferData = micromapDataBufferAlloc.getHostPtr();
363 
364 	const int TriangleOffset = 0;
365 	const int IndexOffset = 256;
366 	const int DataOffset = 512;
367 
368 	// Fill out VkMicromapUsageEXT with size information
369 	VkMicromapUsageEXT mmUsage = { };
370 	mmUsage.count = 1;
371 	mmUsage.subdivisionLevel = m_params.subdivisionLevel;
372 	mmUsage.format = m_params.mode == 2 ? VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT : VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT;
373 
374 	{
375 		deUint8* data = static_cast<deUint8*>(micromapDataBufferData);
376 
377 		deMemset(data, 0, size_t(micromapDataBufferCreateInfo.size));
378 
379 		DE_STATIC_ASSERT(sizeof(VkMicromapTriangleEXT) == 8);
380 
381 		// Triangle information
382 		VkMicromapTriangleEXT* tri = (VkMicromapTriangleEXT*)(&data[TriangleOffset]);
383 		tri->dataOffset = 0;
384 		tri->subdivisionLevel = uint16_t(mmUsage.subdivisionLevel);
385 		tri->format = uint16_t(mmUsage.format);
386 
387 		// Micromap data
388 		{
389 			for (size_t i = 0; i < opacityMicromapData.size(); i++) {
390 				data[DataOffset + i] = opacityMicromapData[i];
391 			}
392 		}
393 
394 		// Index information
395 		*((deUint32*)&data[IndexOffset]) = m_params.useSpecialIndex ? m_params.mode : 0;
396 	}
397 
398 	// Query the size from the build info
399 	VkMicromapBuildInfoEXT mmBuildInfo = {
400 		VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT,	// VkStructureType						sType;
401 		DE_NULL,									// const void*							pNext;
402 		VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT,		// VkMicromapTypeEXT					type;
403 		0,											// VkBuildMicromapFlagsEXT				flags;
404 		VK_BUILD_MICROMAP_MODE_BUILD_EXT,			// VkBuildMicromapModeEXT				mode;
405 		DE_NULL,									// VkMicromapEXT						dstMicromap;
406 		1,											// uint32_t							usageCountsCount;
407 		&mmUsage,									// const VkMicromapUsageEXT*			pUsageCounts;
408 		DE_NULL,									// const VkMicromapUsageEXT* const*	ppUsageCounts;
409 		makeDeviceOrHostAddressConstKHR(DE_NULL),	// VkDeviceOrHostAddressConstKHR		data;
410 		makeDeviceOrHostAddressKHR(DE_NULL),		// VkDeviceOrHostAddressKHR			scratchData;
411 		makeDeviceOrHostAddressConstKHR(DE_NULL),	// VkDeviceOrHostAddressConstKHR		triangleArray;
412 		0,											// VkDeviceSize						triangleArrayStride;
413 	};
414 
415 	VkMicromapBuildSizesInfoEXT sizeInfo = {
416 		VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT,	// VkStructureType	sType;
417 		DE_NULL,											// const void* pNext;
418 		0,													// VkDeviceSize	micromapSize;
419 		0,													// VkDeviceSize	buildScratchSize;
420 		DE_FALSE,											// VkBool32		discardable;
421 	};
422 
423 	vkd.getMicromapBuildSizesEXT(device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &mmBuildInfo, &sizeInfo);
424 
425 	// Create the backing and scratch storage
426 	const auto micromapBackingBufferCreateInfo = makeBufferCreateInfo(sizeInfo.micromapSize,
427 		VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
428 	BufferWithMemory micromapBackingBuffer(vkd, device, alloc, micromapBackingBufferCreateInfo, MemoryRequirement::Local | MemoryRequirement::DeviceAddress);
429 
430 	const auto micromapScratchBufferCreateInfo = makeBufferCreateInfo(sizeInfo.buildScratchSize,
431 		VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
432 	BufferWithMemory micromapScratchBuffer(vkd, device, alloc, micromapScratchBufferCreateInfo, MemoryRequirement::Local | MemoryRequirement::DeviceAddress);
433 
434 	// Create the micromap itself
435 	VkMicromapCreateInfoEXT maCreateInfo = {
436 		VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT,	  // VkStructureType				sType;
437 		DE_NULL,									  // const void* pNext;
438 		0,											  // VkMicromapCreateFlagsEXT	createFlags;
439 		micromapBackingBuffer.get(),				  // VkBuffer					buffer;
440 		0,											  // VkDeviceSize				offset;
441 		sizeInfo.micromapSize,						  // VkDeviceSize				size;
442 		VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT,		  // VkMicromapTypeEXT			type;
443 		0ull										  // VkDeviceAddress				deviceAddress;
444 	};
445 
446 	VkMicromapEXT micromap;
447 
448 	VK_CHECK(vkd.createMicromapEXT(device, &maCreateInfo, nullptr, &micromap));
449 
450 	// Do the build
451 	mmBuildInfo.dstMicromap = micromap;
452 	mmBuildInfo.data = makeDeviceOrHostAddressConstKHR(vkd, device, micromapDataBuffer.get(), DataOffset);
453 	mmBuildInfo.triangleArray = makeDeviceOrHostAddressConstKHR(vkd, device, micromapDataBuffer.get(), TriangleOffset);
454 	mmBuildInfo.scratchData = makeDeviceOrHostAddressKHR(vkd, device, micromapScratchBuffer.get(), 0);
455 
456 	vkd.cmdBuildMicromapsEXT(cmdBuffer, 1, &mmBuildInfo);
457 
458 	{
459 		VkMemoryBarrier2 memoryBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, NULL,
460 			VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT, VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT,
461 			VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_ACCESS_2_MICROMAP_READ_BIT_EXT };
462 		VkDependencyInfoKHR dependencyInfo = {
463 			VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,		// VkStructureType						sType;
464 			DE_NULL,									// const void*							pNext;
465 			0u,											// VkDependencyFlags					dependencyFlags;
466 			1u,											// uint32_t							memoryBarrierCount;
467 			&memoryBarrier,								// const VkMemoryBarrier2KHR*			pMemoryBarriers;
468 			0u,											// uint32_t							bufferMemoryBarrierCount;
469 			DE_NULL,									// const VkBufferMemoryBarrier2KHR*	pBufferMemoryBarriers;
470 			0u,											// uint32_t							imageMemoryBarrierCount;
471 			DE_NULL,									// const VkImageMemoryBarrier2KHR*		pImageMemoryBarriers;
472 		};
473 
474 		vkd.cmdPipelineBarrier2(cmdBuffer, &dependencyInfo);
475 	}
476 
477 	// Attach the micromap to the geometry
478 	VkAccelerationStructureTrianglesOpacityMicromapEXT opacityGeometryMicromap = {
479 		VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT,				//VkStructureType						sType;
480 		DE_NULL,																				//void*								pNext;
481 		VK_INDEX_TYPE_UINT32,																	//VkIndexType							indexType;
482 		makeDeviceOrHostAddressConstKHR(vkd, device, micromapDataBuffer.get(), IndexOffset),	//VkDeviceOrHostAddressConstKHR		indexBuffer;
483 		0u,																						//VkDeviceSize						indexStride;
484 		0u,																						//uint32_t							baseTriangle;
485 		1u,																						//uint32_t							usageCountsCount;
486 		& mmUsage,																				//const VkMicromapUsageEXT*			pUsageCounts;
487 		DE_NULL,																				//const VkMicromapUsageEXT* const*	ppUsageCounts;
488 		micromap																				//VkMicromapEXT						micromap;
489 	};
490 
491 	const std::vector<tcu::Vec3> triangle =
492 	{
493 		tcu::Vec3(0.0f, 0.0f, 0.0f),
494 		tcu::Vec3(1.0f, 0.0f, 0.0f),
495 		tcu::Vec3(0.0f, 1.0f, 0.0f),
496 	};
497 
498 	bottomLevelAS->addGeometry(triangle, true/*is triangles*/, 0, &opacityGeometryMicromap);
499 	if (m_params.testFlagMask & TEST_FLAG_BIT_DISABLE_OPACITY_MICROMAP_INSTANCE)
500 		bottomLevelAS->setBuildFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT);
501 	bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
502 	de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
503 
504 	VkGeometryInstanceFlagsKHR instanceFlags = 0;
505 
506 	if (m_params.testFlagMask & TEST_FLAG_BIT_FORCE_2_STATE_INSTANCE)
507 		instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT;
508 	if (m_params.testFlagMask & TEST_FLAG_BIT_FORCE_OPAQUE_INSTANCE)
509 		instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR;
510 	if (m_params.testFlagMask & TEST_FLAG_BIT_DISABLE_OPACITY_MICROMAP_INSTANCE)
511 		instanceFlags |= VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT;
512 
513 	topLevelAS->setInstanceCount(1);
514 	topLevelAS->addInstance(blasSharedPtr, identityMatrix3x4, 0, 0xFFu, 0u, instanceFlags);
515 	topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
516 
517 	// One ray per subtriangle for this test
518 	deUint32 numRays = numSubtriangles;
519 
520 	// SSBO buffer for origins.
521 	const auto originsBufferSize		= static_cast<VkDeviceSize>(sizeof(tcu::Vec4) * numRays);
522 	const auto originsBufferInfo		= makeBufferCreateInfo(originsBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
523 	BufferWithMemory originsBuffer	(vkd, device, alloc, originsBufferInfo, MemoryRequirement::HostVisible);
524 	auto& originsBufferAlloc			= originsBuffer.getAllocation();
525 	void* originsBufferData				= originsBufferAlloc.getHostPtr();
526 
527 	std::vector<tcu::Vec4> origins;
528 	std::vector<deUint32> expectedOutputModes;
529 	origins.reserve(numRays);
530 	expectedOutputModes.reserve(numRays);
531 
532 	// Fill in vector of expected outputs
533 	for (deUint32 index = 0; index < numRays; index++) {
534 		deUint32 state = m_params.testFlagMask & (TEST_FLAG_BIT_FORCE_OPAQUE_INSTANCE | TEST_FLAG_BIT_FORCE_OPAQUE_RAY_FLAG) ?
535 			VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT : VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT;
536 
537 		if (!(m_params.testFlagMask & TEST_FLAG_BIT_DISABLE_OPACITY_MICROMAP_INSTANCE))
538 		{
539 			if (m_params.useSpecialIndex)
540 			{
541 				state = m_params.mode;
542 			}
543 			else
544 			{
545 				if (m_params.mode == 2) {
546 					deUint8 byte = opacityMicromapData[index / 8];
547 					state = (byte >> (index % 8)) & 0x1;
548 				} else {
549 					DE_ASSERT(m_params.mode == 4);
550 					deUint8 byte = opacityMicromapData[index / 4];
551 					state = (byte >> 2*(index % 4)) & 0x3;
552 				}
553 				// Process in SPECIAL_INDEX number space
554 				state = ~state;
555 			}
556 
557 			if (m_params.testFlagMask & (TEST_FLAG_BIT_FORCE_2_STATE_INSTANCE | TEST_FLAG_BIT_FORCE_2_STATE_RAY_FLAG))
558 			{
559 				if (state == deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT))
560 					state =  deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT);
561 				if (state == deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT))
562 					state =  deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT);
563 			}
564 		}
565 
566 		if (state != deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT))
567 		{
568 			if (m_params.testFlagMask & (TEST_FLAG_BIT_FORCE_OPAQUE_INSTANCE | TEST_FLAG_BIT_FORCE_OPAQUE_RAY_FLAG))
569 			{
570 				state = deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT);
571 			} else if (state != deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT)) {
572 				state = deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT);
573 			}
574 		}
575 
576 		if (state == deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT))
577 		{
578 			expectedOutputModes.push_back(0);
579 		}
580 		else if (state == deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT))
581 		{
582 			expectedOutputModes.push_back(1);
583 		}
584 		else if (state == deUint32(VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT))
585 		{
586 			expectedOutputModes.push_back(2);
587 		}
588 		else
589 		{
590 			DE_ASSERT(false);
591 		}
592 	}
593 
594 	for (deUint32 index = 0; index < numRays; index++) {
595 		tcu::Vec2 centroid = calcSubtriangleCentroid(index, m_params.subdivisionLevel);
596 		origins.push_back(tcu::Vec4(centroid.x(), centroid.y(), 1.0, 0.0));
597 	}
598 
599 	const auto				originsBufferSizeSz = static_cast<size_t>(originsBufferSize);
600 	deMemcpy(originsBufferData, origins.data(), originsBufferSizeSz);
601 	flushAlloc(vkd, device, originsBufferAlloc);
602 
603 	// Storage buffer for output modes
604 	const auto outputModesBufferSize = static_cast<VkDeviceSize>(sizeof(deUint32) * numRays);
605 	const auto outputModesBufferInfo = makeBufferCreateInfo(outputModesBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
606 	BufferWithMemory outputModesBuffer(vkd, device, alloc, outputModesBufferInfo, MemoryRequirement::HostVisible);
607 	auto& outputModesBufferAlloc = outputModesBuffer.getAllocation();
608 	void* outputModesBufferData = outputModesBufferAlloc.getHostPtr();
609 	deMemset(outputModesBufferData, 0xFF, static_cast<size_t>(outputModesBufferSize));
610 	flushAlloc(vkd, device, outputModesBufferAlloc);
611 
612 	// Descriptor set layout.
613 	DescriptorSetLayoutBuilder dsLayoutBuilder;
614 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
615 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
616 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
617 	const auto setLayout = dsLayoutBuilder.build(vkd, device);
618 
619 	// Pipeline layout.
620 	const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
621 
622 	// Descriptor pool and set.
623 	DescriptorPoolBuilder poolBuilder;
624 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
625 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
626 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
627 	const auto descriptorPool	= poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
628 	const auto descriptorSet	= makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
629 
630 	// Update descriptor set.
631 	{
632 		const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
633 		{
634 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
635 			nullptr,
636 			1u,
637 			topLevelAS.get()->getPtr(),
638 		};
639 		const auto inStorageBufferInfo = makeDescriptorBufferInfo(originsBuffer.get(), 0ull, VK_WHOLE_SIZE);
640 		const auto storageBufferInfo = makeDescriptorBufferInfo(outputModesBuffer.get(), 0ull, VK_WHOLE_SIZE);
641 
642 		DescriptorSetUpdateBuilder updateBuilder;
643 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
644 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inStorageBufferInfo);
645 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageBufferInfo);
646 		updateBuilder.update(vkd, device);
647 	}
648 
649 	// Shader modules.
650 	auto rgenModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0);
651 	auto missModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("miss"), 0);
652 	auto ahModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("ah"), 0);
653 	auto chModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("ch"), 0);
654 
655 	// Get some ray tracing properties.
656 	deUint32 shaderGroupHandleSize		= 0u;
657 	deUint32 shaderGroupBaseAlignment	= 1u;
658 	{
659 		const auto rayTracingPropertiesKHR	= makeRayTracingProperties(vki, physDev);
660 		shaderGroupHandleSize				= rayTracingPropertiesKHR->getShaderGroupHandleSize();
661 		shaderGroupBaseAlignment			= rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
662 	}
663 
664 	// Create raytracing pipeline and shader binding tables.
665 	Move<VkPipeline>				pipeline;
666 	de::MovePtr<BufferWithMemory>	raygenSBT;
667 	de::MovePtr<BufferWithMemory>	missSBT;
668 	de::MovePtr<BufferWithMemory>	hitSBT;
669 	de::MovePtr<BufferWithMemory>	callableSBT;
670 
671 	auto raygenSBTRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
672 	auto missSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
673 	auto hitSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
674 	auto callableSBTRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
675 
676 	{
677 		const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
678 		rayTracingPipeline->setCreateFlags(VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT);
679 		rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,      rgenModule, 0);
680 		rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,        missModule, 1);
681 		rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR,     ahModule, 2);
682 		rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chModule, 2);
683 
684 		pipeline		= rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
685 
686 		raygenSBT		= rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
687 		raygenSBTRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
688 
689 		missSBT			= rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
690 		missSBTRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
691 
692 		hitSBT			= rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 2, 1);
693 		hitSBTRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
694 	}
695 
696 	// Trace rays.
697 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
698 	vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
699 	vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, numRays, 1u, 1u);
700 
701 	// Barrier for the output buffer.
702 	const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
703 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
704 
705 	endCommandBuffer(vkd, cmdBuffer);
706 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
707 
708 	// Verify results.
709 	std::vector<deUint32>	outputData(expectedOutputModes.size());
710 	const auto				outputModesBufferSizeSz = static_cast<size_t>(outputModesBufferSize);
711 
712 	invalidateAlloc(vkd, device, outputModesBufferAlloc);
713 	DE_ASSERT(de::dataSize(outputData) == outputModesBufferSizeSz);
714 	deMemcpy(outputData.data(), outputModesBufferData, outputModesBufferSizeSz);
715 
716 	for (size_t i = 0; i < outputData.size(); ++i)
717 	{
718 		const auto& outVal = outputData[i];
719 		const auto& expectedVal = expectedOutputModes[i];
720 
721 		if (outVal != expectedVal)
722 		{
723 			std::ostringstream msg;
724 			msg << "Unexpected value found for ray " << i << ": expected " << expectedVal << " and found " << outVal << ";";
725 			TCU_FAIL(msg.str());
726 		}
727 #if 0
728 		else
729 		{
730 			std::ostringstream msg;
731 			msg << "Expected value found for ray " << i << ": expected " << expectedVal << " and found " << outVal << ";\n"; // XXX Debug remove
732 			std::cout << msg.str();
733 		}
734 #endif
735 	}
736 
737 
738 	return tcu::TestStatus::pass("Pass");
739 }
740 
741 } // anonymous
742 
743 constexpr deUint32 kMaxSubdivisionLevel = 15;
744 
createOpacityMicromapTests(tcu::TestContext& testCtx)745 tcu::TestCaseGroup*	createOpacityMicromapTests (tcu::TestContext& testCtx)
746 {
747 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "opacity_micromap", "Test acceleration structures using opacity micromap with ray pipelines"));
748 
749 	deUint32 seed = 1614343620u;
750 
751 	const struct
752 	{
753 		bool									useSpecialIndex;
754 		std::string								name;
755 	} specialIndexUse[] =
756 	{
757 		{ false,								"map_value"},
758 		{ true,									"special_index"},
759 	};
760 
761 	for (deUint32 testFlagMask = 0; testFlagMask < TEST_FLAG_BIT_LAST; testFlagMask++)
762 	{
763 		std::string maskName = "";
764 
765 		for (deUint32 bit = 0; bit < testFlagBitNames.size(); bit++)
766 		{
767 			if (testFlagMask & (1 << bit))
768 			{
769 				if (maskName != "")
770 					maskName += "_";
771 				maskName += testFlagBitNames[bit];
772 			}
773 		}
774 		if (maskName == "")
775 			maskName = "NoFlags";
776 
777 		de::MovePtr<tcu::TestCaseGroup> testFlagGroup(new tcu::TestCaseGroup(group->getTestContext(), maskName.c_str(), ""));
778 
779 		for (size_t specialIndexNdx = 0; specialIndexNdx < DE_LENGTH_OF_ARRAY(specialIndexUse); ++specialIndexNdx)
780 		{
781 			de::MovePtr<tcu::TestCaseGroup> specialGroup(new tcu::TestCaseGroup(testFlagGroup->getTestContext(), specialIndexUse[specialIndexNdx].name.c_str(), ""));
782 
783 			if (specialIndexUse[specialIndexNdx].useSpecialIndex)
784 			{
785 				for (deUint32 specialIndex = 0; specialIndex < 4; specialIndex++) {
786 					TestParams testParams
787 					{
788 						specialIndexUse[specialIndexNdx].useSpecialIndex,
789 						testFlagMask,
790 						0,
791 						~specialIndex,
792 						seed++,
793 					};
794 
795 					std::stringstream css;
796 					css << specialIndex;
797 
798 					specialGroup->addChild(new OpacityMicromapCase(testCtx, css.str().c_str(), "", testParams));
799 				}
800 				testFlagGroup->addChild(specialGroup.release());
801 			}
802 			else
803 			{
804 				struct {
805 					deUint32 mode;
806 					std::string name;
807 				} modes[] =
808 				{
809 					{ 2, "2"},
810 					{ 4, "4" }
811 				};
812 				for (deUint32 modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(modes); ++modeNdx)
813 				{
814 					de::MovePtr<tcu::TestCaseGroup> modeGroup(new tcu::TestCaseGroup(testFlagGroup->getTestContext(), modes[modeNdx].name.c_str(), ""));
815 
816 					for (deUint32 level = 0; level <= kMaxSubdivisionLevel; level++)
817 					{
818 						TestParams testParams
819 						{
820 							specialIndexUse[specialIndexNdx].useSpecialIndex,
821 							testFlagMask,
822 							level,
823 							modes[modeNdx].mode,
824 							seed++,
825 						};
826 
827 						std::stringstream css;
828 						css << "level_" << level;
829 
830 						modeGroup->addChild(new OpacityMicromapCase(testCtx, css.str().c_str(), "", testParams));
831 					}
832 					specialGroup->addChild(modeGroup.release());
833 				}
834 				testFlagGroup->addChild(specialGroup.release());
835 			}
836 		}
837 
838 		group->addChild(testFlagGroup.release());
839 	}
840 
841 
842 	return group.release();
843 }
844 
845 } // RayTracing
846 } // vkt
847 
848