1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2020 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 Pipeline Flags tests 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktRayTracingPipelineFlagsTests.hpp" 25 26#include "vkDefs.hpp" 27#include "vktTestCase.hpp" 28#include "vktTestGroupUtil.hpp" 29#include "vktCustomInstancesDevices.hpp" 30#include "vkCmdUtil.hpp" 31#include "vkObjUtil.hpp" 32#include "vkBuilderUtil.hpp" 33#include "vkBarrierUtil.hpp" 34#include "vkBufferWithMemory.hpp" 35#include "vkImageWithMemory.hpp" 36#include "vkTypeUtil.hpp" 37#include "vkImageUtil.hpp" 38#include "vkRayTracingUtil.hpp" 39#include "tcuCommandLine.hpp" 40#include "tcuTextureUtil.hpp" 41#include "tcuStringTemplate.hpp" 42 43#include <algorithm> 44#include <array> 45#include <cmath> 46#include <functional> 47#include <iterator> 48#include <memory> 49#include <set> 50#include <tuple> 51 52#ifdef INTERNAL_DEBUG 53#include <iostream> 54#endif 55 56#define ALL_RAY_TRACING_STAGES (VK_SHADER_STAGE_RAYGEN_BIT_KHR \ 57 | VK_SHADER_STAGE_ANY_HIT_BIT_KHR \ 58 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR \ 59 | VK_SHADER_STAGE_MISS_BIT_KHR \ 60 | VK_SHADER_STAGE_INTERSECTION_BIT_KHR \ 61 | VK_SHADER_STAGE_CALLABLE_BIT_KHR) 62namespace vkt 63{ 64namespace RayTracing 65{ 66namespace 67{ 68using namespace vk; 69using namespace vkt; 70 71#define ALIGN_STD430(type_) alignas(sizeof(type_)) type_ 72 73#define INRANGE(x_, a_, b_) (((x_) >= (a_) && (x_) <= (b_)) || ((x_) >= (b_) && (x_) <= (a_))) 74 75enum class GeometryTypes : deUint32 76{ 77 None = 0x0, 78 Triangle = 0x1, 79 Box = 0x2, 80 TriangleAndBox = Triangle | Box 81}; 82 83struct TestParams 84{ 85 deUint32 width; 86 deUint32 height; 87 VkBool32 onHhost; 88 VkPipelineCreateFlags flags; 89 bool useLibs; 90 bool useMaintenance5; 91 deUint32 instCount; 92 GeometryTypes geomTypes; 93 deUint32 geomCount; 94 deUint32 stbRecStride; 95 deUint32 stbRecOffset; 96 float accuracy; 97#define ENABLED(val_, mask_) (((val_)&(mask_))==(mask_)) 98 bool miss() const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR); } 99 bool ahit() const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR); } 100 bool chit() const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR); } 101 bool isect() const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR); } 102}; 103 104tcu::Vec3 rotateCcwZ (const tcu::Vec3& p, const tcu::Vec3& center, const float& radians) 105{ 106 const float s = std::sin(radians); 107 const float c = std::cos(radians); 108 const auto t = p - center; 109 return tcu::Vec3(c * t.x() - s * t.y(), s * t.x() + c * t.y(), t.z()) + center; 110} 111 112bool pointInRect2D(const tcu::Vec3& p, const tcu::Vec3& p0, const tcu::Vec3& p1) 113{ 114 return INRANGE(p.x(), p0.x(), p1.x()) && INRANGE(p.y(), p0.y(), p1.y()); 115} 116 117deUint32 computeEffectiveShaderGroupCount(const TestParams& p) 118{ 119 DE_ASSERT(p.instCount && p.geomCount); 120 return (p.geomCount * p.stbRecStride + p.stbRecOffset + 1); 121} 122 123class RayTracingTestPipeline; 124 125class PipelineFlagsCase : public TestCase 126{ 127public: 128 PipelineFlagsCase (tcu::TestContext& testCtx, 129 const std::string& name, 130 const TestParams& testParams); 131 virtual ~PipelineFlagsCase (void) = default; 132 virtual void initPrograms (SourceCollections& programCollection) const override; 133 virtual TestInstance* createInstance (Context& context) const override; 134 virtual void checkSupport (Context& context) const override; 135 136 const deUint32& shaderGroupHandleSize; 137 const deUint32& shaderGroupBaseAlignment; 138 139private: 140 const TestParams m_params; 141 142 const tcu::IVec4 m_rgenPayload; 143 const deInt32 m_defMissRetGreenComp; 144 const deInt32 m_defTriRetGreenComp; 145 const deInt32 m_defBoxRetGreenComp; 146 static deInt32 calcDefBoxRetGreenComp (const TestParams& params, 147 deInt32 defTriRetGreenComp); 148 149 static deUint32 m_shaderGroupHandleSize; 150 static deUint32 m_shaderGroupBaseAlignment; 151}; 152 153deInt32 PipelineFlagsCase::calcDefBoxRetGreenComp (const TestParams& params, deInt32 defTriRetGreenComp) 154{ 155 const deUint32 nameCount = params.stbRecStride ? (params.geomCount * params.instCount) : params.instCount; 156 const deUint32 triangleCount = (params.geomTypes == GeometryTypes::Triangle || params.geomTypes == GeometryTypes::TriangleAndBox) ? nameCount : 0u; 157 return defTriRetGreenComp + std::max(triangleCount, 32u); 158} 159deUint32 PipelineFlagsCase::m_shaderGroupHandleSize; 160deUint32 PipelineFlagsCase::m_shaderGroupBaseAlignment; 161 162class PipelineFlagsInstance : public TestInstance 163{ 164 using TopLevelASPtr = de::SharedPtr<TopLevelAccelerationStructure>; 165 using BottomLevelASPtr = de::SharedPtr<BottomLevelAccelerationStructure>; 166 using BottomLevelASPtrs = std::vector<BottomLevelASPtr>; 167 using TriGeometry = std::array<tcu::Vec3, 3>; 168 using BoxGeometry = std::array<tcu::Vec3, 2>; 169 170 friend class RayTracingTestPipeline; 171public: 172 PipelineFlagsInstance (Context& context, 173 const TestParams& params, 174 const deUint32& shaderGroupHandleSize_, 175 const deUint32& shaderGroupBaseAlignment_, 176 const tcu::IVec4& rgenPayload_, 177 deInt32 defMissRetGreenComp_, 178 deInt32 defTriRetGreenComp_, 179 deInt32 defBoxRetGreenComp_); 180 virtual ~PipelineFlagsInstance (void) = default; 181 182 struct ShaderRecordEXT 183 { 184 ALIGN_STD430(GeometryTypes) geomType; 185 ALIGN_STD430(deUint32) geomIndex; 186 ALIGN_STD430(tcu::IVec4) retValue; 187 188 ShaderRecordEXT (); 189 ShaderRecordEXT (GeometryTypes type, deUint32 index, const tcu::IVec4& ret); 190 }; 191 192 virtual tcu::TestStatus iterate (void) override; 193 194 const tcu::IVec4 rgenPayload; 195 const deInt32 defMissRetGreenComp; 196 const deInt32 defTriRetGreenComp; 197 const deInt32 defBoxRetGreenComp; 198 199 const deUint32 shaderGroupHandleSize; 200 const deUint32 shaderGroupBaseAlignment; 201 202private: 203 struct HitGroup; 204 using ShaderRecordEntry = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool /* initalized */>; 205 206 VkImageCreateInfo makeImageCreateInfo () const; 207 std::vector<TriGeometry> prepareTriGeometries (const float zCoord) const; 208 std::vector<BoxGeometry> prepareBoxGeometries (const float zFront, 209 const float zBack) const; 210 std::vector<ShaderRecordEntry> prepareShaderBindingTable (void) const; 211 BottomLevelASPtrs createBottomLevelAccelerationStructs (VkCommandBuffer cmdBuffer) const; 212 TopLevelASPtr createTopLevelAccelerationStruct (VkCommandBuffer cmdBuffer, 213 const BottomLevelASPtrs& blasPtrs) const; 214 bool verifyResult (const BufferWithMemory* resultBuffer) const; 215#ifdef INTERNAL_DEBUG 216 void printImage (const tcu::IVec4* image) const; 217#endif 218 219 template<class rayPayloadEXT, class shaderRecordEXT> 220 struct Shader 221 { 222 virtual bool ignoreIntersection (const rayPayloadEXT&, const shaderRecordEXT&) const { return false; } 223 virtual rayPayloadEXT invoke (const rayPayloadEXT&, const shaderRecordEXT&) const = 0; 224 }; 225 struct ShaderBase : Shader<tcu::IVec4, ShaderRecordEXT> 226 { 227 typedef tcu::IVec4 rayPayloadEXT; 228 typedef ShaderRecordEXT shaderRecordEXT; 229 static const rayPayloadEXT dummyPayload; 230 virtual rayPayloadEXT invoke (const rayPayloadEXT&, const shaderRecordEXT&) const override { 231 return rayPayloadEXT(); 232 } 233 }; 234 struct ClosestHitShader : ShaderBase 235 { 236 virtual rayPayloadEXT invoke (const rayPayloadEXT& hitAttr, const shaderRecordEXT& rec) const override { 237 return (rec.geomType == GeometryTypes::Triangle) ? rec.retValue : hitAttr; 238 } 239 }; 240 struct AnyHitShader : ShaderBase 241 { 242 virtual bool ignoreIntersection(const rayPayloadEXT&, const shaderRecordEXT& rec) const override { 243 return (rec.geomIndex % 2 == 1); 244 } 245 }; 246 struct IntersectionShader : ShaderBase 247 { 248 virtual rayPayloadEXT invoke(const rayPayloadEXT&, const shaderRecordEXT& rec) const override { 249 return (rec.retValue + tcu::IVec4(0, 2, 3, 4)); 250 } 251 }; 252 struct MissShader : ShaderBase 253 { 254 virtual rayPayloadEXT invoke(const rayPayloadEXT&, const shaderRecordEXT& rec) const override { 255 return rec.retValue; } 256 }; 257 struct HitGroup 258 { 259 de::SharedPtr<AnyHitShader> ahit; 260 de::SharedPtr<ClosestHitShader> chit; 261 de::SharedPtr<IntersectionShader> isect; 262 }; 263 264 tcu::IVec2 rayToImage (const tcu::Vec2& rayCoords) const; 265 tcu::Vec2 imageToRay (const tcu::IVec2& imageCoords) const; 266 deUint32 computeSamePixelCount (const std::vector<tcu::IVec4>& image, 267 const tcu::Vec2 pixelCoords, 268 const tcu::IVec4& requiredColor, 269 const tcu::IVec4& floodColor, 270 const std::function<bool(const tcu::Vec3&)>& pointInGeometry, 271 std::vector<std::pair<tcu::IVec4, tcu::IVec2>> &auxBuffer) const; 272 void travelRay (std::vector<tcu::IVec4>& outImage, 273 const deUint32 glLaunchIdExtX, 274 const deUint32 glLaunchIdExtY, 275 const std::vector<ShaderRecordEntry>& shaderBindingTable, 276 const MissShader& missShader, 277 const std::vector<TriGeometry>& triangleGeometries, 278 const std::vector<BoxGeometry>& boxGeometries) const; 279 const TestParams m_params; 280 const VkFormat m_format; 281}; 282PipelineFlagsInstance::ShaderBase::rayPayloadEXT const PipelineFlagsInstance::ShaderBase::dummyPayload{}; 283 284PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT () 285 : geomType (GeometryTypes::None) 286 , geomIndex (~0u) 287 , retValue () 288{ 289} 290 291PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT (GeometryTypes type, deUint32 index, const tcu::IVec4& ret) 292 : geomType(type) 293 , geomIndex(index) 294 , retValue(ret) 295{ 296} 297 298class RayTracingTestPipeline : protected RayTracingPipeline 299{ 300public: 301 RayTracingTestPipeline (Context& context, const PipelineFlagsInstance& testInstance, const TestParams& params) 302 : m_context (context) 303 , m_vkd (context.getDeviceInterface()) 304 , m_device (context.getDevice()) 305 , m_allocator (context.getDefaultAllocator()) 306 , m_testInstance (testInstance) 307 , m_params (params) 308 { 309 m_rgenModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("rgen"), 0); 310 311 // miss shader is loaded into each test regardless m_params.miss() is set 312 m_missModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("miss"), 0); 313 314 // cloest hit shader is loaded into each test regardless m_params.chit() is set 315 m_chitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("chit"), 0); 316 317 if (m_params.ahit()) 318 m_ahitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("ahit"), 0); 319 320 if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)) 321 m_isectModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("isect"), 0); 322 323 setCreateFlags(m_params.flags); 324 if (m_params.useMaintenance5) 325 setCreateFlags2(translateCreateFlag(m_params.flags)); 326 327 setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue)); 328 setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue)); 329 } 330 331 template<class ShaderRecord> struct SBT 332 { 333 static const deUint32 recordSize = static_cast<deUint32>(sizeof(ShaderRecord)); 334 335 const DeviceInterface& m_vkd; 336 const VkDevice m_dev; 337 const VkPipeline m_pipeline; 338 const deUint32 m_groupCount; 339 const deUint32 m_handleSize; 340 const deUint32 m_alignment; 341 de::MovePtr<BufferWithMemory> m_buffer; 342 deUint8* m_content; 343 344 SBT (const DeviceInterface& vkd, VkDevice dev, Allocator& allocator, VkPipeline pipeline, 345 deUint32 groupCount, deUint32 shaderGroupHandleSize, deUint32 shaderGroupBaseAlignment) 346 : m_vkd(vkd), m_dev(dev), m_pipeline(pipeline) 347 , m_groupCount(groupCount), m_handleSize(shaderGroupHandleSize) 348 , m_alignment(deAlign32(shaderGroupHandleSize + recordSize, shaderGroupBaseAlignment)) 349 , m_buffer(), m_content() 350 { 351 const deUint32 size = groupCount * m_alignment; 352 const VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; 353 VkBufferCreateInfo info = makeBufferCreateInfo(size, flags); 354 const MemoryRequirement memReq = MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::DeviceAddress; 355 m_buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(m_vkd, m_dev, allocator, info, memReq)); 356 m_content = (deUint8*)m_buffer->getAllocation().getHostPtr(); 357 } 358 359 void updateAt (deUint32 index, const deUint8* handle, const ShaderRecord& rec) 360 { 361 DE_ASSERT(index < m_groupCount); 362 deUint8* groupPos = m_content + index * m_alignment; 363 deMemcpy(groupPos, handle, m_handleSize); 364 deMemcpy(groupPos + m_handleSize, &rec, recordSize); 365 } 366 367 void flush () 368 { 369 Allocation& alloc = m_buffer->getAllocation(); 370 flushMappedMemoryRange(m_vkd, m_dev, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE); 371 } 372 373 deUint32 getAlignment () const { return m_alignment; } 374 375 de::MovePtr<BufferWithMemory> get () { return m_buffer; } 376 }; 377 378 struct PLDeleter 379 { 380 const RayTracingTestPipeline* pipeline; 381 std::function<void(RayTracingPipeline*)> whenDestroying; 382 PLDeleter (RayTracingTestPipeline* pl, std::function<void(RayTracingPipeline*)> doWhenDestroying) 383 : pipeline(pl), whenDestroying(doWhenDestroying) {} 384 void operator()(RayTracingPipeline* pl) 385 { 386 if (pipeline != pl && pipeline->m_params.useLibs) 387 { 388 if (whenDestroying) whenDestroying(pl); 389 delete pl; 390 } 391 } 392 }; 393 394 auto createLibraryPipeline (std::function<void(RayTracingPipeline*)> doWhenDestroying) 395 -> de::UniquePtr<RayTracingPipeline, PLDeleter> 396 { 397 RayTracingPipeline* pl = this; 398 if (m_params.useLibs) { 399 pl = new RayTracingPipeline; 400 pl->setCreateFlags(m_params.flags | VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); 401 pl->setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue)); 402 pl->setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue)); 403 } 404 return de::UniquePtr<RayTracingPipeline, PLDeleter>(pl, PLDeleter(this, doWhenDestroying)); 405 } 406 407 Move<VkPipeline> createPipeline (const VkPipelineLayout pipelineLayout) 408 { 409 deUint32 groupIndex = 0; 410 const bool checkIsect = (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox); 411 412 auto appendPipelineLibrary = [this, &pipelineLayout](RayTracingPipeline* pl) -> void 413 { 414 m_libraries.emplace_back(makeVkSharedPtr(pl->createPipeline(m_vkd, m_device, pipelineLayout))); 415 }; 416 417 DE_ASSERT( (VkShaderModule(0) != *m_rgenModule)); 418 DE_ASSERT( (VkShaderModule(0) != *m_missModule)); 419 DE_ASSERT(m_params.ahit() == (VkShaderModule(0) != *m_ahitModule)); 420 DE_ASSERT( (VkShaderModule(0) != *m_chitModule)); 421 DE_ASSERT(checkIsect == (VkShaderModule(0) != *m_isectModule)); 422 423 // rgen in the main pipeline only 424 addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, *m_rgenModule, groupIndex++); 425 426 createLibraryPipeline(appendPipelineLibrary)->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, *m_missModule, (m_params.useLibs ? 0 : groupIndex++)); 427 428 { 429 const deUint32 hitGroupIndex = m_params.useLibs ? 0 : groupIndex; 430 auto pipeline = createLibraryPipeline(appendPipelineLibrary); 431 if (m_params.ahit()) pipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, *m_ahitModule, hitGroupIndex); 432 pipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, *m_chitModule, hitGroupIndex); 433 if (checkIsect) pipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, *m_isectModule, hitGroupIndex); 434 } 435 436 for (const auto& sg : m_shadersGroupCreateInfos) 437 { 438 static_cast<void>(sg); 439 DE_ASSERT(sg.type != VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR); 440 } 441 442 return RayTracingPipeline::createPipeline(m_vkd, m_device, pipelineLayout, m_libraries); 443 } 444 445 std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createRaygenShaderBindingTable (VkPipeline pipeline) 446 { 447 de::MovePtr<BufferWithMemory> sbt = createShaderBindingTable(m_vkd, m_device, pipeline, m_allocator, 448 m_testInstance.shaderGroupHandleSize, 449 m_testInstance.shaderGroupBaseAlignment, 0, 1); 450 VkStridedDeviceAddressRegionKHR rgn = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **sbt, 0), 451 m_testInstance.shaderGroupHandleSize, 452 m_testInstance.shaderGroupHandleSize); 453 return { de::SharedPtr<BufferWithMemory>(sbt.release()), rgn }; 454 } 455 456 std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createMissShaderBindingTable (VkPipeline pipeline) 457 { 458 const auto entries = m_testInstance.prepareShaderBindingTable(); 459 const void* shaderRecPtr = static_cast<PipelineFlagsInstance::ShaderRecordEXT const*>(&std::get<2>(entries[1])); 460 const deUint32 shaderRecSize = static_cast<deUint32>(sizeof(PipelineFlagsInstance::ShaderRecordEXT)); 461 const deUint32 alignment = deAlign32(m_testInstance.shaderGroupHandleSize + shaderRecSize, m_testInstance.shaderGroupBaseAlignment); 462 const deUint32 sbtOffset = 0; 463 464 de::MovePtr<BufferWithMemory> sbt = createShaderBindingTable(m_vkd, m_device, pipeline, m_allocator, 465 m_testInstance.shaderGroupHandleSize, 466 m_testInstance.shaderGroupBaseAlignment, 467 1, 1, 468 VkBufferCreateFlags(0u), 469 VkBufferUsageFlags(0u), 470 MemoryRequirement::Any, 471 VkDeviceAddress(0), 472 sbtOffset, 473 shaderRecSize, 474 &shaderRecPtr); 475 476 VkStridedDeviceAddressRegionKHR rgn = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **sbt, 0), 477 alignment, 478 m_testInstance.shaderGroupHandleSize); 479 return { de::SharedPtr<BufferWithMemory>(sbt.release()), rgn }; 480 } 481 482 std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createHitShaderBindingTable (VkPipeline pipeline) 483 { 484 de::MovePtr<BufferWithMemory> buf; 485 VkStridedDeviceAddressRegionKHR rgn; 486 487 std::vector<deUint8> handles (m_testInstance.shaderGroupHandleSize); 488 auto records = m_testInstance.prepareShaderBindingTable(); 489 const deUint32 hitGroupCount = deUint32(records.size() - 2); 490 491 SBT<PipelineFlagsInstance::ShaderRecordEXT> sbt(m_vkd, m_device, m_allocator, pipeline, hitGroupCount, 492 m_testInstance.shaderGroupHandleSize, m_testInstance.shaderGroupBaseAlignment); 493 494 VK_CHECK(m_vkd.getRayTracingShaderGroupHandlesKHR(m_device, pipeline, 2, 1, handles.size(), handles.data())); 495 496 for (deUint32 i = 0; i < hitGroupCount; ++i) 497 { 498 // copy the SBT record if it was initialized in prepareShaderBindingTable() 499 if (std::get<3>(records[i + 2])) 500 { 501 const PipelineFlagsInstance::ShaderRecordEXT& rec = std::get<2>(records[i + 2]); 502 sbt.updateAt(i, handles.data(), rec); 503 } 504 } 505 506 sbt.flush(); 507 buf = sbt.get(); 508 rgn = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **buf, 0), 509 sbt.getAlignment(), m_testInstance.shaderGroupHandleSize); 510 511 return { de::SharedPtr<BufferWithMemory>(buf.release()), rgn }; 512 } 513 514private: 515 Context& m_context; 516 const DeviceInterface& m_vkd; 517 const VkDevice m_device; 518 Allocator& m_allocator; 519 const PipelineFlagsInstance& m_testInstance; 520 const TestParams m_params; 521 Move<VkShaderModule> m_rgenModule; 522 Move<VkShaderModule> m_chitModule; 523 Move<VkShaderModule> m_ahitModule; 524 Move<VkShaderModule> m_isectModule; 525 Move<VkShaderModule> m_missModule; 526 Move<VkShaderModule> m_gapModule; 527 std::vector<de::SharedPtr<Move<VkPipeline>>> m_libraries; 528}; 529 530template<class T, class P = T(*)[1], class R = decltype(std::begin(*std::declval<P>()))> 531auto makeStdBeginEnd(T* p, deUint32 n) -> std::pair<R, R> 532{ 533 auto tmp = std::begin(*P(p)); 534 auto begin = tmp; 535 std::advance(tmp, n); 536 return { begin, tmp }; 537} 538 539PipelineFlagsCase::PipelineFlagsCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params) 540 : TestCase (testCtx, name) 541 , shaderGroupHandleSize (m_shaderGroupHandleSize) 542 , shaderGroupBaseAlignment (m_shaderGroupBaseAlignment) 543 , m_params (params) 544 , m_rgenPayload (0, ':', 0, 0) 545 , m_defMissRetGreenComp ('-') 546 , m_defTriRetGreenComp ('A') 547 , m_defBoxRetGreenComp (calcDefBoxRetGreenComp(params, m_defTriRetGreenComp)) 548{ 549} 550 551void PipelineFlagsCase::checkSupport (Context& context) const 552{ 553 if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & m_params.flags) 554 && (GeometryTypes::Triangle == m_params.geomTypes)) 555 { 556 TCU_THROW(InternalError, "Illegal params combination: VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR and Triangles"); 557 } 558 559 if (!context.isDeviceFunctionalitySupported("VK_KHR_ray_tracing_pipeline")) 560 TCU_THROW(NotSupportedError, "VK_KHR_ray_tracing_pipeline not supported"); 561 562 // VK_KHR_acceleration_structure is required by VK_KHR_ray_tracing_pipeline. 563 if (!context.isDeviceFunctionalitySupported("VK_KHR_acceleration_structure")) 564 TCU_FAIL("VK_KHR_acceleration_structure not supported but VK_KHR_ray_tracing_pipeline supported"); 565 566 // The same for VK_KHR_buffer_device_address. 567 if (!context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address")) 568 TCU_FAIL("VK_KHR_buffer_device_address not supported but VK_KHR_acceleration_structure supported"); 569 570 if (m_params.useLibs && !context.isDeviceFunctionalitySupported("VK_KHR_pipeline_library")) 571 TCU_FAIL("VK_KHR_pipeline_library not supported but VK_KHR_ray_tracing_pipeline supported"); 572 573 if (m_params.useMaintenance5) 574 context.requireDeviceFunctionality("VK_KHR_maintenance5"); 575 576 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR& rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures(); 577 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE) 578 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline"); 579 580 const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures(); 581 if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE) 582 TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure"); 583 584 if (m_params.onHhost && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == DE_FALSE) 585 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureHostCommands"); 586 587 checkAccelerationStructureVertexBufferFormat(context.getInstanceInterface(), context.getPhysicalDevice(), VK_FORMAT_R32G32B32_SFLOAT); 588 589 auto rayTracingProperties = makeRayTracingProperties(context.getInstanceInterface(), context.getPhysicalDevice()); 590 m_shaderGroupHandleSize = rayTracingProperties->getShaderGroupHandleSize(); 591 m_shaderGroupBaseAlignment = rayTracingProperties->getShaderGroupBaseAlignment(); 592} 593 594void PipelineFlagsCase::initPrograms (SourceCollections& programCollection) const 595{ 596 const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true); 597 const char endl = '\n'; 598 const deUint32 missIdx = 0; 599 600 const std::string payloadInDecl = 601 "layout(location = 0) rayPayloadInEXT ivec4 payload;"; 602 603 const std::string recordDecl = 604 "layout(shaderRecordEXT, std430) buffer Rec {\n" 605 " uint geomType;\n" 606 " uint geomIndex;\n" 607 " ivec4 retValue;\n" 608 "} record;"; 609 610 { 611 std::stringstream str; 612 str << "#version 460 core" << endl 613 << "#extension GL_EXT_ray_tracing : require" << endl 614 << "layout(location = 0) rayPayloadEXT ivec4 payload;" << endl 615 << "layout(rgba32i, set = 0, binding = 0) uniform iimage2D result;" << endl 616 << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;" << endl 617 << "void main()" << endl 618 << "{" << endl 619 << " float rx = (float(gl_LaunchIDEXT.x * 2) / float(gl_LaunchSizeEXT.x)) - 1.0;" << endl 620 << " float ry = (float(gl_LaunchIDEXT.y) + 0.5) / float(gl_LaunchSizeEXT.y);" << endl 621 << " payload = ivec4" << m_rgenPayload << ";" << endl 622 << " uint rayFlags = gl_RayFlagsNoneEXT;" << endl 623 << " uint cullMask = 0xFFu;" << endl 624 << " uint stbRecOffset = " << m_params.stbRecOffset << "u;" << endl 625 << " uint stbRecStride = " << m_params.stbRecStride << "u;" << endl 626 << " uint missIdx = " << missIdx << "u;" << endl 627 << " vec3 orig = vec3(rx, ry, 1.0);" << endl 628 << " float tmin = 0.0;" << endl 629 << " vec3 dir = vec3(0.0, 0.0, -1.0);" << endl 630 << " float tmax = 1000.0;" << endl 631 << " traceRayEXT(topLevelAS, rayFlags, cullMask, stbRecOffset, stbRecStride, missIdx, orig, tmin, dir, tmax, 0);" << endl 632 << " imageStore(result, ivec2(gl_LaunchIDEXT.xy), payload);" << endl 633 << "}"; 634 programCollection.glslSources.add("rgen") << glu::RaygenSource(str.str()) << buildOptions; 635 } 636 637 // miss shader is created in each test regardless the m_params.miss() is set 638 { 639 std::stringstream str; 640 str << "#version 460 core" << endl 641 << "#extension GL_EXT_ray_tracing : require" << endl 642 << payloadInDecl << endl 643 << recordDecl << endl 644 << "void main()" << endl 645 << "{" << endl 646 << " payload = record.retValue;" << endl 647 << "}"; 648 programCollection.glslSources.add("miss") << glu::MissSource(str.str()) << buildOptions; 649 } 650 651 // closest hit shader is created in each test regardless the m_params.chit() is set 652 { 653 std::stringstream str; 654 str << "#version 460 core" << endl 655 << "#extension GL_EXT_ray_tracing : require" << endl 656 << "hitAttributeEXT ivec4 hitAttribute;" << endl 657 << payloadInDecl << endl 658 << recordDecl << endl 659 << "void main()" << endl 660 << "{" << endl 661 << " if (record.geomType == " << deUint32(GeometryTypes::Triangle) << ")" << endl 662 << " payload = record.retValue;" << endl 663 << " else payload = hitAttribute;" << endl 664 << "}"; 665 programCollection.glslSources.add("chit") << glu::ClosestHitSource(str.str()) << buildOptions; 666 } 667 668 if (m_params.ahit()) 669 { 670 std::stringstream str; 671 str << "#version 460 core" << endl 672 << "#extension GL_EXT_ray_tracing : require" << endl 673 << recordDecl << endl 674 << "void main()" << endl 675 << "{" << endl 676 << " if (record.geomIndex % 2 == 1)" << endl 677 << " ignoreIntersectionEXT;" << endl 678 << "}"; 679 programCollection.glslSources.add("ahit") << glu::AnyHitSource(str.str()) << buildOptions; 680 } 681 682 if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)) 683 { 684 std::stringstream str; 685 str << "#version 460 core" << endl 686 << "#extension GL_EXT_ray_tracing : require" << endl 687 << "hitAttributeEXT ivec4 hitAttribute;" << endl 688 << recordDecl << endl 689 << "void main()" << endl 690 << "{" << endl 691 << " hitAttribute = ivec4(record.retValue.x + 0" << endl 692 << " ,record.retValue.y + 2" << endl 693 << " ,record.retValue.z + 3" << endl 694 << " ,record.retValue.w + 4);" << endl 695 << " reportIntersectionEXT(0.0, 0);" << endl 696 << "}"; 697 programCollection.glslSources.add("isect") << glu::IntersectionSource(str.str()) << buildOptions; 698 } 699} 700 701TestInstance* PipelineFlagsCase::createInstance (Context& context) const 702{ 703 return new PipelineFlagsInstance(context, m_params, shaderGroupHandleSize, shaderGroupBaseAlignment, 704 m_rgenPayload, m_defMissRetGreenComp, m_defTriRetGreenComp, m_defBoxRetGreenComp); 705} 706 707PipelineFlagsInstance::PipelineFlagsInstance (Context& context, 708 const TestParams& params, 709 const deUint32& shaderGroupHandleSize_, 710 const deUint32& shaderGroupBaseAlignment_, 711 const tcu::IVec4& rgenPayload_, 712 deInt32 defMissRetGreenComp_, 713 deInt32 defTriRetGreenComp_, 714 deInt32 defBoxRetGreenComp_) 715 : TestInstance (context) 716 , rgenPayload (rgenPayload_) 717 , defMissRetGreenComp (defMissRetGreenComp_) 718 , defTriRetGreenComp (defTriRetGreenComp_) 719 , defBoxRetGreenComp (defBoxRetGreenComp_) 720 , shaderGroupHandleSize (shaderGroupHandleSize_) 721 , shaderGroupBaseAlignment (shaderGroupBaseAlignment_) 722 , m_params (params) 723 , m_format (VK_FORMAT_R32G32B32A32_SINT) 724{ 725} 726 727VkImageCreateInfo PipelineFlagsInstance::makeImageCreateInfo () const 728{ 729 const deUint32 familyIndex = m_context.getUniversalQueueFamilyIndex(); 730 const VkImageCreateInfo imageCreateInfo = 731 { 732 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 733 DE_NULL, // const void* pNext; 734 (VkImageCreateFlags)0u, // VkImageCreateFlags flags; 735 VK_IMAGE_TYPE_2D, // VkImageType imageType; 736 m_format, // VkFormat format; 737 makeExtent3D(m_params.width, m_params.height, 1u), // VkExtent3D extent; 738 1u, // deUint32 mipLevels; 739 1u, // deUint32 arrayLayers; 740 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 741 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 742 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage; 743 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 744 1u, // deUint32 queueFamilyIndexCount; 745 &familyIndex, // const deUint32* pQueueFamilyIndices; 746 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; 747 }; 748 749 return imageCreateInfo; 750} 751 752std::vector<PipelineFlagsInstance::TriGeometry> 753PipelineFlagsInstance::prepareTriGeometries (const float zCoord) const 754{ 755 const tcu::Vec3 center(-0.5f, 0.5f, zCoord); 756 const tcu::Vec3 start(0.0f, 0.5f, zCoord); 757 const deUint32 maxTriangles = m_params.instCount * m_params.geomCount; 758 const deUint32 trianglesCount = deMaxu32(maxTriangles, 3); 759 const float angle = (4.0f * std::acos(0.0f)) / float(trianglesCount); 760 761 tcu::Vec3 point(start); 762 std::vector<TriGeometry> geometries(maxTriangles); 763 for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst) 764 { 765 for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx) 766 { 767 TriGeometry& geometry = geometries[idx]; 768 769 geometry[0] = center; 770 geometry[1] = point; 771 geometry[2] = (maxTriangles >= 3 && trianglesCount - idx == 1u) ? start : rotateCcwZ(point, center, angle); 772 773 point = geometry[2]; 774 } 775 } 776 777 return geometries; 778} 779 780std::vector<PipelineFlagsInstance::BoxGeometry> 781PipelineFlagsInstance::prepareBoxGeometries (const float zFront, const float zBack) const 782{ 783 const deUint32 maxBoxes = m_params.instCount * m_params.geomCount; 784 785 std::vector<BoxGeometry> boxes (maxBoxes); 786 deUint32 boxesPerDim = 0u; 787 float boxWidth = 0.0f; 788 float boxHeight = 0.0f; 789 790 // find nearest square ceil number 791 do 792 { 793 ++boxesPerDim; 794 boxWidth = 1.0f / float(boxesPerDim); 795 boxHeight = 1.0f / float(boxesPerDim); 796 } while (boxesPerDim * boxesPerDim < maxBoxes); 797 798 for (deUint32 boxY = 0, boxIdx = 0; boxY < boxesPerDim && boxIdx < maxBoxes; ++boxY) 799 { 800 for (deUint32 boxX = 0; boxX < boxesPerDim && boxIdx < maxBoxes; ++boxX, ++boxIdx) 801 { 802 const float x = float(boxX) * boxWidth; 803 const float y = float(boxY) * boxHeight; 804 BoxGeometry box = { { tcu::Vec3(x, y, zFront), tcu::Vec3((x + boxWidth), (y + boxHeight), zBack) } }; 805 boxes[boxIdx].swap(box); 806 } 807 } 808 809 return boxes; 810} 811 812PipelineFlagsInstance::BottomLevelASPtrs 813PipelineFlagsInstance::createBottomLevelAccelerationStructs (VkCommandBuffer cmdBuffer) const 814{ 815 const DeviceInterface& vkd = m_context.getDeviceInterface(); 816 const VkDevice device = m_context.getDevice(); 817 Allocator& allocator = m_context.getDefaultAllocator(); 818 const VkGeometryFlagsKHR geomFlags = m_params.ahit() ? VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR : VK_GEOMETRY_OPAQUE_BIT_KHR; 819 820 BottomLevelASPtrs result; 821 822 if (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))) 823 { 824 const auto geometries = prepareTriGeometries(0.0f); 825 826 for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst) 827 { 828 auto blas = makeBottomLevelAccelerationStructure(); 829 blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR); 830 831 for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx) 832 { 833 const TriGeometry& triangle = geometries[idx]; 834 blas->addGeometry(std::vector<tcu::Vec3>(triangle.begin(), triangle.end()), true, geomFlags); 835 } 836 837 blas->createAndBuild(vkd, device, cmdBuffer, allocator); 838 result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release())); 839 } 840 } 841 842 if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)) 843 { 844 const auto geometries = prepareBoxGeometries(0.0f, 0.0f); 845 846 for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst) 847 { 848 auto blas = makeBottomLevelAccelerationStructure(); 849 blas->setUseMaintenance5(m_params.useMaintenance5); 850 blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR); 851 852 for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx) 853 { 854 const BoxGeometry& box = geometries[idx]; 855 blas->addGeometry(std::vector<tcu::Vec3>(box.begin(), box.end()), false, geomFlags); 856 } 857 858 blas->createAndBuild(vkd, device, cmdBuffer, allocator); 859 result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release())); 860 } 861 } 862 863 return result; 864} 865 866PipelineFlagsInstance::TopLevelASPtr 867PipelineFlagsInstance::createTopLevelAccelerationStruct (VkCommandBuffer cmdBuffer, const BottomLevelASPtrs& blasPtrs) const 868{ 869 const DeviceInterface& vkd = m_context.getDeviceInterface(); 870 const VkDevice device = m_context.getDevice(); 871 Allocator& allocator = m_context.getDefaultAllocator(); 872 const deUint32 groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params); 873 874 auto tlas = makeTopLevelAccelerationStructure(); 875 876 tlas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR); 877 tlas->setInstanceCount(blasPtrs.size()); 878 for (auto begin = blasPtrs.begin(), end = blasPtrs.end(), i = begin; i != end; ++i) 879 { 880 const deUint32 instanceShaderBindingTableRecordOffset = static_cast<deUint32>(std::distance(begin, i) * groupsAndGapsPerInstance); 881 tlas->addInstance(*i, identityMatrix3x4, 0, 0xFF, instanceShaderBindingTableRecordOffset); 882 } 883 tlas->createAndBuild(vkd, device, cmdBuffer, allocator); 884 885 return TopLevelASPtr(tlas.release()); 886} 887 888std::vector<PipelineFlagsInstance::ShaderRecordEntry> PipelineFlagsInstance::prepareShaderBindingTable() const 889{ 890 const bool includeTriangles = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))); 891 const bool includeBoxes = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)); 892 const deUint32 groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params); 893 const deUint32 commonGroupCount = 2; // general groups for rgen and miss 894 const deUint32 triangleGroupCount = includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0; 895 const deUint32 proceduralGroupCount = includeBoxes ? (groupsAndGapsPerInstance * m_params.instCount) : 0; 896 const deUint32 totalGroupCount = commonGroupCount + triangleGroupCount + proceduralGroupCount; 897 898 std::vector<ShaderRecordEntry> shaderRecords(totalGroupCount); 899 900 shaderRecords[0] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( VK_SHADER_STAGE_RAYGEN_BIT_KHR, {}, {}, true ); 901 shaderRecords[1] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( VK_SHADER_STAGE_MISS_BIT_KHR, {}, { GeometryTypes::Box, (~0u), tcu::IVec4(0, defMissRetGreenComp, 0, 0) }, true ); 902 903 de::SharedPtr<AnyHitShader> ahit(new AnyHitShader); 904 de::SharedPtr<ClosestHitShader> chit(new ClosestHitShader); 905 de::SharedPtr<IntersectionShader> isect(new IntersectionShader); 906 907 if (includeTriangles) 908 { 909 std::set<deUint32> usedIndexes; 910 deInt32 greenComp = defTriRetGreenComp; 911 912 const deUint32 recordsToSkip = commonGroupCount; 913 914 for (deUint32 instance = 0; instance < m_params.instCount; ++instance) 915 { 916 const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance; 917 for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex) 918 { 919 const deUint32 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset; 920 if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end()) 921 { 922 HitGroup hitGroup; 923 VkShaderStageFlags flags = 0; 924 if (m_params.ahit()) { 925 flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR; 926 hitGroup.ahit = ahit; 927 } 928 flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; 929 hitGroup.chit = chit; 930 shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( flags, hitGroup, { GeometryTypes::Triangle, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0) }, true ); 931 usedIndexes.insert(shaderGroupIndex); 932 } 933 } 934 } 935 } 936 937 if (includeBoxes) 938 { 939 std::set<deUint32> usedIndexes; 940 deInt32 greenComp = defBoxRetGreenComp; 941 942 const deUint32 recordsToSkip = triangleGroupCount + commonGroupCount; 943 944 for (deUint32 instance = 0; instance < m_params.instCount; ++instance) 945 { 946 const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance; 947 for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex) 948 { 949 const deUint32 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset; 950 if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end()) 951 { 952 HitGroup hitGroup; 953 VkShaderStageFlags flags = 0; 954 if (m_params.ahit()) { 955 flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR; 956 hitGroup.ahit = ahit; 957 } 958 flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; 959 hitGroup.chit = chit; 960 { //In the case of AABB isect must be provided, otherwise we will process AABB with TRIANGLES_HIT_GROUP 961 flags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR; 962 hitGroup.isect = isect; 963 } 964 shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( flags, hitGroup, { GeometryTypes::Box, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0) }, true ); 965 usedIndexes.insert(shaderGroupIndex); 966 } 967 } 968 } 969 } 970 971 return shaderRecords; 972} 973 974tcu::IVec2 PipelineFlagsInstance::rayToImage(const tcu::Vec2& rayCoords) const 975{ 976 return tcu::IVec2( 977 deInt32(((rayCoords.x() + 1.0f) * float(m_params.width)) / 2.0f), 978 deInt32((rayCoords.y() * float(m_params.height)) - 0.5f) 979 ); 980} 981 982tcu::Vec2 PipelineFlagsInstance::imageToRay(const tcu::IVec2& imageCoords) const 983{ 984 const float rx = (float(imageCoords.x() * 2) / float(m_params.width)) - 1.0f; 985 const float ry = (float(imageCoords.y()) + 0.5f) / float(m_params.height); 986 return tcu::Vec2(rx, ry); 987} 988 989deUint32 PipelineFlagsInstance::computeSamePixelCount (const std::vector<tcu::IVec4>& image, 990 const tcu::Vec2 pixelCoords, 991 const tcu::IVec4& requiredColor, 992 const tcu::IVec4& floodColor, 993 const std::function<bool(const tcu::Vec3&)>& pointInGeometry, 994 std::vector<std::pair<tcu::IVec4, tcu::IVec2>>& auxBuffer) const 995{ 996 if (!pointInGeometry(tcu::Vec3(pixelCoords.x(), pixelCoords.y(), 0.0f))) return 0; 997 998 auxBuffer.resize(image.size() * 4); 999 std::transform(image.begin(), image.end(), auxBuffer.begin(), [](const tcu::IVec4& c) -> std::pair<tcu::IVec4, tcu::IVec2> { return { c, tcu::IVec2() }; }); 1000 1001 tcu::Vec2 rayCoord; 1002 tcu::IVec2 imageCoords = rayToImage(pixelCoords); 1003 deUint32 pixelIndex = imageCoords.y() * m_params.width + imageCoords.x(); 1004 tcu::IVec4 imageColor = image[pixelIndex]; 1005 1006 if (requiredColor != imageColor) return 0; 1007 1008 deInt32 stackIndex = 0; 1009 deUint32 sameCount = 1; 1010 auxBuffer[stackIndex].second = imageCoords; 1011 1012 while (stackIndex >= 0) 1013 { 1014 imageCoords = auxBuffer[stackIndex].second; --stackIndex; 1015 1016 if (imageCoords.x() < 0 || imageCoords.x() >= deInt32(m_params.width) 1017 || imageCoords.y() < 0 || imageCoords.y() >= deInt32(m_params.height)) continue; 1018 1019 rayCoord = imageToRay(imageCoords); 1020 if (!pointInGeometry(tcu::Vec3(rayCoord.x(), rayCoord.y(), 0.0f))) continue; 1021 1022 pixelIndex = imageCoords.y() * m_params.width + imageCoords.x(); 1023 imageColor = auxBuffer[pixelIndex].first; 1024 if (requiredColor != imageColor) continue; 1025 1026 auxBuffer[pixelIndex].first = floodColor; 1027 sameCount += 1; 1028 1029 auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() - 1, imageCoords.y()); 1030 auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() + 1, imageCoords.y()); 1031 auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() - 1); 1032 auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() + 1); 1033 } 1034 1035 return sameCount; 1036} 1037 1038void PipelineFlagsInstance::travelRay (std::vector<tcu::IVec4>& outImage, 1039 const deUint32 glLaunchIdExtX, 1040 const deUint32 glLaunchIdExtY, 1041 const std::vector<ShaderRecordEntry>& shaderBindingTable, 1042 const MissShader& missShader, 1043 const std::vector<TriGeometry>& triangleGeometries, 1044 const std::vector<BoxGeometry>& boxGeometries) const 1045{ 1046 const tcu::Vec2 rayCoords = imageToRay(tcu::IVec2(glLaunchIdExtX, glLaunchIdExtY)); 1047 const bool includeTriangles = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))); 1048 const bool includeBoxes = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)); 1049 const deUint32 commonGroupCount = 2; // general groups for rgen and miss 1050 const deUint32 groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params); 1051 const deUint32 triangleGroupCount = includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0; 1052 1053 bool hitHappened (false); 1054 deUint32 shaderGroupIndex (~0u); 1055 tcu::IVec4 payload (rgenPayload); 1056 const tcu::Vec3 origin (rayCoords.x(), rayCoords.y(), 1.0f); 1057 1058 if (includeTriangles) 1059 { 1060 const deUint32 recordsToSkip = commonGroupCount; 1061 for (deUint32 instance = 0; !hitHappened && (instance < m_params.instCount); ++instance) 1062 { 1063 const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance; 1064 for (deUint32 geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex) 1065 { 1066 const TriGeometry& geometry = triangleGeometries[instance * m_params.geomCount + geometryIndex]; 1067 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset; 1068 if (pointInTriangle2D(origin, geometry[0], geometry[1], geometry[2])) 1069 { 1070 hitHappened = true; 1071 } 1072 } 1073 } 1074 } 1075 1076 if (includeBoxes) 1077 { 1078 const deUint32 recordsToSkip = triangleGroupCount + commonGroupCount; 1079 for (deUint32 instance = 0; !hitHappened && (instance < m_params.instCount); ++instance) 1080 { 1081 const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance; 1082 for (deUint32 geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex) 1083 { 1084 const BoxGeometry& geometry = boxGeometries[instance * m_params.geomCount + geometryIndex]; 1085 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset; 1086 if (pointInRect2D(origin, geometry[0], geometry[1])) 1087 { 1088 hitHappened = true; 1089 } 1090 } 1091 } 1092 } 1093 1094 if (hitHappened) 1095 { 1096 const ShaderRecordEXT& shaderRecord = std::get<2>(shaderBindingTable[shaderGroupIndex]); 1097 const HitGroup& hitGroup = std::get<1>(shaderBindingTable[shaderGroupIndex]); 1098 const VkShaderStageFlags flags = std::get<0>(shaderBindingTable[shaderGroupIndex]); 1099 auto hitAttribute = rgenPayload; 1100 bool ignoreIsect = false; 1101 1102 // check if the SBT entry was was initialized 1103 DE_ASSERT(std::get<3>(shaderBindingTable[shaderGroupIndex])); 1104 1105 if (flags & VK_SHADER_STAGE_INTERSECTION_BIT_KHR) 1106 { 1107 hitAttribute = hitGroup.isect->invoke(IntersectionShader::dummyPayload, shaderRecord); 1108 } 1109 if (flags & VK_SHADER_STAGE_ANY_HIT_BIT_KHR) 1110 { 1111 ignoreIsect = hitGroup.ahit->ignoreIntersection(AnyHitShader::dummyPayload, shaderRecord); 1112 } 1113 if (ignoreIsect) 1114 { 1115 payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1])); 1116 } 1117 else if (flags & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) 1118 { 1119 payload = hitGroup.chit->invoke(hitAttribute, shaderRecord); 1120 } 1121 } 1122 else 1123 { 1124 payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1])); 1125 } 1126 1127 outImage[glLaunchIdExtY * m_params.width + glLaunchIdExtX] = payload; 1128} 1129 1130#ifdef INTERNAL_DEBUG 1131void PipelineFlagsInstance::printImage(const tcu::IVec4* image) const 1132{ 1133 for (deUint32 y = 0; y < m_params.height; ++y) 1134 { 1135 for (deUint32 x = 0; x < m_params.width; ++x) 1136 std::cout << static_cast<char>(image[(m_params.height - y - 1) * m_params.width + x].y()); 1137 std::cout << std::endl; 1138 } 1139} 1140#endif 1141 1142bool PipelineFlagsInstance::verifyResult (const BufferWithMemory* resultBuffer) const 1143{ 1144 const auto triangleGeometries = prepareTriGeometries(0.0f); 1145 const auto boxGeometries = prepareBoxGeometries(0.0f, 0.0f); 1146 1147 const bool includeTriangles = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))); 1148 const bool includeBoxes = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)); 1149 1150 const tcu::IVec4* resultImageData = (tcu::IVec4*)(resultBuffer->getAllocation().getHostPtr()); 1151 auto resultImageBounds = makeStdBeginEnd(resultImageData, (m_params.width * m_params.height)); 1152 const std::vector<tcu::IVec4> resultImage (resultImageBounds.first, resultImageBounds.second); 1153 std::vector<tcu::IVec4> referenceImage (m_params.width * m_params.height); 1154 1155 const std::vector<ShaderRecordEntry> shaderBindingTable = prepareShaderBindingTable(); 1156 1157 MissShader missShader{}; 1158 1159 // perform offline ray-tracing 1160 for (deUint32 glLaunchIdExtY = 0; glLaunchIdExtY < m_params.height; ++glLaunchIdExtY) 1161 { 1162 for (deUint32 glLaunchIdExtX = 0; glLaunchIdExtX < m_params.width; ++glLaunchIdExtX) 1163 { 1164 travelRay(referenceImage, glLaunchIdExtX, glLaunchIdExtY, 1165 shaderBindingTable, missShader, 1166 triangleGeometries, boxGeometries); 1167 } 1168 } 1169 1170#ifdef INTERNAL_DEBUG 1171 std::cout << "===== RES =====" << std::endl; 1172 printImage(resultImageData); 1173 std::cout << std::endl; 1174 std::cout << "===== REF =====" << std::endl; 1175 printImage(referenceImage.data()); 1176 std::cout << std::endl; 1177#endif 1178 1179 const tcu::IVec4 floodColor(0, '*', 0, 0); 1180 std::vector<std::pair<tcu::IVec4, tcu::IVec2>> auxBuffer(referenceImage.size() * 4); 1181 1182 if (includeTriangles) 1183 { 1184 TriGeometry tri; 1185 std::function<bool(const tcu::Vec3&)> pointInGeometry = std::bind(pointInTriangle2D, std::placeholders::_1, std::ref(tri[0]), std::ref(tri[1]), std::ref(tri[2])); 1186 1187 for (deUint32 instance = 0; instance < m_params.instCount; ++instance) 1188 { 1189 for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex) 1190 { 1191 if (!(m_params.ahit() && (geometryIndex % 2 == 1))) 1192 { 1193 tri = triangleGeometries[instance * m_params.geomCount + geometryIndex]; 1194 const tcu::Vec2 center((tri[0].x() + tri[1].x() + tri[2].x()) / 3.0f, (tri[0].y() + tri[1].y() + tri[2].y()) / 3.0f); 1195 1196 const tcu::IVec2 refImageCoords = rayToImage(center); 1197 const tcu::IVec4 requiredColor = referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()]; 1198 1199 deUint32 resultPixelCount = computeSamePixelCount(resultImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer); 1200 deUint32 referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer); 1201 1202 if (!resultPixelCount || !referencePixelCount) return false; 1203 if (resultPixelCount > referencePixelCount) std::swap(resultPixelCount, referencePixelCount); 1204 1205 const float similarity = float(resultPixelCount) / float(referencePixelCount); 1206 if (similarity < m_params.accuracy) return false; 1207 } 1208 } 1209 } 1210 } 1211 1212 if (includeBoxes) 1213 { 1214 BoxGeometry box; 1215 std::function<bool(const tcu::Vec3&)> pointInGeometry = std::bind(pointInRect2D, std::placeholders::_1, std::ref(box[0]), std::ref(box[1])); 1216 1217 for (deUint32 instance = 0; instance < m_params.instCount; ++instance) 1218 { 1219 for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex) 1220 { 1221 if (!(m_params.ahit() && (geometryIndex % 2 == 1))) 1222 { 1223 box = boxGeometries[instance * m_params.geomCount + geometryIndex]; 1224 const tcu::Vec2 center((box[0].x() + box[1].x()) / 2.0f, (box[0].y() + box[1].y()) / 2.0f); 1225 1226 const tcu::IVec2 refImageCoords = rayToImage(center); 1227 const tcu::IVec4 requiredColor = referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()]; 1228 1229 deUint32 resultPixelCount = computeSamePixelCount(resultImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer); 1230 deUint32 referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer); 1231 1232 if (!resultPixelCount || !referencePixelCount) return false; 1233 if (resultPixelCount > referencePixelCount) std::swap(resultPixelCount, referencePixelCount); 1234 1235 const float similarity = float(resultPixelCount) / float(referencePixelCount); 1236 if (similarity < m_params.accuracy) return false; 1237 } 1238 } 1239 } 1240 } 1241 1242 return true; 1243} 1244 1245tcu::TestStatus PipelineFlagsInstance::iterate(void) 1246{ 1247 const DeviceInterface& vkd = m_context.getDeviceInterface(); 1248 const VkDevice device = m_context.getDevice(); 1249 const deUint32 familyIndex = m_context.getUniversalQueueFamilyIndex(); 1250 const VkQueue queue = m_context.getUniversalQueue(); 1251 Allocator& allocator = m_context.getDefaultAllocator(); 1252 1253 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(); 1254 const VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u); 1255 const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any)); 1256 const Move<VkImageView> imageView = makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange); 1257 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL); 1258 1259 const deUint32 resultBufferSize = (m_params.width * m_params.height * mapVkFormat(m_format).getPixelSize()); 1260 const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 1261 const VkImageSubresourceLayers resultBufferImageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); 1262 const VkBufferImageCopy resultBufferImageRegion = makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u), resultBufferImageSubresourceLayers); 1263 de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible)); 1264 1265 const Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder() 1266 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES) 1267 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES) 1268 .build(vkd, device); 1269 const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder() 1270 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) 1271 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) 1272 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 1273 const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout); 1274 1275 de::MovePtr<RayTracingTestPipeline> rayTracingPipeline = de::newMovePtr<RayTracingTestPipeline>(std::ref(m_context), std::cref(*this), m_params); 1276 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, *descriptorSetLayout); 1277 Move<VkPipeline> pipeline = rayTracingPipeline->createPipeline(*pipelineLayout); 1278 1279 de::SharedPtr<BufferWithMemory> raygenShaderBindingTable; 1280 VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion; 1281 std::tie(raygenShaderBindingTable, raygenShaderBindingTableRegion) = rayTracingPipeline->createRaygenShaderBindingTable(*pipeline); 1282 1283 de::SharedPtr<BufferWithMemory> missShaderBindingTable; 1284 VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion; 1285 std::tie(missShaderBindingTable, missShaderBindingTableRegion) = rayTracingPipeline->createMissShaderBindingTable(*pipeline); 1286 1287 de::SharedPtr<BufferWithMemory> hitShaderBindingTable; 1288 VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion; 1289 std::tie(hitShaderBindingTable, hitShaderBindingTableRegion) = rayTracingPipeline->createHitShaderBindingTable(*pipeline); 1290 1291 const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); 1292 1293 const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, familyIndex); 1294 const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); 1295 1296 beginCommandBuffer(vkd, *cmdBuffer); 1297 1298 BottomLevelASPtrs blasPtrs = createBottomLevelAccelerationStructs(*cmdBuffer); 1299 TopLevelASPtr tlasPtr = createTopLevelAccelerationStruct(*cmdBuffer, blasPtrs); 1300 1301 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = 1302 { 1303 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType; 1304 DE_NULL, // const void* pNext; 1305 1u, // deUint32 accelerationStructureCount; 1306 tlasPtr->getPtr() // const VkAccelerationStructureKHR* pAccelerationStructures; 1307 }; 1308 1309 DescriptorSetUpdateBuilder() 1310 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo) 1311 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet) 1312 .update(vkd, device); 1313 1314 vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL); 1315 1316 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline); 1317 1318 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 1319 const VkImageMemoryBarrier imageMemoryBarrier = makeImageMemoryBarrier(VK_ACCESS_NONE, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, image->get(), subresourceRange); 1320 cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &imageMemoryBarrier); 1321 1322 cmdTraceRays(vkd, 1323 *cmdBuffer, 1324 &raygenShaderBindingTableRegion, // rgen 1325 &missShaderBindingTableRegion, // miss 1326 &hitShaderBindingTableRegion, // hit 1327 &callableShaderBindingTableRegion, // call 1328 m_params.width, m_params.height, 1); 1329 1330 const VkMemoryBarrier postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); 1331 const VkMemoryBarrier postCopyMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 1332 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier); 1333 1334 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u, &resultBufferImageRegion); 1335 1336 cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier); 1337 1338 endCommandBuffer(vkd, *cmdBuffer); 1339 1340 submitCommandsAndWait(vkd, device, queue, *cmdBuffer); 1341 1342 invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), resultBufferSize); 1343 1344 return verifyResult(resultBuffer.get()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail(""); 1345} 1346 1347class NoNullShadersFlagGenerator 1348{ 1349public: 1350 using FlagsSet = std::set<VkPipelineCreateFlags>; 1351 struct BitAndName { 1352 VkPipelineCreateFlagBits bit; 1353 const char* name; 1354 }; 1355 static const BitAndName bits[4]; 1356 static std::string name (VkPipelineCreateFlags flags) { 1357 int count = 0; 1358 std::stringstream ss; 1359 for (auto begin = std::begin(bits), end = std::end(bits), i = begin; i != end; ++i) { 1360 if (flags & i->bit) { 1361 if (count++) ss << "_or_"; 1362 ss << i->name; 1363 } 1364 } 1365 return count ? ss.str() : "none"; 1366 } 1367 static VkPipelineCreateFlags mask (const FlagsSet& flags) { 1368 VkPipelineCreateFlags result{}; 1369 for (auto f : flags) result |= f; 1370 return result; 1371 } 1372 NoNullShadersFlagGenerator() : m_next(0) { 1373 FlagsSet fs; 1374 for (const auto& b : bits) fs.insert(b.bit); 1375 combine(m_combs, fs); 1376 } 1377 void reset() { m_next = 0; } 1378 bool next(VkPipelineCreateFlags& flags) { 1379 if (m_next < m_combs.size()) { 1380 flags = mask(m_combs[m_next++]); 1381 return true; 1382 } 1383 return false; 1384 } 1385 void combine(std::vector<FlagsSet>& result, const FlagsSet& v) { 1386 if (v.empty() || result.end() != std::find(result.begin(), result.end(), v)) return; 1387 result.push_back(v); 1388 for (deUint32 i = 0; i < v.size(); ++i) { 1389 FlagsSet w(v); 1390 w.erase(std::next(w.begin(), i)); 1391 combine(result, w); 1392 } 1393 } 1394private: 1395 size_t m_next; 1396 std::vector<FlagsSet> m_combs; 1397}; 1398const NoNullShadersFlagGenerator::BitAndName NoNullShadersFlagGenerator::bits[] = { 1399 { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR, "any" }, 1400 { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR, "chit" }, 1401 { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR, "isect" }, 1402 { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR, "miss" }, 1403}; 1404 1405} // unnamed 1406 1407tcu::TestCaseGroup* createPipelineFlagsTests (tcu::TestContext& testCtx) 1408{ 1409 const deUint32 strides[] = { 3, 5 }; 1410 const deUint32 offsets[] = { 7 }; 1411 1412 struct { 1413 bool type; 1414 const char* name; 1415 } const processors[] = { { false, "gpu" }, { true, "cpu" } }; 1416 struct { 1417 bool type; 1418 const char* name; 1419 } const libs[]{ { true, "use_libs" }, { false, "no_libs" } }; 1420 struct { 1421 GeometryTypes type; 1422 const char* name; 1423 } const geometries[] = { { GeometryTypes::Triangle, "triangles" }, { GeometryTypes::Box, "boxes" }, { GeometryTypes::TriangleAndBox, "tri_and_box" } }; 1424 1425 NoNullShadersFlagGenerator flagsGenerator; 1426 1427 TestParams p; 1428#ifdef INTERNAL_DEBUG 1429 p.width = 30; 1430 p.height = 8; 1431 p.accuracy = 0.80f; 1432#else 1433 p.width = 256; 1434 p.height = 256; 1435 p.accuracy = 0.95f; 1436#endif 1437 p.onHhost = false; 1438 p.useLibs = false; 1439 p.useMaintenance5 = false; 1440 p.flags = 0; 1441 p.geomTypes = GeometryTypes::None; 1442 p.instCount = 3; 1443 p.geomCount = 2; 1444 p.stbRecStride = 0; 1445 p.stbRecOffset = 0; 1446 1447 auto group = new tcu::TestCaseGroup(testCtx, "pipeline_no_null_shaders_flag"); 1448 1449 for (auto& processor : processors) 1450 { 1451 auto processorGroup = new tcu::TestCaseGroup(testCtx, processor.name); 1452 1453 for (auto& geometry : geometries) 1454 { 1455 auto geometryGroup = new tcu::TestCaseGroup(testCtx, geometry.name); 1456 1457 for (auto& stride : strides) 1458 { 1459 auto strideGroup = new tcu::TestCaseGroup(testCtx, ("stride_" + std::to_string(stride)).c_str()); 1460 1461 for (auto& offset : offsets) 1462 { 1463 auto offsetGroup = new tcu::TestCaseGroup(testCtx, ("offset_" + std::to_string(offset)).c_str()); 1464 1465 for (auto& lib : libs) 1466 { 1467 auto libGroup = new tcu::TestCaseGroup(testCtx, lib.name); 1468 1469 VkPipelineCreateFlags flags; 1470 1471 flagsGenerator.reset(); 1472 1473 while (flagsGenerator.next(flags)) 1474 { 1475 if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & flags) 1476 && (GeometryTypes::Triangle == geometry.type)) continue; 1477 1478 p.onHhost = processor.type; 1479 p.geomTypes = geometry.type; 1480 p.stbRecStride = stride; 1481 p.stbRecOffset = offset; 1482 p.flags = flags; 1483 p.useLibs = lib.type; 1484 1485 libGroup->addChild(new PipelineFlagsCase(testCtx, flagsGenerator.name(flags), p)); 1486 } 1487 offsetGroup->addChild(libGroup); 1488 } 1489 strideGroup->addChild(offsetGroup); 1490 } 1491 geometryGroup->addChild(strideGroup); 1492 } 1493 processorGroup->addChild(geometryGroup); 1494 } 1495 group->addChild(processorGroup); 1496 } 1497 1498 de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testCtx, "misc", "")); 1499 1500 p.onHhost = false; 1501 p.geomTypes = GeometryTypes::Box; 1502 p.stbRecStride = 3; 1503 p.stbRecOffset = 7; 1504 p.useLibs = true; 1505 p.useMaintenance5 = true; 1506 1507 for(const auto flag : NoNullShadersFlagGenerator::bits) 1508 { 1509 p.flags = flag.bit; 1510 miscGroup->addChild(new PipelineFlagsCase(testCtx, std::string(flag.name) + "_maintenance5", p)); 1511 } 1512 1513 group->addChild(miscGroup.release()); 1514 1515 return group; 1516} 1517 1518} // RayTracing 1519} // vkt 1520