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