1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Ray Tracing Watertightness tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRayTracingWatertightnessTests.hpp"
25
26 #include "vkDefs.hpp"
27
28 #include "vktTestCase.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkTypeUtil.hpp"
36
37 #include "vkRayTracingUtil.hpp"
38
39 #include "deRandom.hpp"
40
41 #include <sstream>
42
43 namespace vkt
44 {
45 namespace RayTracing
46 {
47 namespace
48 {
49 using namespace vk;
50 using namespace std;
51
52 static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
53 VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
54 VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
55
56 struct CaseDef
57 {
58 uint32_t width;
59 uint32_t height;
60 uint32_t squaresGroupCount;
61 uint32_t geometriesGroupCount;
62 uint32_t instancesGroupCount;
63 uint32_t randomSeed;
64 uint32_t depth;
65 uint32_t useManyGeometries;
66 };
67
getImageFormat(void)68 VkFormat getImageFormat(void)
69 {
70 return VK_FORMAT_R32_UINT;
71 }
72
getImageType(uint32_t depth)73 VkImageType getImageType(uint32_t depth)
74 {
75 DE_ASSERT(depth > 0u);
76 return ((depth == 1u) ? VK_IMAGE_TYPE_2D : VK_IMAGE_TYPE_3D);
77 }
78
getImageTiling(void)79 VkImageTiling getImageTiling(void)
80 {
81 return VK_IMAGE_TILING_OPTIMAL;
82 }
83
getImageUsage(void)84 VkImageUsageFlags getImageUsage(void)
85 {
86 return (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
87 }
88
89 enum ShaderGroups
90 {
91 FIRST_GROUP = 0,
92 RAYGEN_GROUP = FIRST_GROUP,
93 MISS_GROUP,
94 HIT_GROUP,
95 };
96
mixVec3(const tcu::Vec3 & a,const tcu::Vec3 & b,const float alpha)97 static inline tcu::Vec3 mixVec3(const tcu::Vec3 &a, const tcu::Vec3 &b, const float alpha)
98 {
99 const tcu::Vec3 result = a * alpha + b * (1.0f - alpha);
100
101 return result;
102 }
103
doCrossProduct(tcu::DVec2 a,tcu::DVec2 b)104 static inline double doCrossProduct(tcu::DVec2 a, tcu::DVec2 b)
105 {
106 return a.x() * b.y() - a.y() * b.x();
107 }
108
pointInTriangle2D(tcu::Vec3 p,tcu::Vec3 a,tcu::Vec3 b,tcu::Vec3 c)109 static bool pointInTriangle2D(tcu::Vec3 p, tcu::Vec3 a, tcu::Vec3 b, tcu::Vec3 c)
110 {
111 tcu::DVec2 pa = {a.x() - p.x(), a.y() - p.y()};
112 tcu::DVec2 pb = {b.x() - p.x(), b.y() - p.y()};
113 tcu::DVec2 pc = {c.x() - p.x(), c.y() - p.y()};
114 double v1 = doCrossProduct(pa, pb);
115 double v2 = doCrossProduct(pb, pc);
116 double v3 = doCrossProduct(pc, pa);
117
118 // The winding of all the triangles in the test on XY plane is the same, so a negative value can be assumed
119 return v1 < 0 && v2 < 0 && v3 < 0;
120 }
121
getShaderGroupSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)122 uint32_t getShaderGroupSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
123 {
124 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
125
126 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
127
128 return rayTracingPropertiesKHR->getShaderGroupHandleSize();
129 }
130
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)131 uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
132 {
133 de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
134
135 rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
136
137 return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
138 }
139
makePipeline(const DeviceInterface & vkd,const VkDevice device,vk::BinaryCollection & collection,de::MovePtr<RayTracingPipeline> & rayTracingPipeline,VkPipelineLayout pipelineLayout,const uint32_t raygenGroup,const uint32_t missGroup,const uint32_t hitGroup,const uint32_t hitGroupCount)140 Move<VkPipeline> makePipeline(const DeviceInterface &vkd, const VkDevice device, vk::BinaryCollection &collection,
141 de::MovePtr<RayTracingPipeline> &rayTracingPipeline, VkPipelineLayout pipelineLayout,
142 const uint32_t raygenGroup, const uint32_t missGroup, const uint32_t hitGroup,
143 const uint32_t hitGroupCount)
144 {
145 Move<VkShaderModule> raygenShader = createShaderModule(vkd, device, collection.get("rgen"), 0);
146 Move<VkShaderModule> hitShader = createShaderModule(vkd, device, collection.get("ahit"), 0);
147 Move<VkShaderModule> missShader = createShaderModule(vkd, device, collection.get("miss"), 0);
148
149 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, raygenShader.get(), raygenGroup);
150 rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missShader.get(), missGroup);
151
152 for (uint32_t i = 0u; i < hitGroupCount; ++i)
153 rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, hitShader.get(), hitGroup + i);
154
155 Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout);
156
157 return pipeline;
158 }
159
makeImageCreateInfo(uint32_t width,uint32_t height,uint32_t depth,VkFormat format)160 VkImageCreateInfo makeImageCreateInfo(uint32_t width, uint32_t height, uint32_t depth, VkFormat format)
161 {
162 const VkImageCreateInfo imageCreateInfo = {
163 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
164 DE_NULL, // const void* pNext;
165 0u, // VkImageCreateFlags flags;
166 getImageType(depth),
167 format, // VkFormat format;
168 makeExtent3D(width, height, depth), // VkExtent3D extent;
169 1u, // uint32_t mipLevels;
170 1u, // uint32_t arrayLayers;
171 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
172 getImageTiling(), // VkImageTiling tiling;
173 getImageUsage(), // VkImageUsageFlags usage;
174 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
175 0u, // uint32_t queueFamilyIndexCount;
176 DE_NULL, // const uint32_t* pQueueFamilyIndices;
177 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
178 };
179
180 return imageCreateInfo;
181 }
182
183 class RayTracingWatertightnessTestInstance : public TestInstance
184 {
185 public:
186 RayTracingWatertightnessTestInstance(Context &context, const CaseDef &data, const bool &useClosedFan);
187 ~RayTracingWatertightnessTestInstance(void);
188 tcu::TestStatus iterate(void);
189
190 protected:
191 void checkSupportInInstance(void) const;
192 de::MovePtr<BufferWithMemory> runTest(void);
193 de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure(
194 VkCommandBuffer cmdBuffer,
195 vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures);
196 vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures(VkCommandBuffer cmdBuffer);
197 de::MovePtr<BottomLevelAccelerationStructure> initBottomAccelerationStructure(VkCommandBuffer cmdBuffer,
198 bool triangles);
199
200 private:
201 CaseDef m_data;
202 const bool m_useClosedFan;
203 };
204
RayTracingWatertightnessTestInstance(Context & context,const CaseDef & data,const bool & useClosedFan)205 RayTracingWatertightnessTestInstance::RayTracingWatertightnessTestInstance(Context &context, const CaseDef &data,
206 const bool &useClosedFan)
207 : vkt::TestInstance(context)
208 , m_data(data)
209 , m_useClosedFan(useClosedFan)
210 {
211 }
212
~RayTracingWatertightnessTestInstance(void)213 RayTracingWatertightnessTestInstance::~RayTracingWatertightnessTestInstance(void)
214 {
215 }
216
217 class RayTracingTestCase : public TestCase
218 {
219 public:
220 RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data, const bool &useClosedFan);
221 ~RayTracingTestCase(void);
222
223 virtual void initPrograms(SourceCollections &programCollection) const;
224 virtual TestInstance *createInstance(Context &context) const;
225 virtual void checkSupport(Context &context) const;
226
227 private:
228 CaseDef m_data;
229 const bool m_useClosedFan;
230 };
231
RayTracingTestCase(tcu::TestContext & context,const char * name,const CaseDef data,const bool & useClosedFan)232 RayTracingTestCase::RayTracingTestCase(tcu::TestContext &context, const char *name, const CaseDef data,
233 const bool &useClosedFan)
234 : vkt::TestCase(context, name)
235 , m_data(data)
236 , m_useClosedFan(useClosedFan)
237 {
238 }
239
~RayTracingTestCase(void)240 RayTracingTestCase::~RayTracingTestCase(void)
241 {
242 }
243
checkSupport(Context & context) const244 void RayTracingTestCase::checkSupport(Context &context) const
245 {
246 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
247 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
248
249 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
250 context.getRayTracingPipelineFeatures();
251 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
252 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
253
254 const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
255 context.getAccelerationStructureFeatures();
256 if (accelerationStructureFeaturesKHR.accelerationStructure == false)
257 TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
258 "VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
259
260 const auto &vki = context.getInstanceInterface();
261 const auto physDev = context.getPhysicalDevice();
262 const auto format = getImageFormat();
263 const auto formatProps = getPhysicalDeviceImageFormatProperties(vki, physDev, format, getImageType(m_data.depth),
264 getImageTiling(), getImageUsage(), 0u);
265 const auto &maxExtent = formatProps.maxExtent;
266
267 if (m_data.width > maxExtent.width || m_data.height > maxExtent.height || m_data.depth > maxExtent.depth)
268 {
269 std::ostringstream msg;
270 msg << "Result image dimensions not supported (" << getFormatName(format) << " " << m_data.width << "x"
271 << m_data.height << "x" << m_data.depth << ")";
272 TCU_THROW(NotSupportedError, msg.str());
273 }
274 }
275
initPrograms(SourceCollections & programCollection) const276 void RayTracingTestCase::initPrograms(SourceCollections &programCollection) const
277 {
278 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
279 {
280 std::stringstream css;
281
282 if (!m_useClosedFan)
283 {
284 css << "#version 460 core\n"
285 "#extension GL_EXT_ray_tracing : require\n"
286 "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
287 "hitAttributeEXT vec3 attribs;\n"
288 "layout(r32ui, set = 0, binding = 0) uniform uimage2D result;\n"
289 "void main()\n"
290 "{\n"
291 " uvec4 color = uvec4(1,0,0,1);\n"
292 " imageStore(result, ivec2(gl_LaunchIDEXT.xy), color);\n"
293 "}\n";
294 }
295 else
296 {
297 const char *zCoord = (m_data.useManyGeometries ? "gl_GeometryIndexEXT" : "gl_PrimitiveID");
298
299 css << "#version 460 core\n"
300 "\n"
301 "#extension GL_EXT_ray_tracing : require\n"
302 "\n"
303 "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
304 "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n"
305 "\n"
306 "hitAttributeEXT vec3 attribs;\n"
307 "\n"
308 "void main()\n"
309 "{\n"
310 " imageAtomicAdd(result, ivec3(gl_LaunchIDEXT.xy, "
311 << zCoord
312 << "), 1);\n"
313 "}\n";
314 }
315
316 programCollection.glslSources.add("ahit") << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
317 }
318
319 {
320 std::stringstream css;
321
322 if (!m_useClosedFan)
323 {
324 css << "#version 460 core\n"
325 "#extension GL_EXT_ray_tracing : require\n"
326 "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
327 "layout(r32ui, set = 0, binding = 0) uniform uimage2D result;\n"
328 "void main()\n"
329 "{\n"
330 " uvec4 color = uvec4(2,0,0,1);\n"
331 " imageStore(result, ivec2(gl_LaunchIDEXT.xy), color);\n"
332 "}\n";
333 }
334 else
335 {
336 css << "#version 460 core\n"
337 "\n"
338 "#extension GL_EXT_ray_tracing : require\n"
339 "\n"
340 "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
341 "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n"
342 "\n"
343 "void main()\n"
344 "{\n"
345 " imageAtomicAdd(result, ivec3(gl_LaunchIDEXT.xy, 0), 10000);\n"
346 "}\n";
347 }
348
349 programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
350 }
351
352 if (!m_useClosedFan)
353 {
354 programCollection.glslSources.add("rgen")
355 << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
356 }
357 else
358 {
359 std::stringstream css;
360 const auto &nSharedEdges = m_data.squaresGroupCount;
361
362 // NOTE: Zeroth invocation fires at the center of the closed fan. Subsequent invocations trace rays against center of shared edges.
363 css << "#version 460 core\n"
364 "\n"
365 "#extension GL_EXT_ray_tracing : require\n"
366 "\n"
367 "layout(location = 0) rayPayloadEXT vec3 hitValue;\n"
368 "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
369 "\n"
370 "void main()\n"
371 "{\n"
372 " uint rayFlags = 0;\n"
373 " uint cullMask = 0xFF;\n"
374 " float tmin = 0.01;\n"
375 " float tmax = 9.0;\n"
376 " uint nRay = gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
377 " vec3 origin = vec3(0.0, 0.0, -1.0);\n"
378 "\n"
379 " if (nRay > "
380 << de::toString(nSharedEdges + 1)
381 << ")\n"
382 " {\n"
383 " return;\n"
384 " }\n"
385 "\n"
386 " float kPi = 3.141592653589;\n"
387 " float angleDiff = 2.0 * kPi / "
388 << de::toString(nSharedEdges)
389 << ";\n"
390 " float angle = ((nRay == 0) ? 0.0\n"
391 " : (angleDiff * (nRay - 1) - kPi));\n"
392 " vec2 sharedEdgeP1 = vec2(0, 0);\n"
393 " vec2 sharedEdgeP2 = ((nRay == 0) ? vec2 (0, 0)\n"
394 " : vec2 (sin(angle), cos(angle)));\n"
395 " vec3 target = vec3 (mix(sharedEdgeP1, sharedEdgeP2, vec2(0.5)), 0.0);\n"
396 " vec3 direct = normalize(target - origin);\n"
397 "\n"
398 " traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
399 "}\n";
400
401 programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
402 }
403 }
404
createInstance(Context & context) const405 TestInstance *RayTracingTestCase::createInstance(Context &context) const
406 {
407 return new RayTracingWatertightnessTestInstance(context, m_data, m_useClosedFan);
408 }
409
initTopAccelerationStructure(VkCommandBuffer cmdBuffer,vector<de::SharedPtr<BottomLevelAccelerationStructure>> & bottomLevelAccelerationStructures)410 de::MovePtr<TopLevelAccelerationStructure> RayTracingWatertightnessTestInstance::initTopAccelerationStructure(
411 VkCommandBuffer cmdBuffer,
412 vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)
413 {
414 const DeviceInterface &vkd = m_context.getDeviceInterface();
415 const VkDevice device = m_context.getDevice();
416 Allocator &allocator = m_context.getDefaultAllocator();
417 de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
418
419 result->setInstanceCount(bottomLevelAccelerationStructures.size());
420
421 for (size_t structNdx = 0; structNdx < bottomLevelAccelerationStructures.size(); ++structNdx)
422 result->addInstance(bottomLevelAccelerationStructures[structNdx]);
423
424 result->createAndBuild(vkd, device, cmdBuffer, allocator);
425
426 return result;
427 }
428
initBottomAccelerationStructure(VkCommandBuffer cmdBuffer,bool triangle)429 de::MovePtr<BottomLevelAccelerationStructure> RayTracingWatertightnessTestInstance::initBottomAccelerationStructure(
430 VkCommandBuffer cmdBuffer, bool triangle)
431 {
432 const DeviceInterface &vkd = m_context.getDeviceInterface();
433 const VkDevice device = m_context.getDevice();
434 Allocator &allocator = m_context.getDefaultAllocator();
435 de::MovePtr<BottomLevelAccelerationStructure> result = makeBottomLevelAccelerationStructure();
436 de::Random rng(m_data.randomSeed);
437 std::vector<tcu::Vec3> vertices;
438 std::vector<tcu::UVec3> triangles;
439 std::vector<tcu::Vec3> geometryData;
440
441 result->setGeometryCount(1u);
442
443 DE_ASSERT(!m_useClosedFan);
444
445 vertices.reserve(3u * m_data.squaresGroupCount);
446
447 vertices.push_back(tcu::Vec3(0.0f, 0.0f, -1.0f));
448 vertices.push_back(tcu::Vec3(0.0f, 1.0f, -1.0f));
449 vertices.push_back(tcu::Vec3(1.0f, 0.0f, -1.0f));
450 vertices.push_back(tcu::Vec3(1.0f, 1.0f, -1.0f));
451
452 triangles.reserve(m_data.squaresGroupCount);
453
454 triangles.push_back(tcu::UVec3(0, 1, 2));
455 triangles.push_back(tcu::UVec3(3, 2, 1));
456
457 while (triangles.size() < m_data.squaresGroupCount)
458 {
459 const uint32_t n = (uint32_t)rng.getInt(0, (uint32_t)triangles.size() - 1);
460 tcu::UVec3 &t = triangles[n];
461 const tcu::Vec3 &a = vertices[t.x()];
462 const tcu::Vec3 &b = vertices[t.y()];
463 const tcu::Vec3 &c = vertices[t.z()];
464 const float alfa = rng.getFloat(0.01f, 0.99f);
465 const float beta = rng.getFloat(0.01f, 0.99f);
466 const tcu::Vec3 mixed = mixVec3(mixVec3(a, b, alfa), c, beta);
467 const float z = -rng.getFloat(0.01f, 0.99f);
468 const tcu::Vec3 d = tcu::Vec3(mixed.x(), mixed.y(), z);
469
470 // A check to avoid vertices that are outside the triangle in the XY plane due to floating-point precision,
471 // resulting in inconsistent winding order
472 if (!pointInTriangle2D(d, a, b, c))
473 continue;
474
475 const uint32_t &p = t.x();
476 const uint32_t &q = t.y();
477 uint32_t &r = t.z();
478 const uint32_t R = (uint32_t)vertices.size();
479
480 vertices.push_back(d);
481
482 triangles.push_back(tcu::UVec3(q, r, R));
483 triangles.push_back(tcu::UVec3(p, R, r));
484 r = R;
485 }
486
487 geometryData.reserve(3u * triangles.size());
488
489 for (size_t i = 0; i < triangles.size(); ++i)
490 {
491 geometryData.push_back(vertices[triangles[i].x()]);
492 geometryData.push_back(vertices[triangles[i].y()]);
493 geometryData.push_back(vertices[triangles[i].z()]);
494 }
495
496 result->addGeometry(geometryData, triangle);
497 result->createAndBuild(vkd, device, cmdBuffer, allocator);
498
499 return result;
500 }
501
502 vector<de::SharedPtr<BottomLevelAccelerationStructure>> RayTracingWatertightnessTestInstance::
initBottomAccelerationStructures(VkCommandBuffer cmdBuffer)503 initBottomAccelerationStructures(VkCommandBuffer cmdBuffer)
504 {
505 vector<de::SharedPtr<BottomLevelAccelerationStructure>> result;
506
507 if (!m_useClosedFan)
508 {
509 for (size_t instanceNdx = 0; instanceNdx < m_data.instancesGroupCount; ++instanceNdx)
510 {
511 de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure =
512 initBottomAccelerationStructure(cmdBuffer, true);
513
514 result.push_back(
515 de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
516 }
517 }
518 else
519 {
520 // Build a closed fan.
521 std::vector<tcu::Vec3> vertices;
522 std::vector<tcu::UVec3> triangles;
523 const float angleDiff = 2.0f * DE_PI / static_cast<float>(m_data.squaresGroupCount);
524
525 vertices.push_back(tcu::Vec3(0.0f, 0.0f, 0.0f));
526
527 for (uint32_t nSharedEdge = 0; nSharedEdge < m_data.squaresGroupCount; ++nSharedEdge)
528 {
529 const auto angle = static_cast<float>(nSharedEdge) * angleDiff - DE_PI;
530 const auto newVertex = tcu::Vec3(deFloatSin(angle), deFloatCos(angle), 0.0f);
531
532 vertices.push_back(newVertex);
533 }
534
535 for (uint32_t nSharedEdge = 0; nSharedEdge < m_data.squaresGroupCount; ++nSharedEdge)
536 {
537 const auto newTri =
538 tcu::UVec3(0, 1 + nSharedEdge, (nSharedEdge != m_data.squaresGroupCount - 1) ? (2 + nSharedEdge) : 1);
539
540 triangles.push_back(newTri);
541 }
542
543 {
544 Allocator &allocator = m_context.getDefaultAllocator();
545 const VkDevice device = m_context.getDevice();
546 const DeviceInterface &vkd = m_context.getDeviceInterface();
547
548 if (!m_data.useManyGeometries)
549 {
550 de::MovePtr<BottomLevelAccelerationStructure> resultBLAS = makeBottomLevelAccelerationStructure();
551
552 for (size_t i = 0; i < triangles.size(); ++i)
553 {
554 std::vector<tcu::Vec3> geometryData;
555 geometryData.reserve(3u);
556
557 geometryData.push_back(vertices[triangles[i].x()]);
558 geometryData.push_back(vertices[triangles[i].y()]);
559 geometryData.push_back(vertices[triangles[i].z()]);
560
561 resultBLAS->addGeometry(geometryData, true /* triangles */,
562 VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
563 }
564
565 resultBLAS->createAndBuild(vkd, device, cmdBuffer, allocator);
566
567 result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(resultBLAS.release()));
568 }
569 else
570 {
571 for (size_t i = 0; i < triangles.size(); ++i)
572 {
573 std::vector<tcu::Vec3> geometryData;
574 de::MovePtr<BottomLevelAccelerationStructure> resultBLAS = makeBottomLevelAccelerationStructure();
575
576 geometryData.push_back(vertices[triangles[i].x()]);
577 geometryData.push_back(vertices[triangles[i].y()]);
578 geometryData.push_back(vertices[triangles[i].z()]);
579
580 resultBLAS->addGeometry(geometryData, true /* triangles */,
581 VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
582 resultBLAS->createAndBuild(vkd, device, cmdBuffer, allocator);
583
584 result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(resultBLAS.release()));
585 }
586 }
587 }
588 }
589
590 return result;
591 }
592
runTest(void)593 de::MovePtr<BufferWithMemory> RayTracingWatertightnessTestInstance::runTest(void)
594 {
595 const InstanceInterface &vki = m_context.getInstanceInterface();
596 const DeviceInterface &vkd = m_context.getDeviceInterface();
597 const VkDevice device = m_context.getDevice();
598 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
599 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
600 const VkQueue queue = m_context.getUniversalQueue();
601 Allocator &allocator = m_context.getDefaultAllocator();
602 const VkFormat format = getImageFormat();
603 const uint32_t pixelCount = m_data.width * m_data.height * m_data.depth;
604 const uint32_t shaderGroupHandleSize = getShaderGroupSize(vki, physicalDevice);
605 const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
606
607 const Move<VkDescriptorSetLayout> descriptorSetLayout =
608 DescriptorSetLayoutBuilder()
609 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
610 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
611 .build(vkd, device);
612 const Move<VkDescriptorPool> descriptorPool =
613 DescriptorPoolBuilder()
614 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
615 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
616 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
617 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
618 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
619 const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
620 const Move<VkCommandBuffer> cmdBuffer =
621 allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
622
623 de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
624 const auto hitGroupCount = (m_data.useManyGeometries ? m_data.squaresGroupCount : 1u);
625 const Move<VkPipeline> pipeline = makePipeline(vkd, device, m_context.getBinaryCollection(), rayTracingPipeline,
626 *pipelineLayout, RAYGEN_GROUP, MISS_GROUP, HIT_GROUP, hitGroupCount);
627 const de::MovePtr<BufferWithMemory> raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
628 vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, RAYGEN_GROUP, 1u);
629 const de::MovePtr<BufferWithMemory> missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
630 vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, MISS_GROUP, 1u);
631 const de::MovePtr<BufferWithMemory> hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
632 vkd, device, *pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, HIT_GROUP, hitGroupCount);
633 const VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion =
634 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0),
635 shaderGroupHandleSize, shaderGroupHandleSize);
636 const VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion =
637 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0),
638 shaderGroupHandleSize, shaderGroupHandleSize);
639 const VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion =
640 makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0),
641 shaderGroupHandleSize, shaderGroupHandleSize * hitGroupCount);
642 const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion =
643 makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
644
645 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, m_data.depth, format);
646 const VkImageSubresourceRange imageSubresourceRange =
647 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
648 const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(
649 new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
650 const Move<VkImageView> imageView =
651 makeImageView(vkd, device, **image, (m_data.depth != 1) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D, format,
652 imageSubresourceRange);
653
654 const VkBufferCreateInfo bufferCreateInfo =
655 makeBufferCreateInfo(pixelCount * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
656 const VkImageSubresourceLayers bufferImageSubresourceLayers =
657 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1);
658 const VkBufferImageCopy bufferImageRegion =
659 makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, m_data.depth), bufferImageSubresourceLayers);
660 de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>(
661 new BufferWithMemory(vkd, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
662
663 const VkDescriptorImageInfo descriptorImageInfo =
664 makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
665
666 const VkImageMemoryBarrier preImageBarrier =
667 makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
668 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **image, imageSubresourceRange);
669 const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(
670 VK_ACCESS_TRANSFER_WRITE_BIT,
671 VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
672 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, **image, imageSubresourceRange);
673 const VkMemoryBarrier postTraceMemoryBarrier =
674 makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
675 const VkMemoryBarrier postCopyMemoryBarrier =
676 makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
677 const VkClearValue clearValue =
678 (!m_useClosedFan) ? makeClearValueColorU32(5u, 5u, 5u, 255u) : makeClearValueColorU32(0u, 0u, 0u, 0u);
679
680 vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructures;
681 de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
682
683 beginCommandBuffer(vkd, *cmdBuffer, 0u);
684 {
685 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
686 VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier);
687 vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1,
688 &imageSubresourceRange);
689 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
690 VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier);
691
692 bottomLevelAccelerationStructures = initBottomAccelerationStructures(*cmdBuffer);
693 topLevelAccelerationStructure = initTopAccelerationStructure(*cmdBuffer, bottomLevelAccelerationStructures);
694
695 const TopLevelAccelerationStructure *topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get();
696 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
697 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
698 DE_NULL, // const void* pNext;
699 1u, // uint32_t accelerationStructureCount;
700 topLevelAccelerationStructurePtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
701 };
702
703 DescriptorSetUpdateBuilder()
704 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
705 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
706 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
707 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
708 .update(vkd, device);
709
710 vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
711 &descriptorSet.get(), 0, DE_NULL);
712
713 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
714
715 if (!m_useClosedFan)
716 {
717 cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
718 &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, m_data.width, m_data.height,
719 1);
720 }
721 else
722 {
723 cmdTraceRays(vkd, *cmdBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion,
724 &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, 1 + m_data.width,
725 m_data.height, 1);
726 }
727
728 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
729 VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
730
731 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **buffer, 1u, &bufferImageRegion);
732
733 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
734 &postCopyMemoryBarrier);
735 }
736 endCommandBuffer(vkd, *cmdBuffer);
737
738 submitCommandsAndWait(vkd, device, queue, cmdBuffer.get());
739
740 invalidateAlloc(vkd, device, buffer->getAllocation());
741
742 return buffer;
743 }
744
checkSupportInInstance(void) const745 void RayTracingWatertightnessTestInstance::checkSupportInInstance(void) const
746 {
747 const InstanceInterface &vki = m_context.getInstanceInterface();
748 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
749 const vk::VkPhysicalDeviceProperties &properties = m_context.getDeviceProperties();
750 const uint32_t requiredAllocations =
751 8u + TopLevelAccelerationStructure::getRequiredAllocationCount() +
752 m_data.instancesGroupCount * BottomLevelAccelerationStructure::getRequiredAllocationCount();
753 de::MovePtr<RayTracingProperties> rayTracingProperties = makeRayTracingProperties(vki, physicalDevice);
754
755 if (rayTracingProperties->getMaxPrimitiveCount() < m_data.squaresGroupCount)
756 TCU_THROW(NotSupportedError, "Triangles required more than supported");
757
758 if (rayTracingProperties->getMaxGeometryCount() < m_data.geometriesGroupCount)
759 TCU_THROW(NotSupportedError, "Geometries required more than supported");
760
761 if (rayTracingProperties->getMaxInstanceCount() < m_data.instancesGroupCount)
762 TCU_THROW(NotSupportedError, "Instances required more than supported");
763
764 if (properties.limits.maxMemoryAllocationCount < requiredAllocations)
765 TCU_THROW(NotSupportedError, "Test requires more allocations allowed");
766 }
767
iterate(void)768 tcu::TestStatus RayTracingWatertightnessTestInstance::iterate(void)
769 {
770 checkSupportInInstance();
771
772 const de::MovePtr<BufferWithMemory> bufferGPU = runTest();
773 const uint32_t *bufferPtrGPU = (uint32_t *)bufferGPU->getAllocation().getHostPtr();
774 uint32_t failures = 0u;
775 uint32_t qualityWarningIssued = 0u;
776 if (!m_useClosedFan)
777 {
778 uint32_t pos = 0;
779
780 for (uint32_t nIntersection = 0; nIntersection < m_data.squaresGroupCount; ++nIntersection)
781 {
782 if (bufferPtrGPU[pos] != 1)
783 failures++;
784
785 ++pos;
786 }
787 }
788 else
789 {
790 // Values larger than 1, excl. 10000 raise a failure since they indicate the impl ignored the VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR flag.
791 // A value of 10000 triggers a quality warning, as this indicates a miss which, per spec language, is discouraged but not forbidden.
792 //
793 // See the miss shader for explanation of the magic number.
794 for (uint32_t pos = 0; pos < m_data.width * m_data.height * m_data.depth; ++pos)
795 {
796 if (bufferPtrGPU[pos] == 10000u)
797 {
798 qualityWarningIssued = 1u;
799 }
800 else if (bufferPtrGPU[pos] > 1u)
801 {
802 failures++;
803 }
804 }
805 }
806
807 if (failures == 0u)
808 {
809 if (qualityWarningIssued)
810 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Miss shader invoked for a shared edge/vertex.");
811 else
812 return tcu::TestStatus::pass("Pass");
813 }
814 else
815 return tcu::TestStatus::fail("failures=" + de::toString(failures));
816 }
817
818 } // namespace
819
createWatertightnessTests(tcu::TestContext & testCtx)820 tcu::TestCaseGroup *createWatertightnessTests(tcu::TestContext &testCtx)
821 {
822 // Ray watertightness tests
823 de::MovePtr<tcu::TestCaseGroup> watertightnessGroup(new tcu::TestCaseGroup(testCtx, "watertightness"));
824
825 const size_t numTests = 10;
826
827 for (size_t testNdx = 0; testNdx < numTests; ++testNdx)
828 {
829 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, de::toString(testNdx).c_str()));
830 const uint32_t sizes[] = {4, 16, 64, 256, 1024, 4096, 16384, 65536};
831
832 // Legacy tests
833 for (size_t sizesNdx = 0; sizesNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizesNdx)
834 {
835 const uint32_t squaresGroupCount = sizes[sizesNdx];
836 const uint32_t geometriesGroupCount = 1;
837 const uint32_t instancesGroupCount = 1;
838 const uint32_t randomSeed = (uint32_t)(5 * testNdx + 11 * sizes[sizesNdx]);
839 const CaseDef caseDef = {
840 256u, 256u, squaresGroupCount, geometriesGroupCount, instancesGroupCount,
841 randomSeed, 1, /* depth - irrelevant */
842 0 /* useManyBottomASes - irrelevant */
843 };
844 const std::string testName = de::toString(caseDef.squaresGroupCount);
845
846 group->addChild(new RayTracingTestCase(testCtx, testName.c_str(), caseDef, false /* useClosedFan */));
847 }
848
849 watertightnessGroup->addChild(group.release());
850 }
851
852 // Closed fan tests
853 {
854 const uint32_t sizes[] = {4, 16, 64, 256, 1024};
855
856 for (uint32_t nBottomASConfig = 0; nBottomASConfig < 2; ++nBottomASConfig)
857 {
858 const auto groupName = (nBottomASConfig == 0) ? "closedFan" : "closedFan2";
859
860 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, groupName));
861
862 for (size_t sizesNdx = 0; sizesNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizesNdx)
863 {
864 const uint32_t sharedEdgeCount = sizes[sizesNdx];
865 const CaseDef caseDef = {
866 // The extra item in <width> is required to accomodate the extra center vertex, against which the test also shoots rays.
867 1 + static_cast<uint32_t>(deSqrt(sharedEdgeCount)), /* width */
868 static_cast<uint32_t>(deSqrt(sharedEdgeCount)), /* height */
869 sharedEdgeCount,
870 1, /* geometriesGroupCount - irrelevant */
871 1, /* instancesGroupCount - irrelevant */
872 1, /* randomSeed - irrelevant */
873 sharedEdgeCount, /* depth */
874 nBottomASConfig};
875 const std::string testName = de::toString(sharedEdgeCount);
876
877 group->addChild(new RayTracingTestCase(testCtx, testName.c_str(), caseDef, true /* useClosedFan */));
878 }
879
880 watertightnessGroup->addChild(group.release());
881 }
882 }
883
884 return watertightnessGroup.release();
885 }
886
887 } // namespace RayTracing
888 } // namespace vkt
889