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