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, µmap));
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