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