/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2020 The Khronos Group Inc. * Copyright (c) 2020 Valve Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Ray Tracing barrier tests *//*--------------------------------------------------------------------*/ #include "vktRayTracingBarrierTests.hpp" #include "vktTestCase.hpp" #include "vkDefs.hpp" #include "vkQueryUtil.hpp" #include "vkRayTracingUtil.hpp" #include "vkObjUtil.hpp" #include "vkBufferWithMemory.hpp" #include "vkTypeUtil.hpp" #include "vkBarrierUtil.hpp" #include "vkImageWithMemory.hpp" #include "vkBuilderUtil.hpp" #include "vkCmdUtil.hpp" #include "deUniquePtr.hpp" #include #include #include #include #include #include namespace vkt { namespace RayTracing { namespace { using namespace vk; constexpr deUint32 kBufferElements = 1024u; constexpr deUint32 kBufferSize = kBufferElements * static_cast(sizeof(tcu::UVec4)); // std140 constexpr deUint32 kBufferSize430 = kBufferElements * static_cast(sizeof(deUint32)); // std430 constexpr deUint32 kValuesOffset = 2048u; constexpr deUint32 kImageDim = 32u; // So that kImageDim*kImageDim == kBufferElements. constexpr VkFormat kImageFormat = VK_FORMAT_R32_UINT; // So that each pixel has the same size as a deUint32. const auto kImageExtent = makeExtent3D(kImageDim, kImageDim, 1u); const std::vector kFullScreenQuad = { tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), }; enum class Stage { HOST = 0, TRANSFER, RAYGEN, INTERSECT, ANY_HIT, CLOSEST_HIT, MISS, CALLABLE, COMPUTE, FRAGMENT, }; VkImageLayout getOptimalReadLayout (Stage stage) { VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; switch (stage) { case Stage::HOST: break; // Images will not be read directly from the host. case Stage::TRANSFER: layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; break; case Stage::RAYGEN: case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: case Stage::COMPUTE: case Stage::FRAGMENT: layout = VK_IMAGE_LAYOUT_GENERAL; break; default: DE_ASSERT(false); break; } return layout; } VkPipelineStageFlagBits getPipelineStage (Stage stage) { VkPipelineStageFlagBits bits = VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM; switch (stage) { case Stage::HOST: bits = VK_PIPELINE_STAGE_HOST_BIT; break; case Stage::TRANSFER: bits = VK_PIPELINE_STAGE_TRANSFER_BIT; break; case Stage::RAYGEN: case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: bits = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; break; case Stage::COMPUTE: bits = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break; case Stage::FRAGMENT: bits = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: DE_ASSERT(false); break; } return bits; } VkAccessFlagBits getWriterAccessFlag (Stage stage) { VkAccessFlagBits bits = VK_ACCESS_FLAG_BITS_MAX_ENUM; switch (stage) { case Stage::HOST: bits = VK_ACCESS_HOST_WRITE_BIT; break; case Stage::TRANSFER: bits = VK_ACCESS_TRANSFER_WRITE_BIT; break; case Stage::RAYGEN: case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: case Stage::COMPUTE: case Stage::FRAGMENT: bits = VK_ACCESS_SHADER_WRITE_BIT; break; default: DE_ASSERT(false); break; } return bits; } VkAccessFlagBits getReaderAccessFlag (Stage stage, VkDescriptorType resourceType) { VkAccessFlagBits bits = VK_ACCESS_FLAG_BITS_MAX_ENUM; switch (stage) { case Stage::HOST: bits = VK_ACCESS_HOST_READ_BIT; break; case Stage::TRANSFER: bits = VK_ACCESS_TRANSFER_READ_BIT; break; case Stage::RAYGEN: case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: case Stage::COMPUTE: case Stage::FRAGMENT: bits = ((resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_ACCESS_UNIFORM_READ_BIT : VK_ACCESS_SHADER_READ_BIT); break; default: DE_ASSERT(false); break; } return bits; } // Translate a stage to the corresponding single stage flag. VkShaderStageFlagBits getShaderStageFlagBits (Stage stage) { VkShaderStageFlagBits bits = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM; switch (stage) { case Stage::RAYGEN: bits = VK_SHADER_STAGE_RAYGEN_BIT_KHR; break; case Stage::INTERSECT: bits = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; break; case Stage::ANY_HIT: bits = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; break; case Stage::CLOSEST_HIT: bits = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break; case Stage::MISS: bits = VK_SHADER_STAGE_MISS_BIT_KHR; break; case Stage::CALLABLE: bits = VK_SHADER_STAGE_CALLABLE_BIT_KHR; break; case Stage::COMPUTE: bits = VK_SHADER_STAGE_COMPUTE_BIT; break; case Stage::FRAGMENT: bits = VK_SHADER_STAGE_FRAGMENT_BIT; break; default: DE_ASSERT(false); break; } return bits; } // Gets shader stage flags that will be used when choosing a given stage. VkShaderStageFlags getStageFlags (Stage stage) { VkShaderStageFlags flags = 0u; switch (stage) { case Stage::HOST: break; case Stage::TRANSFER: break; case Stage::RAYGEN: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR); break; case Stage::INTERSECT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); break; case Stage::ANY_HIT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); break; case Stage::CLOSEST_HIT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); break; case Stage::MISS: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR); break; case Stage::CALLABLE: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR); break; case Stage::COMPUTE: flags |= (VK_SHADER_STAGE_COMPUTE_BIT); break; case Stage::FRAGMENT: flags |= (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); break; default: DE_ASSERT(false); break; } return flags; } bool isRayTracingStage (Stage stage) { bool isRT = false; switch (stage) { case Stage::HOST: case Stage::TRANSFER: case Stage::COMPUTE: case Stage::FRAGMENT: break; case Stage::RAYGEN: case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: isRT = true; break; default: DE_ASSERT(false); break; } return isRT; } enum class BarrierType { GENERAL = 0, SPECIFIC = 1, }; struct TestParams { VkDescriptorType resourceType; Stage writerStage; Stage readerStage; BarrierType barrierType; TestParams (VkDescriptorType resourceType_, Stage writerStage_, Stage readerStage_, BarrierType barrierType_) : resourceType (resourceType_) , writerStage (writerStage_) , readerStage (readerStage_) , barrierType (barrierType_) { DE_ASSERT(resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); } }; bool resourceNeedsHostVisibleMemory (const TestParams& params) { return (params.writerStage == Stage::HOST || params.readerStage == Stage::HOST); } bool needsAccelerationStructure (Stage stage) { bool needed; switch (stage) { case Stage::INTERSECT: case Stage::ANY_HIT: case Stage::CLOSEST_HIT: case Stage::MISS: case Stage::CALLABLE: needed = true; break; default: needed = false; break; } return needed; } // The general idea is having a resource like a buffer or image that is generated from a given pipeline stage (including host, // transfer and all ray shader stages) and read from another stage, using a barrier to synchronize access to the resource. Read // values are copied to an output host-visible buffer for verification. class BarrierTestCase : public vkt::TestCase { public: BarrierTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& testParams); virtual ~BarrierTestCase (void) {} virtual void initPrograms (SourceCollections& programCollection) const; virtual TestInstance* createInstance (Context& context) const; virtual void checkSupport (Context& context) const; private: TestParams m_params; }; class BarrierTestInstance : public vkt::TestInstance { public: BarrierTestInstance (Context& context, const TestParams& testParams); virtual ~BarrierTestInstance (void) {} virtual tcu::TestStatus iterate (void); private: TestParams m_params; }; BarrierTestCase::BarrierTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& testParams) : vkt::TestCase (testCtx, name, description) , m_params (testParams) { } void BarrierTestCase::initPrograms (SourceCollections& programCollection) const { const auto& wstage = m_params.writerStage; const auto& rstage = m_params.readerStage; const bool readNeedAS = needsAccelerationStructure(rstage); const deUint32 readerVerifierBinding = (readNeedAS ? 2u : 1u); // 0 is the barrier resource, 1 may be the AS. const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_4, 0u, true); const std::string valStatement = " const uint val = id1d + " + de::toString(kValuesOffset) + ";\n"; const std::string readerSaveStatement = " verificationBuffer.data[id1d] = val;\n"; // Common for all ray tracing shaders. std::stringstream rayTracingIdsStream; rayTracingIdsStream << " const uint id1d = gl_LaunchIDEXT.y * " << kImageDim << " + gl_LaunchIDEXT.x;\n" << " const ivec2 id2d = ivec2(gl_LaunchIDEXT.xy);\n" ; const std::string rayTracingIds = rayTracingIdsStream.str(); // Common for all compute shaders. std::stringstream computeIdsStream; computeIdsStream << " const uint id1d = gl_GlobalInvocationID.y * " << kImageDim << " + gl_GlobalInvocationID.x;\n" << " const ivec2 id2d = ivec2(gl_GlobalInvocationID.xy);\n" ; const std::string computeIds = computeIdsStream.str(); // Common for all fragment shaders. std::stringstream fragIdsStream; fragIdsStream << " const uint id1d = uint(gl_FragCoord.y) * " << kImageDim << " + uint(gl_FragCoord.x);\n" << " const ivec2 id2d = ivec2(gl_FragCoord.xy);\n" ; const std::string fragIds = fragIdsStream.str(); // Statements to declare the resource in the writer and reader sides, as well as writing to and reading from it. std::stringstream writerResourceDecl; std::stringstream readerResourceDecl; std::stringstream writeStatement; std::stringstream readStatement; switch (m_params.resourceType) { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: writerResourceDecl << "layout(set = 0, binding = 0, std140) uniform ubodef { uint data[" << kBufferElements << "]; } ubo;\n"; readerResourceDecl << "layout(set = 0, binding = 0, std140) uniform ubodef { uint data[" << kBufferElements << "]; } ubo;\n"; // No writes can happen from shaders in this case. readStatement << " const uint val = ubo.data[id1d];\n"; break; case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: writerResourceDecl << "layout(set = 0, binding = 0, std140) buffer ssbodef { uint data[" << kBufferElements << "]; } ssbo;\n"; readerResourceDecl << "layout(set = 0, binding = 0, std140) buffer ssbodef { uint data[" << kBufferElements << "]; } ssbo;\n"; writeStatement << " ssbo.data[id1d] = val;\n"; readStatement << " const uint val = ssbo.data[id1d];\n"; break; case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: writerResourceDecl << "layout(r32ui, set = 0, binding = 0) uniform uimage2D simage;\n"; readerResourceDecl << "layout(r32ui, set = 0, binding = 0) uniform uimage2D simage;\n"; writeStatement << " imageStore(simage, id2d, uvec4(val, 0, 0, 0));\n"; readStatement << " const uint val = imageLoad(simage, id2d).x;\n"; break; default: DE_ASSERT(false); break; } // This extra buffer will be used to copy values from the resource as obtained by the reader and will later be verified on the host. std::stringstream readerVerifierDeclStream; readerVerifierDeclStream << "layout(set = 0, binding = " << readerVerifierBinding << ") buffer vssbodef { uint data[" << kBufferElements << "]; } verificationBuffer;\n"; const std::string readerVerifierDecl = readerVerifierDeclStream.str(); // These are always used together in writer shaders. const std::string writerCalcAndWrite = valStatement + writeStatement.str(); // Add shaders that will be used to write to the resource. if (wstage == Stage::HOST || wstage == Stage::TRANSFER) ; // Nothing to do here. else if (wstage == Stage::RAYGEN) { std::stringstream rgen; rgen << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions; } else if (wstage == Stage::INTERSECT) { programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream isect; isect << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "hitAttributeEXT vec3 hitAttribute;\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << " hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n" << " reportIntersectionEXT(1.0f, 0);\n" << "}\n" ; programCollection.glslSources.add("writer_isect") << glu::IntersectionSource(updateRayTracingGLSL(isect.str())) << buildOptions; } else if (wstage == Stage::ANY_HIT) { programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream ahit; ahit << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << "hitAttributeEXT vec3 attribs;\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_ahit") << glu::AnyHitSource(updateRayTracingGLSL(ahit.str())) << buildOptions; } else if (wstage == Stage::CLOSEST_HIT) { programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream chit; chit << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << "hitAttributeEXT vec3 attribs;\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions; } else if (wstage == Stage::MISS) { programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream miss; miss << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions; } else if (wstage == Stage::CALLABLE) { { std::stringstream rgen; rgen << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) callableDataEXT float unusedCallableData;" << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n" << "\n" << "void main()\n" << "{\n" << " executeCallableEXT(0, 0);\n" << "}\n" ; programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions; } std::stringstream callable; callable << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) callableDataInEXT float unusedCallableData;\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << rayTracingIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_callable") << glu::CallableSource(updateRayTracingGLSL(callable.str())) << buildOptions; } else if (wstage == Stage::COMPUTE) { std::stringstream compute; compute << "#version 460 core\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << computeIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_comp") << glu::ComputeSource(compute.str()); } else if (wstage == Stage::FRAGMENT) { { std::stringstream vert; vert << "#version 460 core\n" << "layout(location = 0) in highp vec4 position;\n" << "void main()\n" << "{\n" << " gl_Position = position;\n" << "}\n" ; programCollection.glslSources.add("writer_aux_vert") << glu::VertexSource(vert.str()); } std::stringstream frag; frag << "#version 460 core\n" << writerResourceDecl.str() << "void main()\n" << "{\n" << fragIds << writerCalcAndWrite << "}\n" ; programCollection.glslSources.add("writer_frag") << glu::FragmentSource(frag.str()); } else { DE_ASSERT(false); } // These are always used together by reader shaders. const std::string readerAllDecls = readerResourceDecl.str() + readerVerifierDecl; const std::string readerReadAndSave = readStatement.str() + readerSaveStatement; // Add shaders that will be used to read from the resource. if (rstage == Stage::HOST || rstage == Stage::TRANSFER) ; // Nothing to do here. else if (rstage == Stage::RAYGEN) { std::stringstream rgen; rgen << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions; } else if (rstage == Stage::INTERSECT) { programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream isect; isect << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "hitAttributeEXT vec3 hitAttribute;\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << " hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n" << " reportIntersectionEXT(1.0f, 0);\n" << "}\n" ; programCollection.glslSources.add("reader_isect") << glu::IntersectionSource(updateRayTracingGLSL(isect.str())) << buildOptions; } else if (rstage == Stage::ANY_HIT) { programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream ahit; ahit << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << "hitAttributeEXT vec3 attribs;\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_ahit") << glu::AnyHitSource(updateRayTracingGLSL(ahit.str())) << buildOptions; } else if (rstage == Stage::CLOSEST_HIT) { programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream chit; chit << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << "hitAttributeEXT vec3 attribs;\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions; } else if (rstage == Stage::MISS) { programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions; std::stringstream miss; miss << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions; } else if (rstage == Stage::CALLABLE) { { std::stringstream rgen; rgen << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) callableDataEXT float unusedCallableData;" << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n" << "\n" << "void main()\n" << "{\n" << " executeCallableEXT(0, 0);\n" << "}\n" ; programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions; } std::stringstream callable; callable << "#version 460 core\n" << "#extension GL_EXT_ray_tracing : require\n" << "layout(location = 0) callableDataInEXT float unusedCallableData;\n" << readerAllDecls << "void main()\n" << "{\n" << rayTracingIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_callable") << glu::CallableSource(updateRayTracingGLSL(callable.str())) << buildOptions; } else if (rstage == Stage::COMPUTE) { std::stringstream compute; compute << "#version 460 core\n" << readerAllDecls << "void main()\n" << "{\n" << computeIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_comp") << glu::ComputeSource(compute.str()); } else if (rstage == Stage::FRAGMENT) { { std::stringstream vert; vert << "#version 460 core\n" << "layout(location = 0) in highp vec4 position;\n" << "void main()\n" << "{\n" << " gl_Position = position;\n" << "}\n" ; programCollection.glslSources.add("reader_aux_vert") << glu::VertexSource(vert.str()); } std::stringstream frag; frag << "#version 460 core\n" << readerAllDecls << "void main()\n" << "{\n" << fragIds << readerReadAndSave << "}\n" ; programCollection.glslSources.add("reader_frag") << glu::FragmentSource(frag.str()); } else { DE_ASSERT(false); } } TestInstance* BarrierTestCase::createInstance (Context& context) const { return new BarrierTestInstance(context, m_params); } void BarrierTestCase::checkSupport (Context& context) const { if (m_params.writerStage == Stage::FRAGMENT) { const auto& features = context.getDeviceFeatures(); if (!features.fragmentStoresAndAtomics) TCU_THROW(NotSupportedError, "Fragment shader does not support stores"); } if (isRayTracingStage(m_params.readerStage) || isRayTracingStage(m_params.writerStage)) { context.requireDeviceFunctionality("VK_KHR_acceleration_structure"); context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline"); const auto& rtFeatures = context.getRayTracingPipelineFeatures(); if (!rtFeatures.rayTracingPipeline) TCU_THROW(NotSupportedError, "Ray Tracing pipelines not supported"); const auto& asFeatures = context.getAccelerationStructureFeatures(); if (!asFeatures.accelerationStructure) TCU_FAIL("VK_KHR_acceleration_structure supported without accelerationStructure support"); } } BarrierTestInstance::BarrierTestInstance (Context& context, const TestParams& testParams) : vkt::TestInstance (context) , m_params (testParams) { } // Creates a buffer with kBufferElements elements of type deUint32 and std140 padding. std::unique_ptr makeStd140Buffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags, MemoryRequirement memReq) { std::unique_ptr buffer; const auto bufferCreateInfo = makeBufferCreateInfo(static_cast(kBufferSize), flags); buffer.reset(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, memReq)); return buffer; } // Fill buffer with data using std140 padding rules. void fillStd140Buffer (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer) { // Buffer host ptr. auto& bufferAlloc = buffer.getAllocation(); auto* bufferPtr = bufferAlloc.getHostPtr(); // Fill buffer with data. This uses the same strategy as the writer shaders. std::vector bufferData(kBufferElements, tcu::UVec4(kValuesOffset, 0u, 0u, 0u)); for (size_t i = 0; i < bufferData.size(); ++i) bufferData[i].x() += static_cast(i); deMemcpy(bufferPtr, bufferData.data(), static_cast(kBufferSize)); flushAlloc(vkd, device, bufferAlloc); } // Fill buffer with data using std430 padding rules (compact integers). void fillStd430Buffer (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer) { // Buffer host ptr. auto& bufferAlloc = buffer.getAllocation(); auto* bufferPtr = bufferAlloc.getHostPtr(); // Fill buffer with data. This uses the same strategy as the writer shaders. std::vector bufferData(kBufferElements); std::iota(begin(bufferData), end(bufferData), kValuesOffset); deMemcpy(bufferPtr, bufferData.data(), static_cast(kBufferSize430)); flushAlloc(vkd, device, bufferAlloc); } // Creates a host-visible std430 buffer with kBufferElements elements of type deUint32. If requested, fill buffer with values // starting at kValuesOffset. std::unique_ptr makeStd430BufferImpl (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags, bool fill) { std::unique_ptr buffer; const auto bufferCreateInfo = makeBufferCreateInfo(static_cast(kBufferSize430), flags); buffer.reset(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); if (fill) fillStd430Buffer(vkd, device, *buffer); return buffer; } std::unique_ptr makeStd430Buffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags) { return makeStd430BufferImpl(vkd, device, alloc, flags, false); } std::unique_ptr makeStd430BufferFilled (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags) { return makeStd430BufferImpl(vkd, device, alloc, flags, true); } // Helper struct to group data related to the writer or reader stages. // Not every member will be used at the same time. struct StageData { Move descriptorSetLayout; Move pipelineLayout; Move descriptorPool; Move descriptorSet; Move pipeline; Move renderPass; Move framebuffer; std::unique_ptr vertexBuffer; de::MovePtr bottomLevelAccelerationStructure; de::MovePtr topLevelAccelerationStructure; de::MovePtr raygenShaderBindingTable; de::MovePtr missShaderBindingTable; de::MovePtr hitShaderBindingTable; de::MovePtr callableShaderBindingTable; VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion; VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion; VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion; VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion; StageData () : descriptorSetLayout () , pipelineLayout () , descriptorPool () , descriptorSet () , pipeline () , renderPass () , framebuffer () , vertexBuffer () , bottomLevelAccelerationStructure () , topLevelAccelerationStructure () , raygenShaderBindingTable () , missShaderBindingTable () , hitShaderBindingTable () , callableShaderBindingTable () , raygenShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0)) , missShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0)) , hitShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0)) , callableShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0)) { } // Make sure we don't mistakenly pass one of these by value. StageData (const StageData&) = delete; StageData (StageData&&) = delete; }; // Auxiliar function to update the descriptor set for the writer or reader stages. void updateDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkCommandBuffer cmdBuffer, Allocator& alloc, VkDescriptorType resourceType, Stage stage, StageData& stageData, BufferWithMemory* resourceBuffer, VkImageView resourceImgView, VkImageLayout layout, bool asNeeded, BufferWithMemory* verificationBuffer) { DescriptorSetUpdateBuilder updateBuilder; VkWriteDescriptorSetAccelerationStructureKHR writeASInfo; if (resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { const auto descriptorBufferInfo = makeDescriptorBufferInfo(resourceBuffer->get(), 0ull, VK_WHOLE_SIZE); updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), resourceType, &descriptorBufferInfo); } else if (resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { const auto descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, resourceImgView, layout); updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), resourceType, &descriptorImageInfo); } else { DE_ASSERT(false); } // Create top and bottom level acceleration structures if needed. if (asNeeded) { stageData.bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure(); stageData.bottomLevelAccelerationStructure->setDefaultGeometryData(getShaderStageFlagBits(stage)); stageData.bottomLevelAccelerationStructure->createAndBuild(vkd, device, cmdBuffer, alloc); stageData.topLevelAccelerationStructure = makeTopLevelAccelerationStructure(); stageData.topLevelAccelerationStructure->setInstanceCount(1); stageData.topLevelAccelerationStructure->addInstance(de::SharedPtr(stageData.bottomLevelAccelerationStructure.release())); stageData.topLevelAccelerationStructure->createAndBuild(vkd, device, cmdBuffer, alloc); writeASInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; writeASInfo.pNext = nullptr; writeASInfo.accelerationStructureCount = 1u; writeASInfo.pAccelerationStructures = stageData.topLevelAccelerationStructure.get()->getPtr(); updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &writeASInfo); } if (verificationBuffer) { const deUint32 bindingNumber = (asNeeded ? 2u : 1u); const auto descriptorBufferInfo = makeDescriptorBufferInfo(verificationBuffer->get(), 0ull, VK_WHOLE_SIZE); updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingNumber), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo); } updateBuilder.update(vkd, device); } // Auxiliar function to create the writer or reader compute pipeline void createComputePipeline (const DeviceInterface& vkd, VkDevice device, Context& context, const char* shaderName, StageData& stageData) { const auto shaderModule = createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName), 0u); const VkPipelineShaderStageCreateInfo stageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage; shaderModule.get(), // VkShaderModule module; "main", // const char* pName; nullptr, // const VkSpecializationInfo* pSpecializationInfo; }; const VkComputePipelineCreateInfo createInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkPipelineCreateFlags flags; stageInfo, // VkPipelineShaderStageCreateInfo stage; stageData.pipelineLayout.get(), // VkPipelineLayout layout; DE_NULL, // VkPipeline basePipelineHandle; 0, // deInt32 basePipelineIndex; }; // Compute pipeline. stageData.pipeline = createComputePipeline(vkd, device, DE_NULL, &createInfo); } // Auxiliar function to record commands using the compute pipeline. void useComputePipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData) { vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, stageData.pipeline.get()); vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr); vkd.cmdDispatch(cmdBuffer, kImageDim, kImageDim, 1u); } // Auxiliar function to create graphics pipeline objects for writer or reader stages. void createGraphicsPipelineObjects (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, Context& context, const char* vertShaderName, const char* fragShaderName, StageData& stageData) { const auto vertShader = createShaderModule(vkd, device, context.getBinaryCollection().get(vertShaderName), 0u); const auto fragShader = createShaderModule(vkd, device, context.getBinaryCollection().get(fragShaderName), 0u); // Render pass. const auto subpassDescription = makeSubpassDescription(0u, VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, nullptr, 0u, nullptr, nullptr, nullptr, 0u, nullptr); const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkRenderPassCreateFlags flags; 0u, // deUint32 attachmentCount; nullptr, // const VkAttachmentDescription* pAttachments; 1u, // deUint32 subpassCount; &subpassDescription, // const VkSubpassDescription* pSubpasses; 0u, // deUint32 dependencyCount; nullptr, // const VkSubpassDependency* pDependencies; }; stageData.renderPass = createRenderPass(vkd, device, &renderPassInfo); // Viewport. const auto viewport = makeViewport(kImageExtent); const std::vector viewports(1u, viewport); // Scissor. const auto scissor = makeRect2D(kImageExtent); const std::vector scissors(1u, scissor); // Pipeline. stageData.pipeline = makeGraphicsPipeline(vkd, device, stageData.pipelineLayout.get(), vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(), stageData.renderPass.get(), viewports, scissors); // Framebuffer. stageData.framebuffer = makeFramebuffer(vkd, device, stageData.renderPass.get(), 0u, nullptr, kImageDim, kImageDim); // Vertex buffer with full-screen quad. const auto vertexBufferSize = static_cast(kFullScreenQuad.size() * sizeof(decltype(kFullScreenQuad)::value_type)); const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); stageData.vertexBuffer.reset(new BufferWithMemory(vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible)); const auto& vertexBufferAlloc = stageData.vertexBuffer->getAllocation(); deMemcpy(vertexBufferAlloc.getHostPtr(), kFullScreenQuad.data(), static_cast(vertexBufferSize)); flushAlloc(vkd, device, vertexBufferAlloc); } // Auxiliar function to record commands using the graphics pipeline. void useGraphicsPipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData) { const VkDeviceSize vertexBufferOffset = 0ull; const auto scissor = makeRect2D(kImageExtent); beginRenderPass(vkd, cmdBuffer, stageData.renderPass.get(), stageData.framebuffer.get(), scissor); vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stageData.pipeline.get()); vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr); vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &stageData.vertexBuffer->get(), &vertexBufferOffset); vkd.cmdDraw(cmdBuffer, static_cast(kFullScreenQuad.size()), 1u, 0u, 0u); endRenderPass(vkd, cmdBuffer); } // Auxiliar function to create ray tracing pipelines for the writer or reader stages. void createRayTracingPipelineData (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, Context& context, Stage stage, StageData& stageData, deUint32 shaderGroupHandleSize, deUint32 shaderGroupBaseAlignment, const char* rgenAuxName, const char* rgenName, const char* isectName, const char* ahitName, const char* chitName, const char* missName, const char* callableName) { // Ray tracing stage DE_ASSERT(isRayTracingStage(stage)); if (stage == Stage::RAYGEN) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenName), 0), 0); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else if (stage == Stage::INTERSECT) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0); rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(isectName), 0), 1); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else if (stage == Stage::ANY_HIT) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0); rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(ahitName), 0), 1); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else if (stage == Stage::CLOSEST_HIT) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0); rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(chitName), 0), 1); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else if (stage == Stage::MISS) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0); rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(missName), 0), 1); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); stageData.missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); stageData.missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else if (stage == Stage::CALLABLE) { const auto rayTracingPipeline = de::newMovePtr(); rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0); rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(callableName), 0), 1); stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get()); stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); stageData.callableShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); stageData.callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.callableShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); } else { DE_ASSERT(false); } } // Auxiliar function to record commands using the ray tracing pipeline for the writer or reader stages. void useRayTracingPipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData) { vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, stageData.pipeline.get()); vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr); vkd.cmdTraceRaysKHR(cmdBuffer, &stageData.raygenShaderBindingTableRegion, &stageData.missShaderBindingTableRegion, &stageData.hitShaderBindingTableRegion, &stageData.callableShaderBindingTableRegion, kImageDim, kImageDim, 1u); } tcu::TestStatus BarrierTestInstance::iterate (void) { const auto& vki = m_context.getInstanceInterface(); const auto physicalDevice = m_context.getPhysicalDevice(); const auto& vkd = m_context.getDeviceInterface(); const auto device = m_context.getDevice(); const auto queue = m_context.getUniversalQueue(); const auto familyIndex = m_context.getUniversalQueueFamilyIndex(); auto& alloc = m_context.getDefaultAllocator(); const auto imageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); const bool rtInUse = (isRayTracingStage(m_params.readerStage) || isRayTracingStage(m_params.writerStage)); // Stage data for the writer and reader stages. StageData writerStageData; StageData readerStageData; // Get some ray tracing properties. deUint32 shaderGroupHandleSize = 0u; deUint32 shaderGroupBaseAlignment = 1u; if (rtInUse) { const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice); shaderGroupHandleSize = rayTracingPropertiesKHR->getShaderGroupHandleSize(); shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment(); } // Shader stages involved. const auto writerStages = getStageFlags(m_params.writerStage); const auto readerStages = getStageFlags(m_params.readerStage); const auto allStages = (writerStages | readerStages); const bool writerNeedsAS = needsAccelerationStructure(m_params.writerStage); const bool readerNeedsAS = needsAccelerationStructure(m_params.readerStage); // Command buffer. const auto cmdPool = makeCommandPool(vkd, device, familyIndex); const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); const auto cmdBuffer = cmdBufferPtr.get(); beginCommandBuffer(vkd, cmdBuffer); std::unique_ptr resourceImg; Move resourceImgView; VkImageLayout resourceImgLayout = VK_IMAGE_LAYOUT_UNDEFINED; const auto resourceImgSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); std::unique_ptr stagingBuffer; std::unique_ptr resourceBuffer; std::unique_ptr verificationBuffer; const VkBufferUsageFlags stagingBufferFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; // Create verification buffer for later use. { VkBufferUsageFlags verificationBufferFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; if (m_params.readerStage == Stage::TRANSFER) verificationBufferFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; verificationBuffer = makeStd430Buffer(vkd, device, alloc, verificationBufferFlags); } // Create resource buffer or resource image. if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) DE_ASSERT(m_params.writerStage == Stage::HOST || m_params.writerStage == Stage::TRANSFER); VkBufferUsageFlags bufferFlags = ((m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); if (m_params.writerStage == Stage::TRANSFER) bufferFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; if (m_params.readerStage == Stage::TRANSFER) bufferFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; MemoryRequirement bufferMemReq = (resourceNeedsHostVisibleMemory(m_params) ? MemoryRequirement::HostVisible : MemoryRequirement::Any); resourceBuffer = makeStd140Buffer(vkd, device, alloc, bufferFlags, bufferMemReq); } else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { DE_ASSERT(m_params.writerStage != Stage::HOST); VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_STORAGE_BIT; if (m_params.writerStage == Stage::TRANSFER) imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; if (m_params.readerStage == Stage::TRANSFER) imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; const VkImageCreateInfo resourceImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; kImageFormat, // VkFormat format; kImageExtent, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; imageUsage, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 0u, // deUint32 queueFamilyIndexCount; nullptr, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; }; resourceImg.reset(new ImageWithMemory(vkd, device, alloc, resourceImageInfo, MemoryRequirement::Any)); resourceImgLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Image view. resourceImgView = makeImageView(vkd, device, resourceImg->get(), VK_IMAGE_VIEW_TYPE_2D, kImageFormat, resourceImgSubresourceRange); } else { DE_ASSERT(false); } // Populate resource from the writer stage. if (m_params.writerStage == Stage::HOST) { DE_ASSERT(m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); // Fill buffer data from the host. fillStd140Buffer(vkd, device, *resourceBuffer); } else if (m_params.writerStage == Stage::TRANSFER) { // Similar to the previous one, but using a staging buffer. if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { // Create and fill staging buffer. stagingBuffer = makeStd140Buffer(vkd, device, alloc, stagingBufferFlags, MemoryRequirement::HostVisible); fillStd140Buffer(vkd, device, *stagingBuffer); // Fill resource buffer using a transfer operation. const auto region = makeBufferCopy(0u, 0u, static_cast(kBufferSize)); const auto barrier = makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr); vkd.cmdCopyBuffer(cmdBuffer, stagingBuffer->get(), resourceBuffer->get(), 1u, ®ion); } else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { // Prepare staging buffer with packed pixels. stagingBuffer = makeStd430BufferFilled(vkd, device, alloc, stagingBufferFlags); // Barrier for the staging buffer. const auto stagingBufferBarrier = makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, &stagingBufferBarrier, 0u, nullptr, 0u, nullptr); // Transition image to the proper layout. const auto expectedLayout = ((m_params.barrierType == BarrierType::SPECIFIC) ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL); if (expectedLayout != resourceImgLayout) { const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier); resourceImgLayout = expectedLayout; } // Copy buffer to image. const auto bufferImageCopy = makeBufferImageCopy(kImageExtent, imageSubresourceLayers); vkd.cmdCopyBufferToImage(cmdBuffer, stagingBuffer->get(), resourceImg->get(), resourceImgLayout, 1u, &bufferImageCopy); } else { DE_ASSERT(false); } } else { // Other cases use pipelines and a shader to fill the resource. // Descriptor set layout. DescriptorSetLayoutBuilder dslBuilder; dslBuilder.addBinding(m_params.resourceType, 1u, allStages, nullptr); // The resource is used in the writer and reader stages. if (writerNeedsAS) dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, writerStages, nullptr); writerStageData.descriptorSetLayout = dslBuilder.build(vkd, device); // Pipeline layout. writerStageData.pipelineLayout = makePipelineLayout(vkd, device, writerStageData.descriptorSetLayout.get()); // Descriptor pool and set. DescriptorPoolBuilder poolBuilder; poolBuilder.addType(m_params.resourceType); if (writerNeedsAS) poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR); writerStageData.descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); writerStageData.descriptorSet = makeDescriptorSet(vkd, device, writerStageData.descriptorPool.get(), writerStageData.descriptorSetLayout.get()); // Update descriptor set. updateDescriptorSet(vkd, device, cmdBuffer, alloc, m_params.resourceType, m_params.writerStage, writerStageData, resourceBuffer.get(), resourceImgView.get(), VK_IMAGE_LAYOUT_GENERAL, writerNeedsAS, nullptr); if (m_params.writerStage == Stage::COMPUTE) { createComputePipeline(vkd, device, m_context, "writer_comp", writerStageData); if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { // Make sure the image is in the proper layout for shader writes. const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL; if (expectedLayout != resourceImgLayout) { const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier); resourceImgLayout = expectedLayout; } } // Generate the resource using the pipeline. useComputePipeline(vkd, cmdBuffer, writerStageData); } else if (m_params.writerStage == Stage::FRAGMENT) { createGraphicsPipelineObjects(vkd, device, alloc, m_context, "writer_aux_vert", "writer_frag", writerStageData); if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { // Make sure the image is in the proper layout for shader writes. const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL; if (expectedLayout != resourceImgLayout) { const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier); resourceImgLayout = expectedLayout; } } useGraphicsPipeline(vkd, cmdBuffer, writerStageData); } else { createRayTracingPipelineData(vkd, device, alloc, m_context, m_params.writerStage, writerStageData, shaderGroupHandleSize, shaderGroupBaseAlignment, "writer_aux_rgen", "writer_rgen", "writer_isect", "writer_ahit", "writer_chit", "writer_miss", "writer_callable"); if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { // Make sure the image is in the proper layout for shader writes. const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL; if (expectedLayout != resourceImgLayout) { const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange); vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier); resourceImgLayout = expectedLayout; } } useRayTracingPipeline(vkd, cmdBuffer, writerStageData); } } // Main barrier to synchronize the writer stage to the reader stage. const auto writerPipelineStage = getPipelineStage(m_params.writerStage); const auto readerPipelineStage = getPipelineStage(m_params.readerStage); const auto writerAccessFlag = getWriterAccessFlag(m_params.writerStage); const auto readerAccessFlag = getReaderAccessFlag(m_params.readerStage, m_params.resourceType); if (m_params.barrierType == BarrierType::GENERAL) { const auto memoryBarrier = makeMemoryBarrier(writerAccessFlag, readerAccessFlag); vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 1u, &memoryBarrier, 0u, nullptr, 0u, nullptr); // Note the image will remain in the general layout in this case. if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) DE_ASSERT(resourceImgLayout == VK_IMAGE_LAYOUT_GENERAL); } else if (m_params.barrierType == BarrierType::SPECIFIC) { if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { const auto bufferBarrier = makeBufferMemoryBarrier(writerAccessFlag, readerAccessFlag, resourceBuffer->get(), 0ull, VK_WHOLE_SIZE); vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 0u, nullptr, 1u, &bufferBarrier, 0u, nullptr); } else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { // We'll switch the image layout from the current layout to the one the reader expects. const auto newLayout = getOptimalReadLayout(m_params.readerStage); const auto imageBarrier = makeImageMemoryBarrier(writerAccessFlag, readerAccessFlag, resourceImgLayout, newLayout, resourceImg->get(), resourceImgSubresourceRange); vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &imageBarrier); resourceImgLayout = newLayout; } else { DE_ASSERT(false); } } else { DE_ASSERT(false); } // Read resource from the reader stage copying it to the verification buffer. if (m_params.readerStage == Stage::HOST) { // This needs to wait until we have submitted the command buffer. See below. } else if (m_params.readerStage == Stage::TRANSFER) { if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) { // This is a bit tricky because the resource buffer is in std140 format and the verification buffer is in std430 format. std::vector regions; regions.reserve(kBufferElements); for (deUint32 i = 0; i < kBufferElements; ++i) { const VkBufferCopy region = { static_cast(i * sizeof(tcu::UVec4)), // VkDeviceSize srcOffset; static_cast(i * sizeof(deUint32)), // VkDeviceSize dstOffset; static_cast(sizeof(deUint32)), // VkDeviceSize size; }; regions.push_back(region); } vkd.cmdCopyBuffer(cmdBuffer, resourceBuffer->get(), verificationBuffer->get(), static_cast(regions.size()), regions.data()); } else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { const auto bufferImageCopyRegion = makeBufferImageCopy(kImageExtent, imageSubresourceLayers); vkd.cmdCopyImageToBuffer(cmdBuffer, resourceImg->get(), resourceImgLayout, verificationBuffer->get(), 1u, &bufferImageCopyRegion); } else { DE_ASSERT(false); } } else { // All other stages use shaders to read the resource into the verification buffer. // Descriptor set layout. DescriptorSetLayoutBuilder dslBuilder; dslBuilder.addBinding(m_params.resourceType, 1u, allStages, nullptr); // Resource accessed in writers and readers. if (readerNeedsAS) dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, readerStages, nullptr); dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, readerStages, nullptr); // Verification buffer. readerStageData.descriptorSetLayout = dslBuilder.build(vkd, device); // Pipeline layout. readerStageData.pipelineLayout = makePipelineLayout(vkd, device, readerStageData.descriptorSetLayout.get()); // Descriptor pool and set. DescriptorPoolBuilder poolBuilder; poolBuilder.addType(m_params.resourceType); if (readerNeedsAS) poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR); poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); readerStageData.descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); readerStageData.descriptorSet = makeDescriptorSet(vkd, device, readerStageData.descriptorPool.get(), readerStageData.descriptorSetLayout.get()); // Update descriptor set. updateDescriptorSet(vkd, device, cmdBuffer, alloc, m_params.resourceType, m_params.readerStage, readerStageData, resourceBuffer.get(), resourceImgView.get(), resourceImgLayout, readerNeedsAS, verificationBuffer.get()); if (m_params.readerStage == Stage::COMPUTE) { createComputePipeline(vkd, device, m_context, "reader_comp", readerStageData); useComputePipeline(vkd, cmdBuffer, readerStageData); } else if (m_params.readerStage == Stage::FRAGMENT) { createGraphicsPipelineObjects(vkd, device, alloc, m_context, "reader_aux_vert", "reader_frag", readerStageData); useGraphicsPipeline(vkd, cmdBuffer, readerStageData); } else { createRayTracingPipelineData(vkd, device, alloc, m_context, m_params.readerStage, readerStageData, shaderGroupHandleSize, shaderGroupBaseAlignment, "reader_aux_rgen", "reader_rgen", "reader_isect", "reader_ahit", "reader_chit", "reader_miss", "reader_callable"); useRayTracingPipeline(vkd, cmdBuffer, readerStageData); } } // Sync verification buffer. { const auto readerVerificationFlags = getWriterAccessFlag(m_params.readerStage); const auto barrier = makeBufferMemoryBarrier(readerVerificationFlags, VK_ACCESS_HOST_READ_BIT, verificationBuffer->get(), 0ull, VK_WHOLE_SIZE); vkd.cmdPipelineBarrier(cmdBuffer, readerPipelineStage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr); } // Submit all recorded commands. endCommandBuffer(vkd, cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer); invalidateAlloc(vkd, device, verificationBuffer->getAllocation()); // If the reader stage is the host, we have to wait until the commands have been submitted and the work has been done. if (m_params.readerStage == Stage::HOST) { DE_ASSERT(m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); auto& resourceBufferAlloc = resourceBuffer->getAllocation(); auto* resourceBufferPtr = resourceBufferAlloc.getHostPtr(); std::vector resourceData(kBufferElements); invalidateAlloc(vkd, device, resourceBufferAlloc); deMemcpy(resourceData.data(), resourceBufferPtr, static_cast(kBufferElements) * sizeof(tcu::UVec4)); // Convert from std140 to std430 on the host. std::vector verificationData(kBufferElements); std::transform(begin(resourceData), end(resourceData), begin(verificationData), [](const tcu::UVec4 &v) -> deUint32 { return v.x(); }); auto& verificationBufferAlloc = verificationBuffer->getAllocation(); auto* verificationBufferPtr = verificationBufferAlloc.getHostPtr(); deMemcpy(verificationBufferPtr, verificationData.data(), static_cast(kBufferElements) * sizeof(deUint32)); flushAlloc(vkd, device, verificationBufferAlloc); } // Check verification buffer on the host. { auto& verificationAlloc = verificationBuffer->getAllocation(); auto* verificationPtr = verificationAlloc.getHostPtr(); std::vector verificationData(kBufferElements); deMemcpy(verificationData.data(), verificationPtr, static_cast(kBufferElements) * sizeof(deUint32)); for (size_t i = 0; i < verificationData.size(); ++i) { const auto& value = verificationData[i]; const auto expected = kValuesOffset + i; if (value != expected) { std::ostringstream msg; msg << "Unexpected value found at position " << i << ": found " << value << " and expected " << expected; return tcu::TestStatus::fail(msg.str()); } } } return tcu::TestStatus::pass("Pass"); } } // anonymous. tcu::TestCaseGroup* createBarrierTests(tcu::TestContext& testCtx) { de::MovePtr group(new tcu::TestCaseGroup(testCtx, "barrier", "Tests involving pipeline barriers and ray tracing")); const struct { VkDescriptorType type; const char* name; } resourceTypes[] = { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "ubo" }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, "ssbo" }, { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "simg" }, }; const struct { Stage stage; const char* name; } stageList[] = { { Stage::HOST, "host" }, { Stage::TRANSFER, "xfer" }, { Stage::RAYGEN, "rgen" }, { Stage::INTERSECT, "isec" }, { Stage::ANY_HIT, "ahit" }, { Stage::CLOSEST_HIT, "chit" }, { Stage::MISS, "miss" }, { Stage::CALLABLE, "call" }, { Stage::COMPUTE, "comp" }, { Stage::FRAGMENT, "frag" }, }; const struct { BarrierType barrierType; const char* name; } barrierTypes[] = { { BarrierType::GENERAL, "memory_barrier" }, { BarrierType::SPECIFIC, "specific_barrier" }, }; for (int resourceTypeIdx = 0; resourceTypeIdx < DE_LENGTH_OF_ARRAY(resourceTypes); ++resourceTypeIdx) { de::MovePtr resourceTypeGroup(new tcu::TestCaseGroup(testCtx, resourceTypes[resourceTypeIdx].name, "")); for (int barrierTypeIdx = 0; barrierTypeIdx < DE_LENGTH_OF_ARRAY(barrierTypes); ++barrierTypeIdx) { de::MovePtr barrierTypeGroup(new tcu::TestCaseGroup(testCtx, barrierTypes[barrierTypeIdx].name, "")); for (int writerStageIdx = 0; writerStageIdx < DE_LENGTH_OF_ARRAY(stageList); ++writerStageIdx) for (int readerStageIdx = 0; readerStageIdx < DE_LENGTH_OF_ARRAY(stageList); ++readerStageIdx) { const auto resourceType = resourceTypes[resourceTypeIdx].type; const auto barrierType = barrierTypes[barrierTypeIdx].barrierType; const auto readerStage = stageList[readerStageIdx].stage; const auto writerStage = stageList[writerStageIdx].stage; // Skip tests that do not involve ray tracing. if (!isRayTracingStage(readerStage) && !isRayTracingStage(writerStage)) continue; // Skip tests which require host acess to images. if (resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && (writerStage == Stage::HOST || readerStage == Stage::HOST)) continue; // Skip tests that would require writes from shaders to an UBO. if (resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER && writerStage != Stage::HOST && writerStage != Stage::TRANSFER) continue; const std::string testName = std::string("from_") + stageList[writerStageIdx].name + "_to_" + stageList[readerStageIdx].name; barrierTypeGroup->addChild(new BarrierTestCase(testCtx, testName, "", TestParams(resourceType, writerStage, readerStage, barrierType))); } resourceTypeGroup->addChild(barrierTypeGroup.release()); } group->addChild(resourceTypeGroup.release()); } return group.release(); } } // RayTracing } // vkt