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