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 &params);
~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 &params);
~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 &params)
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 &params)
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 &micromapDataBufferAlloc = 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