From 0bbed91c7575761dbb5e0488770eb80299d188f9 Mon Sep 17 00:00:00 2001 From: Sylvain Doremus Date: Sat, 2 Aug 2025 12:14:48 +0200 Subject: [PATCH] FramePasses are now attachment based instead of Image/Buffer based. It allows for dependency handling through the attachments themselves. --- .github/workflows/cmake.yml | 100 +- .gitmodules | 3 + CMakeLists.txt | 15 +- CMakePresets.json | 16 +- external/vcpkg | 1 + include/RenderGraph/Attachment.hpp | 295 +- include/RenderGraph/AttachmentTransition.hpp | 15 +- include/RenderGraph/BufferData.hpp | 33 + include/RenderGraph/BufferViewData.hpp | 119 + include/RenderGraph/DotExport.hpp | 1 + include/RenderGraph/FrameGraph.hpp | 44 +- include/RenderGraph/FrameGraphBase.hpp | 33 +- include/RenderGraph/FrameGraphEnums.hpp | 66 +- include/RenderGraph/FrameGraphFunctions.hpp | 69 +- .../RenderGraph/FrameGraphPrerequisites.hpp | 10 - include/RenderGraph/FrameGraphStructs.hpp | 246 +- include/RenderGraph/FramePass.hpp | 817 ++-- include/RenderGraph/FramePassGroup.hpp | 68 +- include/RenderGraph/GraphContext.hpp | 2 + include/RenderGraph/GraphNode.hpp | 45 +- include/RenderGraph/Hash.hpp | 36 + include/RenderGraph/Id.hpp | 5 - include/RenderGraph/ImageData.hpp | 5 +- include/RenderGraph/RecordContext.hpp | 89 +- include/RenderGraph/ResourceHandler.hpp | 64 +- include/RenderGraph/RunnableGraph.hpp | 12 +- include/RenderGraph/RunnablePass.hpp | 21 +- .../RunnablePasses/ComputePass.hpp | 1 + .../RunnablePasses/GenerateMipmaps.hpp | 3 + .../RenderGraph/RunnablePasses/ImageBlit.hpp | 6 +- .../RenderGraph/RunnablePasses/ImageCopy.hpp | 9 + .../RunnablePasses/PipelineHolder.hpp | 4 +- .../RunnablePasses/RenderMeshConfig.hpp | 18 - .../RunnablePasses/RenderMeshHolder.hpp | 1 + .../RunnablePasses/RenderPassHolder.hpp | 10 +- .../RunnablePasses/RenderQuadConfig.hpp | 3 +- source/RenderGraph/Attachment.cpp | 201 +- source/RenderGraph/AttachmentTransition.cpp | 12 +- source/RenderGraph/DotExport.cpp | 522 +-- source/RenderGraph/FrameGraph.cpp | 405 +- source/RenderGraph/FrameGraph.natvis | 97 +- .../RenderGraph/FrameGraphPrerequisites.cpp | 72 +- source/RenderGraph/FramePass.cpp | 1471 +++---- .../FramePassDependenciesBuilder.cpp | 762 ---- .../FramePassDependenciesBuilder.hpp | 17 - source/RenderGraph/FramePassGroup.cpp | 41 +- source/RenderGraph/GraphBuilder.cpp | 645 ++- source/RenderGraph/GraphBuilder.hpp | 10 +- source/RenderGraph/GraphContext.cpp | 2 + source/RenderGraph/GraphNode.cpp | 61 +- source/RenderGraph/Log.cpp | 25 +- source/RenderGraph/RecordContext.cpp | 364 +- source/RenderGraph/ResourceHandler.cpp | 548 ++- source/RenderGraph/RunnableGraph.cpp | 71 +- source/RenderGraph/RunnablePass.cpp | 116 +- .../RenderGraph/RunnablePasses/BufferCopy.cpp | 69 +- .../RunnablePasses/BufferToImageCopy.cpp | 46 +- .../RunnablePasses/ComputePass.cpp | 26 +- .../RunnablePasses/GenerateMipmaps.cpp | 14 +- .../RenderGraph/RunnablePasses/ImageBlit.cpp | 58 +- .../RenderGraph/RunnablePasses/ImageCopy.cpp | 156 +- .../RunnablePasses/ImageToBufferCopy.cpp | 45 +- .../RunnablePasses/PipelineHolder.cpp | 127 +- .../RenderGraph/RunnablePasses/RenderMesh.cpp | 3 +- .../RunnablePasses/RenderMeshHolder.cpp | 26 +- .../RenderGraph/RunnablePasses/RenderPass.cpp | 9 +- .../RunnablePasses/RenderPassHolder.cpp | 106 +- .../RenderGraph/RunnablePasses/RenderQuad.cpp | 3 +- .../RunnablePasses/RenderQuadHolder.cpp | 65 +- test/BaseTest.cpp | 163 +- test/BaseTest.hpp | 471 +- test/CMakeLists.txt | 9 + test/Common.cpp | 350 +- test/Common.hpp | 29 +- test/TestAttachment.cpp | 2426 ++++++----- test/TestBases.cpp | 1463 ++++--- test/TestRenderGraph.cpp | 3857 ++++++++--------- test/TestRenderPass.cpp | 320 +- test/TestRunnablePass.cpp | 741 +++- vcpkg.json | 17 + 80 files changed, 9895 insertions(+), 8431 deletions(-) create mode 160000 external/vcpkg create mode 100644 include/RenderGraph/BufferData.hpp create mode 100644 include/RenderGraph/BufferViewData.hpp create mode 100644 include/RenderGraph/Hash.hpp delete mode 100644 source/RenderGraph/FramePassDependenciesBuilder.cpp delete mode 100644 source/RenderGraph/FramePassDependenciesBuilder.hpp create mode 100644 vcpkg.json diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 9264d67..5a7ba27 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -20,17 +20,15 @@ jobs: runs-on: ${{ matrix.os[0] }} steps: - uses: actions/checkout@v4 - - name: Setup vcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: '7a57b42f959ad138a5283477fe2e6c97a7cb852f' - - name: Install dependencies from vcpkg - shell: bash - run: | - $VCPKG_ROOT/vcpkg install vulkan-headers:${{ matrix.os[1] }} - name: Checkout submodules run: | git submodule update --init -- "CMake" + git submodule update --init -- "external/vcpkg" + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ github.workspace }}/external/vcpkg' + vcpkgJsonGlob: 'vcpkg.json' - name: Setup OpenCppCoverage id: setup_opencppcoverage run: | @@ -39,23 +37,11 @@ jobs: - name: Create Build Environment run: | cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }} - - name: Configure Warnings as errors (OFF) - if: github.event_name == 'push' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=OFF" >> $GITHUB_ENV - - name: Configure Warnings as errors (ON) - if: github.event_name == 'pull_request' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=ON" >> $GITHUB_ENV - name: Configure CMake shell: bash working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} run: | - cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DPROJECTS_WARNINGS_AS_ERRORS=$PROJ_WAE -DPROJECTS_COVERAGE=ON -DCRG_BUILD_STATIC=OFF -DCRG_UNITY_BUILD=ON -DCRG_BUILD_TESTS=ON -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include + cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/external/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DPROJECTS_COVERAGE=ON -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include --preset ci - name: Build working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} shell: bash @@ -98,37 +84,23 @@ jobs: runs-on: ${{ matrix.os[0] }} steps: - uses: actions/checkout@v4 - - name: Setup vcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: 'f740d6f22908ccd8a519228a26b267f7a68dda9c' - - name: Install dependencies from vcpkg - shell: bash - run: | - $VCPKG_ROOT/vcpkg install vulkan-headers:${{ matrix.os[1] }} - name: Checkout submodules run: | git submodule update --init -- "CMake" + git submodule update --init -- "external/vcpkg" + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ github.workspace }}/external/vcpkg' + vcpkgJsonGlob: 'vcpkg.json' - name: Create Build Environment run: | cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }} - - name: Configure Warnings as errors (OFF) - if: github.event_name == 'push' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=OFF" >> $GITHUB_ENV - - name: Configure Warnings as errors (ON) - if: github.event_name == 'pull_request' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=ON" >> $GITHUB_ENV - name: Configure CMake shell: bash working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} run: | - cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DPROJECTS_WARNINGS_AS_ERRORS=$PROJ_WAE -DCRG_UNITY_BUILD=ON -DCRG_BUILD_TESTS=ON -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include + cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/external/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include --preset ci - name: Build working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} shell: bash @@ -166,32 +138,18 @@ jobs: runs-on: ${{ matrix.os[0] }} steps: - uses: actions/checkout@v4 - - name: Setup vcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: 'f740d6f22908ccd8a519228a26b267f7a68dda9c' - - name: Install dependencies from vcpkg - shell: bash - run: | - $VCPKG_ROOT/vcpkg install vulkan-headers:${{ matrix.os[1] }} - name: Checkout submodules run: | git submodule update --init -- "CMake" + git submodule update --init -- "external/vcpkg" + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ github.workspace }}/external/vcpkg' + vcpkgJsonGlob: 'vcpkg.json' - name: Create Build Environment run: | cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }} - - name: Configure Warnings as errors (OFF) - if: github.event_name == 'push' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=OFF" >> $GITHUB_ENV - - name: Configure Warnings as errors (ON) - if: github.event_name == 'pull_request' - shell: bash - working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} - run: | - echo "PROJ_WAE=ON" >> $GITHUB_ENV - name: Configure GCC version shell: bash working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} @@ -202,7 +160,7 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} run: | - cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DPROJECTS_WARNINGS_AS_ERRORS=$PROJ_WAE -DCRG_UNITY_BUILD=ON -DCRG_BUILD_TESTS=ON -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include + cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/external/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include --preset ci - name: Build working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} shell: bash @@ -240,17 +198,15 @@ jobs: runs-on: ${{ matrix.os[0] }} steps: - uses: actions/checkout@v4 - - name: Setup vcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: 'f740d6f22908ccd8a519228a26b267f7a68dda9c' - - name: Install dependencies from vcpkg - shell: bash - run: | - $VCPKG_ROOT/vcpkg install vulkan-headers:${{ matrix.os[1] }} - name: Checkout submodules run: | git submodule update --init -- "CMake" + git submodule update --init -- "external/vcpkg" + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ github.workspace }}/external/vcpkg' + vcpkgJsonGlob: 'vcpkg.json' - name: Create Build Environment run: | cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }} @@ -276,7 +232,7 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} run: | - cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DPROJECTS_WARNINGS_AS_ERRORS=$PROJ_WAE -DCRG_UNITY_BUILD=ON -DCRG_BUILD_TESTS=ON -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include + cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/external/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/package/rendergraph -DVULKAN_HEADERS_INCLUDE_DIRS=$VCPKG_ROOT/installed/${{matrix.os[1]}}/include --preset ci - name: Build working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }} shell: bash diff --git a/.gitmodules b/.gitmodules index b2ba9cc..c1cb08a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "CMake"] path = CMake url = https://github.com/DragonJoker/CMakeUtils.git +[submodule "external/vcpkg"] + path = external/vcpkg + url = https://github.com/microsoft/vcpkg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d89b0ca..c8e84b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,14 +68,13 @@ endif () set( PROJECTS_UNITY_BUILD ${CRG_UNITY_BUILD} ) if ( MSVC OR NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" ) - if ( NOT DEFINED VULKAN_HEADERS_INCLUDE_DIRS ) - find_path( VULKAN_HEADERS_INCLUDE_DIRS "vulkan/vk_icd.h" ) - endif () # RenderGraph library project( RenderGraph ) set( ${PROJECT_NAME}_HDR_FILES ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Attachment.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/AttachmentTransition.hpp + ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferData.hpp + ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferViewData.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/DotExport.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Exception.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraph.hpp @@ -90,6 +89,7 @@ if ( MSVC OR NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" ) ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphContext.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphNode.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphVisitor.hpp + ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Hash.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Id.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageData.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageViewData.hpp @@ -102,7 +102,6 @@ if ( MSVC OR NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" ) ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Signal.hpp ${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/WriteDescriptorSet.hpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.hpp - ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassDependenciesBuilder.hpp ) set( ${PROJECT_NAME}_SRC_FILES ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/Attachment.cpp @@ -111,7 +110,6 @@ if ( MSVC OR NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" ) ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraph.cpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraphPrerequisites.cpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePass.cpp - ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassDependenciesBuilder.cpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassGroup.cpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassTimer.cpp ${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.cpp @@ -248,9 +246,12 @@ if ( MSVC OR NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" ) $ $ $ - PRIVATE - ${VULKAN_HEADERS_INCLUDE_DIRS} ) + find_package( VulkanHeaders CONFIG ) + target_link_libraries( ${PROJECT_NAME} + PRIVATE + Vulkan::Headers + ) set_target_properties( ${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 diff --git a/CMakePresets.json b/CMakePresets.json index 0a605c4..2dd7bd7 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,7 +24,9 @@ "description": "Developer build configuration using Visual Studio", "inherits": "default-base", "cacheVariables": { - "PROJECTS_WARNINGS_AS_ERRORS": true + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/external/vcpkg/scripts/buildsystems/vcpkg.cmake", + "PROJECTS_WARNINGS_AS_ERRORS": true, + "VCPKG_MANIFEST_FEATURES": "tests" } }, { @@ -92,6 +94,18 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } + }, + { + "name": "ci", + "installDir": "${sourceDir}/package/Castor3D", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/external/vcpkg/scripts/buildsystems/vcpkg.cmake", + "CRG_BUILD_STATIC": false, + "CRG_UNITY_BUILD": true, + "CRG_BUILD_TESTS": true, + "PROJECTS_WARNINGS_AS_ERRORS": true, + "VCPKG_MANIFEST_FEATURES": "tests" + } } ] } diff --git a/external/vcpkg b/external/vcpkg new file mode 160000 index 0000000..e140b1f --- /dev/null +++ b/external/vcpkg @@ -0,0 +1 @@ +Subproject commit e140b1fde236eb682b0d47f905e65008a191800f diff --git a/include/RenderGraph/Attachment.hpp b/include/RenderGraph/Attachment.hpp index a5121d6..a4e5225 100644 --- a/include/RenderGraph/Attachment.hpp +++ b/include/RenderGraph/Attachment.hpp @@ -4,6 +4,7 @@ See LICENSE file in root folder. */ #pragma once +#include "BufferViewData.hpp" #include "ImageViewData.hpp" #include @@ -98,6 +99,11 @@ namespace crg return flags; } + FlagKind getFormatFlags()const + { + return FlagKind( flags & FlagKind( Flag::DepthStencil ) ); + } + uint32_t getViewCount()const { return uint32_t( views.size() ); @@ -128,42 +134,42 @@ namespace crg return hasFlag( Flag::Transition ); } - bool isDepthAttach()const + bool isDepthTarget()const { return hasFlag( Flag::Depth ) && !isTransitionView(); } - bool isStencilAttach()const + bool isStencilTarget()const { return hasFlag( Flag::Stencil ) && !isTransitionView(); } - bool isDepthStencilAttach()const + bool isDepthStencilTarget()const { - return isDepthAttach() && isStencilAttach(); + return isDepthTarget() && isStencilTarget(); } - bool isColourAttach()const + bool isColourTarget()const { return !isSampledView() && !isTransitionView() && !isStorageView() && !isTransferView() - && !isDepthAttach() - && !isStencilAttach(); + && !isDepthTarget() + && !isStencilTarget(); } - bool isStencilClearingAttach()const + bool isStencilClearingTarget()const { return hasFlag( Flag::StencilClearing ); } - bool isStencilInputAttach()const + bool isStencilInputTarget()const { return hasFlag( Flag::StencilInput ); } - bool isStencilOutputAttach()const + bool isStencilOutputTarget()const { return hasFlag( Flag::StencilOutput ); } @@ -175,21 +181,19 @@ namespace crg AttachmentStoreOp storeOp{}; AttachmentLoadOp stencilLoadOp{}; AttachmentStoreOp stencilStoreOp{}; - SamplerDesc samplerDesc{}; ClearValue clearValue{}; PipelineColorBlendAttachmentState blendState = DefaultBlendState; ImageLayout wantedLayout{}; private: CRG_API ImageAttachment() = default; - CRG_API explicit ImageAttachment( ImageViewId view ); + CRG_API explicit ImageAttachment( ImageViewIdArray view ); CRG_API ImageAttachment( FlagKind flags , ImageViewIdArray views , AttachmentLoadOp loadOp , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp - , SamplerDesc samplerDesc , ClearValue clearValue , PipelineColorBlendAttachmentState blendState , ImageLayout wantedLayout ); @@ -205,17 +209,11 @@ namespace crg && lhs.storeOp == rhs.storeOp && lhs.stencilLoadOp == rhs.stencilLoadOp && lhs.stencilStoreOp == rhs.stencilStoreOp - && lhs.samplerDesc == rhs.samplerDesc && lhs.clearValue == rhs.clearValue && lhs.blendState == rhs.blendState; } }; - struct BufferSubresourceRange - { - DeviceSize offset{}; - DeviceSize size{}; - }; /** *\brief * A buffer (uniform or storage) attachment. @@ -242,23 +240,26 @@ namespace crg TransitionView = Transition | View, }; + CRG_API BufferViewId buffer( uint32_t index = 0u )const; CRG_API AccessFlags getAccessMask( bool isInput , bool isOutput )const; CRG_API PipelineStageFlags getPipelineStageFlags( bool isCompute )const; + CRG_API uint32_t getBufferCount()const; + FlagKind getFlags()const { return flags; } - bool hasFlag( Flag flag )const + FlagKind getFormatFlags()const { - return Flag( flags & FlagKind( flag ) ) == flag; + return FlagKind( flags & FlagKind( Flag::View ) ); } - uint32_t getBufferCount()const + bool hasFlag( Flag flag )const { - return uint32_t( buffer.getCount() ); + return Flag( flags & FlagKind( flag ) ) == flag; } bool isUniform()const @@ -301,23 +302,14 @@ namespace crg return isTransition() && isView(); } - Buffer buffer{ {}, std::string{} }; - VkBufferView view{}; - BufferSubresourceRange range{}; + public: + BufferViewIdArray buffers; private: CRG_API BufferAttachment() = default; - CRG_API explicit BufferAttachment( Buffer buffer ); - CRG_API BufferAttachment( FlagKind flags - , Buffer buffer - , DeviceSize offset - , DeviceSize range - , AccessState access = {} ); + CRG_API explicit BufferAttachment( BufferViewIdArray view ); CRG_API BufferAttachment( FlagKind flags - , Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range + , BufferViewIdArray views , AccessState access = {} ); FlagKind flags{}; @@ -326,10 +318,7 @@ namespace crg friend bool operator==( BufferAttachment const & lhs, BufferAttachment const & rhs ) { return lhs.flags == rhs.flags - && lhs.buffer == rhs.buffer - && lhs.view == rhs.view - && lhs.range.offset == rhs.range.offset - && lhs.range.size == rhs.range.size; + && lhs.buffers == rhs.buffers; } }; /** @@ -338,7 +327,16 @@ namespace crg */ struct Attachment { + class Token + { + friend struct Attachment; + friend struct FramePass; + + private: + Token() noexcept = default; + }; friend struct FramePass; + friend class FrameGraph; /** *\brief * The flags qualifying an Attachment. @@ -355,6 +353,11 @@ namespace crg Clearable = 0x01 << 5, InOut = Input | Output, }; + + CRG_API Attachment( Attachment const & rhs ); + CRG_API Attachment & operator=( Attachment const & rhs ); + CRG_API Attachment( Attachment && rhs )noexcept = default; + CRG_API Attachment & operator=( Attachment && rhs )noexcept = default; /** *\name * Getters. @@ -363,10 +366,11 @@ namespace crg CRG_API uint32_t getViewCount()const; CRG_API uint32_t getBufferCount()const; CRG_API ImageViewId view( uint32_t index = 0u )const; - CRG_API VkBuffer buffer( uint32_t index = 0u )const; + CRG_API BufferViewId buffer( uint32_t index = 0u )const; CRG_API ImageLayout getImageLayout( bool separateDepthStencilLayouts )const; CRG_API AccessFlags getAccessMask()const; CRG_API PipelineStageFlags getPipelineStageFlags( bool isCompute )const; + CRG_API Attachment const * getSource( uint32_t index )const; FlagKind getFlags()const { @@ -477,139 +481,134 @@ namespace crg return isBuffer() && bufferAttach.isView(); } - bool isSampledView()const + bool isSampledImageView()const { return isImage() && imageAttach.isSampledView(); } - bool isStorageView()const + bool isStorageImageView()const { return isImage() && imageAttach.isStorageView(); } - bool isTransferView()const + bool isTransferImageView()const { return isImage() && imageAttach.isTransferView(); } - bool isTransitionView()const + bool isTransitionImageView()const { return isImage() && imageAttach.isTransitionView(); } - bool isDepthAttach()const + bool isDepthImageTarget()const { - return isImage() && imageAttach.isDepthAttach(); + return isImage() && imageAttach.isDepthTarget(); } - bool isStencilAttach()const + bool isStencilImageTarget()const { - return isImage() && imageAttach.isStencilAttach(); + return isImage() && imageAttach.isStencilTarget(); } - bool isColourAttach()const + bool isColourImageTarget()const { - return !isSampledView() - && !isTransitionView() - && !isStorageView() - && !isTransferView() - && !isDepthAttach() - && !isStencilAttach(); + return !isSampledImageView() + && !isTransitionImageView() + && !isStorageImageView() + && !isTransferImageView() + && !isDepthImageTarget() + && !isStencilImageTarget(); } - bool isColourInputAttach()const + bool isColourInputImageTarget()const { - return isInput() && isColourAttach(); + return isInput() && isColourImageTarget(); } - bool isColourOutputAttach()const + bool isColourOutputImageTarget()const { - return isOutput() && isColourAttach(); + return isOutput() && isColourImageTarget(); } - bool isColourInOutAttach()const + bool isColourInOutImageTarget()const { - return isInput() && isOutput() && isColourAttach(); + return isInput() && isOutput() && isColourImageTarget(); } - bool isDepthInputAttach()const + bool isDepthInputImageTarget()const { - return isInput() && isDepthAttach(); + return isInput() && isDepthImageTarget(); } - bool isDepthOutputAttach()const + bool isDepthOutputImageTarget()const { - return isOutput() && isDepthAttach(); + return isOutput() && isDepthImageTarget(); } - bool isDepthInOutAttach()const + bool isDepthInOutImageTarget()const { - return isInput() && isOutput() && isDepthAttach(); + return isInput() && isOutput() && isDepthImageTarget(); } - bool isStencilClearingAttach()const + bool isStencilClearingImageTarget()const { - return isImage() && imageAttach.isStencilClearingAttach(); + return isImage() && imageAttach.isStencilClearingTarget(); } - bool isStencilInputAttach()const + bool isStencilInputImageTarget()const { - return isImage() && imageAttach.isStencilInputAttach(); + return isImage() && imageAttach.isStencilInputTarget(); } - bool isStencilOutputAttach()const + bool isStencilOutputImageTarget()const { - return isImage() && imageAttach.isStencilOutputAttach(); + return isImage() && imageAttach.isStencilOutputTarget(); } - bool isStencilInOutAttach()const + bool isStencilInOutImageTarget()const { - return isStencilInputAttach() && isStencilOutputAttach(); + return isStencilInputImageTarget() && isStencilOutputImageTarget(); } - bool isDepthStencilInputAttach()const + bool isDepthStencilInputImageTarget()const { - return isDepthInputAttach() && isStencilInputAttach(); + return isDepthInputImageTarget() && isStencilInputImageTarget(); } - bool isDepthStencilOutputAttach()const + bool isDepthStencilOutputImageTarget()const { - return isDepthOutputAttach() && isStencilOutputAttach(); + return isDepthOutputImageTarget() && isStencilOutputImageTarget(); } - bool isDepthStencilInOutAttach()const + bool isDepthStencilInOutImageTarget()const { - return isDepthInOutAttach() && isStencilInOutAttach(); + return isDepthInOutImageTarget() && isStencilInOutImageTarget(); } - bool isTransferInputView()const + bool isTransferInputImageView()const { - return isInput() && isTransferView(); + return isInput() && isTransferImageView(); } - bool isTransferOutputView()const + bool isTransferOutputImageView()const { - return isOutput() && isTransferView(); + return isOutput() && isTransferImageView(); } - bool isStorageInputView()const + bool isStorageInputImageView()const { - return isInput() && isStorageView(); + return isInput() && isStorageImageView(); } - bool isStorageOutputView()const + bool isStorageOutputImageView()const { - return isOutput() && isStorageView(); + return isOutput() && isStorageImageView(); } BufferSubresourceRange const & getBufferRange()const { - return bufferAttach.range; - } - - SamplerDesc const & getSamplerDesc()const - { - return imageAttach.samplerDesc; + return getSubresourceRange( bufferAttach.buffer() ); } ClearValue const & getClearValue()const @@ -646,35 +645,87 @@ namespace crg *\brief * Creates a default empty attachment. */ + static Attachment createDefault( ImageViewIdArray views ) + { + return Attachment{ std::move( views ) }; + } + static Attachment createDefault( BufferViewIdArray views ) + { + return Attachment{ std::move( views ) }; + } static Attachment createDefault( ImageViewId view ) { - return Attachment{ std::move( view ) }; + return createDefault( ImageViewIdArray{ view } ); } - static Attachment createDefault( Buffer buffer ) + static Attachment createDefault( BufferViewId view ) { - return Attachment{ std::move( buffer ) }; + return createDefault( BufferViewIdArray{ view } ); } /** *\name * Members. */ /**@[*/ - FramePass * pass{}; - uint32_t binding{}; + FramePass const * pass{}; std::string name{}; ImageAttachment imageAttach{}; BufferAttachment bufferAttach{}; + struct Source + { + Source( Attachment const * parent + , FramePass const * pass + , ImageAttachment const & attach ) + : parent{ parent } + , pass{ pass } + , imageAttach{ &attach } + { + } + + Source( Attachment const * parent + , FramePass const * pass + , BufferAttachment const & attach ) + : parent{ parent } + , pass{ pass } + , bufferAttach{ &attach } + { + } + + explicit Source( AttachmentPtr sourceAttach ) + : pass{ sourceAttach->pass } + , imageAttach{ sourceAttach->isImage() ? &sourceAttach->imageAttach : nullptr } + , bufferAttach{ sourceAttach->isBuffer() ? &sourceAttach->bufferAttach : nullptr } + , attach{ std::move( sourceAttach ) } + { + } + + Attachment const * parent{}; + FramePass const * pass{}; + ImageAttachment const * imageAttach{}; + BufferAttachment const * bufferAttach{}; + AttachmentPtr attach; + }; + std::vector< Source > source{}; /**@}*/ CRG_API Attachment( ImageViewId view , Attachment const & origin ); + CRG_API Attachment( BufferViewId view + , Attachment const & origin ); + CRG_API explicit Attachment( ImageViewIdArray view ); + CRG_API explicit Attachment( BufferViewIdArray view ); - private: - CRG_API explicit Attachment( ImageViewId view ); - CRG_API explicit Attachment( Buffer buffer ); - CRG_API Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding + Attachment( FlagKind flags + , std::string name + , FramePass const * pass + , ImageAttachment attach + , Token token ); + Attachment( FlagKind flags + , std::string name + , FramePass const * pass + , BufferAttachment attach + , Token token ); + Attachment( FlagKind flags + , FramePass const & pass , std::string name , ImageAttachment::FlagKind imageFlags , ImageViewIdArray views @@ -682,29 +733,21 @@ namespace crg , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp - , SamplerDesc samplerDesc , ClearValue clearValue , PipelineColorBlendAttachmentState blendState - , ImageLayout wantedLayout ); - CRG_API Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding + , ImageLayout wantedLayout + , Token token ); + Attachment( FlagKind flags + , FramePass const & pass , std::string name , BufferAttachment::FlagKind bufferFlags - , Buffer buffer - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ); - CRG_API Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding - , std::string name - , BufferAttachment::FlagKind bufferFlags - , Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ); + , BufferViewIdArray views + , AccessState wantedAccess + , Token token ); + + private: + + void initSources(); FlagKind flags{}; diff --git a/include/RenderGraph/AttachmentTransition.hpp b/include/RenderGraph/AttachmentTransition.hpp index 47ce736..4ac058d 100644 --- a/include/RenderGraph/AttachmentTransition.hpp +++ b/include/RenderGraph/AttachmentTransition.hpp @@ -13,6 +13,13 @@ namespace crg template< typename DataT > struct DataTransitionT { + DataTransitionT( DataT data, Attachment outputAttach, Attachment inputAttach )noexcept + : data{ std::move( data ) } + , outputAttach{ std::move( outputAttach ) } + , inputAttach{ std::move( inputAttach ) } + { + } + DataT data; Attachment outputAttach; Attachment inputAttach; @@ -28,15 +35,9 @@ namespace crg struct AttachmentTransitions { - ViewTransitionArray viewTransitions; + ImageTransitionArray imageTransitions; BufferTransitionArray bufferTransitions; }; AttachmentTransitions mergeIdenticalTransitions( AttachmentTransitions value ); - - struct FramePassTransitions - { - FramePass const * pass; - AttachmentTransitions transitions; - }; } diff --git a/include/RenderGraph/BufferData.hpp b/include/RenderGraph/BufferData.hpp new file mode 100644 index 0000000..19cec33 --- /dev/null +++ b/include/RenderGraph/BufferData.hpp @@ -0,0 +1,33 @@ +/* +This file belongs to FrameGraph. +See LICENSE file in root folder. +*/ +#pragma once + +#include "Id.hpp" + +namespace crg +{ + /** + *\brief + * Basic buffer data, from which buffers will be created. + */ + struct BufferData + { + std::string name; + BufferCreateInfo info; + + explicit BufferData( std::string name = {} + , BufferCreateFlags flags = {} + , DeviceSize size = {} + , BufferUsageFlags usage = {} + , MemoryPropertyFlags memory = MemoryPropertyFlags::eDeviceLocal ) + : name{ std::move( name ) } + , info{ flags, size, usage, memory } + { + } + + private: + friend bool operator==( BufferData const & lhs, BufferData const & rhs ) = default; + }; +} diff --git a/include/RenderGraph/BufferViewData.hpp b/include/RenderGraph/BufferViewData.hpp new file mode 100644 index 0000000..94b3dcd --- /dev/null +++ b/include/RenderGraph/BufferViewData.hpp @@ -0,0 +1,119 @@ +/* +This file belongs to FrameGraph. +See LICENSE file in root folder. +*/ +#pragma once + +#include "Id.hpp" + +namespace crg +{ + /** + *\brief + * Basic buffer view data, from which views will be created. + */ + struct BufferViewData + { + std::string name; + BufferId buffer; + BufferViewCreateInfo info; + BufferViewIdArray source{}; + + explicit BufferViewData( std::string name = {} + , BufferId buffer = BufferId{} + , BufferSubresourceRange subresourceRange = {} + , PixelFormat format = PixelFormat::eUNDEFINED ) + : name{ std::move( name ) } + , buffer{ std::move( buffer ) } + , info{ format, subresourceRange } + { + } + + private: + friend bool operator==( BufferViewData const & lhs, BufferViewData const & rhs ) + { + return lhs.buffer == rhs.buffer + && lhs.info == rhs.info; + } + }; + + struct VertexBuffer + { + explicit VertexBuffer( BufferViewId pbuffer = BufferViewId{} + , VkVertexInputAttributeDescriptionArray pvertexAttribs = {} + , VkVertexInputBindingDescriptionArray pvertexBindings = {} ) + : buffer{ std::move( pbuffer ) } + , vertexAttribs{ std::move( pvertexAttribs ) } + , vertexBindings{ std::move( pvertexBindings ) } + { + inputState.vertexAttributeDescriptionCount = uint32_t( vertexAttribs.size() ); + inputState.pVertexAttributeDescriptions = vertexAttribs.data(); + inputState.vertexBindingDescriptionCount = uint32_t( vertexBindings.size() ); + inputState.pVertexBindingDescriptions = vertexBindings.data(); + } + + BufferViewId buffer; + VkVertexInputAttributeDescriptionArray vertexAttribs; + VkVertexInputBindingDescriptionArray vertexBindings; + VkPipelineVertexInputStateCreateInfo inputState{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, {}, {}, {}, {}, {} }; + }; + + struct IndexBuffer + { + explicit IndexBuffer( BufferViewId pbuffer = BufferViewId{} ) + : buffer{ std::move( pbuffer ) } + { + } + + BufferViewId buffer; + + private: + friend bool operator==( IndexBuffer const & lhs, IndexBuffer const & rhs ) = default; + }; + + struct IndirectBuffer + { + explicit IndirectBuffer( BufferViewId pbuffer + , uint32_t pstride ) + : buffer{ std::move( pbuffer ) } + , stride{ pstride } + { + } + + BufferViewId buffer; + uint32_t stride; + + private: + friend bool operator==( IndirectBuffer const & lhs, IndirectBuffer const & rhs ) = default; + }; + + template<> + struct DefaultValueGetterT< VertexBuffer > + { + static VertexBuffer get() + { + VertexBuffer const result{}; + return result; + } + }; + + template<> + struct DefaultValueGetterT< IndexBuffer > + { + static IndexBuffer get() + { + IndexBuffer const result{ BufferViewId{} }; + return result; + } + }; + + template<> + struct DefaultValueGetterT< IndirectBuffer > + { + static IndirectBuffer get() + { + IndirectBuffer const result{ BufferViewId{}, 0u }; + return result; + } + }; +} diff --git a/include/RenderGraph/DotExport.hpp b/include/RenderGraph/DotExport.hpp index 0d221a4..ddc2780 100644 --- a/include/RenderGraph/DotExport.hpp +++ b/include/RenderGraph/DotExport.hpp @@ -22,6 +22,7 @@ namespace crg::dot bool withIds{}; bool withGroups{}; bool splitGroups{}; + std::string toRemove{}; }; using DisplayResult = std::map< std::string, std::stringstream, std::less<> >; diff --git a/include/RenderGraph/FrameGraph.hpp b/include/RenderGraph/FrameGraph.hpp index 935f7dd..c720006 100644 --- a/include/RenderGraph/FrameGraph.hpp +++ b/include/RenderGraph/FrameGraph.hpp @@ -5,6 +5,8 @@ See LICENSE file in root folder. #pragma once #include "Attachment.hpp" +#include "BufferData.hpp" +#include "BufferViewData.hpp" #include "FramePassGroup.hpp" #include "GraphNode.hpp" #include "ImageData.hpp" @@ -39,11 +41,44 @@ namespace crg * Resource creation. */ /**@{*/ + CRG_API BufferId createBuffer( BufferData const & img ); + CRG_API BufferViewId createView( BufferViewData const & view ); CRG_API ImageId createImage( ImageData const & img ); CRG_API ImageViewId createView( ImageViewData const & view ); /**@}*/ /** *\name + * Views merging. + */ + /**@{*/ + /** + *\brief + * Creates a view which represents the given views merging. + */ + CRG_API ImageViewId mergeViews( ImageViewIdArray const & views + , bool mergeMipLevels = true + , bool mergeArrayLayers = true ); + /** + *\brief + * Creates a view which represents the given views merging. + */ + CRG_API BufferViewId mergeViews( BufferViewIdArray const & views ); + /**@}*/ + /** + *\name + * Attachments merging. + */ + /**@{*/ + /** + *\brief + * Creates a view which represents the given views merging. + */ + CRG_API Attachment const * mergeAttachments( AttachmentArray const & attachments + , bool mergeMipLevels = true + , bool mergeArrayLayers = true ); + /**@}*/ + /** + *\name * Passes and groups. */ /**@{*/ @@ -78,7 +113,9 @@ namespace crg , ImageSubresourceRange const & range )const; CRG_API LayoutState getFinalLayoutState( ImageViewId view , uint32_t passIndex = 0u )const; - CRG_API AccessState const & getFinalAccessState( Buffer const & buffer + CRG_API AccessState const & getFinalAccessState( BufferId buffer + , BufferSubresourceRange const & range )const; + CRG_API AccessState const & getFinalAccessState( BufferViewId view , uint32_t passIndex = 0u )const; CRG_API void addInput( ImageId image , ImageViewType viewType @@ -135,8 +172,8 @@ namespace crg ResourceHandler & m_handler; std::string m_name; FramePassGroupPtr m_defaultGroup; - ImageIdAliasMap m_imageAliases; - ImageViewIdAliasMap m_imageViewAliases; + std::set< BufferId > m_buffers; + std::set< BufferViewId > m_bufferViews; std::set< ImageId > m_images; std::set< ImageViewId > m_imageViews; std::map< std::string, ImageViewId, std::less<> > m_attachViews; @@ -144,5 +181,6 @@ namespace crg FrameGraphArray m_depends; LayerLayoutStatesHandler m_inputs; LayerLayoutStatesHandler m_outputs; + std::unordered_map< size_t, AttachmentPtr > m_mergedAttachments; }; } diff --git a/include/RenderGraph/FrameGraphBase.hpp b/include/RenderGraph/FrameGraphBase.hpp index 977c9c5..f794453 100644 --- a/include/RenderGraph/FrameGraphBase.hpp +++ b/include/RenderGraph/FrameGraphBase.hpp @@ -34,10 +34,10 @@ namespace crg { struct Attachment; struct AttachmentTransitions; - struct Buffer; + struct BufferData; + struct BufferViewData; struct FramePass; struct FramePassGroup; - struct FramePassTransitions; struct GraphContext; struct GraphNode; struct ImageData; @@ -82,6 +82,8 @@ namespace crg template< typename TypeT > struct RawTyperT; + using BufferId = Id< BufferData >; + using BufferViewId = Id< BufferViewData >; using ImageId = Id< ImageData >; using ImageViewId = Id< ImageViewData >; using AccessState = PipelineState; @@ -89,6 +91,7 @@ namespace crg using PassDependencyCache = std::unordered_map< FramePass const *, DependencyCache >; using DeviceSize = VkDeviceSize; + using AttachmentPtr = std::unique_ptr< Attachment >; using FramePassPtr = std::unique_ptr< FramePass >; using FramePassGroupPtr = std::unique_ptr< FramePassGroup >; using GraphNodePtr = std::unique_ptr< GraphNode >; @@ -103,16 +106,17 @@ namespace crg *\brief * The transition between two states of an image view. */ - using ViewTransition = DataTransitionT< ImageViewId >; - using ViewTransitionArray = DataTransitionArrayT< ImageViewId >; + using ImageTransition = DataTransitionT< ImageViewId >; + using ImageTransitionArray = DataTransitionArrayT< ImageViewId >; /** *\brief - * The transition between two states of a storage buffer. + * The transition between two states of a buffer. */ - using BufferTransition = DataTransitionT< Buffer >; - using BufferTransitionArray = DataTransitionArrayT< Buffer >; + using BufferTransition = DataTransitionT< BufferViewId >; + using BufferTransitionArray = DataTransitionArrayT< BufferViewId >; - using AttachmentArray = std::vector< Attachment >; + using AttachmentArray = std::vector< Attachment const * >; + using BufferViewIdArray = std::vector< BufferViewId >; using FramePassPtrArray = std::vector< FramePassPtr >; using FramePassGroupPtrArray = std::vector< FramePassGroupPtr >; using FrameGraphArray = std::vector< FrameGraph const * >; @@ -120,22 +124,19 @@ namespace crg using GraphAdjacentNodeArray = std::vector< GraphAdjacentNode >; using ConstGraphAdjacentNodeArray = std::vector< ConstGraphAdjacentNode >; using GraphNodePtrArray = std::vector< GraphNodePtr >; - using FramePassDependencies = std::vector< FramePassTransitions >; using WriteDescriptorSetArray = std::vector< WriteDescriptorSet >; using AttachmentsNodeMap = std::map< ConstGraphAdjacentNode, AttachmentTransitions >; + using BufferMemoryMap = std::map< BufferId, std::pair< VkBuffer, VkDeviceMemory > >; + using BufferViewMap = std::map< BufferViewId, VkBufferView >; using ImageMemoryMap = std::map< ImageId, std::pair< VkImage, VkDeviceMemory > >; using ImageViewMap = std::map< ImageViewId, VkImageView >; - using ImageIdArray = std::vector< ImageId >; using ImageViewIdArray = std::vector< ImageViewId >; using SemaphoreWaitArray = std::vector< SemaphoreWait >; - template< typename DataT > - using IdAliasMap = std::map< Id< DataT >, Id< DataT > >; - using ImageIdAliasMap = IdAliasMap< ImageData >; - using ImageViewIdAliasMap = IdAliasMap< ImageViewData >; - template< typename DataT > using IdDataOwnerCont = std::map< Id< DataT >, std::unique_ptr< DataT > >; + using BufferIdDataOwnerCont = IdDataOwnerCont< BufferData >; + using BufferViewIdDataOwnerCont = IdDataOwnerCont< BufferViewData >; using ImageIdDataOwnerCont = IdDataOwnerCont< ImageData >; using ImageViewIdDataOwnerCont = IdDataOwnerCont< ImageViewData >; @@ -162,7 +163,7 @@ namespace crg using LayerLayoutStates = std::map< uint32_t, MipLayoutStates >; using LayoutStateMap = std::unordered_map< uint32_t, LayerLayoutStates >; using LayerLayoutStatesMap = std::map< uint32_t, LayerLayoutStates >; - using AccessStateMap = std::unordered_map< VkBuffer, AccessState >; + using AccessStateMap = std::unordered_map< uint32_t, AccessState >; using ViewsLayout = LayoutStateMap; using BuffersLayout = AccessStateMap; using ViewsLayoutPtr = std::unique_ptr< ViewsLayout >; diff --git a/include/RenderGraph/FrameGraphEnums.hpp b/include/RenderGraph/FrameGraphEnums.hpp index 511a6d7..c50d200 100644 --- a/include/RenderGraph/FrameGraphEnums.hpp +++ b/include/RenderGraph/FrameGraphEnums.hpp @@ -110,8 +110,8 @@ namespace crg { eRepeat, eMirroredRepeat, - eClampToBorder, eClampToEdge, + eClampToBorder, eMirrorClampToEdge, }; @@ -208,6 +208,66 @@ namespace crg eBlue = 1000148045, }; + enum class BufferCreateFlags : int32_t + { + eNone = 0x00000000, + eSparseBinding = 0x00000001, + eSparseResidency = 0x00000002, + eSparseAliased = 0x00000004, + eProtected = 0x00000008, + eDeviceAddressCaptureReplay = 0x00000010, + eDescriptorBufferCaptureReplay = 0x00000020, + eVideoProfileIndependent = 0x00000040, + }; + CRG_MakeFlags( BufferCreateFlags ) + + enum class BufferUsageFlags : int32_t + { + eNone = 0x00000000, + eTransferSrc = 0x00000001, + eTransferDst = 0x00000002, + eUniformTexelBuffer = 0x00000004, + eStorageTexelBuffer = 0x00000008, + eUniformBuffer = 0x00000010, + eStorageBuffer = 0x00000020, + eIndexBuffer = 0x00000040, + eVertexBuffer = 0x00000080, + eIndirectBuffer = 0x00000100, + eShaderDeviceAddress = 0x00020000, + eVideoDecodeSrc = 0x00002000, + eVideoDecodeDst = 0x00004000, + eTransformFeedbackBuffer = 0x00000800, + eTransformFeedbackCounterBuffer = 0x00001000, + eConditionalRendering = 0x00000200, + eAccelerationStructureBuildInputReadOnly = 0x00080000, + eAccelerationStructureStorage = 0x00100000, + eShaderBindingTable = 0x00000400, + eVideoEncodeDst = 0x00008000, + eVideoEncodeSrc = 0x00010000, + eSamplerDescriptorBuffer = 0x00200000, + eResourceDescriptorBuffer = 0x00400000, + ePushDescriptorsDescriptorBuffer = 0x04000000, + eMicromapBuildInputReadOnly = 0x00800000, + eMicromapStorage = 0x01000000, + eTileMemory = 0x08000000, + }; + CRG_MakeFlags( BufferUsageFlags ) + + enum class MemoryPropertyFlags : int32_t + { + eNone = 0x0000000, + eDeviceLocal = 0x00000001, + eHostVisible = 0x00000002, + eHostCoherent = 0x00000004, + eHostCached = 0x00000008, + eLazilyAllocated = 0x00000010, + eProtected = 0x00000020, + eDeviceCoherent = 0x00000040, + eDeviceUncached = 0x00000080, + eRdmaCapable = 0x00000100, + }; + CRG_MakeFlags( MemoryPropertyFlags ) + enum class ImageCreateFlags : int32_t { eNone = 0, @@ -344,8 +404,8 @@ namespace crg eMemoryRead = 0x00008000, eMemoryWrite = 0x00010000, eTransformFeedbackWrite = 0x02000000, - eTransformFeedback_counterRead = 0x04000000, - eTransformFeedback_counterWrite = 0x08000000, + eTransformFeedbackCounterRead = 0x04000000, + eTransformFeedbackCounterWrite = 0x08000000, eConditionalRenderingRead = 0x00100000, eColorAttachmentReadNonCoherent = 0x00080000, eAccelerationStructureRead = 0x00200000, diff --git a/include/RenderGraph/FrameGraphFunctions.hpp b/include/RenderGraph/FrameGraphFunctions.hpp index 055099d..dde318f 100644 --- a/include/RenderGraph/FrameGraphFunctions.hpp +++ b/include/RenderGraph/FrameGraphFunctions.hpp @@ -15,12 +15,12 @@ namespace crg CRG_API std::string_view getName( MipmapMode v ); CRG_API std::string_view getName( WrapMode v ); - CRG_API bool operator==( Buffer const & lhs, Buffer const & rhs ); - CRG_API ImageCreateFlags getImageCreateFlags( ImageId const & image )noexcept; CRG_API ImageCreateFlags getImageCreateFlags( ImageViewId const & image )noexcept; CRG_API Extent3D const & getExtent( ImageId const & image )noexcept; CRG_API Extent3D const & getExtent( ImageViewId const & image )noexcept; + CRG_API DeviceSize getSize( BufferId const & image )noexcept; + CRG_API DeviceSize getSize( BufferViewId const & image )noexcept; CRG_API Extent3D getMipExtent( ImageViewId const & image )noexcept; CRG_API PixelFormat getFormat( ImageId const & image )noexcept; CRG_API PixelFormat getFormat( ImageViewId const & image )noexcept; @@ -32,7 +32,8 @@ namespace crg CRG_API uint32_t getArrayLayers( ImageId const & image )noexcept; CRG_API uint32_t getArrayLayers( ImageViewId const & image )noexcept; CRG_API ImageAspectFlags getAspectFlags( ImageViewId const & image )noexcept; - CRG_API ImageSubresourceRange const & getSubresourceRange( ImageViewId const & format )noexcept; + CRG_API ImageSubresourceRange const & getSubresourceRange( ImageViewId const & image )noexcept; + CRG_API BufferSubresourceRange const & getSubresourceRange( BufferViewId const & buffer )noexcept; CRG_API AccessFlags getAccessMask( ImageLayout layout )noexcept; CRG_API PipelineStageFlags getStageMask( ImageLayout layout )noexcept; CRG_API PipelineState getPipelineState( PipelineStageFlags flags )noexcept; @@ -47,9 +48,11 @@ namespace crg , ImageViewType viewType , ImageSubresourceRange const & range )noexcept; CRG_API bool match( ImageViewId const & lhs, ImageViewId const & rhs )noexcept; - CRG_API bool match( Buffer const & lhs, Buffer const & rhs )noexcept; + CRG_API bool match( BufferViewId const & lhs, BufferViewId const & rhs )noexcept; CRG_API ImageViewId const & resolveView( ImageViewId const & view , uint32_t passIndex ); + CRG_API BufferViewId const & resolveView( BufferViewId const & view + , uint32_t passIndex ); CRG_API void convert( SemaphoreWaitArray const & toWait , std::vector< VkSemaphore > & semaphores @@ -225,6 +228,36 @@ namespace crg return AttachmentStoreOp( v ); } + constexpr VkBufferCreateFlags getBufferCreateFlags( BufferCreateFlags v )noexcept + { + return VkBufferCreateFlags( v ); + } + + constexpr BufferCreateFlags getBufferCreateFlags( VkBufferCreateFlags v )noexcept + { + return BufferCreateFlags( v ); + } + + constexpr VkBufferUsageFlags getBufferUsageFlags( BufferUsageFlags v )noexcept + { + return VkBufferUsageFlags( v ); + } + + constexpr BufferUsageFlags getBufferUsageFlags( VkBufferUsageFlags v )noexcept + { + return BufferUsageFlags( v ); + } + + constexpr VkMemoryPropertyFlags getMemoryPropertyFlags( MemoryPropertyFlags v )noexcept + { + return VkMemoryPropertyFlags( v ); + } + + constexpr MemoryPropertyFlags getMemoryPropertyFlags( VkMemoryPropertyFlags v )noexcept + { + return MemoryPropertyFlags( v ); + } + constexpr VkImageCreateFlags getImageCreateFlags( ImageCreateFlags v )noexcept { return VkImageCreateFlags( v ); @@ -415,6 +448,34 @@ namespace crg return result; } + constexpr VkBufferViewCreateInfo convert( BufferViewCreateInfo const & v )noexcept + { + return VkBufferViewCreateInfo{ VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, nullptr + , 0, VkBuffer{}, convert( v.format ) + , v.subresourceRange.offset, v.subresourceRange.size }; + } + + constexpr BufferViewCreateInfo convert( VkBufferViewCreateInfo const & v )noexcept + { + return BufferViewCreateInfo{ convert( v.format ) + , { v.offset, v.range } }; + } + + constexpr VkBufferCreateInfo convert( BufferCreateInfo const & v )noexcept + { + return VkBufferCreateInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr + , getBufferCreateFlags( v.flags ), v.size + , getBufferUsageFlags( v.usage ) + , VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr }; + } + + constexpr BufferCreateInfo convert( VkBufferCreateInfo const & v )noexcept + { + return BufferCreateInfo{ getBufferCreateFlags( v.flags ) + , v.size + , getBufferUsageFlags( v.usage ) }; + } + constexpr VkImageViewCreateInfo convert( ImageViewCreateInfo const & v )noexcept { return VkImageViewCreateInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr diff --git a/include/RenderGraph/FrameGraphPrerequisites.hpp b/include/RenderGraph/FrameGraphPrerequisites.hpp index ac35809..da3ae06 100644 --- a/include/RenderGraph/FrameGraphPrerequisites.hpp +++ b/include/RenderGraph/FrameGraphPrerequisites.hpp @@ -38,16 +38,6 @@ namespace crg } }; - template<> - struct DefaultValueGetterT< IndirectBuffer > - { - static IndirectBuffer get() - { - IndirectBuffer const result{ Buffer{ VkBuffer{}, std::string{} }, 0u }; - return result; - } - }; - template< typename TypeT > using RawTypeT = typename RawTyperT< TypeT >::Type; } diff --git a/include/RenderGraph/FrameGraphStructs.hpp b/include/RenderGraph/FrameGraphStructs.hpp index 97764f3..e773495 100644 --- a/include/RenderGraph/FrameGraphStructs.hpp +++ b/include/RenderGraph/FrameGraphStructs.hpp @@ -13,8 +13,8 @@ namespace crg { struct Offset2D { - int32_t x; - int32_t y; + int32_t x{}; + int32_t y{}; private: friend bool operator==( Offset2D const & lhs, Offset2D const & rhs ) = default; @@ -22,8 +22,8 @@ namespace crg struct Extent2D { - uint32_t width; - uint32_t height; + uint32_t width{}; + uint32_t height{}; private: friend bool operator==( Extent2D const & lhs, Extent2D const & rhs ) = default; @@ -31,8 +31,8 @@ namespace crg struct Rect2D { - Offset2D offset; - Extent2D extent; + Offset2D offset{}; + Extent2D extent{}; private: friend bool operator==( Rect2D const & lhs, Rect2D const & rhs ) = default; @@ -40,9 +40,9 @@ namespace crg struct Offset3D { - int32_t x; - int32_t y; - int32_t z; + int32_t x{}; + int32_t y{}; + int32_t z{}; private: friend bool operator==( Offset3D const & lhs, Offset3D const & rhs ) = default; @@ -50,37 +50,76 @@ namespace crg struct Extent3D { - uint32_t width; - uint32_t height; - uint32_t depth; + uint32_t width{}; + uint32_t height{}; + uint32_t depth{}; private: friend bool operator==( Extent3D const & lhs, Extent3D const & rhs ) = default; }; + struct Rect3D + { + Offset3D offset{}; + Extent3D extent{}; + + private: + friend bool operator==( Rect3D const & lhs, Rect3D const & rhs ) = default; + }; + + struct BufferSubresourceRange + { + DeviceSize offset{}; + DeviceSize size{}; + + private: + friend bool operator==( BufferSubresourceRange const & lhs, BufferSubresourceRange const & rhs ) = default; + }; + struct ImageSubresourceRange { - ImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; + ImageAspectFlags aspectMask{}; + uint32_t baseMipLevel{}; + uint32_t levelCount{}; + uint32_t baseArrayLayer{}; + uint32_t layerCount{}; private: friend bool operator==( ImageSubresourceRange const & lhs, ImageSubresourceRange const & rhs ) = default; }; + struct BufferCreateInfo + { + BufferCreateFlags flags{}; + DeviceSize size{}; + BufferUsageFlags usage{}; + MemoryPropertyFlags memory{}; + + private: + friend bool operator==( BufferCreateInfo const & lhs, BufferCreateInfo const & rhs ) = default; + }; + + struct BufferViewCreateInfo + { + PixelFormat format{}; + BufferSubresourceRange subresourceRange{}; + + private: + friend bool operator==( BufferViewCreateInfo const & lhs, BufferViewCreateInfo const & rhs ) = default; + }; + struct ImageCreateInfo { - ImageCreateFlags flags; - ImageType imageType; - PixelFormat format; - Extent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - SampleCount samples; - ImageTiling tiling; - ImageUsageFlags usage; + ImageCreateFlags flags{}; + ImageType imageType{}; + PixelFormat format{}; + Extent3D extent{}; + uint32_t mipLevels{}; + uint32_t arrayLayers{}; + SampleCount samples{}; + ImageTiling tiling{}; + ImageUsageFlags usage{}; + MemoryPropertyFlags memory{}; private: friend bool operator==( ImageCreateInfo const & lhs, ImageCreateInfo const & rhs ) = default; @@ -88,10 +127,10 @@ namespace crg struct ImageViewCreateInfo { - ImageViewCreateFlags flags; - ImageViewType viewType; - PixelFormat format; - ImageSubresourceRange subresourceRange; + ImageViewCreateFlags flags{}; + ImageViewType viewType{}; + PixelFormat format{}; + ImageSubresourceRange subresourceRange{}; private: friend bool operator==( ImageViewCreateInfo const & lhs, ImageViewCreateInfo const & rhs ) = default; @@ -167,8 +206,8 @@ namespace crg struct ClearDepthStencilValue { - float depth; - uint32_t stencil; + float depth{}; + uint32_t stencil{}; private: friend bool operator==( ClearDepthStencilValue const & lhs, ClearDepthStencilValue const & rhs ) = default; @@ -235,14 +274,17 @@ namespace crg struct PipelineState { - AccessFlags access; - PipelineStageFlags pipelineStage; + AccessFlags access{}; + PipelineStageFlags pipelineStage{}; + + private: + friend bool operator==( PipelineState const & lhs, PipelineState const & rhs ) = default; }; struct LayoutState { - ImageLayout layout; - PipelineState state; + ImageLayout layout{}; + PipelineState state{}; }; template< typename VkTypeT > @@ -275,138 +317,10 @@ namespace crg void ( *destroy )( GraphContext &, VkTypeT & )noexcept; }; - struct Buffer - { - std::string name; - - Buffer( VkBufferArray pbuffers - , std::string pname )noexcept - : name{ std::move( pname ) } - , m_buffers{ std::move( pbuffers ) } - { - } - - Buffer( VkBuffer buffer - , std::string name )noexcept - : Buffer{ VkBufferArray{ buffer }, std::move( name ) } - { - } - - VkBuffer const & buffer( uint32_t index = 0 )const noexcept - { - return m_buffers.size() == 1u - ? m_buffers.front() - : m_buffers[index]; - } - - VkBuffer & buffer( uint32_t index = 0 )noexcept - { - return m_buffers.size() == 1u - ? m_buffers.front() - : m_buffers[index]; - } - - size_t getCount()const noexcept - { - return m_buffers.size(); - } - - private: - VkBufferArray m_buffers; - - friend CRG_API bool operator==( Buffer const & lhs, Buffer const & rhs ); - }; - - struct VertexBuffer - { - VertexBuffer( VertexBuffer const & rhs ) = delete; - VertexBuffer & operator=( VertexBuffer const & rhs ) = delete; - ~VertexBuffer()noexcept = default; - - explicit VertexBuffer( Buffer pbuffer = { VkBuffer{}, std::string{} } - , VkDeviceMemory pmemory = VkDeviceMemory{} - , VkVertexInputAttributeDescriptionArray pvertexAttribs = {} - , VkVertexInputBindingDescriptionArray pvertexBindings = {} ) - : buffer{ std::move( pbuffer ) } - , memory{ pmemory } - , vertexAttribs{ std::move( pvertexAttribs ) } - , vertexBindings{ std::move( pvertexBindings ) } - { - inputState.vertexAttributeDescriptionCount = uint32_t( vertexAttribs.size() ); - inputState.pVertexAttributeDescriptions = vertexAttribs.data(); - inputState.vertexBindingDescriptionCount = uint32_t( vertexBindings.size() ); - inputState.pVertexBindingDescriptions = vertexBindings.data(); - } - - VertexBuffer( VertexBuffer && rhs )noexcept - : buffer{ rhs.buffer } - , memory{ rhs.memory } - , vertexAttribs{ std::move( rhs.vertexAttribs ) } - , vertexBindings{ std::move( rhs.vertexBindings ) } - , inputState{ std::move( rhs.inputState ) } - { - inputState.vertexAttributeDescriptionCount = uint32_t( vertexAttribs.size() ); - inputState.pVertexAttributeDescriptions = vertexAttribs.data(); - inputState.vertexBindingDescriptionCount = uint32_t( vertexBindings.size() ); - inputState.pVertexBindingDescriptions = vertexBindings.data(); - } - - VertexBuffer & operator=( VertexBuffer && rhs )noexcept - { - buffer = rhs.buffer; - memory = rhs.memory; - vertexAttribs = std::move( rhs.vertexAttribs ); - vertexBindings = std::move( rhs.vertexBindings ); - inputState = std::move( rhs.inputState ); - - inputState.vertexAttributeDescriptionCount = uint32_t( vertexAttribs.size() ); - inputState.pVertexAttributeDescriptions = vertexAttribs.data(); - inputState.vertexBindingDescriptionCount = uint32_t( vertexBindings.size() ); - inputState.pVertexBindingDescriptions = vertexBindings.data(); - - return *this; - } - - Buffer buffer{ VkBuffer{}, std::string{} }; - VkDeviceMemory memory{}; - VkVertexInputAttributeDescriptionArray vertexAttribs{}; - VkVertexInputBindingDescriptionArray vertexBindings{}; - VkPipelineVertexInputStateCreateInfo inputState{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, {}, {}, {}, {}, {} }; - }; - - struct IndexBuffer - { - explicit IndexBuffer( Buffer pbuffer = { VkBuffer{}, std::string{} } - , VkDeviceMemory pmemory = VkDeviceMemory{} ) - : buffer{ std::move( pbuffer ) } - , memory{ pmemory } - { - } - - Buffer buffer; - VkDeviceMemory memory; - }; - - struct IndirectBuffer - { - explicit IndirectBuffer( Buffer pbuffer - , uint32_t pstride - , DeviceSize poffset = {} ) - : buffer{ std::move( pbuffer ) } - , offset{ poffset } - , stride{ pstride } - { - } - - Buffer buffer; - DeviceSize offset; - uint32_t stride; - }; - struct SemaphoreWait { - VkSemaphore semaphore; - PipelineStageFlags dstStageMask; + VkSemaphore semaphore{}; + PipelineStageFlags dstStageMask{}; }; template< typename TypeT > diff --git a/include/RenderGraph/FramePass.hpp b/include/RenderGraph/FramePass.hpp index 3a3e5e2..dad7301 100644 --- a/include/RenderGraph/FramePass.hpp +++ b/include/RenderGraph/FramePass.hpp @@ -9,6 +9,7 @@ See LICENSE file in root folder. #include #include +#include namespace crg { @@ -38,612 +39,451 @@ namespace crg * Dependencies. */ /**@{*/ - void addDependency( FramePass const & pass ) - { - passDepends.push_back( &pass ); - } - - void addDependencies( FramePassArray const & passes ) - { - passDepends.insert( passDepends.end() - , passes.begin() - , passes.end() ); - } - /** - *\brief - * Tells if, for given view, this pass directly depends on given pass. - *\param[in] pass - * The pass to test. - *\param[in] view - * The view. - */ - CRG_API bool dependsOn( FramePass const & pass - , ImageViewId const & view - , PassDependencyCache & cache )const; /** *\brief - * Tells if, for given buffer, this pass directly depends on given pass. - *\param[in] pass - * The pass to test. - *\param[in] view - * The view. + * Gets the attachment parent from the givent one. + *\param[in] attach + * The child attachment. */ - CRG_API bool dependsOn( FramePass const & pass - , Buffer const & buffer - , PassDependencyCache & cache )const; + CRG_API Attachment const * getParentAttachment( Attachment const & attach )const; + /**@}*/ +#pragma region Attachments /** - *\brief - * Tells if this pass directly depends on given pass. - *\param[in] pass - * The pass to test. + *\name + * Attachments */ - CRG_API bool dependsOn( FramePass const & pass )const; - /**@}*/ + /**@{*/ +# pragma region Uniform /** *\name - * Buffer attachments. + * Uniform */ /**@{*/ /** *\brief - * Creates an implicit buffer attachment. - *\remarks - * This buffer will only be used to compute dependencies, and is considered an input, in that goal. + * Creates a uniform buffer multi-pass attachment. */ - CRG_API void addImplicitBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ); + CRG_API void addInputUniformBuffer( BufferViewIdArray buffers + , uint32_t binding ); /** *\brief - * Creates a uniform buffer attachment. + * Creates a uniform buffer single-pass attachment. */ - CRG_API void addUniformBuffer( Buffer buffer - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + void addInputUniformBuffer( BufferViewId buffer + , uint32_t binding ) + { + addInputUniformBuffer( BufferViewIdArray{ buffer }, binding ); + } /** *\brief - * Creates an input storage buffer attachment. + * Creates a sampled image multi-pass attachment. */ - CRG_API void addInputStorageBuffer( Buffer buffer + CRG_API void addInputSampledImage( ImageViewIdArray views , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + , SamplerDesc samplerDesc = SamplerDesc{} ); /** *\brief - * Creates an output storage buffer attachment. + * Creates a sampled image single-pass attachment. */ - CRG_API void addOutputStorageBuffer( Buffer buffer + void addInputSampledImage( ImageViewId view , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + , SamplerDesc samplerDesc = SamplerDesc{} ) + { + addInputSampledImage( ImageViewIdArray{ view }, binding, std::move( samplerDesc ) ); + } /** *\brief - * Creates a storage buffer attachment that will be cleared a the beginning of the pass. + * Creates an input uniform attachment. */ - CRG_API void addClearableOutputStorageBuffer( Buffer buffer - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + CRG_API void addInputUniform( Attachment const & attach + , uint32_t binding ); /** *\brief - * Creates an input/output storage buffer attachment. + * Creates a sampled image attachment. */ - CRG_API void addInOutStorageBuffer( Buffer buffer + CRG_API void addInputSampled( Attachment const & attach , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + , SamplerDesc samplerDesc = SamplerDesc{} ); + /**@}*/ +# pragma endregion +# pragma region Storage + /** + *\name + * Storage + */ + /**@{*/ /** *\brief - * Creates an implicit buffer view attachment. - *\remarks - * This buffer will only be used to compute dependencies, and is considered an input, in that goal. + * Creates a storage buffer multi-pass attachment. */ - CRG_API void addImplicitBufferView( Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ); + CRG_API void addInputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ); /** *\brief - * Creates a uniform texel buffer view attachment. + * Creates a storage buffer single-pass attachment. */ - CRG_API void addUniformBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + void addInputStorageBuffer( BufferViewId buffer + , uint32_t binding ) + { + addInputStorageBuffer( BufferViewIdArray{ buffer }, binding ); + } /** *\brief - * Creates an input storage texel buffer view attachment. + * Creates an input storage attachment. */ - CRG_API void addInputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + CRG_API void addInputStorageImage( ImageViewIdArray views + , uint32_t binding ); /** *\brief - * Creates an output storage texel buffer view attachment. + * Creates an input storage attachment. */ - CRG_API void addOutputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + void addInputStorageImage( ImageViewId view + , uint32_t binding ) + { + addInputStorageImage( ImageViewIdArray{ view }, binding ); + } /** *\brief - * Creates a storage texel buffer attachment that will be cleared a the beginning of the pass. + * Creates an input storage attachment. */ - CRG_API void addClearableOutputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + CRG_API void addInputStorage( Attachment const & attach + , uint32_t binding ); /** *\brief - * Creates an input/output storage texel buffer view attachment. + * Creates an input/output storage attachment. */ - CRG_API void addInOutStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ); + CRG_API Attachment const * addInOutStorage( Attachment const & attach + , uint32_t binding ); /** *\brief - * Creates a transfer input buffer attachment. + * Creates an output storage buffer multi-pass attachment. */ - CRG_API void addTransferInputBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range ); + CRG_API Attachment const * addOutputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ); /** *\brief - * Creates a transfer output buffer attachment. + * Creates an output storage buffer single-pass attachment. */ - CRG_API void addTransferOutputBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range ); + Attachment const * addOutputStorageBuffer( BufferViewId buffer + , uint32_t binding ) + { + return addOutputStorageBuffer( BufferViewIdArray{ buffer }, binding ); + } /** *\brief - * Creates a transfer input/output buffer attachment. + * Creates a storage buffer multi-pass attachment that will be cleared a the beginning of the pass. */ - CRG_API void addTransferInOutBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range - , Attachment::Flag flag = {} ); - /**@}*/ + CRG_API Attachment const * addClearableOutputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ); /** - *\name - * Image view split/merge. + *\brief + * Creates a storage buffer single-pass attachment that will be cleared a the beginning of the pass. */ - /**@{*/ + Attachment const * addClearableOutputStorageBuffer( BufferViewId buffer + , uint32_t binding ) + { + return addClearableOutputStorageBuffer( BufferViewIdArray{ buffer }, binding ); + } /** *\brief - * Creates a view which represents the given views merging. + * Creates a storage image multi-pass attachment. */ - CRG_API ImageViewId mergeViews( ImageViewIdArray const & views - , bool mergeMipLevels = true - , bool mergeArrayLayers = true ); - /**@}*/ + CRG_API Attachment const * addOutputStorageImage( ImageViewIdArray view + , uint32_t binding ); /** - *\name - * Image multi-pass attachments. + *\brief + * Creates a storage image single-pass attachment. */ - /**@{*/ + Attachment const * addOutputStorageImage( ImageViewId view + , uint32_t binding ) + { + return addOutputStorageImage( ImageViewIdArray{ view } + , binding ); + } /** *\brief - * Creates a sampled image attachment. + * Creates a storage image multi-pass attachment. */ - CRG_API void addSampledView( ImageViewIdArray view + CRG_API Attachment const * addClearableOutputStorageImage( ImageViewIdArray view , uint32_t binding - , SamplerDesc samplerDesc = SamplerDesc{} ); + , ClearValue clearValue = ClearValue{} ); /** *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + * Creates a storage image single-pass attachment. */ - CRG_API void addImplicitColourView( ImageViewIdArray view - , ImageLayout wantedLayout ); + Attachment const * addClearableOutputStorageImage( ImageViewId view + , uint32_t binding + , ClearValue clearValue = ClearValue{} ) + { + return addClearableOutputStorageImage( ImageViewIdArray{ view } + , binding + , std::move( clearValue ) ); + } + /**@}*/ +# pragma endregion +# pragma region Transfer /** - *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + *\name + * Transfer */ - CRG_API void addImplicitDepthView( ImageViewIdArray view - , ImageLayout wantedLayout ); + /**@{*/ /** *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + * Creates a transfer input external buffer. */ - CRG_API void addImplicitDepthStencilView( ImageViewIdArray view - , ImageLayout wantedLayout ); + CRG_API void addInputTransferBuffer( BufferViewIdArray views ); /** *\brief - * Creates a storage image attachment. + * Creates a transfer input external buffer. */ - CRG_API void addInputStorageView( ImageViewIdArray view - , uint32_t binding ); + void addInputTransferBuffer( BufferViewId view ) + { + addInputTransferBuffer( BufferViewIdArray{ view } ); + } /** *\brief - * Creates a storage image attachment. + * Creates a transfer input external image. */ - CRG_API void addOutputStorageView( ImageViewIdArray view - , uint32_t binding ); + CRG_API void addInputTransferImage( ImageViewIdArray views ); /** *\brief - * Creates a storage image attachment. + * Creates a transfer input external image. */ - CRG_API void addClearableOutputStorageView( ImageViewIdArray view - , uint32_t binding ); + void addInputTransferImage( ImageViewId view ) + { + addInputTransferImage( ImageViewIdArray{ view } ); + } /** *\brief - * Creates a storage image attachment. + * Creates a transfer input attachment. */ - CRG_API void addInOutStorageView( ImageViewIdArray view - , uint32_t binding ); + CRG_API void addInputTransfer( Attachment const & attach ); /** *\brief - * Creates an transfer input attachment. + * Creates a transfer input/output attachment. */ - CRG_API void addTransferInputView( ImageViewIdArray view ); + CRG_API Attachment const * addInOutTransfer( Attachment const & attach + , Attachment::Flag flag = {} ); /** *\brief - * Creates an transfer output attachment. + * Creates a transfer output buffer multi-pass attachment. */ - CRG_API void addTransferOutputView( ImageViewIdArray view ); + CRG_API Attachment const * addOutputTransferBuffer( BufferViewIdArray buffers ); /** *\brief - * Creates an transfer input/output attachment. + * Creates a transfer output buffer single-pass attachment. */ - CRG_API void addTransferInOutView( ImageViewIdArray view - , Attachment::Flag flag = {} ); - /**@}*/ + Attachment const * addOutputTransferBuffer( BufferViewId buffer ) + { + return addOutputTransferBuffer( BufferViewIdArray{ buffer } ); + } /** - *\name - * Image single-pass attachments. + *\brief + * Creates a transfer output multi-pass attachment. */ - /**@{*/ + CRG_API Attachment const * addOutputTransferImage( ImageViewIdArray view ); /** *\brief - * Creates a sampled image attachment. + * Creates an transfer output single-pass attachment. */ - inline void addSampledView( ImageViewId view - , uint32_t binding - , SamplerDesc samplerDesc = SamplerDesc{} ) + Attachment const * addOutputTransferImage( ImageViewId view ) { - addSampledView( ImageViewIdArray{ view } - , binding - , std::move( samplerDesc ) ); + return addOutputTransferImage( ImageViewIdArray{ view } ); } + /**@}*/ +# pragma endregion +# pragma region Target + /** + *\name + * Target + */ + /**@{*/ /** *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + * Creates an input colour attachment. */ - inline void addImplicitColourView( ImageViewId view - , ImageLayout wantedLayout ) - { - addImplicitColourView( ImageViewIdArray{ view } - , wantedLayout ); - } + CRG_API void addInputColourTargetImage( ImageViewIdArray views ); /** *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + * Creates an input colour attachment. */ - inline void addImplicitDepthView( ImageViewId view - , ImageLayout wantedLayout ) + void addInputColourTargetImage( ImageViewId view ) { - addImplicitDepthView( ImageViewIdArray{ view } - , wantedLayout ); + return addInputColourTargetImage( ImageViewIdArray{ view } ); } /** *\brief - * Creates an implicit image attachment. - *\remarks - * This image will only be transitioned to wanted layout at pass start, without being actually used. - * It will also be used to compute dependencies, and is considered an input, in that goal. + * Creates an input depth attachment. */ - inline void addImplicitDepthStencilView( ImageViewId view - , ImageLayout wantedLayout ) - { - addImplicitDepthStencilView( ImageViewIdArray{ view } - , wantedLayout ); - } + CRG_API void addInputDepthTargetImage( ImageViewIdArray views ); /** *\brief - * Creates a storage image attachment. + * Creates an input depth attachment. */ - inline void addInputStorageView( ImageViewId view - , uint32_t binding ) + void addInputDepthTargetImage( ImageViewId view ) { - addInputStorageView( ImageViewIdArray{ view } - , binding ); + return addInputDepthTargetImage( ImageViewIdArray{ view } ); } /** *\brief - * Creates a storage image attachment. + * Creates an input stencil attachment. */ - inline void addOutputStorageView( ImageViewId view - , uint32_t binding ) - { - addOutputStorageView( ImageViewIdArray{ view } - , binding ); - } + CRG_API void addInputStencilTargetImage( ImageViewIdArray views ); /** *\brief - * Creates a storage image attachment. + * Creates an input stencil attachment. */ - inline void addClearableOutputStorageView( ImageViewId view - , uint32_t binding ) + void addInputStencilTargetImage( ImageViewId view ) { - addClearableOutputStorageView( ImageViewIdArray{ view } - , binding ); + return addInputStencilTargetImage( ImageViewIdArray{ view } ); } /** *\brief - * Creates a storage image attachment. + * Creates an input depth and stencil attachment. */ - inline void addInOutStorageView( ImageViewId view - , uint32_t binding ) - { - addInOutStorageView( ImageViewIdArray{ view } - , binding ); - } + CRG_API void addInputDepthStencilTargetImage( ImageViewIdArray views ); /** *\brief - * Creates an transfer input attachment. + * Creates an input depth and stencil attachment. */ - inline void addTransferInputView( ImageViewId view ) + void addInputDepthStencilTargetImage( ImageViewId view ) { - addTransferInputView( ImageViewIdArray{ view } ); + return addInputDepthStencilTargetImage( ImageViewIdArray{ view } ); } /** *\brief - * Creates an transfer output attachment. + * Creates an input colour attachment. */ - inline void addTransferOutputView( ImageViewId view ) - { - addTransferOutputView( ImageViewIdArray{ view } ); - } + CRG_API void addInputColourTarget( Attachment const & attach ); /** *\brief - * Creates an transfer input/output attachment. + * Creates an input depth attachment. */ - inline void addTransferInOutView( ImageViewId view - , Attachment::Flag flag = {} ) - { - addTransferInOutView( ImageViewIdArray{ view } - , flag ); - } - /**@}*/ + CRG_API void addInputDepthTarget( Attachment const & attach ); /** - *\name - * Image specified attachments. + *\brief + * Creates an input stencil attachment. */ - /**@{*/ + CRG_API void addInputStencilTarget( Attachment const & attach ); /** *\brief - * Creates an input colour attachment. + * Creates an input depth and stencil attachment. */ - template< typename ImageViewT > - void addInputColourView( ImageViewT view ) - { - addColourView( "Ic" - , Attachment::FlagKind( Attachment::Flag::Input ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eDontCare - , ImageLayout::eColorAttachment ); - } + CRG_API void addInputDepthStencilTarget( Attachment const & attach ); /** *\brief * Creates an in/out colour attachment. */ - template< typename ImageViewT > - void addInOutColourView( ImageViewT view - , PipelineColorBlendAttachmentState blendState = DefaultBlendState ) - { - addColourView( "IOc" - , Attachment::FlagKind( Attachment::Flag::InOut ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eStore - , ImageLayout::eColorAttachment - , ClearColorValue{} - , std::move( blendState ) ); - } + CRG_API Attachment const * addInOutColourTarget( Attachment const & attach + , PipelineColorBlendAttachmentState blendState = DefaultBlendState ); /** *\brief - * Creates an output colour attachment. + * Creates an in/out depth attachment. */ - template< typename ImageViewT > - void addOutputColourView( ImageViewT view - , ClearColorValue clearValue = ClearColorValue{} ) - { - addColourView( "Oc" - , Attachment::FlagKind( Attachment::Flag::Output ) - , std::move( view ) - , AttachmentLoadOp::eClear - , AttachmentStoreOp::eStore - , ImageLayout::eColorAttachment - , std::move( clearValue ) ); - } + CRG_API Attachment const * addInOutDepthTarget( Attachment const & attach ); /** *\brief - * Creates an input depth attachment. + * Creates an in/out stencil attachment. */ - template< typename ImageViewT > - void addInputDepthView( ImageViewT view ) - { - addDepthView( "Id" - , Attachment::FlagKind( Attachment::Flag::Input ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); - } + CRG_API Attachment const * addInOutStencilTarget( Attachment const & attach ); /** *\brief - * Creates an in/out depth attachment. + * Creates an in/out depth and stencil attachment. */ - template< typename ImageViewT > - void addInOutDepthView( ImageViewT view ) - { - addDepthView( "IOd" - , Attachment::FlagKind( Attachment::Flag::InOut ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eStore - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); - } + CRG_API Attachment const * addInOutDepthStencilTarget( Attachment const & attach ); /** *\brief - * Creates an output depth attachment. + * Creates an output colour multi-pass attachment. */ - template< typename ImageViewT > - void addOutputDepthView( ImageViewT view - , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) - { - addDepthView( "Od" - , Attachment::FlagKind( Attachment::Flag::Output ) - , std::move( view ) - , AttachmentLoadOp::eClear - , AttachmentStoreOp::eStore - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , ImageLayout::eDepthStencilAttachment - , std::move( clearValue ) ); - } + CRG_API Attachment const * addOutputColourTarget( ImageViewIdArray views + , ClearColorValue clearValue = ClearColorValue{} ); /** *\brief - * Creates an input depth and stencil attachment. + * Creates an output colour single-pass attachment. */ - template< typename ImageViewT > - void addInputDepthStencilView( ImageViewT view ) + Attachment const * addOutputColourTarget( ImageViewId view + , ClearColorValue clearValue = ClearColorValue{} ) { - addDepthStencilView( "Ids" - , Attachment::FlagKind( Attachment::Flag::Input ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eDontCare - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); + return addOutputColourTarget( ImageViewIdArray{ view } + , std::move( clearValue ) ); } /** *\brief - * Creates an in/out depth and stencil attachment. + * Creates an output depth multi-pass attachment. */ - template< typename ImageViewT > - void addInOutDepthStencilView( ImageViewT view ) - { - addDepthStencilView( "IOds" - , Attachment::FlagKind( Attachment::Flag::InOut ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) - , std::move( view ) - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eStore - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eStore - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); - } + CRG_API Attachment const * addOutputDepthTarget( ImageViewIdArray views + , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); /** *\brief - * Creates an output depth and stencil attachment. + * Creates an output depth single-pass attachment. */ - template< typename ImageViewT > - void addOutputDepthStencilView( ImageViewT view + Attachment const * addOutputDepthTarget( ImageViewId view , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) { - addDepthStencilView( "Ods" - , Attachment::FlagKind( Attachment::Flag::Output ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) - , std::move( view ) - , AttachmentLoadOp::eClear - , AttachmentStoreOp::eStore - , AttachmentLoadOp::eClear - , AttachmentStoreOp::eStore - , ImageLayout::eDepthStencilAttachment - , std::move( clearValue ) ); + return addOutputDepthTarget( ImageViewIdArray{ view } + , std::move( clearValue ) ); } /** *\brief - * Creates an input stencil attachment. + * Creates an output stencil multi-pass attachment. */ - template< typename ImageViewT > - void addInputStencilView( ImageViewT view ) - { - addStencilView( "Is" - , Attachment::FlagKind( Attachment::Flag::Input ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) - , std::move( view ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eDontCare - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); - } + CRG_API Attachment const * addOutputStencilTarget( ImageViewIdArray views + , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); /** *\brief - * Creates an in/out stencil attachment. + * Creates an output stencil single-pass attachment. */ - template< typename ImageViewT > - void addInOutStencilView( ImageViewT view ) + Attachment const * addOutputStencilTarget( ImageViewId view + , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) { - addStencilView( "IOs" - , Attachment::FlagKind( Attachment::Flag::InOut ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) - , std::move( view ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eLoad - , AttachmentStoreOp::eStore - , ImageLayout::eDepthStencilAttachment - , ClearDepthStencilValue{} ); + return addOutputStencilTarget( ImageViewIdArray{ view } + , std::move( clearValue ) ); } /** *\brief - * Creates an output stencil attachment. + * Creates an output depth and stencil multi-pass attachment. */ - template< typename ImageViewT > - void addOutputStencilView( ImageViewT view + CRG_API Attachment const * addOutputDepthStencilTarget( ImageViewIdArray views + , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); + /** + *\brief + * Creates an output depth and stencil single-pass attachment. + */ + Attachment const * addOutputDepthStencilTarget( ImageViewId view , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) { - addStencilView( "Os" - , Attachment::FlagKind( Attachment::Flag::Output ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) - , std::move( view ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eClear - , AttachmentStoreOp::eStore - , ImageLayout::eDepthStencilAttachment - , std::move( clearValue ) ); + return addOutputDepthStencilTarget( ImageViewIdArray{ view } + , std::move( clearValue ) ); } /**@}*/ + /**@}*/ +# pragma endregion +# pragma region Implicit + /** + *\name + * Implicit + */ + /**@{*/ + /** + *\brief + * Creates an implicit attachment. + *\remarks + * This attachment will only be used to compute dependencies, and is considered an input, in that goal. + */ + CRG_API void addImplicit( Attachment const & attach + , AccessState wantedAccess ); + /** + *\brief + * Creates an implicit attachment. + *\remarks + * This attachment will only be used to compute dependencies, and is considered an input, in that goal. + */ + CRG_API void addImplicit( Attachment const & attach + , ImageLayout wantedLayout ); + /**@}*/ +# pragma endregion + /**@}*/ +#pragma endregion /** *\name * Graph compilation. @@ -661,46 +501,66 @@ namespace crg return m_name; } + auto begin()const + { + return m_ownAttaches.cbegin(); + } + + auto end()const + { + return m_ownAttaches.cend(); + } + FramePassGroup const & group; FrameGraph & graph; uint32_t id; - AttachmentArray images; - AttachmentArray buffers; + struct SampledAttachment + { + SampledAttachment( Attachment const * attach, SamplerDesc sampler )noexcept + : attach{ attach } + , sampler{ std::move( sampler ) } + { + } + + Attachment const * attach; + SamplerDesc sampler; + }; + std::map< uint32_t, Attachment const * > uniforms; + std::map< uint32_t, SampledAttachment > sampled; + std::map< uint32_t, Attachment const * > inputs; + std::map< uint32_t, Attachment const * > inouts; + std::map< uint32_t, Attachment const * > outputs; + std::vector< Attachment const * > targets; RunnablePassCreator runnableCreator; - FramePassArray passDepends; private: - CRG_API void addColourView( std::string const & name + CRG_API Attachment const * addColourTarget( std::string const & name , Attachment::FlagKind flags - , ImageViewIdArray view + , ImageViewIdArray views , AttachmentLoadOp loadOp , AttachmentStoreOp storeOp , ImageLayout wantedLayout = ImageLayout::eUndefined , ClearColorValue clearValue = ClearColorValue{} , PipelineColorBlendAttachmentState blendState = DefaultBlendState ); - CRG_API void addDepthView( std::string const & name + CRG_API Attachment const * addDepthTarget( std::string const & name , Attachment::FlagKind flags - , ImageViewIdArray view + , ImageViewIdArray views , AttachmentLoadOp loadOp , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp , ImageLayout wantedLayout = ImageLayout::eUndefined , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); - CRG_API void addStencilView( std::string const & name + CRG_API Attachment const * addStencilTarget( std::string const & name , Attachment::FlagKind flags , ImageAttachment::FlagKind stencilFlags - , ImageViewIdArray view - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp + , ImageViewIdArray views , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp , ImageLayout wantedLayout = ImageLayout::eUndefined , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); - CRG_API void addDepthStencilView( std::string const & name + CRG_API Attachment const * addDepthStencilTarget( std::string const & name , Attachment::FlagKind flags , ImageAttachment::FlagKind stencilFlags - , ImageViewIdArray view + , ImageViewIdArray views , AttachmentLoadOp loadOp , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp @@ -708,93 +568,34 @@ namespace crg , ImageLayout wantedLayout = ImageLayout::eUndefined , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ); - void addColourView( std::string const & name + Attachment const * addOwnAttach( ImageViewIdArray views + , std::string attachName , Attachment::FlagKind flags - , ImageViewId view - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , ImageLayout wantedLayout = ImageLayout::eUndefined - , ClearColorValue clearValue = ClearColorValue{} - , PipelineColorBlendAttachmentState blendState = DefaultBlendState ) - { - addColourView( name - , flags - , ImageViewIdArray{ view } - , loadOp - , storeOp - , wantedLayout - , clearValue - , std::move( blendState ) ); - } - - void addDepthView( std::string const & name - , Attachment::FlagKind flags - , ImageViewId view + , ImageAttachment::FlagKind imageFlags , AttachmentLoadOp loadOp , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout = ImageLayout::eUndefined - , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) - { - addDepthView( name - , flags - , ImageViewIdArray{ view } - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , wantedLayout - , clearValue ); - } - - void addStencilView( std::string const & name + , ClearValue clearValue + , PipelineColorBlendAttachmentState blendState + , ImageLayout wantedLayout + , Attachment const * parent ); + Attachment const * addOwnAttach( BufferViewIdArray views + , std::string attachName , Attachment::FlagKind flags - , ImageAttachment::FlagKind stencilFlags - , ImageViewId view - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout = ImageLayout::eUndefined - , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) - { - addStencilView( name - , flags - , stencilFlags - , ImageViewIdArray{ view } - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , wantedLayout - , clearValue ); - } - - void addDepthStencilView( std::string const & name - , Attachment::FlagKind flags - , ImageAttachment::FlagKind stencilFlags - , ImageViewId view - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout = ImageLayout::eUndefined - , ClearDepthStencilValue clearValue = ClearDepthStencilValue{} ) - { - addDepthStencilView( name - , flags - , stencilFlags - , ImageViewIdArray{ view } - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , wantedLayout - , clearValue ); - } + , BufferAttachment::FlagKind bufferFlags + , AccessState access + , Attachment const * parent ); + Attachment * addOwnAttach( Attachment * mine + , Attachment const * parent ); private: std::string m_name; + struct OwnAttachment + { + AttachmentPtr mine{}; + Attachment const * parent{}; + }; + std::unordered_map< Attachment const *, OwnAttachment > m_ownAttaches; }; } diff --git a/include/RenderGraph/FramePassGroup.hpp b/include/RenderGraph/FramePassGroup.hpp index ca14fd2..a6de1b8 100644 --- a/include/RenderGraph/FramePassGroup.hpp +++ b/include/RenderGraph/FramePassGroup.hpp @@ -12,19 +12,28 @@ namespace crg { struct FramePassGroup { - protected: friend class FrameGraph; + class Token + { + friend class FrameGraph; + friend struct FramePassGroup; + + private: + Token() noexcept = default; + }; /** *\name * Construction. */ - /**@[*/ + /**@{*/ CRG_API FramePassGroup( FrameGraph & graph , uint32_t id - , std::string const & name ); + , std::string const & name + , Token token ); CRG_API FramePassGroup( FramePassGroup & parent , uint32_t id - , std::string const & name ); + , std::string const & name + , Token token ); /**@}*/ public: @@ -32,7 +41,7 @@ namespace crg *\name * Passes. */ - /**@[*/ + /**@{*/ CRG_API FramePass & createPass( std::string const & name , RunnablePassCreator runnableCreator ); CRG_API FramePassGroup & createPassGroup( std::string const & name ); @@ -43,7 +52,7 @@ namespace crg *\name * Group I/O. */ - /**@[*/ + /**@{*/ CRG_API void addGroupInput( ImageViewId view ); CRG_API void addGroupOutput( ImageViewId view ); /**@}*/ @@ -51,23 +60,68 @@ namespace crg *\name * Graph interface. */ - /**@[*/ + /**@{*/ + /** + *\copydoc crg::FrameGraph::getFinalLayoutState + */ CRG_API LayoutState getFinalLayoutState( ImageViewId view , uint32_t passIndex = 0u )const; + /** + *\copydoc crg::FrameGraph::createBuffer + */ + CRG_API BufferId createBuffer( BufferData const & img )const; + /** + *\copydoc crg::FrameGraph::createView + */ + CRG_API BufferViewId createView( BufferViewData const & view )const; + /** + *\copydoc crg::FrameGraph::createImage + */ CRG_API ImageId createImage( ImageData const & img )const; + /** + *\copydoc crg::FrameGraph::createView + */ CRG_API ImageViewId createView( ImageViewData const & view )const; + /** + *\copydoc crg::FrameGraph::addInput + */ CRG_API void addInput( ImageId image , ImageViewType viewType , ImageSubresourceRange const & range , LayoutState const & outputLayout ); + /** + *\copydoc crg::FrameGraph::addInput + */ CRG_API void addInput( ImageViewId view , LayoutState const & outputLayout ); + /** + *\copydoc crg::FrameGraph::addOutput + */ CRG_API void addOutput( ImageId image , ImageViewType viewType , ImageSubresourceRange const & range , LayoutState const & outputLayout ); + /** + *\copydoc crg::FrameGraph::addOutput + */ CRG_API void addOutput( ImageViewId view , LayoutState const & outputLayout ); + /** + *\copydoc crg::FrameGraph::mergeViews + */ + CRG_API ImageViewId mergeViews( ImageViewIdArray const & views + , bool mergeMipLevels = true + , bool mergeArrayLayers = true ); + /** + *\copydoc crg::FrameGraph::mergeViews + */ + CRG_API BufferViewId mergeViews( BufferViewIdArray const & views ); + /** + *\copydoc crg::FrameGraph::mergeAttachments + */ + CRG_API Attachment const * mergeAttachments( AttachmentArray const & attachments + , bool mergeMipLevels = true + , bool mergeArrayLayers = true ); /**@}*/ CRG_API std::string getFullName()const; diff --git a/include/RenderGraph/GraphContext.hpp b/include/RenderGraph/GraphContext.hpp index e68685e..e6762c1 100644 --- a/include/RenderGraph/GraphContext.hpp +++ b/include/RenderGraph/GraphContext.hpp @@ -409,6 +409,8 @@ namespace crg DECL_vkFunction( FreeDescriptorSets ); DECL_vkFunction( CreateBuffer ); DECL_vkFunction( DestroyBuffer ); + DECL_vkFunction( CreateBufferView ); + DECL_vkFunction( DestroyBufferView ); DECL_vkFunction( GetBufferMemoryRequirements ); DECL_vkFunction( GetImageMemoryRequirements ); DECL_vkFunction( AllocateMemory ); diff --git a/include/RenderGraph/GraphNode.hpp b/include/RenderGraph/GraphNode.hpp index 058cbad..3d1b6cb 100644 --- a/include/RenderGraph/GraphNode.hpp +++ b/include/RenderGraph/GraphNode.hpp @@ -33,56 +33,67 @@ namespace crg CRG_API GraphNode( GraphNode && rhs )noexcept; - CRG_API void addAttaches( ConstGraphAdjacentNode const prev - , AttachmentTransitions inputAttaches ); - CRG_API void attachNode( GraphAdjacentNode next - , AttachmentTransitions inputAttaches ); - CRG_API AttachmentTransitions const & getInputAttaches( ConstGraphAdjacentNode pred = nullptr )const; + CRG_API void attachNode( GraphNode & child ); CRG_API virtual void accept( GraphVisitor * vis )const = 0; + void setTransitions( AttachmentTransitions transitions )noexcept + { + m_transitions = std::move( transitions ); + } + template< typename NodeT > - NodeT const & cast()const + NodeT const & cast()const noexcept { assert( kind == NodeT::MyKind ); return static_cast< NodeT const & >( *this ); } template< typename NodeT > - NodeT & cast() + NodeT & cast()noexcept { assert( kind == NodeT::MyKind ); return static_cast< NodeT & >( *this ); } - Kind getKind()const + Kind getKind()const noexcept { return kind; } - std::string const & getName()const + std::string const & getName()const noexcept { return name; } - FramePassGroup const & getGroup()const + FramePassGroup const & getGroup()const noexcept { return group; } - uint32_t getId()const + uint32_t getId()const noexcept { return id; } - GraphAdjacentNodeArray const & getNext()const + GraphAdjacentNodeArray const & getPredecessors()const noexcept + { + return prev; + } + + GraphAdjacentNodeArray & getPredecessors()noexcept + { + return prev; + } + + ImageTransitionArray const & getImageTransitions()const noexcept { - return next; + return m_transitions.imageTransitions; } - bool hasPrev()const + BufferTransitionArray const & getBufferTransitions()const noexcept { - return !inputAttaches.empty(); + return m_transitions.bufferTransitions; } protected: @@ -96,8 +107,8 @@ namespace crg uint32_t id{}; std::string name{}; FramePassGroup const & group; - GraphAdjacentNodeArray next{}; - AttachmentsNodeMap inputAttaches{}; + GraphAdjacentNodeArray prev{}; + AttachmentTransitions m_transitions{}; }; /** *\brief diff --git a/include/RenderGraph/Hash.hpp b/include/RenderGraph/Hash.hpp new file mode 100644 index 0000000..81f79b0 --- /dev/null +++ b/include/RenderGraph/Hash.hpp @@ -0,0 +1,36 @@ +/* +This file belongs to FrameGraph. +See LICENSE file in root folder. +*/ +#pragma once + +namespace crg +{ + template< typename T > + inline size_t hashCombine( size_t hash + , T const & rhs ) + { + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + auto seed = hash; + + std::hash< T > hasher; + uint64_t a = ( hasher( rhs ) ^ seed ) * kMul; + a ^= ( a >> 47 ); + + uint64_t b = ( seed ^ a ) * kMul; + b ^= ( b >> 47 ); + +#pragma warning( push ) +#pragma warning( disable: 4068 ) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuseless-cast" + hash = static_cast< std::size_t >( b * kMul ); +#pragma GCC diagnostic pop +#pragma clang diagnostic pop +#pragma warning( pop ) + return hash; + } + +} diff --git a/include/RenderGraph/Id.hpp b/include/RenderGraph/Id.hpp index 0a182df..df5094c 100644 --- a/include/RenderGraph/Id.hpp +++ b/include/RenderGraph/Id.hpp @@ -11,11 +11,6 @@ namespace crg template< typename TypeT > struct Id { - friend struct Attachment; - friend struct ImageViewData; - friend struct ImageData; - friend class FrameGraph; - uint32_t id; TypeT const * data; diff --git a/include/RenderGraph/ImageData.hpp b/include/RenderGraph/ImageData.hpp index 5a0483b..5764eaa 100644 --- a/include/RenderGraph/ImageData.hpp +++ b/include/RenderGraph/ImageData.hpp @@ -26,11 +26,12 @@ namespace crg , uint32_t mipLevels = 1u , uint32_t arrayLayers = 1u , SampleCount samples = SampleCount::e1 - , ImageTiling tiling = ImageTiling::eOptimal ) + , ImageTiling tiling = ImageTiling::eOptimal + , MemoryPropertyFlags memory = MemoryPropertyFlags::eDeviceLocal ) : name{ std::move( name ) } , info{ flags, imageType, format , extent, mipLevels, arrayLayers, samples - , tiling, usage } + , tiling, usage, memory } { } diff --git a/include/RenderGraph/RecordContext.hpp b/include/RenderGraph/RecordContext.hpp index 5c6e431..e2eb94f 100644 --- a/include/RenderGraph/RecordContext.hpp +++ b/include/RenderGraph/RecordContext.hpp @@ -20,13 +20,20 @@ namespace crg using GraphIndexMap = std::map< FrameGraph const *, PassIndexArray >; using ImplicitAction = std::function< void( RecordContext &, VkCommandBuffer, uint32_t ) >; - struct ImplicitTransition + struct ImplicitImageTransition { RunnablePass const * pass; ImageViewId view; ImplicitAction action; }; + struct ImplicitBufferTransition + { + RunnablePass const * pass; + BufferViewId view; + ImplicitAction action; + }; + public: CRG_API explicit RecordContext( ContextResourcesCache & resources ); CRG_API explicit RecordContext( ResourceHandler & handler ); @@ -66,19 +73,30 @@ namespace crg CRG_API void registerImplicitTransition( RunnablePass const & pass , crg::ImageViewId view , ImplicitAction action = []( RecordContext &, VkCommandBuffer, uint32_t ){} ); - CRG_API void registerImplicitTransition( ImplicitTransition transition ); + CRG_API void registerImplicitTransition( RunnablePass const & pass + , crg::BufferViewId view + , ImplicitAction action = []( RecordContext &, VkCommandBuffer, uint32_t ){} ); + CRG_API void registerImplicitTransition( ImplicitImageTransition transition ); + CRG_API void registerImplicitTransition( ImplicitBufferTransition transition ); CRG_API void runImplicitTransition( VkCommandBuffer commandBuffer , uint32_t index , crg::ImageViewId view ); + CRG_API void runImplicitTransition( VkCommandBuffer commandBuffer + , uint32_t index + , crg::BufferViewId view ); //@} /** *\name Buffers */ //@{ - CRG_API void setAccessState( VkBuffer buffer + CRG_API void setAccessState( BufferViewId buffer + , AccessState const & accessState ); + CRG_API AccessState getAccessState( BufferViewId view )const; + + CRG_API void setAccessState( BufferId buffer , BufferSubresourceRange const & subresourceRange - , AccessState const & layoutState ); - CRG_API AccessState const & getAccessState( VkBuffer buffer + , AccessState const & accessState ); + CRG_API AccessState const & getAccessState( BufferId buffer , BufferSubresourceRange const & subresourceRange )const; //@} //@} @@ -129,23 +147,25 @@ namespace crg */ //@{ CRG_API void memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer + , BufferId buffer , BufferSubresourceRange const & subresourceRange , AccessState const & initialState , AccessState const & wantedState , bool force = false ); CRG_API void memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer - , BufferSubresourceRange const & subresourceRange - , AccessFlags initialMask - , PipelineStageFlags initialStage + , BufferViewId view + , AccessState const & initialState , AccessState const & wantedState , bool force = false ); CRG_API void memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer + , BufferId buffer , BufferSubresourceRange const & subresourceRange , AccessState const & wantedState , bool force = false ); + CRG_API void memoryBarrier( VkCommandBuffer commandBuffer + , BufferViewId view + , AccessState const & wantedState + , bool force = false ); //@} //@} CRG_API GraphContext & getContext()const; @@ -156,6 +176,40 @@ namespace crg return &getContext(); } + CRG_API void copyImage( VkCommandBuffer commandBuffer + , uint32_t index + , ImageViewId srcView + , ImageViewId dstView + , Extent2D const & extent + , ImageLayout finalLayout = ImageLayout::eUndefined ); + CRG_API void blitImage( VkCommandBuffer commandBuffer + , uint32_t index + , ImageViewId srcView + , ImageViewId dstView + , Rect2D const & srcRect + , Rect2D const & dstRect + , FilterMode filter + , ImageLayout finalLayout = ImageLayout::eUndefined ); + CRG_API void clearAttachment( VkCommandBuffer commandBuffer + , ImageViewId dstView + , ClearColorValue const & clearValue + , ImageLayout finalLayout = ImageLayout::eUndefined ); + CRG_API void clearAttachment( VkCommandBuffer commandBuffer + , ImageViewId dstView + , ClearDepthStencilValue const & clearValue + , ImageLayout finalLayout = ImageLayout::eUndefined ); + CRG_API void copyBuffer( VkCommandBuffer commandBuffer + , uint32_t index + , BufferViewId srcView + , BufferViewId dstView + , DeviceSize srcOffset, DeviceSize dstOffset + , DeviceSize size + , AccessState const & finalState = {} ); + CRG_API void clearBuffer( VkCommandBuffer commandBuffer + , BufferViewId dstView + , uint32_t clearValue + , AccessState const & finalState = {} ); + CRG_API static ImplicitAction copyImage( ImageViewId srcView , ImageViewId dstView , Extent2D const & extent @@ -174,6 +228,16 @@ namespace crg CRG_API static ImplicitAction clearAttachment( ImageViewId view , ClearDepthStencilValue const & clearValue , ImageLayout finalLayout = ImageLayout::eUndefined ); + CRG_API static ImplicitAction clearBuffer( BufferViewId dstView + , AccessState const & finalState = {} ); + CRG_API static ImplicitAction clearBuffer( BufferViewId dstView + , uint32_t clearValue + , AccessState const & finalState = {} ); + CRG_API static ImplicitAction copyBuffer( BufferViewId srcView + , BufferViewId dstView + , DeviceSize srcOffset, DeviceSize dstOffset + , DeviceSize size + , AccessState const & finalState = {} ); ResourceHandler & getHandler()const { @@ -205,7 +269,8 @@ namespace crg ContextResourcesCache * m_resources; LayerLayoutStatesHandler m_images; AccessStateMap m_buffers; - std::vector< ImplicitTransition > m_implicitTransitions; + std::vector< ImplicitImageTransition > m_implicitImageTransitions; + std::vector< ImplicitBufferTransition > m_implicitBufferTransitions; PassIndexArray m_state; PipelineState m_prevPipelineState{}; PipelineState m_currPipelineState{}; diff --git a/include/RenderGraph/ResourceHandler.hpp b/include/RenderGraph/ResourceHandler.hpp index f09a3e3..cb222db 100644 --- a/include/RenderGraph/ResourceHandler.hpp +++ b/include/RenderGraph/ResourceHandler.hpp @@ -24,7 +24,19 @@ namespace crg class ResourceHandler { template< typename ValueT > - using CreatedT = std::pair< ValueT, bool >; + struct CreatedT + { + bool created{}; + ValueT resource{}; + VkDeviceMemory memory{}; + }; + + template< typename ValueT > + struct CreatedViewT + { + bool created{}; + ValueT view{}; + }; public: ResourceHandler( ResourceHandler const & ) = delete; @@ -34,12 +46,18 @@ namespace crg CRG_API ResourceHandler() = default; CRG_API ~ResourceHandler()noexcept; + CRG_API BufferId createBufferId( BufferData const & img ); + CRG_API BufferViewId createViewId( BufferViewData const & view ); CRG_API ImageId createImageId( ImageData const & img ); CRG_API ImageViewId createViewId( ImageViewData const & view ); + CRG_API CreatedT< VkBuffer > createBuffer( GraphContext & context + , BufferId bufferId ); + CRG_API CreatedViewT< VkBufferView > createBufferView( GraphContext & context + , BufferViewId viewId ); CRG_API CreatedT< VkImage > createImage( GraphContext & context , ImageId imageId ); - CRG_API CreatedT< VkImageView > createImageView( GraphContext & context + CRG_API CreatedViewT< VkImageView > createImageView( GraphContext & context , ImageViewId viewId ); CRG_API VkSampler createSampler( GraphContext & context , std::string const & suffix @@ -48,6 +66,10 @@ namespace crg , std::string const & suffix , bool texCoords , Texcoord const & config ); + CRG_API void destroyBuffer( GraphContext & context + , BufferId bufferId ); + CRG_API void destroyBufferView( GraphContext & context + , BufferViewId viewId ); CRG_API void destroyImage( GraphContext & context , ImageId imageId ); CRG_API void destroyImageView( GraphContext & context @@ -58,15 +80,21 @@ namespace crg , VertexBuffer const * buffer ); private: + mutable std::mutex m_buffersMutex; + BufferIdDataOwnerCont m_bufferIds; + mutable std::mutex m_bufferViewsMutex; + BufferViewIdDataOwnerCont m_bufferViewIds; + BufferMemoryMap m_buffers; + BufferViewMap m_bufferViews; mutable std::mutex m_imagesMutex; ImageIdDataOwnerCont m_imageIds; - mutable std::mutex m_viewsMutex; + mutable std::mutex m_imageViewsMutex; ImageViewIdDataOwnerCont m_imageViewIds; ImageMemoryMap m_images; ImageViewMap m_imageViews; std::mutex m_samplersMutex; std::unordered_map< VkSampler, Sampler > m_samplers; - std::mutex m_buffersMutex; + std::mutex m_vertexBuffersMutex; std::unordered_set< VertexBufferPtr > m_vertexBuffers; }; @@ -82,7 +110,14 @@ namespace crg , GraphContext & context ); CRG_API ~ContextResourcesCache()noexcept; + CRG_API VkBuffer createBuffer( BufferId const & bufferId ); + CRG_API VkBuffer createBuffer( BufferId const & bufferId, VkDeviceMemory & memory ); + CRG_API VkBufferView createBufferView( BufferViewId const & viewId ); + CRG_API bool destroyBuffer( BufferId const & imageId ); + CRG_API bool destroyBufferView( BufferViewId const & viewId ); + CRG_API VkImage createImage( ImageId const & imageId ); + CRG_API VkImage createImage( ImageId const & imageId, VkDeviceMemory & memory ); CRG_API VkImageView createImageView( ImageViewId const & viewId ); CRG_API bool destroyImage( ImageId const & imageId ); CRG_API bool destroyImageView( ImageViewId const & viewId ); @@ -107,11 +142,15 @@ namespace crg } private: + using VkBufferIdMap = std::map< BufferId, VkBuffer >; + using VkBufferViewIdMap = std::map< BufferViewId, VkBufferView >; using VkImageIdMap = std::map< ImageId, VkImage >; using VkImageViewIdMap = std::map< ImageViewId, VkImageView >; ResourceHandler & m_handler; GraphContext & m_context; + VkBufferIdMap m_buffers; + VkBufferViewIdMap m_bufferViews; VkImageIdMap m_images; VkImageViewIdMap m_imageViews; std::unordered_map< size_t, VkSampler > m_samplers; @@ -123,8 +162,25 @@ namespace crg public: CRG_API explicit ResourcesCache( ResourceHandler & handler ); + CRG_API VkBuffer createBuffer( GraphContext & context + , BufferId const & bufferId ); + CRG_API VkBuffer createBuffer( GraphContext & context + , BufferId const & bufferId + , VkDeviceMemory & memory ); + CRG_API VkBufferView createBufferView( GraphContext & context + , BufferViewId const & viewId ); + CRG_API bool destroyBuffer( BufferId const & bufferId ); + CRG_API bool destroyBufferView( BufferViewId const & viewId ); + CRG_API bool destroyBuffer( GraphContext & context + , BufferId const & bufferId ); + CRG_API bool destroyBufferView( GraphContext & context + , BufferViewId const & viewId ); + CRG_API VkImage createImage( GraphContext & context , ImageId const & imageId ); + CRG_API VkImage createImage( GraphContext & context + , ImageId const & imageId + , VkDeviceMemory & memory ); CRG_API VkImageView createImageView( GraphContext & context , ImageViewId const & viewId ); CRG_API bool destroyImage( ImageId const & imageId ); diff --git a/include/RenderGraph/RunnableGraph.hpp b/include/RenderGraph/RunnableGraph.hpp index 1963435..0b4afd5 100644 --- a/include/RenderGraph/RunnableGraph.hpp +++ b/include/RenderGraph/RunnableGraph.hpp @@ -51,7 +51,6 @@ namespace crg * All transitions. */ CRG_API RunnableGraph( FrameGraph & graph - , AttachmentTransitions transitions , GraphNodePtrArray nodes , RootNode rootNode , GraphContext & context ); @@ -65,6 +64,8 @@ namespace crg CRG_API SemaphoreWaitArray run( SemaphoreWaitArray const & toWait , VkQueue queue ); + CRG_API VkBuffer createBuffer( BufferId const & buffer ); + CRG_API VkBufferView createBufferView( BufferViewId const & view ); CRG_API VkImage createImage( ImageId const & image ); CRG_API VkImageView createImageView( ImageViewId const & view ); CRG_API VkSampler createSampler( SamplerDesc const & samplerDesc ); @@ -83,7 +84,8 @@ namespace crg CRG_API LayoutState getOutputLayoutState( ImageViewId view )const; CRG_API VkDescriptorType getDescriptorType( Attachment const & attach )const; - CRG_API WriteDescriptorSet getBufferWrite( Attachment const & attach, uint32_t index = 0u )const; + CRG_API WriteDescriptorSet getDescriptorWrite( Attachment const & attach, uint32_t binding, uint32_t index = 0u ); + CRG_API WriteDescriptorSet getDescriptorWrite( Attachment const & attach, SamplerDesc const & samplerDesc, uint32_t binding, uint32_t index = 0u ); ConstGraphAdjacentNode getGraph()const noexcept { @@ -95,11 +97,6 @@ namespace crg return m_graph.getName(); } - AttachmentTransitions const & getTransitions()const noexcept - { - return m_transitions; - } - VkCommandPool getCommandPool()const noexcept { return m_commandPool.object; @@ -149,7 +146,6 @@ namespace crg FrameGraph & m_graph; GraphContext & m_context; ContextResourcesCache m_resources; - AttachmentTransitions m_transitions; GraphNodePtrArray m_nodes; RootNode m_rootNode; ContextObjectT< VkQueryPool > m_timerQueries; diff --git a/include/RenderGraph/RunnablePass.hpp b/include/RenderGraph/RunnablePass.hpp index feff252..71e85a6 100644 --- a/include/RenderGraph/RunnablePass.hpp +++ b/include/RenderGraph/RunnablePass.hpp @@ -83,10 +83,21 @@ namespace crg auto & implicitAction( ImageViewId view , RecordContext::ImplicitAction action ) { - implicitActions.try_emplace( view, action ); + implicitImageActions.try_emplace( view, action ); + return *this; + } + /** + *\param[in] view + * The action's target viex. + *\param[in] action + * The implicit action. + */ + auto & implicitAction( BufferViewId view + , RecordContext::ImplicitAction action ) + { + implicitBufferActions.try_emplace( view, action ); return *this; } - /** *\param[in] action * The action to run before the pass recording. @@ -96,7 +107,6 @@ namespace crg prePassActions.emplace_back( action ); return *this; } - /** *\param[in] action * The action to run after the pass recording. @@ -111,7 +121,8 @@ namespace crg bool resettable{ false }; std::vector< RecordContext::ImplicitAction > prePassActions{}; std::vector< RecordContext::ImplicitAction > postPassActions{}; - std::map< ImageViewId, RecordContext::ImplicitAction > implicitActions{}; + std::map< ImageViewId, RecordContext::ImplicitAction > implicitImageActions{}; + std::map< BufferViewId, RecordContext::ImplicitAction > implicitBufferActions{}; }; } @@ -304,7 +315,7 @@ namespace crg private: using LayoutTransitionMap = std::map< ImageViewId, LayoutTransition >; - using AccessTransitionMap = std::map< VkBuffer, AccessTransition >; + using AccessTransitionMap = std::map< BufferViewId, AccessTransition >; struct PassData { diff --git a/include/RenderGraph/RunnablePasses/ComputePass.hpp b/include/RenderGraph/RunnablePasses/ComputePass.hpp index 8585443..2fcbb68 100644 --- a/include/RenderGraph/RunnablePasses/ComputePass.hpp +++ b/include/RenderGraph/RunnablePasses/ComputePass.hpp @@ -3,6 +3,7 @@ See LICENSE file in root folder. */ #pragma once +#include "RenderGraph/BufferViewData.hpp" #include "RenderGraph/RunnablePass.hpp" #include "RenderGraph/RunnablePasses/PipelineHolder.hpp" diff --git a/include/RenderGraph/RunnablePasses/GenerateMipmaps.hpp b/include/RenderGraph/RunnablePasses/GenerateMipmaps.hpp index 2c6cf50..3ad0a6a 100644 --- a/include/RenderGraph/RunnablePasses/GenerateMipmaps.hpp +++ b/include/RenderGraph/RunnablePasses/GenerateMipmaps.hpp @@ -23,6 +23,9 @@ namespace crg void doRecordInto( RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index ); + void doProcessImageView( RecordContext & context + , VkCommandBuffer commandBuffer + , ImageViewId viewId ); private: LayoutState m_outputLayout; diff --git a/include/RenderGraph/RunnablePasses/ImageBlit.hpp b/include/RenderGraph/RunnablePasses/ImageBlit.hpp index 21bb9b1..e8195d8 100644 --- a/include/RenderGraph/RunnablePasses/ImageBlit.hpp +++ b/include/RenderGraph/RunnablePasses/ImageBlit.hpp @@ -14,10 +14,8 @@ namespace crg CRG_API ImageBlit( FramePass const & pass , GraphContext & context , RunnableGraph & graph - , Offset3D const & blitSrcOffset - , Extent3D const & blitSrcSize - , Offset3D const & blitDstOffset - , Extent3D const & blitDstSize + , Rect3D const & blitSrc + , Rect3D const & blitDst , FilterMode filter , ru::Config ruConfig = {} , GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } ) diff --git a/include/RenderGraph/RunnablePasses/ImageCopy.hpp b/include/RenderGraph/RunnablePasses/ImageCopy.hpp index 86057e4..9dcc68f 100644 --- a/include/RenderGraph/RunnablePasses/ImageCopy.hpp +++ b/include/RenderGraph/RunnablePasses/ImageCopy.hpp @@ -31,6 +31,15 @@ namespace crg void doRecordInto( RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index ); + void doRecordMultiToMulti( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ); + void doRecordMultiToSingle( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ); + void doRecordSingleToMulti( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ); private: VkExtent3D m_copySize; diff --git a/include/RenderGraph/RunnablePasses/PipelineHolder.hpp b/include/RenderGraph/RunnablePasses/PipelineHolder.hpp index 1436ff3..4863385 100644 --- a/include/RenderGraph/RunnablePasses/PipelineHolder.hpp +++ b/include/RenderGraph/RunnablePasses/PipelineHolder.hpp @@ -84,8 +84,8 @@ namespace crg VkDescriptorPool m_descriptorSetPool{}; struct DescriptorSet { - WriteDescriptorSetArray writes; - VkDescriptorSet set; + WriteDescriptorSetArray writes{}; + VkDescriptorSet set{}; }; std::vector< DescriptorSet > m_descriptorSets; diff --git a/include/RenderGraph/RunnablePasses/RenderMeshConfig.hpp b/include/RenderGraph/RunnablePasses/RenderMeshConfig.hpp index a4223e9..33f2fd6 100644 --- a/include/RenderGraph/RunnablePasses/RenderMeshConfig.hpp +++ b/include/RenderGraph/RunnablePasses/RenderMeshConfig.hpp @@ -291,22 +291,4 @@ namespace crg return result; } }; - - template<> - struct DefaultValueGetterT< VertexBuffer > - { - static VertexBuffer get() - { - return VertexBuffer{}; - } - }; - - template<> - struct DefaultValueGetterT< IndexBuffer > - { - static IndexBuffer get() - { - return IndexBuffer{}; - } - }; } diff --git a/include/RenderGraph/RunnablePasses/RenderMeshHolder.hpp b/include/RenderGraph/RunnablePasses/RenderMeshHolder.hpp index ed8145b..ca747a7 100644 --- a/include/RenderGraph/RunnablePasses/RenderMeshHolder.hpp +++ b/include/RenderGraph/RunnablePasses/RenderMeshHolder.hpp @@ -49,6 +49,7 @@ namespace crg , VkRect2D & scissor )const; private: + RunnableGraph & m_graph; rm::ConfigData m_config; PipelineHolder m_pipeline; VkRenderPass m_renderPass{}; diff --git a/include/RenderGraph/RunnablePasses/RenderPassHolder.hpp b/include/RenderGraph/RunnablePasses/RenderPassHolder.hpp index fc977ef..e219943 100644 --- a/include/RenderGraph/RunnablePasses/RenderPassHolder.hpp +++ b/include/RenderGraph/RunnablePasses/RenderPassHolder.hpp @@ -82,11 +82,11 @@ namespace crg VkRenderPass renderPass{}; mutable VkFramebuffer frameBuffer{}; Rect2D renderArea{}; - std::vector< Attachment const * > attachments; - std::vector< VkClearValue > clearValues; - std::vector< Entry > attaches; - PipelineState previousState; - PipelineState nextState; + std::vector< Attachment const * > attachments{}; + std::vector< VkClearValue > clearValues{}; + std::vector< Entry > attaches{}; + PipelineState previousState{}; + PipelineState nextState{}; void cleanup( crg::GraphContext & context )noexcept; }; diff --git a/include/RenderGraph/RunnablePasses/RenderQuadConfig.hpp b/include/RenderGraph/RunnablePasses/RenderQuadConfig.hpp index 1ffcdb8..27bd9ea 100644 --- a/include/RenderGraph/RunnablePasses/RenderQuadConfig.hpp +++ b/include/RenderGraph/RunnablePasses/RenderQuadConfig.hpp @@ -4,6 +4,7 @@ See LICENSE file in root folder. */ #pragma once +#include "RenderGraph/BufferViewData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include "RenderGraph/RunnablePasses/PipelineConfig.hpp" @@ -194,7 +195,7 @@ namespace crg RawTypeT< RunnablePass::RecordCallback > recordInto; RawTypeT< RunnablePass::RecordCallback > end; RawTypeT< uint32_t > m_instances; - RawTypeT< IndirectBuffer > indirectBuffer{ Buffer{ VkBuffer{}, std::string{} }, 0u }; + RawTypeT< IndirectBuffer > indirectBuffer{ BufferViewId{}, 0u }; }; using Config = ConfigT< std::optional >; diff --git a/source/RenderGraph/Attachment.cpp b/source/RenderGraph/Attachment.cpp index 937c20d..a960d41 100644 --- a/source/RenderGraph/Attachment.cpp +++ b/source/RenderGraph/Attachment.cpp @@ -3,6 +3,9 @@ This file belongs to FrameGraph. See LICENSE file in root folder. */ #include "RenderGraph/Attachment.hpp" +#include "RenderGraph/BufferData.hpp" +#include "RenderGraph/BufferViewData.hpp" +#include "RenderGraph/Exception.hpp" #include "RenderGraph/ImageData.hpp" #include "RenderGraph/ImageViewData.hpp" #include "RenderGraph/WriteDescriptorSet.hpp" @@ -14,35 +17,29 @@ namespace crg { //********************************************************************************************* - BufferAttachment::BufferAttachment( Buffer buffer ) - : buffer{ std::move( buffer ) } + BufferAttachment::BufferAttachment( BufferViewIdArray views ) + : buffers{ std::move( views ) } + , flags{ FlagKind( buffers.front().data->info.format == PixelFormat::eUNDEFINED + ? Flag::None + : Flag::View ) } { } BufferAttachment::BufferAttachment( FlagKind flags - , Buffer buffer - , DeviceSize offset - , DeviceSize range + , BufferViewIdArray views , AccessState access ) - : buffer{ std::move( buffer ) } - , range{ offset, range } - , flags{ flags } + : buffers{ std::move( views ) } + , flags{ FlagKind( flags + | FlagKind( buffers.front().data->info.format == PixelFormat::eUNDEFINED ? Flag::None : Flag::View ) ) } , wantedAccess{ std::move( access ) } { } - BufferAttachment::BufferAttachment( FlagKind flags - , Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range - , AccessState access ) - : buffer{ std::move( buffer ) } - , view{ view } - , range{ offset, range } - , flags{ flags } - , wantedAccess{ std::move( access ) } + BufferViewId BufferAttachment::buffer( uint32_t index )const { + return buffers.size() == 1u + ? buffers.front() + : buffers[index]; } AccessFlags BufferAttachment::getAccessMask( bool isInput @@ -110,10 +107,15 @@ namespace crg return result; } + uint32_t BufferAttachment::getBufferCount()const + { + return uint32_t( buffers.size() ); + } + //********************************************************************************************* - ImageAttachment::ImageAttachment( ImageViewId view ) - : views{ 1u, view } + ImageAttachment::ImageAttachment( ImageViewIdArray views ) + : views{std::move( views ) } { } @@ -123,7 +125,6 @@ namespace crg , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp - , SamplerDesc samplerDesc , ClearValue clearValue , PipelineColorBlendAttachmentState blendState , ImageLayout wantedLayout ) @@ -132,7 +133,6 @@ namespace crg , storeOp{ storeOp } , stencilLoadOp{ stencilLoadOp } , stencilStoreOp{ stencilStoreOp } - , samplerDesc{ std::move( samplerDesc ) } , clearValue{ std::move( clearValue ) } , blendState{ std::move( blendState ) } , wantedLayout{ wantedLayout } @@ -181,28 +181,28 @@ namespace crg else if ( isInput ) result = ImageLayout::eTransferSrc; } - else if ( isColourAttach() ) + else if ( isColourTarget() ) { result = ImageLayout::eColorAttachment; } #if VK_KHR_separate_depth_stencil_layouts else if ( separateDepthStencilLayouts ) { - if ( isDepthStencilAttach() ) + if ( isDepthStencilTarget() ) { if ( isOutput ) result = ImageLayout::eDepthStencilAttachment; else if ( isInput ) result = ImageLayout::eDepthStencilReadOnly; } - else if ( isStencilAttach() ) + else if ( isStencilTarget() ) { - if ( isOutput && isStencilOutputAttach() ) + if ( isOutput && isStencilOutputTarget() ) result = ImageLayout::eStencilAttachment; - else if ( isInput && isStencilInputAttach() ) + else if ( isInput && isStencilInputTarget() ) result = ImageLayout::eStencilReadOnly; } - else if ( isDepthAttach() ) + else if ( isDepthTarget() ) { if ( isOutput ) result = ImageLayout::eDepthAttachment; @@ -214,12 +214,12 @@ namespace crg #endif { if ( isOutput - && ( isDepthAttach() || isStencilOutputAttach() ) ) + && ( isDepthTarget() || isStencilOutputTarget() ) ) { result = ImageLayout::eDepthStencilAttachment; } else if ( isInput - && ( isDepthAttach() || isStencilInputAttach() ) ) + && ( isDepthTarget() || isStencilInputTarget() ) ) { result = ImageLayout::eDepthStencilReadOnly; } @@ -255,7 +255,7 @@ namespace crg if ( isOutput ) result |= AccessFlags::eTransferWrite; } - else if ( isDepthAttach() || isStencilAttach() ) + else if ( isDepthTarget() || isStencilTarget() ) { if ( isInput ) result |= AccessFlags::eDepthStencilAttachmentRead; @@ -296,7 +296,7 @@ namespace crg { result |= PipelineStageFlags::eTransfer; } - else if ( isDepthAttach() || isStencilAttach() ) + else if ( isDepthTarget() || isStencilTarget() ) { result |= PipelineStageFlags::eLateFragmentTests; } @@ -310,32 +310,60 @@ namespace crg //********************************************************************************************* + Attachment::Attachment( Attachment const & rhs ) + : pass{ rhs.pass } + , name{ rhs.name } + , imageAttach{ rhs.imageAttach } + , bufferAttach{ rhs.bufferAttach } + , flags{ rhs.flags } + { + } + + Attachment & Attachment::operator=( Attachment const & rhs ) + { + pass = rhs.pass; + name = rhs.name; + imageAttach = rhs.imageAttach; + bufferAttach = rhs.bufferAttach; + flags = rhs.flags; + + return *this; + } + Attachment::Attachment( ImageViewId view , Attachment const & origin ) : pass{ origin.pass } - , binding{ origin.binding } , name{ origin.name + view.data->name } , imageAttach{ origin.imageAttach } + , flags{ origin.flags } + { + imageAttach.views = { view }; + } + + Attachment::Attachment( BufferViewId view + , Attachment const & origin ) + : pass{ origin.pass } + , name{ origin.name + view.data->name } , bufferAttach{ origin.bufferAttach } , flags{ origin.flags } { + bufferAttach.buffers = { view }; } - Attachment::Attachment( ImageViewId view ) - : imageAttach{ std::move( view ) } + Attachment::Attachment( ImageViewIdArray views ) + : imageAttach{ std::move( views ) } , flags{ FlagKind( Attachment::Flag::Image ) } { } - Attachment::Attachment( Buffer buffer ) - : bufferAttach{ std::move( buffer ) } + Attachment::Attachment( BufferViewIdArray views ) + : bufferAttach{ std::move( views ) } , flags{ FlagKind( Attachment::Flag::Buffer ) } { } Attachment::Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding + , FramePass const & pass , std::string name , ImageAttachment::FlagKind imageFlags , ImageViewIdArray views @@ -343,12 +371,11 @@ namespace crg , AttachmentStoreOp storeOp , AttachmentLoadOp stencilLoadOp , AttachmentStoreOp stencilStoreOp - , SamplerDesc samplerDesc , ClearValue clearValue , PipelineColorBlendAttachmentState blendState - , ImageLayout wantedLayout ) + , ImageLayout wantedLayout + , Token ) : pass{ &pass } - , binding{ binding } , name{ std::move( name ) } , imageAttach{ imageFlags , std::move( views ) @@ -356,7 +383,6 @@ namespace crg , storeOp , stencilLoadOp , stencilStoreOp - , std::move( samplerDesc ) , std::move( clearValue ) , std::move( blendState ) , wantedLayout } @@ -378,39 +404,41 @@ namespace crg } Attachment::Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding + , FramePass const & pass , std::string name , BufferAttachment::FlagKind bufferFlags - , Buffer buffer - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ) + , BufferViewIdArray views + , AccessState wantedAccess + , Token ) : pass{ &pass } - , binding{ binding } , name{ std::move( name ) } - , bufferAttach{ bufferFlags, std::move( buffer ), offset, range, std::move( wantedAccess ) } + , bufferAttach{ bufferFlags, std::move( views ), std::move( wantedAccess ) } , flags{ FlagKind( flags | FlagKind( Flag::Buffer ) ) } { } Attachment::Attachment( FlagKind flags - , FramePass & pass - , uint32_t binding , std::string name - , BufferAttachment::FlagKind bufferFlags - , Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ) - : pass{ &pass } - , binding{ binding } + , FramePass const * pass + , ImageAttachment attach + , Token ) + : pass{ pass } , name{ std::move( name ) } - , bufferAttach{ bufferFlags, std::move( buffer ), view, offset, range, std::move( wantedAccess ) } - , flags{ FlagKind( flags - | FlagKind( Flag::Buffer ) ) } + , imageAttach{ std::move( attach ) } + , flags{ flags } + { + } + + Attachment::Attachment( FlagKind flags + , std::string name + , FramePass const * pass + , BufferAttachment attach + , Token ) + : pass{ pass } + , name{ std::move( name ) } + , bufferAttach{ std::move( attach ) } + , flags{ flags } { } @@ -435,11 +463,11 @@ namespace crg : ImageViewId{}; } - VkBuffer Attachment::buffer( uint32_t index )const + BufferViewId Attachment::buffer( uint32_t index )const { return isBuffer() - ? bufferAttach.buffer.buffer( index ) - : VkBuffer{}; + ? bufferAttach.buffer( index ) + : BufferViewId{}; } ImageLayout Attachment::getImageLayout( bool separateDepthStencilLayouts )const @@ -472,5 +500,42 @@ namespace crg return bufferAttach.getPipelineStageFlags( isCompute ); } + Attachment const * Attachment::getSource( uint32_t index )const + { + if ( index > 0 && index >= source.size() ) + CRG_Exception( "Invalid index" ); + + if ( source.empty() ) + return this; + + return source[index].attach.get(); + } + + void Attachment::initSources() + { + for ( uint32_t index = 0u; index < source.size(); ++index ) + { + Source & attachSource = source[index]; + if ( isImage() ) + { + attachSource.attach = std::make_unique< Attachment >( flags + , name + std::to_string( index ) + , attachSource.pass + , *attachSource.imageAttach + , Token{} ); + attachSource.imageAttach = &attachSource.attach->imageAttach; + } + else + { + attachSource.attach = std::make_unique< Attachment >( flags + , name + std::to_string( index ) + , attachSource.pass + , *attachSource.bufferAttach + , Token{} ); + attachSource.bufferAttach = &attachSource.attach->bufferAttach; + } + } + } + //********************************************************************************************* } diff --git a/source/RenderGraph/AttachmentTransition.cpp b/source/RenderGraph/AttachmentTransition.cpp index 73ceea9..6110ed5 100644 --- a/source/RenderGraph/AttachmentTransition.cpp +++ b/source/RenderGraph/AttachmentTransition.cpp @@ -20,9 +20,8 @@ namespace crg for ( auto & transition : transitions ) { - auto it = std::find( result.begin(), result.end(), transition ); - - if ( it == result.end() ) + if ( auto it = std::find( result.begin(), result.end(), transition ); + it == result.end() ) { result.push_back( transition ); } @@ -32,15 +31,10 @@ namespace crg } } - bool operator==( Buffer const & lhs, Buffer const & rhs ) - { - return lhs.m_buffers == rhs.m_buffers; - } - AttachmentTransitions mergeIdenticalTransitions( AttachmentTransitions transitions ) { AttachmentTransitions result{}; - result.viewTransitions = attTran::mergeIdenticalTransitionsT( std::move( transitions.viewTransitions ) ); + result.imageTransitions = attTran::mergeIdenticalTransitionsT( std::move( transitions.imageTransitions ) ); result.bufferTransitions = attTran::mergeIdenticalTransitionsT( std::move( transitions.bufferTransitions ) ); return result; } diff --git a/source/RenderGraph/DotExport.cpp b/source/RenderGraph/DotExport.cpp index 0b57220..d7d7843 100644 --- a/source/RenderGraph/DotExport.cpp +++ b/source/RenderGraph/DotExport.cpp @@ -9,6 +9,7 @@ See LICENSE file in root folder. #include #include +#include #include #include @@ -182,6 +183,8 @@ namespace crg::dot template< typename char_type, typename traits > std::atomic_int BasicIndentBufferManager< char_type, traits >::sm_instances = 0; + inline void addIndent( std::ios_base & ios, long val ); + struct Indent { explicit Indent( long i ) @@ -220,17 +223,15 @@ namespace crg::dot template< typename CharType > inline void callback( std::ios_base::event ev, std::ios_base & ios, int ) { - if ( BasicIndentBufferManager< CharType >::instances() ) + if ( BasicIndentBufferManager< CharType >::instances() + && ev == std::ios_base::erase_event ) { - if ( ev == std::ios_base::erase_event ) - { - BasicIndentBufferManager< CharType >::instance()->erase( ios ); - } + BasicIndentBufferManager< CharType >::instance()->erase( ios ); } } template< typename CharType > - inline std::basic_ostream< CharType > & operator <<( std::basic_ostream< CharType > & stream, Indent const & ind ) + inline std::basic_ostream< CharType > & operator<<( std::basic_ostream< CharType > & stream, Indent const & ind ) { auto sbuf = dynamic_cast< BasicIndentBuffer< CharType > * >( stream.rdbuf() ); @@ -266,11 +267,8 @@ namespace crg::dot std::pair< FramePassGroupStreams *, bool > emplace( FramePassGroup const * group ) { auto streams = find( group ); - if ( streams ) - { return { streams, false }; - } assert( group != nullptr ); @@ -291,22 +289,15 @@ namespace crg::dot FramePassGroupStreams * find( FramePassGroup const * group ) { if ( m_group == group ) - { return this; - } FramePassGroupStreams * result{}; - auto it = std::find_if( m_children.begin() - , m_children.end() + auto it = std::find_if( m_children.begin(), m_children.end() , [group, &result]( FramePassGroupStreamsPtr const & lookup ) { auto ret = lookup->find( group ); - if ( ret ) - { result = ret; - } - return ret != nullptr; } ); @@ -442,353 +433,284 @@ namespace crg::dot std::set< std::string, std::less<> > m_nodes; }; - class DotOutVisitor - : public GraphVisitor + static void displayNode( std::ostream & stream + , std::string const & name + , std::string const & shape + , std::string_view colour + , std::set< std::string, std::less<> > & nodes + , Config const & config ) { - public: - static void submit( DisplayResult & streams - , FramePassGroupStreams & groups - , ConstGraphAdjacentNode node - , Config const & config - , std::set< ConstGraphAdjacentNode > & visited ) + if ( nodes.insert( name ).second ) { - DotOutVisitor vis{ streams, groups, config, visited }; - node->accept( &vis ); - } - - static void submit( DisplayResult & streams - , FramePassGroupStreams & groups - , ConstGraphAdjacentNode node - , Config const & config ) - { - std::set< ConstGraphAdjacentNode > visited; - submit( streams, groups, node, config, visited ); - } + stream << Indent{ 2 }; + stream << "\"" << name << "\" [ shape=" << shape; - static void displayNode( std::ostream & stream - , std::string const & name - , std::string const & shape - , std::string_view colour - , std::set< std::string, std::less<> > & nodes - , Config const & config ) - { - if ( nodes.insert( name ).second ) + if ( config.withColours ) { - stream << Indent{ 2 }; - stream << "\"" << name << "\" [ shape=" << shape; - - if ( config.withColours ) - { - stream << " style=filled"; - stream << " fillcolor=white"; - stream << " color=\"" << colour << "\""; - } - - stream << " ];\n"; - stream << Indent{ -2 }; + stream << " style=filled"; + stream << " fillcolor=white"; + stream << " color=\"" << colour << "\""; } - } - static FramePassGroupStreams & displayGroupNode( FramePassGroup const * group - , FramePassGroupStreams & groups - , Config const & ) - { - return *groups.emplace( group ).first; + stream << " ];\n"; + stream << Indent{ -2 }; } + } - static FramePassGroupStreams & displayPassNode( uint32_t id - , std::string const & name - , FramePassGroup const * group - , std::string_view colour - , FramePassGroupStreams & groups - , Config const & config ) - { - auto & groupStream = displayGroupNode( group, groups, config ); - auto & stream = groupStream.getStream(); - - if ( groupStream.getNodes().insert( name ).second ) - { - stream << Indent{ 2 }; - stream << "\"" << name << "\" [ shape=ellipse"; - - if ( config.withIds ) - { - stream << " id=\"" << id << "\""; - } - - if ( config.withColours ) - { - stream << " style=filled"; - stream << " fillcolor=white"; - stream << " color=\"" << colour << "\""; - } - - stream << " ];\n"; - stream << Indent{ -2 }; - } + static FramePassGroupStreams & displayGroupNode( FramePassGroup const * group + , FramePassGroupStreams & groups + , Config const & ) + { + return *groups.emplace( group ).first; + } - return groupStream; - } + static FramePassGroupStreams & displayPassNode( uint32_t id + , std::string const & name + , FramePassGroup const * group + , std::string_view colour + , FramePassGroupStreams & groups + , Config const & config ) + { + auto & groupStream = displayGroupNode( group, groups, config ); + auto & stream = groupStream.getStream(); - static void displayEdge( std::ostream & stream - , std::string const & from - , std::string const & to - , std::string const & label - , std::string_view colour - , Config const & config ) + if ( groupStream.getNodes().insert( name ).second ) { stream << Indent{ 2 }; - stream << "\"" << from << "\" -> \"" << to << "\" [ label=\"" << label << "\""; + stream << "\"" << name << "\" [ shape=ellipse"; + + if ( config.withIds ) + { + stream << " id=\"" << id << "\""; + } if ( config.withColours ) { - stream << " color = \"" << colour << "\" fontcolor=\"" << colour << "\""; + stream << " style=filled"; + stream << " fillcolor=white"; + stream << " color=\"" << colour << "\""; } stream << " ];\n"; stream << Indent{ -2 }; } - template< typename AttachT > - static void displayAttachPass( AttachT const & attach - , FramePassGroupStreams & groups - , Config const & config ) - { - uint32_t nodeId = 0; - std::string node = "ExternalSource"; - FramePassGroup const * group = nullptr; - std::string_view colour = extColour; - - if ( attach.pass ) - { - nodeId = attach.pass->id; - node = attach.pass->getGroupName(); - group = &attach.pass->group; - colour = passColour; - } + return groupStream; + } - displayPassNode( nodeId, node, group, colour, groups, config ); - } + static void displayEdge( std::ostream & stream + , std::string const & from + , std::string const & to + , std::string const & label + , std::string_view colour + , Config const & config ) + { + stream << Indent{ 2 }; + stream << "\"" << from << "\" -> \"" << to << "\" [ label=\"" << label << "\""; - static std::string const & getAttachName( crg::Buffer const & data ) + if ( config.withColours ) { - return data.name; + stream << " color = \"" << colour << "\" fontcolor=\"" << colour << "\""; } - static std::string const & getAttachName( crg::ImageViewId const & data ) - { - return data.data->name; - } + stream << " ];\n"; + stream << Indent{ -2 }; + } - static bool isIn( FramePassGroupStreams const * inner - , FramePassGroupStreams const * outer ) + static void displayAttachPass( Attachment const & attach + , FramePassGroupStreams & groups + , Config const & config ) + { + uint32_t nodeId = 0; + std::string node = "ExternalSource"; + FramePassGroup const * group = nullptr; + std::string_view colour = extColour; + + if ( attach.pass ) { - return outer == inner - || ( outer && isIn( inner, outer->getParent() ) ); + nodeId = attach.pass->id; + node = attach.pass->getGroupName(); + group = &attach.pass->group; + colour = passColour; } - static FramePassGroupStreams * getCommonGroup( FramePassGroupStreams * lhs - , FramePassGroupStreams const * rhs ) - { - auto current = lhs; + displayPassNode( nodeId, node, group, colour, groups, config ); + } - while ( current && !isIn( current, rhs ) ) - { - current = current->getParent(); - } + static std::string const & getAttachName( crg::BufferViewId const & data ) + { + return data.data->name; + } - return current; - } + static std::string const & getAttachName( crg::ImageViewId const & data ) + { + return data.data->name; + } - template< typename TransitionT > - static void displayTransitionEdge( std::ostream & stream - , std::string_view colour - , TransitionT const & transition - , FramePassGroupStreams & groups - , Config const & config ) - { - auto srcName = transition.outputAttach.name; - auto dstName = transition.inputAttach.name; - std::string srcNode = "ExternalSource"; - std::string dstNode = "ExternalDestination"; - auto srcStream = &groups; - auto dstStream = &groups; - auto curStreams = &groups; + static bool isIn( FramePassGroupStreams const * inner + , FramePassGroupStreams const * outer ) + { + return outer == inner + || ( outer && isIn( inner, outer->getParent() ) ); + } - if ( transition.outputAttach.pass ) - { - srcNode = transition.outputAttach.pass->getGroupName(); - srcStream = groups.find( &transition.outputAttach.pass->group ); - } + static FramePassGroupStreams * getCommonGroup( FramePassGroupStreams * lhs + , FramePassGroupStreams const * rhs ) + { + auto current = lhs; - if ( transition.inputAttach.pass ) - { - dstNode = transition.inputAttach.pass->getGroupName(); - dstStream = groups.find( &transition.inputAttach.pass->group ); - } + while ( current && !isIn( current, rhs ) ) + { + current = current->getParent(); + } - std::string name{ srcName + "\\ntransition to\\n" + dstName }; - auto curstream = &stream; + return current; + } - if ( srcStream != &groups - && dstStream != &groups ) - { - if ( srcStream == dstStream ) - { - curStreams = srcStream; - curstream = &srcStream->getStream(); - } - else if ( auto groupStreams = getCommonGroup( srcStream, dstStream ) ) - { - curStreams = groupStreams; - curstream = &groupStreams->getStream(); - } - } + template< typename TransitionT > + static void displayTransitionEdge( std::ostream & stream + , std::string_view colour + , TransitionT const & transition + , FramePassGroupStreams & groups + , Config const & config ) + { + auto srcName = transition.outputAttach.name; + auto dstName = transition.inputAttach.name; + std::string srcNode = "ExternalSource"; + std::string dstNode = "ExternalDestination"; + auto srcStream = &groups; + auto dstStream = &groups; + auto curStreams = &groups; - displayNode( *curstream, name, "box", colour, curStreams->getNodes(), config ); - displayEdge( *curstream, srcNode, name, getAttachName( transition.data ), colour, config ); - displayEdge( *curstream, name, dstNode, getAttachName( transition.data ), colour, config ); + if ( transition.outputAttach.pass ) + { + srcNode = transition.outputAttach.pass->getGroupName(); + srcStream = groups.find( &transition.outputAttach.pass->group ); } - static void submit( DisplayResult & streams - , AttachmentTransitions const & transitions - , Config const & config ) + if ( transition.inputAttach.pass ) { - FramePassGroupStreams groups{ config }; + dstNode = transition.inputAttach.pass->getGroupName(); + dstStream = groups.find( &transition.inputAttach.pass->group ); + } - for ( auto & transition : transitions.viewTransitions ) - { - displayAttachPass( transition.outputAttach, groups, config ); - displayAttachPass( transition.inputAttach, groups, config ); - } + std::string name{ "Transition to\\n" + dstName }; + auto curstream = &stream; - for ( auto & transition : transitions.bufferTransitions ) + if ( srcStream != &groups + && dstStream != &groups ) + { + if ( srcStream == dstStream ) { - displayAttachPass( transition.outputAttach, groups, config ); - displayAttachPass( transition.inputAttach, groups, config ); + curStreams = srcStream; + curstream = &srcStream->getStream(); } - - std::stringstream trstream; - - for ( auto & transition : transitions.viewTransitions ) + else if ( auto groupStreams = getCommonGroup( srcStream, dstStream ) ) { - displayTransitionEdge( trstream, imgColour, transition, groups, config ); + curStreams = groupStreams; + curstream = &groupStreams->getStream(); } + } - for ( auto & transition : transitions.bufferTransitions ) - { - displayTransitionEdge( trstream, bufColour, transition, groups, config ); - } + displayNode( *curstream, name, "box", colour, curStreams->getNodes(), config ); + displayEdge( *curstream, srcNode, name, getAttachName( transition.data ), colour, config ); + displayEdge( *curstream, name, dstNode, getAttachName( transition.data ), colour, config ); + } + class DotTransitionsVisitor + : public GraphVisitor + { + public: + static void submit( DisplayResult & streams + , ConstGraphAdjacentNode node + , Config const & config ) + { + std::set< ConstGraphAdjacentNode > visited; + std::stringstream trstream; + FramePassGroupStreams groups{ config }; + submit( streams, node, config, groups, trstream, visited ); groups.write( streams, trstream ); } private: - DotOutVisitor( DisplayResult & streams + static void submit( DisplayResult & streams + , ConstGraphAdjacentNode node + , Config const & config , FramePassGroupStreams & groups + , std::stringstream & trstream + , std::set< ConstGraphAdjacentNode > & visited ) + { + DotTransitionsVisitor vis{ streams, groups, trstream, config, visited }; + node->accept( &vis ); + } + + DotTransitionsVisitor( DisplayResult & streams + , FramePassGroupStreams & groups + , std::stringstream & trstream , Config const & config , std::set< ConstGraphAdjacentNode > & visited ) : m_streams{ streams } , m_groups{ groups } + , m_trstream{ trstream } , m_config{ config } , m_visited{ visited } { } - void printEdge( ConstGraphAdjacentNode lhs - , ConstGraphAdjacentNode rhs ) - { - std::string sep; - auto transitions = rhs->getInputAttaches( lhs ); - std::sort( transitions.viewTransitions.begin() - , transitions.viewTransitions.end() - , []( ViewTransition const & ilhs, ViewTransition const & irhs ) - { - return ilhs.outputAttach.name < irhs.outputAttach.name; - } ); - std::sort( transitions.bufferTransitions.begin() - , transitions.bufferTransitions.end() - , []( BufferTransition const & ilhs, BufferTransition const & irhs ) - { - return ilhs.outputAttach.name < irhs.outputAttach.name; - } ); - - auto lhsStream = &displayPassNode( lhs->getId(), lhs->getName(), &lhs->getGroup(), passColour, m_groups, m_config ); - auto rhsStream = &displayPassNode( rhs->getId(), rhs->getName(), &rhs->getGroup(), passColour, m_groups, m_config ); - auto curStreams = &m_groups; - auto curstream = &m_groups.getStream(); - auto & lhsName = lhs->getName(); - auto & rhsName = rhs->getName(); - - if ( lhsStream != &m_groups - && rhsStream != &m_groups ) - { - if ( lhsStream == rhsStream ) - { - curStreams = lhsStream; - curstream = &curStreams->getStream(); - } - else if ( auto groupStreams = getCommonGroup( lhsStream, rhsStream ) ) - { - curStreams = groupStreams; - curstream = &groupStreams->getStream(); - } - } - - for ( auto const & transition : transitions.viewTransitions ) - { - auto attachName = transition.inputAttach.name; - std::string name{ "Transition to\\n" + attachName }; - displayNode( *curstream, name, "box", imgColour, curStreams->getNodes(), m_config ); - displayEdge( *curstream, lhsName, name, transition.data.data->name, imgColour, m_config ); - displayEdge( *curstream, name, rhsName, transition.data.data->name, imgColour, m_config ); - } - - for ( auto const & transition : transitions.bufferTransitions ) - { - auto attachName = transition.inputAttach.name; - std::string name{ "Transition to\\n" + attachName }; - displayNode( *curstream, name, "box", bufColour, curStreams->getNodes(), m_config ); - displayEdge( *curstream, lhsName, name, transition.data.name, bufColour, m_config ); - displayEdge( *curstream, name, rhsName, transition.data.name, bufColour, m_config ); - } - } - void submit( ConstGraphAdjacentNode node ) { submit( m_streams - , m_groups , node , m_config + , m_groups + , m_trstream , m_visited ); } void visitRootNode( RootNode const * node )override { - for ( auto & next : node->getNext() ) + for ( auto & pred : node->getPredecessors() ) { submit( m_streams - , m_groups - , next + , pred , m_config + , m_groups + , m_trstream , m_visited ); } - - m_groups.write( m_streams ); } void visitFramePassNode( FramePassNode const * node )override { - m_visited.insert( node ); - auto & nexts = node->getNext(); + for ( auto & transition : node->getImageTransitions() ) + { + displayAttachPass( transition.outputAttach, m_groups, m_config ); + displayAttachPass( transition.inputAttach, m_groups, m_config ); + } + + for ( auto & transition : node->getBufferTransitions() ) + { + displayAttachPass( transition.outputAttach, m_groups, m_config ); + displayAttachPass( transition.inputAttach, m_groups, m_config ); + } + + for ( auto & transition : node->getImageTransitions() ) + { + displayTransitionEdge( m_trstream, imgColour, transition, m_groups, m_config ); + } - for ( auto & next : nexts ) + for ( auto & transition : node->getBufferTransitions() ) { - printEdge( node, next ); + displayTransitionEdge( m_trstream, bufColour, transition, m_groups, m_config ); + } - if ( m_visited.end() == m_visited.find( next ) ) + m_visited.insert( node ); + + for ( auto & pred : node->getPredecessors() ) + { + if ( m_visited.end() == m_visited.find( pred ) ) { - submit( next ); + submit( pred ); } } } @@ -796,33 +718,39 @@ namespace crg::dot private: DisplayResult & m_streams; FramePassGroupStreams & m_groups; + std::stringstream & m_trstream; Config const & m_config; std::set< GraphNode const * > & m_visited; }; - } - DisplayResult displayPasses( RunnableGraph const & value - , Config const & config ) - { - DisplayResult result; - dotexp::FramePassGroupStreams groups{ config }; - dotexp::DotOutVisitor::submit( result, groups, value.getGraph(), config ); - return result; + static std::string applyRemove( std::string const & text, Config const & config ) + { + if ( config.toRemove.empty() ) + return text; + + auto result = text; + size_t startPos = 0u; + + while ( ( startPos = result.find( config.toRemove, startPos ) ) != std::string::npos ) + result.replace( startPos, config.toRemove.length(), "" ); + + return result; + } } DisplayResult displayTransitions( RunnableGraph const & value , Config const & config ) { DisplayResult result; - dotexp::DotOutVisitor::submit( result, value.getTransitions(), config ); + dotexp::DotTransitionsVisitor::submit( result, value.getGraph(), config ); return result; } - void displayPasses( std::ostream & stream + void displayTransitions( std::ostream & stream , RunnableGraph const & value , Config const & config ) { - auto result = displayPasses( value, config ); + auto result = displayTransitions( value, config ); if ( config.splitGroups ) { @@ -830,26 +758,14 @@ namespace crg::dot { if ( !name.empty() ) { - stream << strm.str(); + stream << dotexp::applyRemove( strm.str(), config ); } } } else { auto it = result.find( std::string{} ); - stream << it->second.str(); - } - } - - void displayTransitions( std::ostream & stream - , RunnableGraph const & value - , Config const & config ) - { - auto result = displayTransitions( value, config ); - - for ( auto const & [_, strm] : result ) - { - stream << strm.str(); + stream << dotexp::applyRemove( it->second.str(), config ); } } } diff --git a/source/RenderGraph/FrameGraph.cpp b/source/RenderGraph/FrameGraph.cpp index 7a0b6e4..5500603 100644 --- a/source/RenderGraph/FrameGraph.cpp +++ b/source/RenderGraph/FrameGraph.cpp @@ -7,10 +7,10 @@ See LICENSE file in root folder. #include "RenderGraph/Exception.hpp" #include "RenderGraph/FramePass.hpp" #include "RenderGraph/FramePassGroup.hpp" +#include "RenderGraph/Hash.hpp" #include "RenderGraph/Log.hpp" #include "RenderGraph/ResourceHandler.hpp" #include "RenderGraph/RunnableGraph.hpp" -#include "FramePassDependenciesBuilder.hpp" #include "GraphBuilder.hpp" #include @@ -19,95 +19,149 @@ namespace crg { namespace fgph { - static FramePassArray sortPasses( FramePassArray const & passes ) + static void mergeViewData( ImageViewId const & view + , bool mergeMipLevels + , bool mergeArrayLayers + , ImageViewData & data ) { - FramePassArray sortedPasses; - FramePassArray unsortedPasses; - - for ( auto & pass : passes ) + if ( data.image.id == 0 ) + { + data.image = view.data->image; + data.name = data.image.data->name; + data.info.flags = view.data->info.flags; + data.info.format = view.data->info.format; + data.info.viewType = view.data->info.viewType; + data.info.subresourceRange = getSubresourceRange( view ); + } + else { - if ( pass->passDepends.empty() ) + assert( data.image == view.data->image ); + + if ( mergeMipLevels ) { - sortedPasses.push_back( pass ); + auto maxLevel = std::max( data.info.subresourceRange.levelCount + data.info.subresourceRange.baseMipLevel + , getSubresourceRange( view ).levelCount + getSubresourceRange( view ).baseMipLevel ); + data.info.subresourceRange.baseMipLevel = std::min( getSubresourceRange( view ).baseMipLevel + , data.info.subresourceRange.baseMipLevel ); + data.info.subresourceRange.levelCount = maxLevel - data.info.subresourceRange.baseMipLevel; } else { - unsortedPasses.push_back( pass ); + data.info.subresourceRange.baseMipLevel = std::min( getSubresourceRange( view ).baseMipLevel + , data.info.subresourceRange.baseMipLevel ); + data.info.subresourceRange.levelCount = 1u; + } + + if ( mergeArrayLayers ) + { + auto maxLayer = std::max( data.info.subresourceRange.layerCount + data.info.subresourceRange.baseArrayLayer + , getSubresourceRange( view ).layerCount + getSubresourceRange( view ).baseArrayLayer ); + data.info.subresourceRange.baseArrayLayer = std::min( getSubresourceRange( view ).baseArrayLayer + , data.info.subresourceRange.baseArrayLayer ); + data.info.subresourceRange.layerCount = maxLayer - data.info.subresourceRange.baseArrayLayer; + } + else + { + data.info.subresourceRange.baseArrayLayer = std::min( getSubresourceRange( view ).baseArrayLayer + , data.info.subresourceRange.baseArrayLayer ); + data.info.subresourceRange.layerCount = 1u; } } - if ( sortedPasses.empty() ) + data.source.push_back( view ); + } + + static void mergeViewData( BufferViewId const & view + , BufferViewData & data ) + { + if ( data.buffer.id == 0 ) { - sortedPasses.push_back( unsortedPasses.front() ); - unsortedPasses.erase( unsortedPasses.begin() ); + data.buffer = view.data->buffer; + data.name = data.buffer.data->name; + data.info.format = view.data->info.format; + data.info.subresourceRange = getSubresourceRange( view ); } - - while ( !unsortedPasses.empty() ) + else { - FramePassArray currentPasses; - std::swap( currentPasses, unsortedPasses ); - bool added = false; + assert( data.buffer == view.data->buffer ); + auto maxUpperBound = std::max( data.info.subresourceRange.offset + data.info.subresourceRange.size + , getSubresourceRange( view ).offset + getSubresourceRange( view ).size ); + auto minLowerBound = std::min( data.info.subresourceRange.offset + , getSubresourceRange( view ).offset ); + data.info.subresourceRange.offset = minLowerBound; + data.info.subresourceRange.size = maxUpperBound - minLowerBound; + } - for ( auto & pass : currentPasses ) + data.source.push_back( view ); + } + + static size_t makeHash( AttachmentArray const & attachments + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + auto result = std::hash< bool >{}( mergeMipLevels ); + result = hashCombine( result, mergeArrayLayers ); + for ( auto attach : attachments ) + result = hashCombine( result, attach ); + return result; + } + + static AttachmentPtr mergeAttachments( FrameGraph & graph + , AttachmentArray const & attachments + , uint32_t passCount + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + AttachmentPtr result; + + for ( uint32_t passIndex = 0u; passIndex < passCount; ++passIndex ) + { + ImageViewIdArray views; + for ( auto attach : attachments ) { -#if !defined( NDEBUG ) - bool processed = false; -#endif - // Only process this pass if all its dependencies have been processed. - if ( !std::all_of( pass->passDepends.begin() - , pass->passDepends.end() - , [&sortedPasses]( FramePass const * lookup ) - { - return sortedPasses.end() != std::find( sortedPasses.begin() - , sortedPasses.end() - , lookup ); - } ) ) + views.push_back( attach->view( passIndex ) ); + if ( !result ) { - unsortedPasses.push_back( pass ); -#if !defined( NDEBUG ) - processed = true; -#endif - } - else if ( auto it = std::find_if( sortedPasses.begin() - , sortedPasses.end() - , [&pass]( FramePass const * lookup ) - { - return lookup->dependsOn( *pass ); - } ); - it != sortedPasses.end() ) - { - sortedPasses.insert( it, pass ); - added = true; -#if !defined( NDEBUG ) - processed = true; -#endif - } - else if ( auto rit = std::find_if( sortedPasses.rbegin() - , sortedPasses.rend() - , [&pass]( FramePass const * lookup ) - { - return pass->dependsOn( *lookup ); - } ); - rit != sortedPasses.rend() ) - { - sortedPasses.insert( rit.base(), pass ); - added = true; -#if !defined( NDEBUG ) - processed = true; -#endif + result = std::make_unique< Attachment >( views.back(), *attach ); + result->imageAttach.views.clear(); + result->pass = nullptr; } - assert( processed && "Couldn't process pass" ); + result->source.emplace_back( attach, attach->pass, attach->imageAttach ); } - if ( !added ) + result->imageAttach.views.push_back( graph.mergeViews( views, mergeMipLevels, mergeArrayLayers ) ); + } + + return result; + } + + static AttachmentPtr mergeAttachments( FrameGraph & graph + , AttachmentArray const & attachments + , uint32_t passCount ) + { + AttachmentPtr result; + + for ( uint32_t passIndex = 0u; passIndex < passCount; ++passIndex ) + { + BufferViewIdArray views; + for ( auto attach : attachments ) { - Logger::logError( "Couldn't sort passes" ); - CRG_Exception( "Couldn't sort passes" ); + views.push_back( attach->buffer( passIndex ) ); + if ( !result ) + { + result = std::make_unique< Attachment >( views.back(), *attach ); + result->bufferAttach.buffers.clear(); + result->pass = nullptr; + } + + result->source.emplace_back( attach, attach->pass, attach->bufferAttach ); } + + result->bufferAttach.buffers.push_back( graph.mergeViews( views ) ); } - return sortedPasses; + return result; } } @@ -115,7 +169,7 @@ namespace crg , std::string name ) : m_handler{ handler } , m_name{ std::move( name ) } - , m_defaultGroup{ new FramePassGroup{ *this, 0u, m_name } } + , m_defaultGroup{ std::make_unique< FramePassGroup >( *this, 0u, m_name, FramePassGroup::Token{} ) } , m_finalState{ handler } { } @@ -131,6 +185,20 @@ namespace crg return m_defaultGroup->createPassGroup( groupName ); } + BufferId FrameGraph::createBuffer( BufferData const & img ) + { + auto result = m_handler.createBufferId( img ); + m_buffers.insert( result ); + return result; + } + + BufferViewId FrameGraph::createView( BufferViewData const & view ) + { + auto result = m_handler.createViewId( view ); + m_bufferViews.insert( result ); + return result; + } + ImageId FrameGraph::createImage( ImageData const & img ) { auto result = m_handler.createImageId( img ); @@ -145,6 +213,150 @@ namespace crg return result; } + ImageViewId FrameGraph::mergeViews( ImageViewIdArray const & views + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + ImageViewData data; + for ( auto & view : views ) + fgph::mergeViewData( view, mergeMipLevels, mergeArrayLayers, data ); + + if ( data.info.subresourceRange.layerCount > 1u ) + { + switch ( data.info.viewType ) + { + case ImageViewType::e1D: + data.info.viewType = ImageViewType::e1DArray; + break; + case ImageViewType::e2D: + if ( checkFlag( data.image.data->info.flags, ImageCreateFlags::eCubeCompatible ) + && ( data.info.subresourceRange.layerCount % 6u ) == 0u + && data.info.subresourceRange.baseArrayLayer == 0u ) + { + if ( data.info.subresourceRange.layerCount > 6u ) + { + data.info.viewType = ImageViewType::eCubeArray; + } + else + { + data.info.viewType = ImageViewType::eCube; + } + } + else + { + data.info.viewType = ImageViewType::e2DArray; + } + break; + case ImageViewType::eCube: + if ( data.info.subresourceRange.layerCount > 6u ) + { + data.info.viewType = ImageViewType::eCubeArray; + } + break; + default: + break; + } + } + + return createView( data ); + } + + BufferViewId FrameGraph::mergeViews( BufferViewIdArray const & views ) + { + BufferViewData data; + for ( auto & view : views ) + fgph::mergeViewData( view, data ); + return createView( data ); + } + + Attachment const * FrameGraph::mergeAttachments( AttachmentArray const & attachments + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + if ( attachments.empty() ) + { + Logger::logWarning( "No attachments to merge" ); + return nullptr; + } + if ( attachments.size() == 1 ) + { + Logger::logDebug( "Single attachment, nothing to merge" ); + return attachments.front(); + } + + auto allImages = std::all_of( attachments.begin(), attachments.end() + , []( Attachment const * attach ) + { + return attach->isImage(); + } ); + if ( auto allBuffers = std::all_of( attachments.begin(), attachments.end() + , []( Attachment const * attach ) + { + return attach->isBuffer(); + } ); + !allImages && !allBuffers ) + { + Logger::logWarning( "Can only merge attachments of the same type" ); + CRG_Exception( "Can only merge attachments of the same type" ); + } + + auto passCount = allImages + ? attachments.front()->getViewCount() + : attachments.front()->getBufferCount(); + + if ( passCount == 0 ) + { + Logger::logWarning( "Can't merge empty attachments" ); + CRG_Exception( "Can't merge empty attachments" ); + } + + if ( allImages ) + { + if ( !std::all_of( attachments.begin(), attachments.end() + , [passCount]( Attachment const * attach ) + { + return attach->getViewCount() == passCount; + } ) ) + { + Logger::logWarning( "Can only merge attachments with the same pass count" ); + CRG_Exception( "Can only merge attachments with the same pass count" ); + } + } + else + { + if ( !std::all_of( attachments.begin(), attachments.end() + , [passCount]( Attachment const * attach ) + { + return attach->getBufferCount() == passCount; + } ) ) + { + Logger::logWarning( "Can only merge attachments with the same pass count" ); + CRG_Exception( "Can only merge attachments with the same pass count" ); + } + } + + size_t hash = allImages + ? fgph::makeHash( attachments, mergeMipLevels, mergeArrayLayers ) + : fgph::makeHash( attachments, false, false ); + auto [it, inserted] = m_mergedAttachments.try_emplace( hash, nullptr ); + + if ( inserted ) + { + if ( allImages ) + { + it->second = fgph::mergeAttachments( *this, attachments, passCount, mergeMipLevels, mergeArrayLayers ); + } + else + { + it->second = fgph::mergeAttachments( *this, attachments, passCount ); + } + + it->second->initSources(); + } + + return it->second.get(); + } + RunnableGraphPtr FrameGraph::compile( GraphContext & context ) { FramePassArray passes; @@ -156,36 +368,11 @@ namespace crg CRG_Exception( "No FramePass registered." ); } - passes = fgph::sortPasses( passes ); - GraphNodePtrArray nodes; - - for ( auto & pass : passes ) - { - auto node = std::make_unique< FramePassNode >( *pass ); - nodes.emplace_back( std::move( node ) ); - } - - FramePassDependencies inputTransitions; - FramePassDependencies outputTransitions; - AttachmentTransitions transitions; - PassDependencyCache imgDepsCache; - PassDependencyCache bufDepsCache; - builder::buildPassAttachDependencies( nodes - , imgDepsCache - , bufDepsCache - , inputTransitions - , outputTransitions - , transitions ); + auto endPoints = builder::findEndPoints( passes ); RootNode root{ *this }; - builder::buildGraph( root - , nodes - , imgDepsCache - , bufDepsCache - , transitions ); - ImageMemoryMap images; - ImageViewMap imageViews; + GraphNodePtrArray nodes; + builder::buildGraph( endPoints, root, nodes, context.separateDepthStencilLayouts ); return std::make_unique< RunnableGraph >( *this - , std::move( transitions ) , std::move( nodes ) , std::move( root ) , context ); @@ -205,16 +392,28 @@ namespace crg { return getFinalLayoutState( view.data->image , view.data->info.viewType - , view.data->info.subresourceRange ); + , getSubresourceRange( view ) ); } return getFinalLayoutState( view.data->source[passIndex], 0u ); } - AccessState const & FrameGraph::getFinalAccessState( Buffer const & buffer + AccessState const & FrameGraph::getFinalAccessState( BufferId buffer + , BufferSubresourceRange const & range )const + { + return m_finalState.getAccessState( buffer, range ); + } + + AccessState const & FrameGraph::getFinalAccessState( BufferViewId view , uint32_t passIndex )const { - return m_finalState.getAccessState( buffer.buffer( passIndex ), { 0u, VK_WHOLE_SIZE } ); + if ( view.data->source.empty() ) + { + return getFinalAccessState( view.data->buffer + , getSubresourceRange( view ) ); + } + + return getFinalAccessState( view.data->source[passIndex], 0u ); } void FrameGraph::addInput( ImageId image @@ -233,7 +432,7 @@ namespace crg { addInput( view.data->image , view.data->info.viewType - , view.data->info.subresourceRange + , getSubresourceRange( view ) , outputLayout ); } @@ -250,7 +449,7 @@ namespace crg { return getInputLayoutState( view.data->image , view.data->info.viewType - , view.data->info.subresourceRange ); + , getSubresourceRange( view ) ); } void FrameGraph::addOutput( ImageId image @@ -269,7 +468,7 @@ namespace crg { addOutput( view.data->image , view.data->info.viewType - , view.data->info.subresourceRange + , getSubresourceRange( view ) , outputLayout ); } @@ -286,7 +485,7 @@ namespace crg { return getOutputLayoutState( view.data->image , view.data->info.viewType - , view.data->info.subresourceRange ); + , getSubresourceRange( view ) ); } LayerLayoutStatesMap const & FrameGraph::getOutputLayoutStates()const diff --git a/source/RenderGraph/FrameGraph.natvis b/source/RenderGraph/FrameGraph.natvis index a500e9d..b6a5c6c 100644 --- a/source/RenderGraph/FrameGraph.natvis +++ b/source/RenderGraph/FrameGraph.natvis @@ -1,16 +1,29 @@ - - {name} + + {name,sb} fmt={info.size} + + name + info.flags + info.size + info.usage + + + + + {name,sb} fmt={info.format} offset={info.subresourceRange.offset} size={info.subresourceRange.size} name buffer + info.format + info.subresourceRange.offset + info.subresourceRange.size - {name} fmt={info.format} mips={info.mipLevels} + {name,sb} fmt={info.format} mips={info.mipLevels} name info.flags @@ -26,7 +39,7 @@ - {name} fmt={info.format} mipLevel={info.subresourceRange.baseMipLevel} mipCount={info.subresourceRange.levelCount} + {name,sb} fmt={info.format} mipLevel={info.subresourceRange.baseMipLevel} mipCount={info.subresourceRange.levelCount} name image @@ -41,7 +54,7 @@ - {id} {data->name} + {id} {data->name,sb} id *data @@ -49,23 +62,24 @@ - Uniform {buffer} - Storage {buffer} - Transfer {buffer} - Transition {buffer} + {buffers[0]} + Uniform {buffers[0]} + Storage {buffers[0]} + Transfer {buffers[0]} + Transition {buffers[0]} - buffer - view - range.offset - range.size + buffers + wantedAccess + {views[0]} Sampled {views[0]}" Storage {views[0]}" Transfer {views[0]}" Transition {views[0]}" + Target {views[0]} views loadOp @@ -74,41 +88,54 @@ stencilStoreOp blendState clearValue - samplerDesc wantedLayout - In {imageAttach} {*pass}" - Out {imageAttach} {*pass}" - InOut {imageAttach} {*pass}" - In {bufferAttach} {*pass}" - Out {bufferAttach} {*pass}" - InOut {bufferAttach} {*pass}" + Image {imageAttach} ({*pass})" + Buffer {bufferAttach} ({*pass})" + Image {imageAttach}" + Buffer {bufferAttach}" + Image In {imageAttach} ({*pass})" + Image Out {imageAttach} ({*pass})" + Image InOut {imageAttach} ({*pass})" + Buffer In {bufferAttach} ({*pass})" + Buffer Out {bufferAttach} ({*pass})" + Buffer InOut {bufferAttach} ({*pass})" + Image In {imageAttach}" + Image Out {imageAttach}" + Image InOut {imageAttach}" + Buffer In {bufferAttach}" + Buffer Out {bufferAttach}" + Buffer InOut {bufferAttach}" name imageAttach bufferAttach - *pass + *pass + source - {group}/{id} {m_name} + {group}/{id} {m_name,sb} - group - id + group + id m_name - images - buffers - passDepends + uniforms + sampled + inputs + inouts + outputs + targets - {m_name} - {*parent}/{m_name} + {m_name,sb} + {*parent}/{m_name,sb} id m_name @@ -120,29 +147,29 @@ - {kind} {name} {next} + {kind} {name} name kind - next + prev attachsToPrev - {kind} {*pass}, {next} + {kind} {*pass} *pass - next + prev attachsToPrev - {kind} {name}, {next} + {kind} {name} name - next + prev diff --git a/source/RenderGraph/FrameGraphPrerequisites.cpp b/source/RenderGraph/FrameGraphPrerequisites.cpp index 04377c4..c18156d 100644 --- a/source/RenderGraph/FrameGraphPrerequisites.cpp +++ b/source/RenderGraph/FrameGraphPrerequisites.cpp @@ -1,4 +1,6 @@ #include "RenderGraph/FrameGraphPrerequisites.hpp" +#include "RenderGraph/BufferData.hpp" +#include "RenderGraph/BufferViewData.hpp" #include "RenderGraph/ImageData.hpp" #include "RenderGraph/ImageViewData.hpp" @@ -24,19 +26,8 @@ namespace crg , ImageSubresourceRange const & lhsRange , ImageSubresourceRange const & rhsRange )noexcept { - auto result = lhsType == rhsType; - - if ( !result ) - { - result = match( getVirtualRange( image, lhsType, lhsRange ) - , getVirtualRange( image, rhsType, rhsRange ) ); - } - else - { - result = match( lhsRange, rhsRange ); - } - - return result; + return match( getVirtualRange( image, lhsType, lhsRange ) + , getVirtualRange( image, rhsType, rhsRange ) ); } static bool match( ImageId const & image @@ -440,26 +431,18 @@ namespace crg std::string_view getName( FilterMode v ) { - switch ( v ) - { - case FilterMode::eLinear: + if ( v == FilterMode::eLinear ) return "linear"; - default: - return "nearest"; - } + return "nearest"; } //********************************************************************************************* std::string_view getName( MipmapMode v ) { - switch ( v ) - { - case MipmapMode::eLinear: + if ( v == MipmapMode::eLinear ) return "linear"; - default: - return "nearest"; - } + return "nearest"; } //********************************************************************************************* @@ -503,6 +486,16 @@ namespace crg return getExtent( image.data->image ); } + DeviceSize getSize( BufferId const & buffer )noexcept + { + return buffer.data->info.size; + } + + DeviceSize getSize( BufferViewId const & buffer )noexcept + { + return buffer.data->info.subresourceRange.size; + } + Extent3D getMipExtent( ImageViewId const & image )noexcept { auto result = getExtent( image.data->image ); @@ -567,6 +560,11 @@ namespace crg return image.data->info.subresourceRange; } + BufferSubresourceRange const & getSubresourceRange( BufferViewId const & buffer )noexcept + { + return buffer.data->info.subresourceRange; + } + AccessFlags getAccessMask( ImageLayout layout )noexcept { AccessFlags result{ 0u }; @@ -717,13 +715,13 @@ namespace crg ImageAspectFlags getAspectMask( PixelFormat format )noexcept { - return ImageAspectFlags( isDepthStencilFormat( format ) - ? ImageAspectFlags::eDepth | ImageAspectFlags::eStencil - : ( isDepthFormat( format ) - ? ImageAspectFlags::eDepth - : ( isStencilFormat( format ) - ? ImageAspectFlags::eStencil - : ImageAspectFlags::eColor ) ) ); + if ( isDepthStencilFormat( format ) ) + return ImageAspectFlags::eDepth | ImageAspectFlags::eStencil; + if ( isDepthFormat( format ) ) + return ImageAspectFlags::eDepth; + if ( isStencilFormat( format ) ) + return ImageAspectFlags::eStencil; + return ImageAspectFlags::eColor; } LayoutState const & addSubresourceRangeLayout( LayerLayoutStates & ranges @@ -807,7 +805,7 @@ namespace crg return fgph::match( *lhs.data, *rhs.data ); } - bool match( Buffer const & lhs, Buffer const & rhs )noexcept + bool match( BufferViewId const & lhs, BufferViewId const & rhs )noexcept { return lhs == rhs; } @@ -820,6 +818,14 @@ namespace crg : view.data->source[passIndex]; } + BufferViewId const & resolveView( BufferViewId const & view + , uint32_t passIndex ) + { + return view.data->source.empty() + ? view + : view.data->source[passIndex]; + } + ClearColorValue getClearColorValue( ClearValue const & v ) { if ( v.isColor() ) diff --git a/source/RenderGraph/FramePass.cpp b/source/RenderGraph/FramePass.cpp index be182e0..e8431be 100644 --- a/source/RenderGraph/FramePass.cpp +++ b/source/RenderGraph/FramePass.cpp @@ -11,134 +11,11 @@ See LICENSE file in root folder. namespace crg { + inline uint32_t constexpr ImplicitOffset = 1024U; + inline uint32_t constexpr TransferOffset = 4096U; + namespace fpass { - static AttachmentArray splitAttach( Attachment const & attach ) - { - AttachmentArray result; - - if ( attach.view().data->source.empty() ) - { - result.push_back( attach ); - } - else - { - for ( auto & view : attach.view().data->source ) - { - result.emplace_back( view, attach ); - } - } - - return result; - } - - static ImageViewIdArray splitView( ImageViewId const & view ) - { - ImageViewIdArray result; - - if ( view.data->source.empty() ) - { - result.push_back( view ); - } - else - { - for ( auto & subview : view.data->source ) - { - result.push_back( subview ); - } - } - - return result; - } - - template< typename PredT > - static bool matchView( Attachment const & lhs - , ImageViewId const & rhs - , PredT predicate ) - { - auto lhsAttaches = splitAttach( lhs ); - auto rhsViews = splitView( rhs ); - - for ( auto & lhsAttach : lhsAttaches ) - { - for ( auto & rhsView : rhsViews ) - { - if ( predicate( lhsAttach, rhsView ) ) - { - return true; - } - } - } - - return false; - } - - static bool isInOutputs( FramePass const & pass - , ImageViewId const & view ) - { - auto it = std::find_if( pass.images.begin() - , pass.images.end() - , [&view]( Attachment const & lookup ) - { - return matchView( lookup - , view - , []( Attachment const & lhs - , ImageViewId const & rhs ) - { - return lhs.isOutput() && match( lhs.view(), rhs ); - } ); - } ); - - return it != pass.images.end(); - } - - static bool isInInputs( FramePass const & pass - , ImageViewId const & view ) - { - auto it = std::find_if( pass.images.begin() - , pass.images.end() - , [&view]( Attachment const & lookup ) - { - return matchView( lookup - , view - , []( Attachment const & lhs - , ImageViewId const & rhs ) - { - return lhs.isInput() && match( lhs.view(), rhs ); - } ); - } ); - - return it != pass.images.end(); - } - - static bool isInOutputs( FramePass const & pass - , Buffer const & buffer ) - { - auto it = std::find_if( pass.buffers.begin() - , pass.buffers.end() - , [&buffer]( Attachment const & lookup ) - { - return lookup.isStorageBuffer() - && lookup.bufferAttach.buffer == buffer; - } ); - - return it != pass.buffers.end(); - } - - static bool isInInputs( FramePass const & pass - , Buffer const & buffer ) - { - auto it = std::find_if( pass.buffers.begin() - , pass.buffers.end() - , [&buffer]( Attachment const & lookup ) - { - return lookup.isStorageBuffer() - && lookup.bufferAttach.buffer == buffer; - } ); - - return it != pass.buffers.end(); - } - static std::string adjustName( FramePass const & pass , std::string const & dataName ) { @@ -152,88 +29,6 @@ namespace crg return result.substr( index ); } - - static size_t makeHash( FramePass const & pass - , ImageViewId const & view ) - { - if constexpr ( sizeof( size_t ) == sizeof( uint64_t ) ) - { - return size_t( pass.id ) << 32u - | size_t( view.id ); - } - else - { - return size_t( pass.id ) << 16u - | size_t( view.id ); - } - } - - static size_t makeHash( FramePass const & pass - , Buffer const & buffer ) - { - if constexpr ( sizeof( size_t ) == sizeof( uint64_t ) ) - { - return size_t( pass.id ) << 32u - | ( ptrdiff_t( buffer.buffer() ) & 0xFFFFFFFF ); - } - else - { - return size_t( pass.id ) << 16u - | ( ptrdiff_t( buffer.buffer() ) & 0x0000FFFF ); - } - } - - static void mergeViewData( ImageViewId const & view - , bool mergeMipLevels - , bool mergeArrayLayers - , ImageViewData & data ) - { - if ( data.image.id == 0 ) - { - data.image = view.data->image; - data.name = data.image.data->name; - data.info.flags = view.data->info.flags; - data.info.format = view.data->info.format; - data.info.viewType = view.data->info.viewType; - data.info.subresourceRange = view.data->info.subresourceRange; - } - else - { - assert( data.image == view.data->image ); - - if ( mergeMipLevels ) - { - auto maxLevel = std::max( data.info.subresourceRange.levelCount + data.info.subresourceRange.baseMipLevel - , view.data->info.subresourceRange.levelCount + view.data->info.subresourceRange.baseMipLevel ); - data.info.subresourceRange.baseMipLevel = std::min( view.data->info.subresourceRange.baseMipLevel - , data.info.subresourceRange.baseMipLevel ); - data.info.subresourceRange.levelCount = maxLevel - data.info.subresourceRange.baseMipLevel; - } - else - { - data.info.subresourceRange.baseMipLevel = std::min( view.data->info.subresourceRange.baseMipLevel - , data.info.subresourceRange.baseMipLevel ); - data.info.subresourceRange.levelCount = 1u; - } - - if ( mergeArrayLayers ) - { - auto maxLayer = std::max( data.info.subresourceRange.layerCount + data.info.subresourceRange.baseArrayLayer - , view.data->info.subresourceRange.layerCount + view.data->info.subresourceRange.baseArrayLayer ); - data.info.subresourceRange.baseArrayLayer = std::min( view.data->info.subresourceRange.baseArrayLayer - , data.info.subresourceRange.baseArrayLayer ); - data.info.subresourceRange.layerCount = maxLayer - data.info.subresourceRange.baseArrayLayer; - } - else - { - data.info.subresourceRange.baseArrayLayer = std::min( view.data->info.subresourceRange.baseArrayLayer - , data.info.subresourceRange.baseArrayLayer ); - data.info.subresourceRange.layerCount = 1u; - } - } - - data.source.push_back( view ); - } } FramePass::FramePass( FramePassGroup const & pgroup @@ -249,730 +44,657 @@ namespace crg { } - bool FramePass::dependsOn( FramePass const & pass - , ImageViewId const & view - , PassDependencyCache & cache )const - { - auto & passCache = cache.try_emplace( this ).first->second; - auto [rit, res] = passCache.emplace( fpass::makeHash( pass, view ), false ); - - if ( res ) - { - auto it = std::find_if( passDepends.begin() - , passDepends.end() - , [&pass, &view, &cache]( FramePass const * lookup ) - { - bool result = false; - - if ( fpass::isInOutputs( *lookup, view ) ) - { - result = ( pass.id == lookup->id ); - } - else if ( !fpass::isInInputs( *lookup, view ) ) - { - result = lookup->dependsOn( pass, view, cache ); - } - - return result; - } ); - rit->second = it != passDepends.end(); - } - - return rit->second; - } - - bool FramePass::dependsOn( FramePass const & pass - , Buffer const & buffer - , PassDependencyCache & cache )const + Attachment const * FramePass::getParentAttachment( Attachment const & attach )const { - auto & passCache = cache.try_emplace( this ).first->second; - auto [rit, res] = passCache.emplace( fpass::makeHash( pass, buffer ), false ); - - if ( res ) - { - auto it = std::find_if( passDepends.begin() - , passDepends.end() - , [&pass, &buffer, &cache]( FramePass const * lookup ) - { - bool result = false; - - if ( fpass::isInOutputs( *lookup, buffer ) ) - { - result = ( pass.id == lookup->id ); - } - else if ( !fpass::isInInputs( *lookup, buffer ) ) - { - result = lookup->dependsOn( pass, buffer, cache ); - } - - return result; - } ); - rit->second = it != passDepends.end(); - } - - return rit->second; + auto it = m_ownAttaches.find( &attach ); + return it != m_ownAttaches.end() + ? it->second.parent + : nullptr; } - bool FramePass::dependsOn( FramePass const & pass )const - { - auto it = std::find_if( passDepends.begin() - , passDepends.end() - , [&pass]( FramePass const * lookup ) - { - return pass.id == lookup->id; - } ); - return it != passDepends.end(); - } - - void FramePass::addImplicitBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ) + void FramePass::addInputUniformBuffer( BufferViewIdArray buffers + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/ImplB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, buffers.front().data->name ) + "/UB"; + auto attach = addOwnAttach( std::move( buffers ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Transition ) - , std::move( buffer ) - , offset - , range - , std::move( wantedAccess ) } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Uniform ) + , AccessState{} + , nullptr ); + uniforms.try_emplace( binding, attach ); } - void FramePass::addUniformBuffer( Buffer buffer + void FramePass::addInputSampledImage( ImageViewIdArray views , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + , SamplerDesc samplerDesc ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/UB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Spl"; + auto attach = addOwnAttach( std::move( views ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Uniform ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Sampled ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eShaderReadOnly + , nullptr ); + sampled.try_emplace( binding, attach, std::move( samplerDesc ) ); } - void FramePass::addInputStorageBuffer( Buffer buffer - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + void FramePass::addInputUniform( Attachment const & attachment + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/ISB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/UB"; + auto attach = addOwnAttach( attachment.bufferAttach.buffers , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Uniform ) + , AccessState{} + , &attachment ); + uniforms.try_emplace( binding, attach ); } - void FramePass::addOutputStorageBuffer( Buffer buffer + void FramePass::addInputSampled( Attachment const & attachment , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + , SamplerDesc samplerDesc ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/OSB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Output ) - , *this - , binding + auto attachName = fpass::adjustName( *this, attachment.view( 0 ).data->name ) + "/Spl"; + auto attach = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Sampled ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eShaderReadOnly + , &attachment ); + sampled.try_emplace( binding, attach, std::move( samplerDesc ) ); } - void FramePass::addClearableOutputStorageBuffer( Buffer buffer - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + void FramePass::addInputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/OSB"; - buffers.push_back( Attachment{ ( Attachment::FlagKind( Attachment::Flag::Output ) - | Attachment::FlagKind( Attachment::Flag::Clearable ) ) - , *this - , binding + auto attachName = fpass::adjustName( *this, buffers.front().data->name ) + "/SB"; + auto attach = addOwnAttach( std::move( buffers ) , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , AccessState{} + , nullptr ); + inputs.try_emplace( binding, attach ); } - void FramePass::addInOutStorageBuffer( Buffer buffer - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + void FramePass::addInputStorageImage( ImageViewIdArray views + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/IOSB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::InOut ) - , *this - , binding + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IStr"; + auto attach = addOwnAttach( std::move( views ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eGeneral + , nullptr ); + inputs.try_emplace( binding, attach ); } - void FramePass::addImplicitBufferView( Buffer buffer - , VkBufferView view - , DeviceSize offset - , DeviceSize range - , AccessState wantedAccess ) + void FramePass::addInputStorage( Attachment const & attachment + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/ImplBV"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId - , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::TransitionView ) - , std::move( buffer ) - , view - , offset - , range - , std::move( wantedAccess ) } ); + if ( attachment.isImage() ) + { + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IStr"; + auto attach = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eGeneral + , &attachment ); + inputs.try_emplace( binding, attach ); + } + else + { + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/IStr"; + auto attach = addOwnAttach( attachment.bufferAttach.buffers + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) + , AccessState{} + , &attachment ); + inputs.try_emplace( binding, attach ); + } } - void FramePass::addUniformBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + Attachment const * FramePass::addInOutStorage( Attachment const & attachment + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/UBV"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding - , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::UniformView ) - , std::move( buffer ) - , view - , offset - , range - , AccessState{} } ); + Attachment const * result{}; + + if ( attachment.isImage() ) + { + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IOStr"; + result = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::InOut ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eGeneral + , &attachment ); + inouts.try_emplace( binding, result ); + } + else + { + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/IOStr"; + result = addOwnAttach( attachment.bufferAttach.buffers + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::InOut ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) + , AccessState{} + , &attachment ); + inouts.try_emplace( binding, result ); + } + + return result; } - void FramePass::addInputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + Attachment const * FramePass::addOutputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/ISBV"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding + auto attachName = fpass::adjustName( *this, buffers.front().data->name ) + "/OSB"; + auto result = addOwnAttach( std::move( buffers ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::StorageView ) - , std::move( buffer ) - , view - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Output ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) + , AccessState{} + , nullptr ); + outputs.try_emplace( binding, result ); + return result; } - void FramePass::addOutputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + Attachment const * FramePass::addClearableOutputStorageBuffer( BufferViewIdArray buffers + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/OSBV"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Output ) - , *this - , binding + auto attachName = fpass::adjustName( *this, buffers.front().data->name ) + "/OSB"; + auto result = addOwnAttach( std::move( buffers ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::StorageView ) - , std::move( buffer ) - , view - , offset - , range - , AccessState{} } ); + , ( Attachment::FlagKind( Attachment::Flag::Output ) | Attachment::FlagKind( Attachment::Flag::Clearable ) ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Storage ) + , AccessState{} + , nullptr ); + outputs.try_emplace( binding, result ); + return result; } - void FramePass::addClearableOutputStorageBufferView( Buffer buffer - , VkBufferView view - , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + Attachment const * FramePass::addOutputStorageImage( ImageViewIdArray views + , uint32_t binding ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/OSBV"; - buffers.push_back( Attachment{ ( Attachment::FlagKind( Attachment::Flag::Output ) - | Attachment::FlagKind( Attachment::Flag::Clearable ) ) - , *this - , binding + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/OStr"; + auto result = addOwnAttach( std::move( views ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::StorageView ) - , std::move( buffer ) - , view - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Output ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eGeneral + , nullptr ); + outputs.try_emplace( binding, result ); + return result; } - void FramePass::addInOutStorageBufferView( Buffer buffer - , VkBufferView view + Attachment const * FramePass::addClearableOutputStorageImage( ImageViewIdArray views , uint32_t binding - , DeviceSize offset - , DeviceSize range ) + , ClearValue clearValue ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/IOSBV"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::InOut ) - , *this - , binding + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/COStr"; + auto result = addOwnAttach( std::move( views ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::StorageView ) - , std::move( buffer ) - , view - , offset - , range - , AccessState{} } ); + , ( Attachment::FlagKind( Attachment::Flag::Output ) | Attachment::FlagKind( Attachment::Flag::Clearable ) ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , std::move( clearValue ) + , PipelineColorBlendAttachmentState{} + , ImageLayout::eGeneral + , nullptr ); + outputs.try_emplace( binding, result ); + return result; } - void FramePass::addTransferInputBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range ) + void FramePass::addInputTransferBuffer( BufferViewIdArray views ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/ITB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ITrf"; + auto attach = addOwnAttach( std::move( views ) , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , AccessState{} + , nullptr ); + inputs.try_emplace( TransferOffset + uint32_t( inputs.size() ), attach ); } - void FramePass::addTransferOutputBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range ) + void FramePass::addInputTransferImage( ImageViewIdArray views ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/OTB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::Flag::Output ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ITrf"; + auto attach = addOwnAttach( std::move( views ) , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eTransferSrc + , nullptr ); + inputs.try_emplace( TransferOffset + uint32_t( inputs.size() ), attach ); } - void FramePass::addTransferInOutBuffer( Buffer buffer - , DeviceSize offset - , DeviceSize range - , Attachment::Flag flag ) + void FramePass::addInputTransfer( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, buffer.name ) + "/IOTB"; - buffers.push_back( Attachment{ Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) ) - , *this - , InvalidBindingId - , std::move( attachName ) - , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) - , std::move( buffer ) - , offset - , range - , AccessState{} } ); + if ( attachment.isImage() ) + { + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/ITrf"; + auto attach = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eTransferSrc + , & attachment ); + inputs.try_emplace( TransferOffset + uint32_t( inputs.size() ), attach ); + } + else + { + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/ITrf"; + auto attach = addOwnAttach( attachment.bufferAttach.buffers + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) + , AccessState{} + , &attachment ); + inputs.try_emplace( TransferOffset + uint32_t( inputs.size() ), attach ); + } } - ImageViewId FramePass::mergeViews( ImageViewIdArray const & views - , bool mergeMipLevels - , bool mergeArrayLayers ) + Attachment const * FramePass::addInOutTransfer( Attachment const & attachment + , Attachment::Flag flag ) { - ImageViewData data; - for ( auto & view : views ) - fpass::mergeViewData( view, mergeMipLevels, mergeArrayLayers, data ); + Attachment const * result{}; - if ( data.info.subresourceRange.layerCount > 1u ) + if ( attachment.isImage() ) { - switch ( data.info.viewType ) - { - case ImageViewType::e1D: - data.info.viewType = ImageViewType::e1DArray; - break; - case ImageViewType::e2D: - if ( checkFlag( data.image.data->info.flags, ImageCreateFlags::eCubeCompatible ) - && ( data.info.subresourceRange.layerCount % 6u ) == 0u - && data.info.subresourceRange.baseArrayLayer == 0u ) - { - if ( data.info.subresourceRange.layerCount > 6u ) - { - data.info.viewType = ImageViewType::eCubeArray; - } - else - { - data.info.viewType = ImageViewType::eCube; - } - } - else - { - data.info.viewType = ImageViewType::e2DArray; - } - break; - case ImageViewType::eCube: - if ( data.info.subresourceRange.layerCount > 6u ) - { - data.info.viewType = ImageViewType::eCubeArray; - } - break; - default: - break; - } + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IOTrf"; + result = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , ImageLayout::eTransferSrc + , &attachment ); + inouts.try_emplace( TransferOffset + uint32_t( inouts.size() ), result ); + } + else + { + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/IOTrf"; + result = addOwnAttach( attachment.bufferAttach.buffers + , std::move( attachName ) + , Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) + , AccessState{} + , &attachment ); + inouts.try_emplace( TransferOffset + uint32_t( inouts.size() ), result ); } - return graph.createView( data ); + return result; } - void FramePass::addSampledView( ImageViewIdArray views - , uint32_t binding - , SamplerDesc samplerDesc ) + Attachment const * FramePass::addOutputTransferBuffer( BufferViewIdArray buffers ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Spl"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding + auto attachName = fpass::adjustName( *this, buffers.front().data->name ) + "/OTB"; + auto result = addOwnAttach( std::move( buffers ) , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Sampled ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , std::move( samplerDesc ) + , Attachment::FlagKind( Attachment::Flag::Output ) + , BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer ) + , AccessState{} + , nullptr ); + outputs.try_emplace( TransferOffset + uint32_t( outputs.size() ), result ); + return result; + } + + Attachment const * FramePass::addOutputTransferImage( ImageViewIdArray views ) + { + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/OT"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Output ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare , ClearValue{} , PipelineColorBlendAttachmentState{} - , ImageLayout::eShaderReadOnly } ); + , ImageLayout::eTransferDst + , nullptr ); + outputs.try_emplace( TransferOffset + uint32_t( outputs.size() ), result ); + return result; } - void FramePass::addImplicitColourView( ImageViewIdArray views - , ImageLayout wantedLayout ) + void FramePass::addInputColourTargetImage( ImageViewIdArray views ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Impl"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId - , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Transition ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IRcl"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::None ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearColorValue{} } , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + , ImageLayout::eColorAttachment + , nullptr ); + targets.emplace_back( result ); } - void FramePass::addImplicitDepthView( ImageViewIdArray views - , ImageLayout wantedLayout ) + void FramePass::addInputDepthTargetImage( ImageViewIdArray views ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Impl"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId - , std::move( attachName ) - , ( ImageAttachment::FlagKind( ImageAttachment::Flag::Transition ) - | ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IRdp"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + , ImageLayout::eDepthStencilAttachment + , nullptr ); + targets.emplace_back( result ); } - void FramePass::addImplicitDepthStencilView( ImageViewIdArray views - , ImageLayout wantedLayout ) + void FramePass::addInputStencilTargetImage( ImageViewIdArray views ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Impl"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId - , std::move( attachName ) - , ( ImageAttachment::FlagKind( ImageAttachment::Flag::Transition ) - | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IRst"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + , ImageLayout::eDepthStencilAttachment + , nullptr ); + targets.emplace_back( result ); } - void FramePass::addInputStorageView( ImageViewIdArray views - , uint32_t binding ) + void FramePass::addInputDepthStencilTargetImage( ImageViewIdArray views ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IStr"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , binding + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IRds"; + auto result = addOwnAttach( std::move( views ) , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eGeneral } ); + , ImageLayout::eDepthStencilAttachment + , nullptr ); + targets.emplace_back( result ); } - void FramePass::addOutputStorageView( ImageViewIdArray views - , uint32_t binding ) + void FramePass::addInputColourTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/OStr"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Output ) - , *this - , binding + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IRcl"; + auto result = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::None ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearColorValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eGeneral } ); + , ImageLayout::eColorAttachment + , &attachment ); + targets.emplace_back( result ); } - void FramePass::addClearableOutputStorageView( ImageViewIdArray views - , uint32_t binding ) + void FramePass::addInputDepthTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/COStr"; - images.push_back( { ( Attachment::FlagKind( Attachment::Flag::Output ) - | Attachment::FlagKind( Attachment::Flag::Clearable ) ) - , *this - , binding + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IRdp"; + auto attach = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eGeneral } ); + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( attach ); } - void FramePass::addInOutStorageView( ImageViewIdArray views - , uint32_t binding ) + void FramePass::addInputStencilTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IOStr"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::InOut ) - , *this - , binding + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IRst"; + auto attach = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Storage ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eGeneral } ); + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( attach ); } - void FramePass::addTransferInputView( ImageViewIdArray views ) + void FramePass::addInputDepthStencilTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/It"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Input ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IRds"; + auto attach = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eTransferSrc } ); + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( attach ); } - void FramePass::addTransferOutputView( ImageViewIdArray views ) + Attachment const * FramePass::addInOutColourTarget( Attachment const & attachment + , PipelineColorBlendAttachmentState blendState ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/Ot"; - images.push_back( { Attachment::FlagKind( Attachment::Flag::Output ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IORcl"; + auto result = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::InOut ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::None ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearColorValue{} } + , std::move( blendState ) + , ImageLayout::eColorAttachment + , &attachment ); + targets.emplace_back( result ); + return result; + } + + Attachment const * FramePass::addInOutDepthTarget( Attachment const & attachment ) + { + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IORdp"; + auto result = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::InOut ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eTransferDst } ); + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( result ); + return result; } - void FramePass::addTransferInOutView( ImageViewIdArray views - , crg::Attachment::Flag flag ) + Attachment const * FramePass::addInOutStencilTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/IOt"; - images.push_back( { Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) ) - , *this - , InvalidBindingId + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IORst"; + auto result = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer ) - , std::move( views ) - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} - , ClearValue{} + , Attachment::FlagKind( Attachment::Flag::InOut ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore + , ClearValue{ ClearDepthStencilValue{} } , PipelineColorBlendAttachmentState{} - , ImageLayout::eTransferSrc } ); + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( result ); + return result; } - void FramePass::addColourView( std::string const & pname - , crg::Attachment::FlagKind flags - , ImageViewIdArray views - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , ImageLayout wantedLayout - , ClearColorValue clearValue - , PipelineColorBlendAttachmentState blendState ) + Attachment const * FramePass::addInOutDepthStencilTarget( Attachment const & attachment ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/" + pname; - images.push_back( { flags - , *this - , uint32_t{} + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/IORds"; + auto result = addOwnAttach( attachment.imageAttach.views , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::InOut ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore + , AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore + , ClearValue{ ClearDepthStencilValue{} } + , PipelineColorBlendAttachmentState{} + , ImageLayout::eDepthStencilAttachment + , &attachment ); + targets.emplace_back( result ); + return result; + } + + Attachment const * FramePass::addOutputColourTarget( ImageViewIdArray views + , ClearColorValue clearValue ) + { + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ORcl"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Output ) , ImageAttachment::FlagKind( ImageAttachment::Flag::None ) - , std::move( views ) - , loadOp - , storeOp - , AttachmentLoadOp::eDontCare - , AttachmentStoreOp::eDontCare - , SamplerDesc{} + , AttachmentLoadOp::eClear, AttachmentStoreOp::eStore + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare , ClearValue{ std::move( clearValue ) } - , std::move( blendState ) - , wantedLayout } ); + , PipelineColorBlendAttachmentState{} + , ImageLayout::eColorAttachment + , nullptr ); + targets.emplace_back( result ); + return result; } - void FramePass::addDepthView( std::string const & pname - , crg::Attachment::FlagKind flags - , ImageViewIdArray views - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout + Attachment const * FramePass::addOutputDepthTarget( ImageViewIdArray views , ClearDepthStencilValue clearValue ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/" + pname; - images.insert( images.begin() - , { flags - , *this - , uint32_t{} - , std::move( attachName ) - , ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) - , std::move( views ) - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , SamplerDesc{} - , ClearValue{ std::move( clearValue ) } - , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ORdp"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Output ) + , ImageAttachment::FlagKind( ImageAttachment::Flag::Depth ) + , AttachmentLoadOp::eClear, AttachmentStoreOp::eStore + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{ std::move( clearValue ) } + , PipelineColorBlendAttachmentState{} + , ImageLayout::eDepthAttachment + , nullptr ); + targets.emplace( targets.begin(), result ); + return result; } - void FramePass::addStencilView( std::string const & pname - , crg::Attachment::FlagKind flags - , ImageAttachment::FlagKind stencilFlags - , ImageViewIdArray views - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout + Attachment const * FramePass::addOutputStencilTarget( ImageViewIdArray views , ClearDepthStencilValue clearValue ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/" + pname; - images.insert( images.begin() - , { flags - , *this - , uint32_t{} - , std::move( attachName ) - , ImageAttachment::FlagKind( stencilFlags - | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) ) - , std::move( views ) - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , SamplerDesc{} - , ClearValue{ std::move( clearValue ) } - , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ORst"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Output ) + , ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eClear, AttachmentStoreOp::eStore + , ClearValue{ std::move( clearValue ) } + , PipelineColorBlendAttachmentState{} + , ImageLayout::eStencilAttachment + , nullptr ); + targets.emplace( targets.begin(), result ); + return result; } - void FramePass::addDepthStencilView( std::string const & pname - , crg::Attachment::FlagKind flags - , ImageAttachment::FlagKind stencilFlags - , ImageViewIdArray views - , AttachmentLoadOp loadOp - , AttachmentStoreOp storeOp - , AttachmentLoadOp stencilLoadOp - , AttachmentStoreOp stencilStoreOp - , ImageLayout wantedLayout + Attachment const * FramePass::addOutputDepthStencilTarget( ImageViewIdArray views , ClearDepthStencilValue clearValue ) { - auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/" + pname; - images.insert( images.begin() - , { flags - , *this - , uint32_t{} - , std::move( attachName ) - , ImageAttachment::FlagKind( stencilFlags - | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) ) - , std::move( views ) - , loadOp - , storeOp - , stencilLoadOp - , stencilStoreOp - , SamplerDesc{} - , ClearValue{ std::move( clearValue ) } - , PipelineColorBlendAttachmentState{} - , wantedLayout } ); + auto attachName = fpass::adjustName( *this, views.front().data->name ) + "/ORds"; + auto result = addOwnAttach( std::move( views ) + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Output ) + , ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) ) + , AttachmentLoadOp::eClear, AttachmentStoreOp::eStore + , AttachmentLoadOp::eClear, AttachmentStoreOp::eStore + , ClearValue{ std::move( clearValue ) } + , PipelineColorBlendAttachmentState{} + , ImageLayout::eDepthStencilAttachment + , nullptr ); + targets.emplace( targets.begin(), result ); + return result; + } + + void FramePass::addImplicit( Attachment const & attachment + , AccessState wantedAccess ) + { + auto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + "/Impl"; + auto attach = addOwnAttach( attachment.bufferAttach.buffers + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , BufferAttachment::FlagKind( BufferAttachment::FlagKind( BufferAttachment::Flag::Transition ) | attachment.bufferAttach.getFormatFlags() ) + , std::move( wantedAccess ) + , &attachment ); + inputs.try_emplace( ImplicitOffset + uint32_t( inputs.size() ), attach ); + } + + void FramePass::addImplicit( Attachment const & attachment + , ImageLayout wantedLayout ) + { + auto attachName = fpass::adjustName( *this, attachment.view().data->name ) + "/Impl"; + auto attach = addOwnAttach( attachment.imageAttach.views + , std::move( attachName ) + , Attachment::FlagKind( Attachment::Flag::Input ) + , ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::Transition ) | attachment.imageAttach.getFormatFlags() ) + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare + , ClearValue{} + , PipelineColorBlendAttachmentState{} + , wantedLayout + , &attachment ); + inputs.try_emplace( ImplicitOffset + uint32_t( inputs.size() ), attach ); } RunnablePassPtr FramePass::createRunnable( GraphContext & context @@ -990,4 +712,171 @@ namespace crg { return group.getName() + "/" + getName(); } + + Attachment const * FramePass::addOwnAttach( ImageViewIdArray views, std::string attachName + , Attachment::FlagKind flags, ImageAttachment::FlagKind imageFlags + , AttachmentLoadOp loadOp, AttachmentStoreOp storeOp + , AttachmentLoadOp stencilLoadOp, AttachmentStoreOp stencilStoreOp + , ClearValue clearValue, PipelineColorBlendAttachmentState blendState + , ImageLayout wantedLayout + , Attachment const * parent ) + { + if ( views.front().data->source.empty() ) + return addOwnAttach( new Attachment{ flags + , *this, std::move( attachName ) + , imageFlags + , std::move( views ) + , loadOp, storeOp + , stencilLoadOp, stencilStoreOp + , std::move( clearValue ) + , std::move( blendState ) + , wantedLayout + , Attachment::Token{} } + , parent ); + + // Dispatch merged views sources in source attachs views + std::vector< ImageViewIdArray > sourceAttachsViews; + sourceAttachsViews.resize( views.front().data->source.size() ); + for ( auto view : views ) + { + for ( uint32_t i = 0u; i < view.data->source.size(); ++i ) + sourceAttachsViews[i].push_back( view.data->source[i] ); + } + + // Use these views to create attachs + uint32_t index{}; + std::vector< AttachmentPtr > sources; + for ( auto & sourceViews : sourceAttachsViews ) + { + sources.push_back( std::make_unique< Attachment >( flags + , *this, attachName + std::to_string( index ) + , imageFlags + , std::move( sourceViews ) + , loadOp, storeOp + , stencilLoadOp, stencilStoreOp + , clearValue, blendState + , wantedLayout + , Attachment::Token{} ) ); + ++index; + } + + // Create the resulting attach + auto result = addOwnAttach( new Attachment{ flags + , *this, std::move( attachName ) + , imageFlags + , std::move( views ) + , loadOp, storeOp + , stencilLoadOp, stencilStoreOp + , std::move( clearValue ) + , std::move( blendState ) + , wantedLayout + , Attachment::Token{} } + , parent ); + result->pass = nullptr; + + // And set its sources + if ( !parent || parent->source.empty() ) + { + for ( auto & sourceAttach : sources ) + result->source.emplace_back( std::move( sourceAttach ) ); + } + else + { + // If parent has sources, link the new attachment sources to the parent ones + assert( parent->source.size() == sources.size() ); + for ( uint32_t i = 0; i < sources.size(); ++i ) + { + auto source = addOwnAttach( sources[i].release() + , ( parent->source[i].parent + ? parent->source[i].parent + : parent->source[i].attach.get() ) ); + result->source.emplace_back( parent->source[i].attach.get(), source->pass, source->imageAttach ); + } + + result->initSources(); + } + + return result; + } + + Attachment const * FramePass::addOwnAttach( BufferViewIdArray views, std::string attachName + , Attachment::FlagKind flags, BufferAttachment::FlagKind bufferFlags + , AccessState access + , Attachment const * parent ) + { + if ( views.front().data->source.empty() ) + return addOwnAttach( new Attachment{ flags + , *this, std::move( attachName ) + , bufferFlags + , std::move( views ) + , std::move( access ) + , Attachment::Token{} } + , parent ); + + // Dispatch merged views sources in source attachs views + std::vector< BufferViewIdArray > sourceAttachsViews; + sourceAttachsViews.resize( views.front().data->source.size() ); + for ( auto view : views ) + { + for ( uint32_t i = 0u; i < view.data->source.size(); ++i ) + sourceAttachsViews[i].push_back( view.data->source[i] ); + } + + // Use these views to create attachs + uint32_t index{}; + std::vector< AttachmentPtr > sources; + for ( auto & sourceViews : sourceAttachsViews ) + { + sources.push_back( std::make_unique< Attachment >( flags + , *this, attachName + std::to_string( index ) + , bufferFlags + , std::move( sourceViews ) + , access + , Attachment::Token{} ) ); + ++index; + } + + // Create the resulting attach + auto result = addOwnAttach( new Attachment{ flags + , *this, std::move( attachName ) + , bufferFlags + , std::move( views ) + , std::move( access ) + , Attachment::Token{} } + , parent ); + result->pass = nullptr; + + // And set its sources + if ( !parent || parent->source.empty() ) + { + for ( auto & sourceAttach : sources ) + result->source.emplace_back( std::move( sourceAttach ) ); + } + else + { + // If parent has sources, link the new attachment sources to the parent ones + assert( parent->source.size() == sources.size() ); + for ( uint32_t i = 0; i < sources.size(); ++i ) + { + auto source = addOwnAttach( sources[i].release() + , ( parent->source[i].parent + ? parent->source[i].parent + : parent->source[i].attach.get() ) ); + result->source.emplace_back( parent->source[i].attach.get(), source->pass, source->bufferAttach ); + } + + result->initSources(); + } + + return result; + } + + Attachment * FramePass::addOwnAttach( Attachment * mine + , Attachment const * parent ) + { + auto & own = m_ownAttaches.try_emplace( mine ).first->second; + own.mine.reset( mine ); + own.parent = parent; + return mine; + } } diff --git a/source/RenderGraph/FramePassDependenciesBuilder.cpp b/source/RenderGraph/FramePassDependenciesBuilder.cpp deleted file mode 100644 index 4fb7b47..0000000 --- a/source/RenderGraph/FramePassDependenciesBuilder.cpp +++ /dev/null @@ -1,762 +0,0 @@ -/* -This file belongs to FrameGraph. -See LICENSE file in root folder. -*/ -#include "FramePassDependenciesBuilder.hpp" - -#include "RenderGraph/AttachmentTransition.hpp" -#include "RenderGraph/Exception.hpp" -#include "RenderGraph/FramePass.hpp" -#include "RenderGraph/GraphNode.hpp" -#include "RenderGraph/Log.hpp" - -#include -#include -#include -#include - -#define CRG_DebugPassAttaches 0 -#define CRG_DebugPassDependencies 0 - -namespace crg::builder -{ - namespace deps - { - static bool isInRange( uint32_t value - , uint32_t left - , uint32_t count ) - { - return value >= left && value < left + count; - } - - static bool isSingleMipView( ImageViewId const & sub - , ImageViewId const & main ) - { - return main.data->image == sub.data->image - && isInRange( sub.data->info.subresourceRange.baseMipLevel - , main.data->info.subresourceRange.baseMipLevel - , main.data->info.subresourceRange.levelCount ) - && sub.data->info.subresourceRange.levelCount == 1u; - } - - static ImageViewId const & getInputView( ImageViewId const & lhs - , ImageViewId const & rhs ) - { - auto result = &rhs; - - if ( lhs == rhs - || isSingleMipView( lhs, rhs ) ) - { - result = &lhs; - } - - return *result; - } - - static ImageViewId const & getOutputView( ImageViewId const & lhs - , ImageViewId const & rhs ) - { - auto result = &lhs; - - if ( isSingleMipView( lhs, rhs ) ) - { - result = &rhs; - } - - return *result; - } - - template< typename DataT > - struct AttachDataTraitsT; - - template<> - struct AttachDataTraitsT< ImageViewId > - { - static ImageViewId get( Attachment const & attach ) - { - return attach.view(); - } - - static ImageViewId getOutput( Attachment const & lhsAttach - , Attachment const & rhsAttach ) - { - return getOutputView( lhsAttach.view(), rhsAttach.view() ); - } - - static ImageViewId getInput( Attachment const & lhsAttach - , Attachment const & inputAttach ) - { - return getInputView( lhsAttach.view(), inputAttach.view() ); - } - - static DataTransitionArrayT< ImageViewId > & getTransitions( AttachmentTransitions & transitions ) - { - return transitions.viewTransitions; - } - - static AttachmentArray split( Attachment const & attach ) - { - AttachmentArray result; - - if ( attach.view().data->source.empty() ) - { - result.push_back( attach ); - } - else - { - for ( auto & view : attach.view().data->source ) - { - result.emplace_back( view, attach ); - } - } - - return result; - } - - static bool isInput( Attachment const & attach ) - { - return attach.isInput(); - } - - static bool isOutput( Attachment const & attach ) - { - return attach.isOutput(); - } - }; - - template<> - struct AttachDataTraitsT< Buffer > - { - static Buffer get( Attachment const & attach ) - { - return attach.bufferAttach.buffer; - } - - static Buffer getOutput( Attachment const & lhsAttach - , Attachment const & ) - { - return lhsAttach.bufferAttach.buffer; - } - - static Buffer getInput( Attachment const & lhsAttach - , Attachment const & ) - { - return lhsAttach.bufferAttach.buffer; - } - - static DataTransitionArrayT< Buffer > & getTransitions( AttachmentTransitions & transitions ) - { - return transitions.bufferTransitions; - } - - static AttachmentArray split( Attachment const & attach ) - { - return { attach }; - } - - static bool isInput( Attachment const & attach ) - { - return attach.isInput() - && ( attach.isStorageBuffer() || attach.isUniformBuffer() || attach.isTransitionBuffer() - || attach.isStorageBufferView() || attach.isUniformBufferView() || attach.isTransitionBufferView() ); - } - - static bool isOutput( Attachment const & attach ) - { - return attach.isOutput() - && ( attach.isStorageBuffer() || attach.isStorageBufferView() ); - } - }; - - template< typename DataT > - static DataT const & getAttachOutputData( Attachment const & inputAttach - , Attachment const & outputAttach ) - { - return AttachDataTraitsT< DataT >::getOutput( inputAttach, outputAttach ); - } - - template< typename DataT > - static DataT const & getAttachInputData( Attachment const & inputAttach - , Attachment const & outputAttach ) - { - return AttachDataTraitsT< DataT >::getInput( inputAttach, outputAttach ); - } - - template< typename DataT > - struct AttachesT - { - DataT data; - std::vector< Attachment > attaches{}; - }; - - template< typename DataT > - using AttachesArrayT = std::vector< AttachesT< DataT > >; - - using ViewAttaches = AttachesT< ImageViewId >; - using BufferAttaches = AttachesT< Buffer >; - - using ViewAttachesArray = AttachesArrayT< ImageViewId >; - using BufferAttachesArray = AttachesArrayT< Buffer >; - -#if CRG_DebugPassAttaches - static std::string const & getAttachDataName( ImageViewId const & data ) - { - return data.data->name; - } - - static std::string const & getAttachDataName( Buffer const & data ) - { - return data.name; - } - - template< typename DataT > - static std::ostream & operator<<( std::ostream & stream, AttachesT< DataT > const & attach ) - { - stream << getAttachDataName( attach.data ); - std::string sep{ " -> " }; - - for ( auto & attach : attach.attaches ) - { - stream << sep << attach.name; - sep = ", "; - } - - return stream; - } - - template< typename DataT > - static std::ostream & operator<<( std::ostream & stream, AttachesArrayT< DataT > const & attaches ) - { - for ( auto & attach : attaches ) - { - stream << attach << std::endl; - } - - return stream; - } - - template< typename DataT > - static std::ostream & operator<<( std::ostream & stream, DataTransitionT< DataT > const & transition ) - { - stream << ( transition.outputAttach.pass ? transition.outputAttach.pass->name : std::string{ "External" } ) - << " -> " - << ( transition.inputAttach.pass ? transition.inputAttach.pass->name : std::string{ "External" } ); - std::string sep = " on ["; - stream << sep << getAttachDataName( transition.data ); - stream << "]"; - return stream; - } -#endif -#if CRG_DebugPassDependencies - static std::ostream & operator<<( std::ostream & stream, FramePassDependencies const & dependencies ) - { - for ( auto & depsIt : dependencies ) - { - stream << depsIt.pass->name << std::endl; - - for ( auto & transition : depsIt.transitions.viewTransitions ) - { - stream << " " << transition << std::endl; - } - - for ( auto & transition : depsIt.transitions.bufferTransitions ) - { - stream << " " << transition << std::endl; - } - } - - return stream; - } -#endif - - static void printDebug( [[maybe_unused]] ViewAttachesArray const & inputs - , [[maybe_unused]] ViewAttachesArray const & outputs ) - { -#if CRG_DebugPassAttaches - Logger::logDebug( "Inputs" ) - Logger::logDebug( inputs ) - Logger::logDebug( "Outputs" ) - Logger::logDebug( outputs ) -#endif - } - - static void printDebug( [[maybe_unused]] BufferAttachesArray const & inputs - , [[maybe_unused]] BufferAttachesArray const & outputs ) - { -#if CRG_DebugPassAttaches - Logger::logDebug( "Inputs" ); - Logger::logDebug( inputs ); - Logger::logDebug( "Outputs" ); - Logger::logDebug( outputs ); -#endif - } - - static void printDebug( [[maybe_unused]] FramePassDependencies const & inputTransitions - , [[maybe_unused]] FramePassDependencies const & outputTransitions ) - { -#if CRG_DebugPassDependencies - Logger::logDebug( "Input Transitions" ) - Logger::logDebug( inputTransitions ) - Logger::logDebug( "Output Transitions" ) - Logger::logDebug( outputTransitions ) -#endif - } - - static bool areIntersecting( uint32_t lhsLBound - , uint32_t lhsCount - , uint32_t rhsLBound - , uint32_t rhsCount ) - { - return isInRange( lhsLBound, rhsLBound, rhsCount ) - || isInRange( rhsLBound, lhsLBound, lhsCount ); - } - - static bool areIntersecting( ImageSubresourceRange const & lhs - , ImageSubresourceRange const & rhs ) - { - return areIntersecting( lhs.baseMipLevel - , lhs.levelCount - , rhs.baseMipLevel - , rhs.levelCount ) - && areIntersecting( lhs.baseArrayLayer - , lhs.layerCount - , rhs.baseArrayLayer - , lhs.layerCount ); - } - - static bool areOverlapping( ImageViewData const & lhs - , ImageViewData const & rhs ) - { - return lhs.image == rhs.image - && areIntersecting( getVirtualRange( lhs.image, lhs.info.viewType, lhs.info.subresourceRange ) - , getVirtualRange( rhs.image, rhs.info.viewType, rhs.info.subresourceRange ) ); - } - - static bool areOverlapping( ImageViewId const & lhs - , ImageViewId const & rhs ) - { - return areOverlapping( *lhs.data, *rhs.data ); - } - - static bool areOverlapping( Buffer const & lhs - , Buffer const & rhs ) - { - return lhs.buffer() == rhs.buffer(); - } - - template< typename DataT > - static bool areOverlapping( Attachment const & lhs - , Attachment const & rhs ) - { - return areOverlapping( AttachDataTraitsT< DataT >::get( lhs ) - , AttachDataTraitsT< DataT >::get( rhs ) ); - } - - template< typename DataT > - static void insertAttach( Attachment const & attach - , AttachesArrayT< DataT > & cont ) - { - auto it = std::find_if( cont.begin(), cont.end() - , [&attach]( AttachesT< DataT > const & lookup ) - { - return lookup.data == AttachDataTraitsT< DataT >::get( attach ); - } ); - - if ( cont.end() == it ) - { - cont.push_back( AttachesT< DataT >{ AttachDataTraitsT< DataT >::get( attach ) } ); - it = std::prev( cont.end() ); - } - - if ( auto attachesIt = std::find( it->attaches.begin(), it->attaches.end(), attach ); - attachesIt == it->attaches.end() ) - { - it->attaches.push_back( attach ); - } - } - - template< typename DataT > - static void processAttachSource( AttachesT< DataT > & lookup - , Attachment const & attach - , DataT const & attachView - , DataT const & sourceView - , std::function< bool( DataT const &, DataT const & ) > processAttach ) - { - if ( processAttach( sourceView, attachView ) - && lookup.attaches.end() == std::find( lookup.attaches.begin(), lookup.attaches.end(), attach ) ) - { - lookup.attaches.push_back( attach ); - } - } - - template< typename DataT > - static void processAttach( Attachment const & attach - , AttachesArrayT< DataT > & cont - , AttachesArrayT< DataT > & all - , std::function< bool( DataT const &, DataT const & ) > processAttach ) - { - FramePassArray passes; - auto attaches = AttachDataTraitsT< DataT >::split( attach ); - - for ( auto & splitAttach : attaches ) - { - for ( auto & lookup : cont ) - { - processAttachSource( lookup - , splitAttach - , lookup.data - , AttachDataTraitsT< DataT >::get( splitAttach ) - , processAttach ); - } - - insertAttach( splitAttach, cont ); - insertAttach( splitAttach, all ); - } - } - - template< typename DataT > - static void processInputAttachs( AttachmentArray const & attachs - , AttachesArrayT< DataT > & cont - , AttachesArrayT< DataT > & all ) - { - for ( auto & attach : attachs ) - { - if ( AttachDataTraitsT< DataT >::isInput( attach ) ) - { - processAttach< DataT >( attach - , cont - , all - , []( DataT const & lookupView - , DataT const & attachView ) - { - return areOverlapping( lookupView, attachView ); - } ); - } - } - } - - template< typename DataT > - static void processOutputAttachs( AttachmentArray const & attachs - , AttachesArrayT< DataT > & cont - , AttachesArrayT< DataT > & all ) - { - for ( auto & attach : attachs ) - { - if ( AttachDataTraitsT< DataT >::isOutput( attach ) ) - { - processAttach< DataT >( attach - , cont - , all - , []( DataT const & lookupView - , DataT const & attachView ) - { - return areOverlapping( lookupView, attachView ); - } ); - } - } - } - - template< typename DataT > - static bool hasTransition( DataTransitionArrayT< DataT > const & transitions - , DataTransitionT< DataT > const & transition ) - { - return transitions.end() != std::find( transitions.begin(), transitions.end(), transition ); - } - - static FramePassTransitions & insertPass( FramePass const * pass - , FramePassDependencies & transitions ) - { - auto passIt = std::find_if( transitions.begin() - , transitions.end() - , [pass]( FramePassTransitions const & lookup ) - { - return lookup.pass == pass; - } ); - - if ( passIt == transitions.end() ) - { - transitions.push_back( FramePassTransitions{ pass, {} } ); - return transitions.back(); - } - - return *passIt; - } - - template< typename DataT > - static bool dependsOn( DataTransitionT< DataT > const & transition - , DataTransitionT< DataT > const & - , PassDependencyCache & cache ) - { - return transition.inputAttach.pass - && transition.outputAttach.pass - && transition.inputAttach.pass->dependsOn( *transition.outputAttach.pass - , transition.data - , cache ); - } - - template< typename DataT > - static void insertTransition( DataTransitionT< DataT > const & transition - , PassDependencyCache & cache - , DataTransitionArrayT< DataT > & transitions ) - { - if ( !hasTransition( transitions, transition ) ) - { - if ( auto it = std::find_if( transitions.begin(), transitions.end() - , [&transition, &cache]( DataTransitionT< DataT > const & lookup ) - { - return dependsOn( lookup, transition, cache ); - } ); - it != transitions.end() ) - { - transitions.insert( it, transition ); - } - else - { - if ( auto rit = std::find_if( transitions.rbegin(), transitions.rend() - , [&transition, &cache]( DataTransitionT< DataT > const & lookup ) - { - return dependsOn( transition, lookup, cache ); - } ); - rit != transitions.rend() ) - { - transitions.insert( rit.base(), transition ); - } - else - { - transitions.push_back( transition ); - } - } - } - } - - static void addRemainingDependency( Attachment const & attach - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , ViewTransitionArray & allTransitions ) - { - auto & transitions = insertPass( attach.pass, inputTransitions ).transitions; - - if ( attach.isColourInputAttach() - || attach.isSampledView() ) - { - ViewTransition transition{ attach.view(), Attachment::createDefault( attach.view() ), attach }; - insertTransition( transition, cache, transitions.viewTransitions ); - } - else - { - ViewTransition transition{ attach.view(), attach, Attachment::createDefault( attach.view() ) }; - insertTransition( transition, cache, transitions.viewTransitions ); - } - - insertTransition( transitions.viewTransitions.back(), cache, allTransitions ); - } - - static void addRemainingDependency( Attachment const & attach - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , BufferTransitionArray & allTransitions ) - { - auto & transitions = insertPass( attach.pass, inputTransitions ).transitions; - - if ( attach.isInput() ) - { - BufferTransition transition{ attach.bufferAttach.buffer, Attachment::createDefault( attach.bufferAttach.buffer ), attach }; - insertTransition( transition, cache, transitions.bufferTransitions ); - } - else - { - BufferTransition transition{ attach.bufferAttach.buffer, attach, Attachment::createDefault( attach.bufferAttach.buffer ) }; - insertTransition( transition, cache, transitions.bufferTransitions ); - } - - insertTransition( transitions.bufferTransitions.back(), cache, allTransitions ); - } - - static void addRemainingDependency( Attachment const & attach - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , AttachmentTransitions & allTransitions ) - { - if ( attach.isImage() ) - { - addRemainingDependency( attach - , cache - , inputTransitions - , allTransitions.viewTransitions ); - } - else - { - addRemainingDependency( attach - , cache - , inputTransitions - , allTransitions.bufferTransitions ); - } - } - - template< typename DataT > - static void addDependency( Attachment const & outputAttach - , Attachment const & inputAttach - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ) - { - DataTransitionT< DataT > inputTransition{ AttachDataTraitsT< DataT >::getInput( outputAttach, inputAttach ) - , outputAttach - , inputAttach }; - DataTransitionT< DataT > outputTransition{ AttachDataTraitsT< DataT >::getOutput( outputAttach, inputAttach ) - , outputAttach - , inputAttach }; - insertTransition( inputTransition, cache, AttachDataTraitsT< DataT >::getTransitions( allTransitions ) ); - - if ( !match( AttachDataTraitsT< DataT >::get( outputAttach ) - , AttachDataTraitsT< DataT >::get( inputAttach ) ) ) - { - insertTransition( outputTransition, cache, AttachDataTraitsT< DataT >::getTransitions( allTransitions ) ); - } - - auto & inTransitions = insertPass( inputAttach.pass, inputTransitions ).transitions; - insertTransition( inputTransition, cache, AttachDataTraitsT< DataT >::getTransitions( inTransitions ) ); - auto & outTransitions = insertPass( outputAttach.pass, outputTransitions ).transitions; - insertTransition( outputTransition, cache, AttachDataTraitsT< DataT >::getTransitions( outTransitions ) ); - } - - template< typename DataT > - static void buildPassDependency( Attachment const & inputAttach - , Attachment const & outputAttach - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ) - { - if ( inputAttach.pass->dependsOn( *outputAttach.pass - , AttachDataTraitsT< DataT >::getOutput( inputAttach, outputAttach ) - , cache ) ) - { - addDependency< DataT >( outputAttach - , inputAttach - , cache - , inputTransitions - , outputTransitions - , allTransitions ); - } - } - - template< typename DataT > - static void buildPassDependencies( AttachesT< DataT > const & input - , AttachesT< DataT > const & output - , AttachesArrayT< DataT > & all - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ) - { - if ( areOverlapping( input.data, output.data ) ) - { - for ( Attachment const & outputAttach : output.attaches ) - { - for ( Attachment const & inputAttach : input.attaches ) - { - buildPassDependency< DataT >( inputAttach - , outputAttach - , cache - , inputTransitions - , outputTransitions - , allTransitions ); - } - } - -// Disabled because GitHub Actions weirdly cries on this -#pragma warning( push ) -#pragma warning( disable:5233 ) - auto it = std::find_if( all.begin(), all.end() - , [&input]( AttachesT< DataT > const & lookup ) - { - return lookup.data == input.data; - } ); -#pragma warning( pop ) - - if ( all.end() != it ) - { - all.erase( it ); - } - } - } - - template< typename DataT > - static void buildPassDependencies( AttachesArrayT< DataT > const & inputs - , AttachesArrayT< DataT > const & outputs - , AttachesArrayT< DataT > & all - , PassDependencyCache & cache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ) - { - for ( AttachesT< DataT > const & output : outputs ) - { - for ( AttachesT< DataT > const & input : inputs ) - { - buildPassDependencies( input, output, all, cache, inputTransitions, outputTransitions, allTransitions ); - } - } - - // `all` should now only contain sampled/input/output from/to nothing attaches. - for ( auto & remaining : all ) - { - for ( auto & attach : remaining.attaches ) - { - addRemainingDependency( attach - , cache - , inputTransitions - , allTransitions ); - } - } - - printDebug( inputs, outputs ); - } - } - - void buildPassAttachDependencies( GraphNodePtrArray const & nodes - , PassDependencyCache & imgDepsCache - , PassDependencyCache & bufDepsCache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ) - { - deps::ViewAttachesArray imgInputs; - deps::ViewAttachesArray imgOutputs; - deps::ViewAttachesArray imgAll; - deps::BufferAttachesArray bufInputs; - deps::BufferAttachesArray bufOutputs; - deps::BufferAttachesArray bufAll; - - for ( auto & node : nodes ) - { - auto pass = getFramePass( *node ); - assert( pass ); - deps::processInputAttachs( pass->images, imgInputs, imgAll ); - deps::processOutputAttachs( pass->images, imgOutputs, imgAll ); - deps::processInputAttachs( pass->buffers, bufInputs, bufAll ); - deps::processOutputAttachs( pass->buffers, bufOutputs, bufAll ); - deps::insertPass( pass, inputTransitions ); - deps::insertPass( pass, outputTransitions ); - } - - deps::buildPassDependencies( imgInputs - , imgOutputs - , imgAll - , imgDepsCache - , inputTransitions - , outputTransitions - , allTransitions ); - deps::buildPassDependencies( bufInputs - , bufOutputs - , bufAll - , bufDepsCache - , inputTransitions - , outputTransitions - , allTransitions ); - deps::printDebug( inputTransitions - , outputTransitions ); - } -} diff --git a/source/RenderGraph/FramePassDependenciesBuilder.hpp b/source/RenderGraph/FramePassDependenciesBuilder.hpp deleted file mode 100644 index 965985d..0000000 --- a/source/RenderGraph/FramePassDependenciesBuilder.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/* -This file belongs to FrameGraph. -See LICENSE file in root folder. -*/ -#pragma once - -#include "BuilderCommon.hpp" - -namespace crg::builder -{ - void buildPassAttachDependencies( GraphNodePtrArray const & nodes - , PassDependencyCache & imgDepsCache - , PassDependencyCache & bufDepsCache - , FramePassDependencies & inputTransitions - , FramePassDependencies & outputTransitions - , AttachmentTransitions & allTransitions ); -} diff --git a/source/RenderGraph/FramePassGroup.cpp b/source/RenderGraph/FramePassGroup.cpp index a1110c7..5375edd 100644 --- a/source/RenderGraph/FramePassGroup.cpp +++ b/source/RenderGraph/FramePassGroup.cpp @@ -47,7 +47,8 @@ namespace crg FramePassGroup::FramePassGroup( FrameGraph & graph , uint32_t pid - , std::string const & name ) + , std::string const & name + , Token ) : id{ pid } , m_name{ name } , m_graph{ graph } @@ -56,7 +57,8 @@ namespace crg FramePassGroup::FramePassGroup( FramePassGroup & pparent , uint32_t pid - , std::string const & name ) + , std::string const & name + , Token ) : id{ pid } , parent{ &pparent } , m_name{ name } @@ -94,7 +96,7 @@ namespace crg if ( it == groups.end() ) { auto count = group::countGroups( group::getOutermost( this ) ); - groups.emplace_back( new FramePassGroup{ *this, count + 1u, groupName } ); + groups.emplace_back( std::make_unique< FramePassGroup >( *this, count + 1u, groupName, Token{} ) ); it = std::next( groups.begin(), ptrdiff_t( groups.size() - 1u ) ); } @@ -140,6 +142,16 @@ namespace crg return m_graph.getFinalLayoutState( view, passIndex ); } + BufferId FramePassGroup::createBuffer( BufferData const & img )const + { + return m_graph.createBuffer( img ); + } + + BufferViewId FramePassGroup::createView( BufferViewData const & view )const + { + return m_graph.createView( view ); + } + ImageId FramePassGroup::createImage( ImageData const & img )const { return m_graph.createImage( img ); @@ -196,4 +208,27 @@ namespace crg ? m_graph.getName() : parent->getFullName() + "/" + getName(); } + + ImageViewId FramePassGroup::mergeViews( ImageViewIdArray const & views + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + return m_graph.mergeViews( views + , mergeMipLevels + , mergeArrayLayers ); + } + + BufferViewId FramePassGroup::mergeViews( BufferViewIdArray const & views ) + { + return m_graph.mergeViews( views ); + } + + Attachment const * FramePassGroup::mergeAttachments( AttachmentArray const & attachments + , bool mergeMipLevels + , bool mergeArrayLayers ) + { + return m_graph.mergeAttachments( attachments + , mergeMipLevels + , mergeArrayLayers ); + } } diff --git a/source/RenderGraph/GraphBuilder.cpp b/source/RenderGraph/GraphBuilder.cpp index 7df79d8..ed6a08d 100644 --- a/source/RenderGraph/GraphBuilder.cpp +++ b/source/RenderGraph/GraphBuilder.cpp @@ -6,79 +6,648 @@ See LICENSE file in root folder. #include "RenderGraph/FramePass.hpp" #include "RenderGraph/GraphNode.hpp" +#include "RenderGraph/Log.hpp" #include namespace crg::builder { - namespace graph + //********************************************************************************************* + + namespace endpoints { - static GraphAdjacentNode findNode( FramePass const * pass - , GraphNodePtrArray const & nodes ) + static void addAttach( Attachment const & attach + , AttachmentArray & result ) { - if ( !pass ) + if ( attach.source.empty() ) + result.push_back( &attach ); + for ( auto & source : attach.source ) + result.push_back( source.attach.get() ); + } + + static void listAllAttachs( FramePassArray const & passes + , AttachmentArray & result ) + { + for ( auto pass : passes ) { - return nullptr; + for ( auto & [binding, attach] : pass->inouts ) + addAttach( *attach, result ); + for ( auto & [binding, attach] : pass->outputs ) + addAttach( *attach, result ); + for ( auto & attach : pass->targets ) + if ( attach->isOutput() ) + addAttach( *attach, result ); } + } + + static void listBuffersRec( Attachment const & attach + , FramePass const * pass + , BufferViewIdArray & result ) + { + if ( attach.source.empty() && ( !pass || attach.pass == pass ) ) + for ( auto & view : attach.bufferAttach.buffers ) + result.push_back( view ); + + for ( auto const & source : attach.source ) + listBuffersRec( *source.attach, pass, result ); + } + + static BufferViewIdArray listBuffers( Attachment const & attach + , FramePass const * pass ) + { + BufferViewIdArray result; + listBuffersRec( attach, pass, result ); + return result; + } + + static void listImagesRec( Attachment const & attach + , FramePass const * pass + , ImageViewIdArray & result ) + { + if ( attach.source.empty() && ( !pass || attach.pass == pass ) ) + for ( auto & view : attach.imageAttach.views ) + result.push_back( view ); - GraphAdjacentNode result{}; - auto it = std::find_if( nodes.begin(), nodes.end() - , [pass]( auto & lookup ) + for ( auto const & source : attach.source ) + listImagesRec( *source.attach, pass, result ); + } + + static ImageViewIdArray listImages( Attachment const & attach + , FramePass const * pass ) + { + ImageViewIdArray result; + listImagesRec( attach, pass, result ); + return result; + } + + static bool isBufferAttachParent( Attachment const & parent, Attachment const & attach ) + { + auto parentBuffers = listBuffers( parent, attach.pass ); + auto attachBuffers = listBuffers( attach, nullptr ); + return std::any_of( attachBuffers.begin(), attachBuffers.end() + , [&parentBuffers]( BufferViewId const & lookup ) { - return getFramePass( *lookup ) == pass; + return parentBuffers.end() != std::find( parentBuffers.begin(), parentBuffers.end(), lookup ); } ); + } - assert( it != nodes.end() ); - result = it->get(); - return result; + static bool isImageAttachParent( Attachment const & parent, Attachment const & attach ) + { + auto parentBuffers = listImages( parent, attach.pass ); + auto attachBuffers = listImages( attach, nullptr ); + return std::any_of( attachBuffers.begin(), attachBuffers.end() + , [&parentBuffers]( ImageViewId const & lookup ) + { + return parentBuffers.end() != std::find( parentBuffers.begin(), parentBuffers.end(), lookup ); + } ); } - static AttachmentTransitions makeTransition( ViewTransition const & transition ) + static bool isAttachParent( Attachment const * parent, Attachment const * attach ) { - return { { transition }, {} }; + if ( bool result = ( parent == attach ); + result || !parent ) + return result; + + if ( attach->isBuffer() != parent->isBuffer() ) + return false; + + if ( attach->isBuffer() ) + return isBufferAttachParent( *parent, *attach ); + + return isImageAttachParent( *parent, *attach ); } - static AttachmentTransitions makeTransition( BufferTransition const & transition ) + static bool isParentAttachForPass( Attachment const * attach, FramePass const * pass ) { - return { {}, { transition } }; + return pass->end() != std::find_if( pass->begin(), pass->end() + , [&attach]( auto const & lookup ) + { + return isAttachParent( lookup.second.parent, attach ); + } ); + } + + static void listNonParentAttachs( FramePassArray const & passes + , AttachmentArray const & allAttachs + , AttachmentArray & result ) + { + for ( auto attach : allAttachs ) + { + if ( std::none_of( passes.begin(), passes.end() + , [&attach]( FramePass const * pass ) + { + return attach->pass != pass + && isParentAttachForPass( attach, pass ); + } ) ) + { + addAttach( *attach, result ); + } + } } - template< typename DataT > - static void buildGraph( DataTransitionArrayT< DataT > const & transitions - , GraphNodePtrArray const & nodes - , PassDependencyCache & depsCache ) + static bool hasOutput( FramePass const & pass ) { - for ( DataTransitionT< DataT > const & transition : transitions ) + auto result = ( !pass.outputs.empty() || !pass.inouts.empty() ); + + if ( !result ) { - GraphAdjacentNode outputAdjNode = findNode( transition.outputAttach.pass, nodes ); - GraphAdjacentNode inputAdjNode = findNode( transition.inputAttach.pass, nodes ); + for ( auto & attach : pass.targets ) + result = result || attach->isOutput(); + } - if ( inputAdjNode - && outputAdjNode - && transition.inputAttach.pass->dependsOn( *transition.outputAttach.pass, transition.data, depsCache ) ) + return result; + } + + static void addPassInputs( FramePass const & pass + , AttachmentArray & result ) + { + for ( auto & [_, attach] : pass.inputs ) + addAttach( *attach, result ); + for ( auto & [_, attach] : pass.uniforms ) + addAttach( *attach, result ); + for ( auto & [_, attach] : pass.sampled ) + result.push_back( attach.attach ); + for ( auto & attach : pass.targets ) + if ( attach->isInput() ) + addAttach( *attach, result ); + } + + static void addSinkPassInputs( FramePassArray const & passes + , AttachmentArray & result ) + { + for ( auto & pass : passes ) + if ( !hasOutput( *pass ) ) { - outputAdjNode->attachNode( inputAdjNode - , makeTransition( transition ) ); + addPassInputs( *pass, result ); } + } + + static AttachmentArray listPassOutputs( FramePass const & pass ) + { + AttachmentArray result; + for ( auto & [_, attach] : pass.outputs ) + addAttach( *attach, result ); + for ( auto & [_, attach] : pass.inouts ) + addAttach( *attach, result ); + for ( auto & attach : pass.targets ) + if ( attach->isOutput() ) + addAttach( *attach, result ); + return result; + } + + static bool areAllPassAttachsListed( FramePass const & pass + , AttachmentArray const & result ) + { + auto passOutputs = listPassOutputs( pass ); + return std::all_of( passOutputs.begin(), passOutputs.end() + , [&result]( Attachment const * lookup ) + { + + return result.end() != std::find( result.begin(), result.end(), lookup ); + } ); + } + + static void removeMismatchs( AttachmentArray & result ) + { + auto it = result.begin(); + + while ( it != result.end() ) + { + if ( !areAllPassAttachsListed( *( *it )->pass, result ) ) + it = result.erase( it ); + else + ++it; } } } - void buildGraph( RootNode & rootNode - , GraphNodePtrArray const & nodes - , PassDependencyCache & imgDepsCache - , PassDependencyCache & bufDepsCache - , AttachmentTransitions const & transitions ) + //********************************************************************************************* + + namespace graph { - graph::buildGraph( transitions.viewTransitions, nodes, imgDepsCache ); - graph::buildGraph( transitions.bufferTransitions, nodes, bufDepsCache ); + struct AttachmentStates + { + bool separateDepthStencilLayouts; + std::vector< ImageLayout > imageStates{}; + std::vector< AccessFlags > bufferStates{}; + }; + + static FramePassArray listAttachmentPasses( Attachment const & attach ) + { + if ( attach.pass ) + return { attach.pass }; + + FramePassArray result; + for ( auto const & source : attach.source ) + result.push_back( source.pass ); + return result; + } + + static AttachmentArray splitImage( Attachment const & attach ) + { + assert( attach.view().data->source.empty() ); + return { &attach }; + } + + static AttachmentArray splitBuffer( Attachment const & attach ) + { + assert( attach.buffer().data->source.empty() ); + return { &attach }; + } - for ( auto & node : nodes ) + static AttachmentArray splitAttach( Attachment const & attach ) { - if ( !node->hasPrev() ) + if ( !attach.source.empty() ) { - rootNode.attachNode( node.get(), {} ); + AttachmentArray result; + for ( auto & source : attach.source ) + { + AttachmentArray splitSource = splitAttach( *source.attach ); + result.insert( result.end(), splitSource.begin(), splitSource.end() ); + } + return result; } + + if ( attach.isImage() ) + return splitImage( attach ); + return splitBuffer( attach ); + } + + template< typename UIntT > + static bool isInRange( UIntT value + , UIntT offset, UIntT count ) + { + return value >= offset && value < offset + count; + } + + template< typename UIntT > + static bool areIntersecting( UIntT lhsOffset, UIntT lhsCount + , UIntT rhsOffset, UIntT rhsCount ) + { + return isInRange( lhsOffset, rhsOffset, rhsCount ) + || isInRange( rhsOffset, lhsOffset, lhsCount ); + } + + static bool areIntersecting( ImageSubresourceRange const & lhs + , ImageSubresourceRange const & rhs ) + { + return areIntersecting( lhs.baseMipLevel, lhs.levelCount, rhs.baseMipLevel, rhs.levelCount ) + && areIntersecting( lhs.baseArrayLayer, lhs.layerCount, rhs.baseArrayLayer, lhs.layerCount ); + } + + static bool areIntersecting( BufferSubresourceRange const & lhs + , BufferSubresourceRange const & rhs ) + { + return areIntersecting( lhs.offset, lhs.size + , rhs.offset, rhs.size ); + } + + static bool areOverlapping( ImageViewData const & lhs + , ImageViewData const & rhs ) + { + return lhs.image == rhs.image + && areIntersecting( getVirtualRange( lhs.image, lhs.info.viewType, lhs.info.subresourceRange ) + , getVirtualRange( rhs.image, rhs.info.viewType, rhs.info.subresourceRange ) ); + } + + static bool areOverlapping( BufferViewData const & lhs + , BufferViewData const & rhs ) + { + return lhs.buffer == rhs.buffer + && areIntersecting( lhs.info.subresourceRange + , rhs.info.subresourceRange ); + } + + static bool areOverlapping( Attachment const & lhs + , Attachment const & rhs ) + { + if ( lhs.isImage() ) + return areOverlapping( *lhs.view().data, *rhs.view().data ); + return areOverlapping( *lhs.buffer().data, *rhs.buffer().data ); + } + + void traverseAttachmentPasses( GraphNode & parent + , Attachment const * currentAttach + , Attachment const * parentAttach + , AttachmentTransitions & transitions + , GraphNodePtrArray & nodes ); + + static void traversePassAttach( FramePassNode & node, std::map< uint32_t, Attachment const * > const & attachments + , AttachmentTransitions & transitions + , GraphNodePtrArray & nodes ) + { + for ( auto [binding, attach] : attachments ) + traverseAttachmentPasses( node + , node.getFramePass().getParentAttachment( *attach ), attach + , transitions, nodes ); + } + + static void traversePassAttach( FramePassNode & node, std::map< uint32_t, FramePass::SampledAttachment > const & attachments + , AttachmentTransitions & transitions + , GraphNodePtrArray & nodes ) + { + for ( auto const & [binding, attach] : attachments ) + traverseAttachmentPasses( node + , node.getFramePass().getParentAttachment( *attach.attach ), attach.attach + , transitions, nodes ); + } + + static void traversePassAttach( FramePassNode & node, AttachmentArray const & targets, Attachment::Flag flag + , AttachmentTransitions & transitions + , GraphNodePtrArray & nodes ) + { + for ( auto attach : targets ) + { + if ( attach->hasFlag( flag ) ) + traverseAttachmentPasses( node + , node.getFramePass().getParentAttachment( *attach ), attach + , transitions, nodes ); + } + } + + static void insertTransition( bool isImage + , Attachment const * output + , Attachment const * input + , AttachmentTransitions & transitions ) + { + if ( isImage ) + { + if ( output && input ) + transitions.imageTransitions.emplace_back( output->view(), *output, *input ); + else if ( output ) + transitions.imageTransitions.emplace_back( output->view(), *output, Attachment::createDefault( output->view() ) ); + else if ( input ) + transitions.imageTransitions.emplace_back( input->view(), Attachment::createDefault( input->view() ), *input ); + } + else + { + if ( output && input ) + transitions.bufferTransitions.emplace_back( output->buffer(), *output, *input ); + else if ( output ) + transitions.bufferTransitions.emplace_back( output->buffer(), *output, Attachment::createDefault( output->buffer() ) ); + else if ( input ) + transitions.bufferTransitions.emplace_back( input->buffer(), Attachment::createDefault( input->buffer() ), *input ); + } + } + + void traverseAttachmentPasses( GraphNode & parent + , Attachment const * outputAttach + , Attachment const * inputAttach + , AttachmentTransitions & parentTransitions + , GraphNodePtrArray & nodes ) + { + if ( outputAttach ) + { + for ( auto pass : listAttachmentPasses( *outputAttach ) ) + { + auto it = std::find_if( nodes.begin(), nodes.end() + , [&pass]( GraphNodePtr const & lookup ) + { + return lookup->getName() == pass->getGroupName(); + } ); + if ( nodes.end() == it ) + { + auto & node = static_cast< FramePassNode & >( *nodes.emplace_back( std::make_unique< FramePassNode >( *pass ) ) ); + AttachmentTransitions transitions; + traversePassAttach( node, pass->targets, Attachment::Flag::InOut, transitions, nodes ); + traversePassAttach( node, pass->inouts, transitions, nodes ); + traversePassAttach( node, pass->uniforms, transitions, nodes ); + traversePassAttach( node, pass->sampled, transitions, nodes ); + traversePassAttach( node, pass->inputs, transitions, nodes ); + traversePassAttach( node, pass->targets, Attachment::Flag::Input, transitions, nodes ); + node.setTransitions( mergeIdenticalTransitions( std::move( transitions ) ) ); + parent.attachNode( node ); + } + else + { + parent.attachNode( **it ); + } + } + } + + if ( outputAttach && inputAttach ) + { + auto outputs = splitAttach( *outputAttach ); + auto inputs = splitAttach( *inputAttach ); + for ( auto output : outputs ) + { + for ( auto input : inputs ) + { + if ( areOverlapping( *output, *input ) ) + insertTransition( output->isImage(), output, input, parentTransitions ); + } + } + } + else if ( outputAttach ) + { + // Attach to external + auto outputs = splitAttach( *outputAttach ); + for ( auto output : outputs ) + insertTransition( output->isImage(), output, nullptr, parentTransitions ); + } + else if ( inputAttach ) + { + // External resource + auto inputs = splitAttach( *inputAttach ); + for ( auto input : inputs ) + insertTransition( input->isImage(), nullptr, input, parentTransitions ); + } + } + + static bool hasInPredecessors( GraphNode & parent, GraphNode & child ) + { + return parent.getPredecessors().end() != std::find( parent.getPredecessors().begin() + , parent.getPredecessors().end() + , &child ); + } + + static void removeShortcuts( GraphNode & node ) + { + GraphAdjacentNodeArray & predecessors = node.getPredecessors(); + auto it = predecessors.begin(); + + while ( it != predecessors.end() ) + { + auto curr = *it; + bool found = false; + auto oit = predecessors.begin(); + while ( oit != predecessors.end() && !found ) + { + if ( oit != it ) + found = hasInPredecessors( **oit, *curr ); + ++oit; + } + + removeShortcuts( *curr ); + if ( found ) + it = predecessors.erase( it ); + else + ++it; + } + } + + static void sortNodes( GraphNode & node + , GraphNodePtrArray & sourceGraph + , GraphNodePtrArray & targetGraph ) + { + for ( auto & pred : node.getPredecessors() ) + sortNodes( *pred, sourceGraph, targetGraph ); + + auto it = std::find_if( sourceGraph.begin(), sourceGraph.end() + , [&node]( GraphNodePtr const & lookup ) + { + return &node == lookup.get(); + } ); + if ( sourceGraph.end() != it ) + { + targetGraph.emplace_back( std::move( *it ) ); + sourceGraph.erase( it ); + } + } + + static void sortNodes( RootNode & root + , GraphNodePtrArray & graph ) + { + auto sourceGraph = std::move( graph ); + graph.clear(); + for ( auto & pred : root.getPredecessors() ) + sortNodes( *pred, sourceGraph, graph ); + } + + static void updateState( Attachment const & inputAttach + , std::vector< ImageLayout > & states + , bool separateDepthStencilLayouts ) + { + auto id = inputAttach.view().id; + while ( states.size() <= id ) + states.resize( std::max< size_t >( 1u, states.size() * 2u ) ); + states[id] = inputAttach.getImageLayout( separateDepthStencilLayouts ); + } + + static void updateState( Attachment const & inputAttach + , std::vector< AccessFlags > & states ) + { + auto id = inputAttach.buffer().id; + while ( states.size() <= id ) + states.resize( std::max< size_t >( 1u, states.size() * 2u ) ); + states[id] = inputAttach.getAccessMask(); + } + + static void insertNeededTransition( Attachment const & output + , Attachment const & input + , AttachmentTransitions & transitions + , graph::AttachmentStates & states ) + { + if ( output.isImage() ) + { + transitions.imageTransitions.emplace_back( output.view(), output, input ); + updateState( input, states.imageStates, states.separateDepthStencilLayouts ); + } + else + { + transitions.bufferTransitions.emplace_back( output.buffer(), output, input ); + updateState( input, states.bufferStates ); + } + } + + static bool isInNeededState( Attachment const & inputAttach + , std::vector< ImageLayout > const & states + , bool separateDepthStencilLayouts ) + { + auto id = inputAttach.view().id; + if ( states.size() <= id ) + return false; + + auto & state = states[id]; + return state == inputAttach.getImageLayout( separateDepthStencilLayouts ); + } + + static bool isInNeededState( Attachment const & inputAttach + , std::vector< AccessFlags > const & states ) + { + auto id = inputAttach.buffer().id; + if ( states.size() <= id ) + return false; + + auto & state = states[id]; + return state == inputAttach.getAccessMask(); + } + + static bool isInNeededState( Attachment const & inputAttach + , AttachmentStates const & states ) + { + if ( inputAttach.isImage() ) + return isInNeededState( inputAttach, states.imageStates, states.separateDepthStencilLayouts ); + return isInNeededState( inputAttach, states.bufferStates ); + } + + static void buildTransitions( GraphNodePtrArray const & graph + , graph::AttachmentStates & states ) + { + for ( auto & node : graph ) + { + if ( node->getKind() == GraphNode::Kind::FramePass ) + { + AttachmentTransitions transitions; + for ( auto & transition : node->getImageTransitions() ) + { + if ( !isInNeededState( transition.inputAttach, states ) ) + insertNeededTransition( transition.outputAttach, transition.inputAttach, transitions, states ); + } + for ( auto & transition : node->getBufferTransitions() ) + { + if ( !isInNeededState( transition.inputAttach, states ) ) + insertNeededTransition( transition.outputAttach, transition.inputAttach, transitions, states ); + } + node->setTransitions( std::move( transitions ) ); + } + } + AttachmentTransitions transitions; } } + + //********************************************************************************************* + + AttachmentArray findEndPoints( FramePassArray const & passes ) + { + // List all attaches + AttachmentArray allAttachs; + endpoints::listAllAttachs( passes, allAttachs ); + + // Filter out the attaches that are used as parent to pass attaches + AttachmentArray result; + endpoints::listNonParentAttachs( passes, allAttachs, result ); + + // Also look for passes without outputs, and add their inputs + endpoints::addSinkPassInputs( passes, result ); + + // Remove attachs for which the pass has other output attachs which are not in the list + endpoints::removeMismatchs( result ); + + return result; + } + + //********************************************************************************************* + + void buildGraph( AttachmentArray const & endPoints + , RootNode & root + , GraphNodePtrArray & graph + , bool separateDepthStencilLayouts ) + { + // First generate the graph with all transitions and links. + AttachmentTransitions transitions; + for ( auto endPoint : endPoints ) + graph::traverseAttachmentPasses( root, endPoint, nullptr, transitions, graph ); + + // Then remove the shortcuts (if pass C depends on A and B, if B depends on A, then remove link between A and C) + graph::removeShortcuts( root ); + + // Now sort the graph nodes regarding their position in the final graph. + graph::sortNodes( root, graph ); + + // Eventually parse the sorted nodes to generate a curated transitions list per node. + graph::AttachmentStates states{ separateDepthStencilLayouts }; + graph::buildTransitions( graph, states ); + } + + //********************************************************************************************* } diff --git a/source/RenderGraph/GraphBuilder.hpp b/source/RenderGraph/GraphBuilder.hpp index 5503671..25a4e1a 100644 --- a/source/RenderGraph/GraphBuilder.hpp +++ b/source/RenderGraph/GraphBuilder.hpp @@ -6,9 +6,9 @@ See LICENSE file in root folder. namespace crg::builder { - void buildGraph( RootNode & rootNode - , GraphNodePtrArray const & passes - , PassDependencyCache & imgDepsCache - , PassDependencyCache & bufDepsCache - , AttachmentTransitions const & transitions ); + AttachmentArray findEndPoints( FramePassArray const & passes ); + void buildGraph( AttachmentArray const & endPoints + , RootNode & root + , GraphNodePtrArray & graph + , bool separateDepthStencilLayouts ); } diff --git a/source/RenderGraph/GraphContext.cpp b/source/RenderGraph/GraphContext.cpp index 2845402..251d11a 100644 --- a/source/RenderGraph/GraphContext.cpp +++ b/source/RenderGraph/GraphContext.cpp @@ -55,6 +55,8 @@ namespace crg DECL_vkFunction( FreeDescriptorSets ); DECL_vkFunction( CreateBuffer ); DECL_vkFunction( DestroyBuffer ); + DECL_vkFunction( CreateBufferView ); + DECL_vkFunction( DestroyBufferView ); DECL_vkFunction( GetBufferMemoryRequirements ); DECL_vkFunction( GetImageMemoryRequirements ); DECL_vkFunction( AllocateMemory ); diff --git a/source/RenderGraph/GraphNode.cpp b/source/RenderGraph/GraphNode.cpp index 5c2ceaa..dfda7e6 100644 --- a/source/RenderGraph/GraphNode.cpp +++ b/source/RenderGraph/GraphNode.cpp @@ -17,7 +17,7 @@ namespace crg , id{ rhs.id } , name{ std::move( rhs.name ) } , group{ rhs.group } - , next{ std::move( rhs.next ) } + , prev{ std::move( rhs.prev ) } { rhs.kind = Kind::Undefined; rhs.id = 0u; @@ -34,63 +34,10 @@ namespace crg { } - void GraphNode::addAttaches( ConstGraphAdjacentNode prev - , AttachmentTransitions inAttaches ) + void GraphNode::attachNode( GraphNode & child ) { - bool dirty = false; - auto * mine = &this->inputAttaches[prev]; - - for ( auto & attach : inAttaches.viewTransitions ) - { - auto it = std::find( mine->viewTransitions.begin() - , mine->viewTransitions.end() - , attach ); - - if ( it == mine->viewTransitions.end() ) - { - mine->viewTransitions.push_back( std::move( attach ) ); - dirty = true; - } - } - - for ( auto & attach : inAttaches.bufferTransitions ) - { - auto it = std::find( mine->bufferTransitions.begin() - , mine->bufferTransitions.end() - , attach ); - - if ( it == mine->bufferTransitions.end() ) - { - mine->bufferTransitions.push_back( std::move( attach ) ); - dirty = true; - } - } - - if ( dirty ) - { - *mine = mergeIdenticalTransitions( std::move( *mine ) ); - } - } - - void GraphNode::attachNode( GraphAdjacentNode nextNode - , AttachmentTransitions nextInputAttaches ) - { - if ( auto it = std::find( next.begin() - , next.end() - , nextNode ); it == next.end() ) - { - this->next.push_back( nextNode ); - } - - nextNode->addAttaches( this - , std::move( nextInputAttaches ) ); - } - - AttachmentTransitions const & GraphNode::getInputAttaches( ConstGraphAdjacentNode const pred )const - { - auto it = inputAttaches.find( pred ); - assert( it != inputAttaches.end() ); - return it->second; + if ( prev.end() == std::find( prev.begin(), prev.end(), &child ) ) + prev.push_back( &child ); } //********************************************************************************************* diff --git a/source/RenderGraph/Log.cpp b/source/RenderGraph/Log.cpp index 381edcc..acf569a 100644 --- a/source/RenderGraph/Log.cpp +++ b/source/RenderGraph/Log.cpp @@ -62,27 +62,42 @@ namespace crg void Logger::setTraceCallback( LogCallback callback ) { - doGetInstance().m_trace = std::move( callback ); + if ( callback ) + doGetInstance().m_trace = std::move( callback ); + else + doGetInstance().m_trace = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); }; } void Logger::setDebugCallback( LogCallback callback ) { - doGetInstance().m_debug = std::move( callback ); + if ( callback ) + doGetInstance().m_debug = std::move( callback ); + else + doGetInstance().m_debug = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); }; } void Logger::setInfoCallback( LogCallback callback ) { - doGetInstance().m_info = std::move( callback ); + if ( callback ) + doGetInstance().m_info = std::move( callback ); + else + doGetInstance().m_info = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); }; } void Logger::setWarningCallback( LogCallback callback ) { - doGetInstance().m_warning = std::move( callback ); + if ( callback ) + doGetInstance().m_warning = std::move( callback ); + else + doGetInstance().m_warning = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); }; } void Logger::setErrorCallback( LogCallback callback ) { - doGetInstance().m_error = std::move( callback ); + if ( callback ) + doGetInstance().m_error = std::move( callback ); + else + doGetInstance().m_error = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stderr ); }; } Logger & Logger::doGetInstance()noexcept diff --git a/source/RenderGraph/RecordContext.cpp b/source/RenderGraph/RecordContext.cpp index 902cd50..f645093 100644 --- a/source/RenderGraph/RecordContext.cpp +++ b/source/RenderGraph/RecordContext.cpp @@ -25,11 +25,18 @@ namespace crg namespace recctx { static ImageSubresourceRange adaptRange( GraphContext const & context + , ImageType type , PixelFormat format , ImageSubresourceRange const & subresourceRange ) { ImageSubresourceRange result = subresourceRange; + if ( type == ImageType::e3D ) + { + result.baseArrayLayer = 0; + result.layerCount = 1; + } + if ( !context.separateDepthStencilLayouts && isDepthStencilFormat( format ) && ( checkFlag( result.aspectMask, ImageAspectFlags::eDepth ) @@ -38,44 +45,6 @@ namespace crg return result; } - - static void clearAttachment( RecordContext & recContext - , VkCommandBuffer commandBuffer - , ImageViewId dstView - , ClearColorValue const & clearValue - , ImageLayout finalLayout ) - { - auto & resources = recContext.getResources(); - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); - auto subresourceRange = convert( getSubresourceRange( dstView ) ); - assert( isColourFormat( getFormat( dstView ) ) ); - auto vkClearValue = convert( clearValue ); - resources->vkCmdClearColorImage( commandBuffer - , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , &vkClearValue, 1u, &subresourceRange ); - - if ( finalLayout != ImageLayout::eUndefined ) - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); - } - - static void clearAttachment( RecordContext & recContext - , VkCommandBuffer commandBuffer - , ImageViewId dstView - , ClearDepthStencilValue const & clearValue - , ImageLayout finalLayout ) - { - auto & resources = recContext.getResources(); - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); - auto subresourceRange = convert( getSubresourceRange( dstView ) ); - assert( isDepthOrStencilFormat( getFormat( dstView ) ) ); - auto vkClearValue = convert( clearValue ); - resources->vkCmdClearDepthStencilImage( commandBuffer - , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , &vkClearValue, 1u, &subresourceRange ); - - if ( finalLayout != ImageLayout::eUndefined ) - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); - } } //************************************************************************************************ @@ -165,33 +134,45 @@ namespace crg } void RecordContext::registerImplicitTransition( RunnablePass const & pass - , ImageViewId view - , RecordContext::ImplicitAction action ) + , ImageViewId view + , RecordContext::ImplicitAction action ) { registerImplicitTransition( { &pass, view, std::move( action ) } ); } - void RecordContext::registerImplicitTransition( ImplicitTransition transition ) + void RecordContext::registerImplicitTransition( RunnablePass const & pass + , BufferViewId view + , RecordContext::ImplicitAction action ) { - m_implicitTransitions.emplace_back( std::move( transition ) ); + registerImplicitTransition( { &pass, view, std::move( action ) } ); + } + + void RecordContext::registerImplicitTransition( ImplicitImageTransition transition ) + { + m_implicitImageTransitions.emplace_back( std::move( transition ) ); + } + + void RecordContext::registerImplicitTransition( ImplicitBufferTransition transition ) + { + m_implicitBufferTransitions.emplace_back( std::move( transition ) ); } void RecordContext::runImplicitTransition( VkCommandBuffer commandBuffer , uint32_t index , ImageViewId view ) { - auto it = std::find_if( m_implicitTransitions.begin() - , m_implicitTransitions.end() - , [&view]( ImplicitTransition const & lookup ) + auto it = std::find_if( m_implicitImageTransitions.begin() + , m_implicitImageTransitions.end() + , [&view]( ImplicitImageTransition const & lookup ) { return lookup.view == view; } ); - if ( it != m_implicitTransitions.end() ) + if ( it != m_implicitImageTransitions.end() ) { auto pass = it->pass; auto action = it->action; - m_implicitTransitions.erase( it ); + m_implicitImageTransitions.erase( it ); if ( !pass->isEnabled() ) { @@ -200,17 +181,52 @@ namespace crg } } - void RecordContext::setAccessState( VkBuffer buffer + void RecordContext::runImplicitTransition( VkCommandBuffer commandBuffer + , uint32_t index + , BufferViewId view ) + { + auto it = std::find_if( m_implicitBufferTransitions.begin() + , m_implicitBufferTransitions.end() + , [&view]( ImplicitBufferTransition const & lookup ) + { + return lookup.view == view; + } ); + + if ( it != m_implicitBufferTransitions.end() ) + { + auto pass = it->pass; + auto action = it->action; + m_implicitBufferTransitions.erase( it ); + + if ( !pass->isEnabled() ) + { + action( *this, commandBuffer, index ); + } + } + } + + void RecordContext::setAccessState( BufferViewId buffer + , AccessState const & accessState ) + { + return setAccessState( buffer.data->buffer, getSubresourceRange( buffer ), accessState ); + } + + AccessState RecordContext::getAccessState( BufferViewId buffer )const + { + return getAccessState( buffer.data->buffer, getSubresourceRange( buffer ) ); + } + + void RecordContext::setAccessState( BufferId buffer , [[maybe_unused]] BufferSubresourceRange const & subresourceRange - , AccessState const & layoutState ) + , AccessState const & accessState ) { - m_buffers.insert_or_assign( buffer, layoutState ); + m_buffers.insert_or_assign( buffer.id, accessState ); } - AccessState const & RecordContext::getAccessState( VkBuffer buffer + AccessState const & RecordContext::getAccessState( BufferId buffer , [[maybe_unused]] BufferSubresourceRange const & subresourceRange )const { - if ( auto bufferIt = m_buffers.find( buffer ); bufferIt != m_buffers.end() ) + if ( auto bufferIt = m_buffers.find( buffer.id ); bufferIt != m_buffers.end() ) { return bufferIt->second; } @@ -228,7 +244,7 @@ namespace crg memoryBarrier( commandBuffer , view.data->image , view.data->info.viewType - , view.data->info.subresourceRange + , getSubresourceRange( view ) , initialLayout , wantedState , force ); @@ -259,6 +275,7 @@ namespace crg , bool force ) { auto range = recctx::adaptRange( *m_resources + , image.data->info.imageType , image.data->info.format , subresourceRange ); auto from = getLayoutState( image @@ -311,7 +328,7 @@ namespace crg memoryBarrier( commandBuffer , view.data->image , view.data->info.viewType - , view.data->info.subresourceRange + , getSubresourceRange( view ) , wantedState , force ); } @@ -347,26 +364,23 @@ namespace crg } void RecordContext::memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer - , BufferSubresourceRange const & subresourceRange + , BufferViewId view , AccessState const & initialState , AccessState const & wantedState , bool force ) { memoryBarrier( commandBuffer - , buffer - , subresourceRange - , initialState.access - , initialState.pipelineStage + , view.data->buffer + , getSubresourceRange( view ) + , initialState , wantedState , force ); } void RecordContext::memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer + , BufferId buffer , BufferSubresourceRange const & subresourceRange - , AccessFlags initialMask - , PipelineStageFlags initialStage + , AccessState const & initialState , AccessState const & wantedState , bool force ) { @@ -375,21 +389,21 @@ namespace crg if ( checkFlag( from.pipelineStage, PipelineStageFlags::eBottomOfPipe ) ) { - from = { initialMask, initialStage }; + from = initialState; } if ( force || ( from.access != wantedState.access || from.pipelineStage != wantedState.pipelineStage ) ) { - auto const & resources = getResources(); + auto & resources = getResources(); VkBufferMemoryBarrier barrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER , nullptr , getAccessFlags( from.access ) , getAccessFlags( wantedState.access ) , VK_QUEUE_FAMILY_IGNORED , VK_QUEUE_FAMILY_IGNORED - , buffer + , resources.createBuffer( buffer ) , subresourceRange.offset , subresourceRange.size }; resources->vkCmdPipelineBarrier( commandBuffer @@ -409,7 +423,7 @@ namespace crg } void RecordContext::memoryBarrier( VkCommandBuffer commandBuffer - , VkBuffer buffer + , BufferId buffer , BufferSubresourceRange const & subresourceRange , AccessState const & wantedState , bool force ) @@ -417,8 +431,19 @@ namespace crg memoryBarrier( commandBuffer , buffer , subresourceRange - , AccessFlags::eNone - , PipelineStageFlags::eBottomOfPipe + , { AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe } + , wantedState + , force ); + } + + void RecordContext::memoryBarrier( VkCommandBuffer commandBuffer + , BufferViewId view + , AccessState const & wantedState + , bool force ) + { + memoryBarrier( commandBuffer + , view.data->buffer + , getSubresourceRange( view ) , wantedState , force ); } @@ -439,6 +464,132 @@ namespace crg return *m_resources; } + void RecordContext::copyImage( VkCommandBuffer commandBuffer + , uint32_t index + , ImageViewId srcView + , ImageViewId dstView + , Extent2D const & extent + , ImageLayout finalLayout ) + { + runImplicitTransition( commandBuffer, index, srcView ); + auto & srcSubresource = getSubresourceRange( srcView ); + auto & dstSubresource = getSubresourceRange( dstView ); + VkImageCopy region{ getSubresourceLayer( srcSubresource ), VkOffset3D{ 0u, 0u, 0u } + , getSubresourceLayer( dstSubresource ), VkOffset3D{ 0u, 0u, 0u } + , { extent.width, extent.height, 1u } }; + memoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) ); + memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); + auto & resources = getResources(); + resources->vkCmdCopyImage( commandBuffer + , resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , 1u, ®ion ); + + if ( finalLayout != ImageLayout::eUndefined ) + memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + } + + void RecordContext::blitImage( VkCommandBuffer commandBuffer + , uint32_t index + , ImageViewId srcView + , ImageViewId dstView + , Rect2D const & srcRect + , Rect2D const & dstRect + , FilterMode filter + , ImageLayout finalLayout ) + { + runImplicitTransition( commandBuffer, index, srcView ); + auto & srcSubresource = getSubresourceRange( srcView ); + auto & dstSubresource = getSubresourceRange( dstView ); + memoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) ); + memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); + auto & resources = getResources(); + VkImageBlit region{ getSubresourceLayer( srcSubresource ), { VkOffset3D{ srcRect.offset.x, srcRect.offset.y, 0u }, VkOffset3D{ int32_t( srcRect.extent.width ), int32_t( srcRect.extent.height ), 1 } } + , getSubresourceLayer( dstSubresource ), { VkOffset3D{ dstRect.offset.x, dstRect.offset.y, 0u }, VkOffset3D{ int32_t( dstRect.extent.width ), int32_t( dstRect.extent.height ), 1 } } }; + resources->vkCmdBlitImage( commandBuffer + , resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , 1u, ®ion, convert( filter ) ); + + if ( finalLayout != ImageLayout::eUndefined ) + memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + } + + void RecordContext::clearAttachment( VkCommandBuffer commandBuffer + , ImageViewId dstView + , ClearColorValue const & clearValue + , ImageLayout finalLayout ) + { + auto & resources = getResources(); + memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); + auto subresourceRange = convert( getSubresourceRange( dstView ) ); + assert( isColourFormat( getFormat( dstView ) ) ); + auto vkClearValue = convert( clearValue ); + resources->vkCmdClearColorImage( commandBuffer + , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , &vkClearValue, 1u, &subresourceRange ); + + if ( finalLayout != ImageLayout::eUndefined ) + memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + } + + void RecordContext::clearAttachment( VkCommandBuffer commandBuffer + , ImageViewId dstView + , ClearDepthStencilValue const & clearValue + , ImageLayout finalLayout ) + { + auto & resources = getResources(); + memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); + auto subresourceRange = convert( getSubresourceRange( dstView ) ); + assert( isDepthOrStencilFormat( getFormat( dstView ) ) ); + auto vkClearValue = convert( clearValue ); + resources->vkCmdClearDepthStencilImage( commandBuffer + , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , &vkClearValue, 1u, &subresourceRange ); + + if ( finalLayout != ImageLayout::eUndefined ) + memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + } + + void RecordContext::copyBuffer( VkCommandBuffer commandBuffer + , uint32_t index + , BufferViewId srcView + , BufferViewId dstView + , DeviceSize srcOffset, DeviceSize dstOffset + , DeviceSize size + , AccessState const & finalState ) + { + runImplicitTransition( commandBuffer, index, srcView ); + memoryBarrier( commandBuffer, srcView, { AccessFlags::eTransferRead, PipelineStageFlags::eTransfer } ); + memoryBarrier( commandBuffer, dstView, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } ); + auto & resources = getResources(); + VkBufferCopy region{ srcOffset, dstOffset, size }; + resources->vkCmdCopyBuffer( commandBuffer + , resources.createBuffer( srcView.data->buffer ) + , resources.createBuffer( dstView.data->buffer ) + , 1u, ®ion ); + + if ( finalState != AccessState{} ) + memoryBarrier( commandBuffer, dstView, finalState ); + } + + void RecordContext::clearBuffer( VkCommandBuffer commandBuffer + , BufferViewId dstView + , uint32_t clearValue + , AccessState const & finalState ) + { + auto & resources = getResources(); + memoryBarrier( commandBuffer, dstView, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } ); + auto subresourceRange = getSubresourceRange( dstView ); + resources->vkCmdFillBuffer( commandBuffer + , resources.createBuffer( dstView.data->buffer ) + , subresourceRange.offset, subresourceRange.size + , clearValue ); + + if ( finalState != AccessState{} ) + memoryBarrier( commandBuffer, dstView, finalState ); + } + RecordContext::ImplicitAction RecordContext::copyImage( ImageViewId srcView , ImageViewId dstView , Extent2D const & extent @@ -448,22 +599,7 @@ namespace crg , VkCommandBuffer commandBuffer , uint32_t index ) { - recContext.runImplicitTransition( commandBuffer, index, srcView ); - auto & srcSubresource = srcView.data->info.subresourceRange; - auto & dstSubresource = dstView.data->info.subresourceRange; - VkImageCopy region{ getSubresourceLayer( srcSubresource ), VkOffset3D{ 0u, 0u, 0u } - , getSubresourceLayer( dstSubresource ), VkOffset3D{ 0u, 0u, 0u } - , { extent.width, extent.height, 1u } }; - recContext.memoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) ); - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); - auto & resources = recContext.getResources(); - resources->vkCmdCopyImage( commandBuffer - , resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL - , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , 1u, ®ion ); - - if ( finalLayout != ImageLayout::eUndefined ) - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + recContext.copyImage( commandBuffer, index, srcView, dstView, extent, finalLayout ); }; } @@ -478,36 +614,22 @@ namespace crg , VkCommandBuffer commandBuffer , uint32_t index ) { - recContext.runImplicitTransition( commandBuffer, index, srcView ); - auto & srcSubresource = srcView.data->info.subresourceRange; - auto & dstSubresource = dstView.data->info.subresourceRange; - VkImageBlit region{ getSubresourceLayer( srcSubresource ), { VkOffset3D{ srcRect.offset.x, srcRect.offset.y, 0u }, VkOffset3D{ int32_t( srcRect.extent.width ), int32_t( srcRect.extent.height ), 1 } } - , getSubresourceLayer( dstSubresource ), { VkOffset3D{ dstRect.offset.x, dstRect.offset.y, 0u }, VkOffset3D{ int32_t( dstRect.extent.width ), int32_t( dstRect.extent.height ), 1 } } }; - recContext.memoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) ); - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) ); - auto & resources = recContext.getResources(); - resources->vkCmdBlitImage( commandBuffer - , resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL - , resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , 1u, ®ion, convert( filter ) ); - - if ( finalLayout != ImageLayout::eUndefined ) - recContext.memoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) ); + recContext.blitImage( commandBuffer, index, srcView, dstView, srcRect, dstRect, filter, finalLayout ); }; } RecordContext::ImplicitAction RecordContext::clearAttachment( Attachment const & attach , ImageLayout finalLayout ) { - return [attach, finalLayout]( RecordContext & recContext + return [&attach, finalLayout]( RecordContext & recContext , VkCommandBuffer commandBuffer , uint32_t index ) { auto dstView = attach.view( index ); if ( isColourFormat( getFormat( dstView ) ) ) - recctx::clearAttachment( recContext, commandBuffer, dstView, getClearColorValue( attach.getClearValue() ), finalLayout ); + recContext.clearAttachment( commandBuffer, dstView, getClearColorValue( attach.getClearValue() ), finalLayout ); else - recctx::clearAttachment( recContext, commandBuffer, dstView, getClearDepthStencilValue( attach.getClearValue() ), finalLayout ); + recContext.clearAttachment( commandBuffer, dstView, getClearDepthStencilValue( attach.getClearValue() ), finalLayout ); }; } @@ -519,7 +641,7 @@ namespace crg , VkCommandBuffer commandBuffer , [[maybe_unused]] uint32_t index ) { - recctx::clearAttachment( recContext, commandBuffer, dstView, clearValue, finalLayout ); + recContext.clearAttachment( commandBuffer, dstView, clearValue, finalLayout ); }; } @@ -531,7 +653,39 @@ namespace crg , VkCommandBuffer commandBuffer , [[maybe_unused]] uint32_t index ) { - recctx::clearAttachment( recContext, commandBuffer, dstView, clearValue, finalLayout ); + recContext.clearAttachment( commandBuffer, dstView, clearValue, finalLayout ); + }; + } + + RecordContext::ImplicitAction RecordContext::clearBuffer( BufferViewId dstView + , AccessState const & finalState ) + { + return clearBuffer( dstView, 0u, finalState ); + } + + RecordContext::ImplicitAction RecordContext::clearBuffer( BufferViewId dstView + , uint32_t clearValue + , AccessState const & finalState ) + { + return [clearValue, dstView, finalState]( RecordContext & recContext + , VkCommandBuffer commandBuffer + , [[maybe_unused]] uint32_t index ) + { + recContext.clearBuffer( commandBuffer, dstView, clearValue, finalState ); + }; + } + + RecordContext::ImplicitAction RecordContext::copyBuffer( BufferViewId srcView + , BufferViewId dstView + , DeviceSize srcOffset, DeviceSize dstOffset + , DeviceSize size + , AccessState const & finalState ) + { + return [srcOffset, dstOffset, size, srcView, dstView, finalState]( RecordContext & recContext + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + recContext.copyBuffer( commandBuffer, index, srcView, dstView, srcOffset, dstOffset, size, finalState ); }; } diff --git a/source/RenderGraph/ResourceHandler.cpp b/source/RenderGraph/ResourceHandler.cpp index 136a6eb..96d0fec 100644 --- a/source/RenderGraph/ResourceHandler.cpp +++ b/source/RenderGraph/ResourceHandler.cpp @@ -5,6 +5,9 @@ See LICENSE file in root folder. #include "RenderGraph/Attachment.hpp" #include "RenderGraph/GraphContext.hpp" +#include "RenderGraph/BufferData.hpp" +#include "RenderGraph/BufferViewData.hpp" +#include "RenderGraph/Hash.hpp" #include "RenderGraph/ImageData.hpp" #include "RenderGraph/ImageViewData.hpp" #include "RenderGraph/Log.hpp" @@ -35,44 +38,30 @@ namespace crg }; }; - static VkImageCreateInfo convert( ImageData const & data ) + static VkBufferCreateInfo convert( BufferData const & data ) { return convert( data.info ); } - static VkImageViewCreateInfo convert( ImageViewData const & data - , VkImage const & image ) + static VkBufferViewCreateInfo convert( BufferViewData const & data + , VkBuffer buffer ) { auto result = convert( data.info ); - result.image = image; + result.buffer = buffer; return result; } - template< typename T > - static size_t hashCombine( size_t hash - , T const & rhs ) + static VkImageCreateInfo convert( ImageData const & data ) { - const uint64_t kMul = 0x9ddfea08eb382d69ULL; - auto seed = hash; - - std::hash< T > hasher; - uint64_t a = ( hasher( rhs ) ^ seed ) * kMul; - a ^= ( a >> 47 ); - - uint64_t b = ( seed ^ a ) * kMul; - b ^= ( b >> 47 ); + return convert( data.info ); + } -#pragma warning( push ) -#pragma warning( disable: 4068 ) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-warning-option" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuseless-cast" - hash = static_cast< std::size_t >( b * kMul ); -#pragma GCC diagnostic pop -#pragma clang diagnostic pop -#pragma warning( pop ) - return hash; + static VkImageViewCreateInfo convert( ImageViewData const & data + , VkImage image ) + { + auto result = convert( data.info ); + result.image = image; + return result; } static size_t makeHash( SamplerDesc const & samplerDesc ) @@ -105,6 +94,18 @@ namespace crg { std::array< char, 1024u > buffer; + for ( auto const & [data, _] : m_bufferViews ) + { + snprintf( buffer.data(), buffer.size(), "Leaked [VkBufferView](%.900s)", data.data->name.c_str() ); + Logger::logError( buffer.data() ); + } + + for ( auto const & [data, _] : m_buffers ) + { + snprintf( buffer.data(), buffer.size(), "Leaked [VkBuffer](%.900s)", data.data->name.c_str() ); + Logger::logError( buffer.data() ); + } + for ( auto const & [data, _] : m_imageViews ) { snprintf( buffer.data(), buffer.size(), "Leaked [VkImageView](%.900s)", data.data->name.c_str() ); @@ -117,26 +118,136 @@ namespace crg Logger::logError( buffer.data() ); } - for ( auto const & vertexBuffer : m_vertexBuffers ) + for ( auto const & [_, data] : m_samplers ) { - if ( vertexBuffer->memory ) + snprintf( buffer.data(), buffer.size(), "Leaked [VkSampler](%.900s)", data.name.c_str() ); + Logger::logError( buffer.data() ); + } + } + + BufferId ResourceHandler::createBufferId( BufferData const & img ) + { + lock_type lock( m_buffersMutex ); + auto data = std::make_unique< BufferData >( img ); + BufferId result{ uint32_t( m_bufferIds.size() + 1u ), data.get() }; + m_bufferIds.try_emplace( result, std::move( data ) ); + return result; + } + + BufferViewId ResourceHandler::createViewId( BufferViewData const & view ) + { + lock_type lock( m_bufferViewsMutex ); + auto it = std::find_if( m_bufferViewIds.begin() + , m_bufferViewIds.end() + , [&view]( BufferViewIdDataOwnerCont::value_type const & lookup ) { - snprintf( buffer.data(), buffer.size(), "Leaked [VkDeviceMemory](%.900s)", vertexBuffer->buffer.name.c_str() ); - Logger::logError( buffer.data() ); - } + return *lookup.second == view; + } ); + BufferViewId result{}; + + if ( it == m_bufferViewIds.end() ) + { + auto data = std::make_unique< BufferViewData >( view ); + result = BufferViewId{ uint32_t( m_bufferViewIds.size() + 1u ), data.get() }; + m_bufferViewIds.try_emplace( result, std::move( data ) ); + } + else + { + result = it->first; + } + + return result; + } + + ResourceHandler::CreatedT< VkBuffer > ResourceHandler::createBuffer( GraphContext & context + , BufferId bufferId ) + { + ResourceHandler::CreatedT< VkBuffer > result{}; + + if ( context.vkCreateBuffer ) + { + lock_type lock( m_buffersMutex ); + auto [it, ins] = m_buffers.try_emplace( bufferId, std::pair< VkBuffer, VkDeviceMemory >{} ); - if ( vertexBuffer->buffer.buffer() ) + if ( ins && context.device ) { - snprintf( buffer.data(), buffer.size(), "Leaked [VkBuffer](%.900s)", vertexBuffer->buffer.name.c_str() ); - Logger::logError( buffer.data() ); + // Create buffer + auto createInfo = reshdl::convert( *bufferId.data ); + auto res = context.vkCreateBuffer( context.device + , &createInfo + , context.allocator + , &it->second.first ); + result.resource = it->second.first; + checkVkResult( res, "Buffer creation" ); + crgRegisterObjectName( context, bufferId.data->name, result.resource ); + + // Create Buffer memory + VkMemoryRequirements requirements{}; + context.vkGetBufferMemoryRequirements( context.device + , result.resource + , &requirements ); + uint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits + , getMemoryPropertyFlags( bufferId.data->info.memory ) ); + VkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO + , nullptr + , requirements.size + , deduced }; + res = context.vkAllocateMemory( context.device + , &allocateInfo + , context.allocator + , &it->second.second ); + result.memory = it->second.second; + checkVkResult( res, "Buffer memory allocation" ); + crgRegisterObjectName( context, bufferId.data->name, result.memory ); + + // Bind buffer and memory + res = context.vkBindBufferMemory( context.device + , result.resource + , result.memory + , 0u ); + checkVkResult( res, "Buffer memory binding" ); + result.created = true; + } + else + { + result.resource = it->second.first; + result.memory = it->second.second; } } - for ( auto const & [_, data] : m_samplers ) + return result; + } + + ResourceHandler::CreatedViewT< VkBufferView > ResourceHandler::createBufferView( GraphContext & context + , BufferViewId view ) + { + ResourceHandler::CreatedViewT< VkBufferView > result{}; + + if ( context.vkCreateBufferView ) { - snprintf( buffer.data(), buffer.size(), "Leaked [VkSampler](%.900s)", data.name.c_str() ); - Logger::logError( buffer.data() ); + lock_type lock( m_bufferViewsMutex ); + auto [it, ins] = m_bufferViews.try_emplace( view, VkBufferView{} ); + + if ( ins ) + { + auto buffer = createBuffer( context, view.data->buffer ).resource; + auto createInfo = reshdl::convert( *view.data, buffer ); + auto res = context.vkCreateBufferView( context.device + , &createInfo + , context.allocator + , &it->second ); + checkVkResult( res, "BufferView creation" ); + crgRegisterObjectName( context, view.data->name, it->second ); + result.view = it->second; + result.created = true; + } + else + { + result.view = it->second; + } } + + return result; } ImageId ResourceHandler::createImageId( ImageData const & img ) @@ -150,7 +261,7 @@ namespace crg ImageViewId ResourceHandler::createViewId( ImageViewData const & view ) { - lock_type lock( m_viewsMutex ); + lock_type lock( m_imageViewsMutex ); auto it = std::find_if( m_imageViewIds.begin() , m_imageViewIds.end() , [&view]( ImageViewIdDataOwnerCont::value_type const & lookup ) @@ -180,11 +291,10 @@ namespace crg if ( context.vkCreateImage ) { - bool created{}; lock_type lock( m_imagesMutex ); auto [it, ins] = m_images.try_emplace( imageId, std::pair< VkImage, VkDeviceMemory >{} ); - if ( ins ) + if ( ins && context.device ) { // Create image auto createInfo = reshdl::convert( *imageId.data ); @@ -192,61 +302,60 @@ namespace crg , &createInfo , context.allocator , &it->second.first ); - auto image = it->second.first; + result.resource = it->second.first; checkVkResult( res, "Image creation" ); - crgRegisterObjectName( context, imageId.data->name, image ); + crgRegisterObjectName( context, imageId.data->name, result.resource ); - if ( context.device ) - { - // Create Image memory - VkMemoryRequirements requirements{}; - context.vkGetImageMemoryRequirements( context.device - , image - , &requirements ); - uint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits - , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); - VkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO - , nullptr - , requirements.size - , deduced }; - res = context.vkAllocateMemory( context.device - , &allocateInfo - , context.allocator - , &it->second.second ); - auto memory = it->second.second; - checkVkResult( res, "Image memory allocation" ); - crgRegisterObjectName( context, imageId.data->name, memory ); - - // Bind image and memory - res = context.vkBindImageMemory( context.device - , image - , memory - , 0u ); - checkVkResult( res, "Image memory binding" ); - created = true; - } + // Create Image memory + VkMemoryRequirements requirements{}; + context.vkGetImageMemoryRequirements( context.device + , result.resource + , &requirements ); + uint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits + , getMemoryPropertyFlags( imageId.data->info.memory ) ); + VkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO + , nullptr + , requirements.size + , deduced }; + res = context.vkAllocateMemory( context.device + , &allocateInfo + , context.allocator + , &it->second.second ); + result.memory = it->second.second; + checkVkResult( res, "Image memory allocation" ); + crgRegisterObjectName( context, imageId.data->name, result.memory ); + + // Bind image and memory + res = context.vkBindImageMemory( context.device + , result.resource + , result.memory + , 0u ); + checkVkResult( res, "Image memory binding" ); + result.created = true; + } + else + { + result.resource = it->second.first; + result.memory = it->second.second; } - - result = { it->second.first, created }; } return result; } - ResourceHandler::CreatedT< VkImageView > ResourceHandler::createImageView( GraphContext & context + ResourceHandler::CreatedViewT< VkImageView > ResourceHandler::createImageView( GraphContext & context , ImageViewId view ) { - ResourceHandler::CreatedT< VkImageView > result{}; + ResourceHandler::CreatedViewT< VkImageView > result{}; if ( context.vkCreateImageView ) { - bool created{}; - lock_type lock( m_viewsMutex ); + lock_type lock( m_bufferViewsMutex ); auto [it, ins] = m_imageViews.try_emplace( view, VkImageView{} ); if ( ins ) { - auto image = createImage( context, view.data->image ).first; + auto image = createImage( context, view.data->image ).resource; auto createInfo = reshdl::convert( *view.data, image ); auto res = context.vkCreateImageView( context.device , &createInfo @@ -254,10 +363,13 @@ namespace crg , &it->second ); checkVkResult( res, "ImageView creation" ); crgRegisterObjectName( context, view.data->name, it->second ); - created = true; + result.view = it->second; + result.created = true; + } + else + { + result.view = it->second; } - - result = { it->second, created }; } return result; @@ -309,55 +421,26 @@ namespace crg , Texcoord const & config ) { VertexBuffer * vertexBuffer{}; - lock_type lock( m_buffersMutex ); + lock_type lock( m_vertexBuffersMutex ); if ( context.vkCreateBuffer ) { - auto result = std::make_unique< VertexBuffer >(); - vertexBuffer = result.get(); - VkBufferCreateInfo createInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO - , nullptr - , 0u + auto bufferId = createBufferId( BufferData{ "QuadVertexMemory_" + suffix + , BufferCreateFlags::eNone , 3u * sizeof( reshdl::Quad::Vertex ) - , VK_BUFFER_USAGE_VERTEX_BUFFER_BIT - , VK_SHARING_MODE_EXCLUSIVE - , 0u - , nullptr }; - auto res = context.vkCreateBuffer( context.device - , &createInfo - , context.allocator - , &vertexBuffer->buffer.buffer() ); - checkVkResult( res, "Vertex buffer creation" ); - crgRegisterObject( context, "QuadVertexBuffer_" + suffix, vertexBuffer->buffer.buffer() ); + , BufferUsageFlags::eVertexBuffer + , MemoryPropertyFlags::eHostVisible } ); + auto result = std::make_unique< VertexBuffer >( createViewId( BufferViewData{ "QuadVertexMemory_" + suffix + , bufferId + , { 0u, bufferId.data->info.size } } ) ); + vertexBuffer = result.get(); if ( context.device ) { - VkMemoryRequirements requirements{}; - context.vkGetBufferMemoryRequirements( context.device - , vertexBuffer->buffer.buffer() - , &requirements ); - uint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits - , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ); - VkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO - , nullptr - , requirements.size - , deduced }; - res = context.vkAllocateMemory( context.device - , &allocateInfo - , context.allocator - , &vertexBuffer->memory ); - checkVkResult( res, "Buffer memory allocation" ); - crgRegisterObject( context, "QuadVertexMemory_" + suffix, vertexBuffer->memory ); - - res = context.vkBindBufferMemory( context.device - , vertexBuffer->buffer.buffer() - , vertexBuffer->memory - , 0u ); - checkVkResult( res, "Buffer memory binding" ); - + auto created = createBuffer( context, vertexBuffer->buffer.data->buffer ); reshdl::Quad::Vertex * buffer{}; - res = context.vkMapMemory( context.device - , vertexBuffer->memory + auto res = context.vkMapMemory( context.device + , created.memory , 0u , VK_WHOLE_SIZE , 0u @@ -384,11 +467,11 @@ namespace crg VkMappedMemoryRange memoryRange{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE , nullptr - , vertexBuffer->memory + , created.memory , 0u , VK_WHOLE_SIZE }; context.vkFlushMappedMemoryRanges( context.device, 1u, &memoryRange ); - context.vkUnmapMemory( context.device, vertexBuffer->memory ); + context.vkUnmapMemory( context.device, created.memory ); } vertexBuffer->vertexAttribs.push_back( { 0u, 0u, VK_FORMAT_R32G32_SFLOAT, offsetof( reshdl::Quad::Vertex, position ) } ); @@ -414,6 +497,45 @@ namespace crg return vertexBuffer; } + void ResourceHandler::destroyBuffer( GraphContext & context + , BufferId bufferId ) + { + lock_type lock( m_buffersMutex ); + auto it = m_buffers.find( bufferId ); + + if ( it != m_buffers.end() ) + { + if ( context.vkDestroyBuffer && it->second.first ) + { + context.vkDestroyBuffer( context.device, it->second.first, context.allocator ); + } + + if ( context.vkFreeMemory && it->second.second ) + { + context.vkFreeMemory( context.device, it->second.second, context.allocator ); + } + + m_buffers.erase( it ); + } + } + + void ResourceHandler::destroyBufferView( GraphContext & context + , BufferViewId viewId ) + { + lock_type lock( m_bufferViewsMutex ); + auto it = m_bufferViews.find( viewId ); + + if ( it != m_bufferViews.end() ) + { + if ( context.vkDestroyBufferView && it->second ) + { + context.vkDestroyBufferView( context.device, it->second, context.allocator ); + } + + m_bufferViews.erase( it ); + } + } + void ResourceHandler::destroyImage( GraphContext & context , ImageId imageId ) { @@ -422,14 +544,14 @@ namespace crg if ( it != m_images.end() ) { - if ( context.vkFreeMemory && it->second.second ) + if ( context.vkDestroyImage && it->second.first ) { - context.vkFreeMemory( context.device, it->second.second, context.allocator ); + context.vkDestroyImage( context.device, it->second.first, context.allocator ); } - if ( context.vkDestroyImage && it->second.first ) + if ( context.vkFreeMemory && it->second.second ) { - context.vkDestroyImage( context.device, it->second.first, context.allocator ); + context.vkFreeMemory( context.device, it->second.second, context.allocator ); } m_images.erase( it ); @@ -439,7 +561,7 @@ namespace crg void ResourceHandler::destroyImageView( GraphContext & context , ImageViewId viewId ) { - lock_type lock( m_viewsMutex ); + lock_type lock( m_bufferViewsMutex ); auto it = m_imageViews.find( viewId ); if ( it != m_imageViews.end() ) @@ -476,7 +598,7 @@ namespace crg void ResourceHandler::destroyVertexBuffer( GraphContext & context , VertexBuffer const * buffer ) { - lock_type lock( m_buffersMutex ); + lock_type lock( m_vertexBuffersMutex ); auto it = std::find_if( m_vertexBuffers.begin() , m_vertexBuffers.end() , [buffer]( VertexBufferPtr const & lookup ) @@ -486,24 +608,8 @@ namespace crg if ( it != m_vertexBuffers.end() ) { - auto & vertexBuffer = **it; - - if ( context.vkFreeMemory && vertexBuffer.memory ) - { - crgUnregisterObject( context, vertexBuffer.memory ); - context.vkFreeMemory( context.device - , vertexBuffer.memory - , context.allocator ); - } - - if ( context.vkDestroyBuffer && vertexBuffer.buffer.buffer() ) - { - crgUnregisterObject( context, vertexBuffer.buffer.buffer() ); - context.vkDestroyBuffer( context.device - , vertexBuffer.buffer.buffer() - , context.allocator ); - } - + auto const & vertexBuffer = **it; + destroyBuffer( context, vertexBuffer.buffer.data->buffer ); m_vertexBuffers.erase( it ); } } @@ -519,6 +625,16 @@ namespace crg ContextResourcesCache::~ContextResourcesCache()noexcept { + for ( auto const & [bufferView, _] : m_bufferViews ) + { + m_handler.destroyBufferView( m_context, bufferView ); + } + + for ( auto const & [buffer, _] : m_buffers ) + { + m_handler.destroyBuffer( m_context, buffer ); + } + for ( auto const & [imageView, _] : m_imageViews ) { m_handler.destroyImageView( m_context, imageView ); @@ -540,21 +656,85 @@ namespace crg } } + VkBuffer ContextResourcesCache::createBuffer( BufferId const & buffer ) + { + VkDeviceMemory memory{}; + return createBuffer( buffer, memory ); + } + + VkBuffer ContextResourcesCache::createBuffer( BufferId const & buffer, VkDeviceMemory & memory ) + { + auto [created, result, mem] = m_handler.createBuffer( m_context, buffer ); + + if ( created ) + { + m_buffers[buffer] = result; + } + + memory = mem; + return result; + } + + VkBufferView ContextResourcesCache::createBufferView( BufferViewId const & view ) + { + auto [created, result] = m_handler.createBufferView( m_context, view ); + + if ( created ) + { + m_bufferViews[view] = result; + } + + return result; + } + + bool ContextResourcesCache::destroyBuffer( BufferId const & bufferId ) + { + auto it = m_buffers.find( bufferId ); + auto result = it != m_buffers.end(); + + if ( result ) + { + m_handler.destroyBuffer( m_context, bufferId ); + } + + return result; + } + + bool ContextResourcesCache::destroyBufferView( BufferViewId const & viewId ) + { + auto it = m_bufferViews.find( viewId ); + auto result = it != m_bufferViews.end(); + + if ( result ) + { + m_handler.destroyBufferView( m_context, viewId ); + } + + return result; + } + VkImage ContextResourcesCache::createImage( ImageId const & image ) { - auto [result, created] = m_handler.createImage( m_context, image ); + VkDeviceMemory memory{}; + return createImage( image, memory ); + } + + VkImage ContextResourcesCache::createImage( ImageId const & image, VkDeviceMemory & memory ) + { + auto [created, result, mem] = m_handler.createImage( m_context, image ); if ( created ) { m_images[image] = result; } + memory = mem; return result; } VkImageView ContextResourcesCache::createImageView( ImageViewId const & view ) { - auto [result, created] = m_handler.createImageView( m_context, view ); + auto [created, result] = m_handler.createImageView( m_context, view ); if ( created ) { @@ -629,6 +809,72 @@ namespace crg { } + VkBuffer ResourcesCache::createBuffer( GraphContext & context + , BufferId const & bufferId + , VkDeviceMemory & memory ) + { + auto & cache = getContextCache( context ); + return cache.createBuffer( bufferId, memory ); + } + + VkBuffer ResourcesCache::createBuffer( GraphContext & context + , BufferId const & bufferId ) + { + auto & cache = getContextCache( context ); + return cache.createBuffer( bufferId ); + } + + VkBufferView ResourcesCache::createBufferView( GraphContext & context + , BufferViewId const & viewId ) + { + auto & cache = getContextCache( context ); + return cache.createBufferView( viewId ); + } + + bool ResourcesCache::destroyBuffer( BufferId const & bufferId ) + { + auto it = std::find_if( m_caches.begin() + , m_caches.end() + , [&bufferId]( ContextCacheMap::value_type & lookup ) + { + return lookup.second.destroyBuffer( bufferId ); + } ); + return it != m_caches.end(); + } + + bool ResourcesCache::destroyBufferView( BufferViewId const & viewId ) + { + auto it = std::find_if( m_caches.begin() + , m_caches.end() + , [&viewId]( ContextCacheMap::value_type & lookup ) + { + return lookup.second.destroyBufferView( viewId ); + } ); + return it != m_caches.end(); + } + + bool ResourcesCache::destroyBuffer( GraphContext & context + , BufferId const & bufferId ) + { + auto & cache = getContextCache( context ); + return cache.destroyBuffer( bufferId ); + } + + bool ResourcesCache::destroyBufferView( GraphContext & context + , BufferViewId const & viewId ) + { + auto & cache = getContextCache( context ); + return cache.destroyBufferView( viewId ); + } + + VkImage ResourcesCache::createImage( GraphContext & context + , ImageId const & imageId + , VkDeviceMemory & memory ) + { + auto & cache = getContextCache( context ); + return cache.createImage( imageId, memory ); + } + VkImage ResourcesCache::createImage( GraphContext & context , ImageId const & imageId ) { diff --git a/source/RenderGraph/RunnableGraph.cpp b/source/RenderGraph/RunnableGraph.cpp index 3f84d85..1d8cc66 100644 --- a/source/RenderGraph/RunnableGraph.cpp +++ b/source/RenderGraph/RunnableGraph.cpp @@ -59,17 +59,15 @@ namespace crg for ( auto & [curLayout, curStates] : currentLayout.second ) { - auto nxtLayerIt = nxtLayout.find( curLayout ); - - if ( nxtLayerIt != nxtLayout.end() ) + if ( auto nxtLayerIt = nxtLayout.find( curLayout ); + nxtLayerIt != nxtLayout.end() ) { auto resLayerIt = result.try_emplace( curLayout ).first; for ( auto & [curLevel, _] : curStates ) { - auto nxtLevelIt = nxtLayerIt->second.find( curLevel ); - - if ( nxtLevelIt != nxtLayerIt->second.end() ) + if ( auto nxtLevelIt = nxtLayerIt->second.find( curLevel ); + nxtLevelIt != nxtLayerIt->second.end() ) { resLayerIt->second.emplace( *nxtLevelIt ); } @@ -149,21 +147,49 @@ namespace crg return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } + static WriteDescriptorSet getWrite( ImageAttachment const & attach + , SamplerDesc const & samplerDesc + , uint32_t binding + , uint32_t count + , uint32_t index + , RunnableGraph & graph ) + { + WriteDescriptorSet result{ binding + , 0u + , count + , getDescriptorType( attach ) }; + VkSampler sampler = attach.isSampledView() + ? graph.createSampler( samplerDesc ) + : VkSampler{}; + VkImageLayout layout = attach.isSampledView() + ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + : VK_IMAGE_LAYOUT_GENERAL; + VkDescriptorImageInfo info{ sampler + , graph.createImageView( attach.view( index ) ) + , layout }; + result.imageInfo.push_back( info ); + return result; + } + static WriteDescriptorSet getWrite( BufferAttachment const & attach , uint32_t binding , uint32_t count - , uint32_t index ) + , uint32_t index + , RunnableGraph & graph ) { WriteDescriptorSet result{ binding , 0u , count , getDescriptorType( attach ) }; - VkDescriptorBufferInfo info{ attach.buffer.buffer( index ), attach.range.offset, attach.range.size }; + auto bufferViewId = attach.buffer( index ); + VkDescriptorBufferInfo info{ graph.createBuffer( bufferViewId.data->buffer ) + , getSubresourceRange( bufferViewId ).offset + , getSubresourceRange( bufferViewId ).size }; if ( attach.isView() ) { result.bufferViewInfo.push_back( info ); - result.texelBufferView.push_back( attach.view ); + result.texelBufferView.push_back( graph.createBufferView( bufferViewId ) ); } else { @@ -204,14 +230,12 @@ namespace crg //************************************************************************************************ RunnableGraph::RunnableGraph( FrameGraph & graph - , AttachmentTransitions transitions , GraphNodePtrArray nodes , RootNode rootNode , GraphContext & context ) : m_graph{ graph } , m_context{ context } , m_resources{ m_graph.getHandler(), m_context } - , m_transitions{ std::move( transitions ) } , m_nodes{ std::move( nodes ) } , m_rootNode{ std::move( rootNode ) } , m_timerQueries{ m_context @@ -434,6 +458,16 @@ namespace crg , m_graph.getFinalStates().getCurrPipelineState().pipelineStage } }; } + VkBuffer RunnableGraph::createBuffer( BufferId const & buffer ) + { + return m_resources.createBuffer( buffer ); + } + + VkBufferView RunnableGraph::createBufferView( BufferViewId const & view ) + { + return m_resources.createBufferView( view ); + } + VkImage RunnableGraph::createImage( ImageId const & image ) { return m_resources.createImage( image ); @@ -494,7 +528,7 @@ namespace crg return getCurrentLayoutState( context , view.data->image , view.data->info.viewType - , view.data->info.subresourceRange ); + , getSubresourceRange( view ) ); } LayoutState RunnableGraph::getNextLayoutState( RecordContext const & context @@ -530,9 +564,16 @@ namespace crg return rungrf::getDescriptorType( attach.bufferAttach ); } - WriteDescriptorSet RunnableGraph::getBufferWrite( Attachment const & attach, uint32_t index )const + WriteDescriptorSet RunnableGraph::getDescriptorWrite( Attachment const & attach, uint32_t binding, uint32_t index ) + { + if ( attach.isImage() ) + return rungrf::getWrite( attach.imageAttach, SamplerDesc{}, binding, 1u, index, *this ); + return rungrf::getWrite( attach.bufferAttach, binding, 1u, index, *this ); + } + + WriteDescriptorSet RunnableGraph::getDescriptorWrite( Attachment const & attach, SamplerDesc const & samplerDesc, uint32_t binding, uint32_t index ) { - assert( attach.isBuffer() ); - return rungrf::getWrite( attach.bufferAttach, attach.binding, 1u, index ); + assert( attach.isImage() ); + return rungrf::getWrite( attach.imageAttach, samplerDesc, binding, 1u, index, *this ); } } diff --git a/source/RenderGraph/RunnablePass.cpp b/source/RenderGraph/RunnablePass.cpp index 226ed7a..f3b418a 100644 --- a/source/RenderGraph/RunnablePass.cpp +++ b/source/RenderGraph/RunnablePass.cpp @@ -61,12 +61,42 @@ namespace crg { for ( uint32_t i = 0u; i < attach.getBufferCount(); ++i ) { - bufferAccesses.insert_or_assign( attach.buffer( i ) + bufferAccesses.insert_or_assign( attach.buffer( i ).data->buffer.id , AccessState{ attach.getAccessMask() , attach.getPipelineStageFlags( isComputePass ) } ); } } + static void registerResources( FramePass const & pass + , RunnablePass::Callbacks const & callbacks + , GraphContext const & graphContext + , LayerLayoutStatesHandler & imageLayouts + , AccessStateMap & bufferAccesses ) + { + bool isComputePass = callbacks.isComputePass(); + for ( auto & [binding, attach] : pass.uniforms ) + registerBuffer( *attach, isComputePass, bufferAccesses ); + for ( auto & [binding, attach] : pass.sampled ) + registerImage( *attach.attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts ); + for ( auto & [binding, attach] : pass.inputs ) + if ( attach->isImage() ) + registerImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts ); + else + registerBuffer( *attach, isComputePass, bufferAccesses ); + for ( auto & [binding, attach] : pass.inouts ) + if ( attach->isImage() ) + registerImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts ); + else + registerBuffer( *attach, isComputePass, bufferAccesses ); + for ( auto & [binding, attach] : pass.outputs ) + if ( attach->isImage() ) + registerImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts ); + else + registerBuffer( *attach, isComputePass, bufferAccesses ); + for ( auto attach : pass.targets ) + registerImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts ); + } + static void prepareImage( VkCommandBuffer commandBuffer , uint32_t index , Attachment const & attach @@ -80,7 +110,7 @@ namespace crg , view ); if ( !attach.isNoTransition() - && ( attach.isSampledView() || attach.isStorageView() || attach.isTransferView() || attach.isTransitionView() ) ) + && ( attach.isSampledImageView() || attach.isStorageImageView() || attach.isTransferImageView() || attach.isTransitionImageView() ) ) { auto needed = makeLayoutState( attach.getImageLayout( separateDepthStencilLayouts ) ); auto currentLayout = ( !attach.isInput() @@ -131,14 +161,20 @@ namespace crg , uint32_t index , Attachment const & attach , bool isComputePass + , RunnableGraph & graph , RecordContext & recordContext ) { + auto view = attach.buffer( index ); + recordContext.runImplicitTransition( commandBuffer + , index + , view ); + if ( !attach.isNoTransition() && ( attach.isStorageBuffer() || attach.isTransferBuffer() || attach.isTransitionBuffer() ) ) { - auto & range = attach.getBufferRange(); - auto buffer = attach.buffer( index ); - auto currentState = recordContext.getAccessState( buffer, range ); + auto buffer = view.data->buffer; + auto & range = getSubresourceRange( view ); + auto currentState = recordContext.getAccessState( view ); if ( attach.isClearableBuffer() ) { @@ -148,7 +184,7 @@ namespace crg , currentState , { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } ); recordContext->vkCmdFillBuffer( commandBuffer - , buffer + , graph.createBuffer( buffer ) , range.offset == 0u ? 0u : details::getAlignedSize( range.offset, 4u ) , range.size == VK_WHOLE_SIZE ? VK_WHOLE_SIZE : details::getAlignedSize( range.size, 4u ) , 0u ); @@ -163,6 +199,37 @@ namespace crg , { attach.getAccessMask(), attach.getPipelineStageFlags( isComputePass ) } ); } } + + static void prepareResources( VkCommandBuffer commandBuffer + , uint32_t index + , RecordContext & recordContext + , RunnableGraph & graph + , FramePass const & pass + , RunnablePass::Callbacks const & callbacks + , GraphContext & graphContext ) + { + for ( auto & [binding, attach] : pass.sampled ) + prepareImage( commandBuffer, index, *attach.attach, graphContext.separateDepthStencilLayouts, graph, recordContext ); + for ( auto & [binding, attach] : pass.uniforms ) + prepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext ); + for ( auto & [binding, attach] : pass.inputs ) + if ( attach->isImage() ) + prepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext ); + else + prepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext ); + for ( auto & [binding, attach] : pass.inouts ) + if ( attach->isImage() ) + prepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext ); + else + prepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext ); + for ( auto & [binding, attach] : pass.outputs ) + if ( attach->isImage() ) + prepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext ); + else + prepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext ); + for ( auto & attach : pass.targets ) + prepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext ); + } } //********************************************************************************************* @@ -172,8 +239,11 @@ namespace crg , ImageViewId const & view , ImageLayout currentLayout ) { - if ( !attach.isTransitionView() && attach.isInput() && currentLayout == ImageLayout::eUndefined ) - Logger::logWarning( stepName + " - [" + attach.pass->getFullName() + "]: Input view [" + view.data->name + "] is currently in undefined layout" ); + if ( !attach.isTransitionImageView() && attach.isInput() && currentLayout == ImageLayout::eUndefined ) + { + auto passName = attach.pass ? attach.pass->getFullName() : attach.source.front().pass->getFullName(); + Logger::logWarning( stepName + " - [" + passName + "]: Input view [" + view.data->name + "] is currently in undefined layout" ); + } } void convert( SemaphoreWaitArray const & toWait @@ -193,15 +263,6 @@ namespace crg } } - std::vector< VkClearValue > convert( std::vector< ClearValue > const & v ) - { - std::vector< VkClearValue > result; - result.reserve( v.size() ); - for ( auto & value : v ) - result.push_back( convert( value ) ); - return result; - } - //********************************************************************************************* RunnablePass::Callbacks::Callbacks( InitialiseCallback initialise @@ -405,11 +466,8 @@ namespace crg m_passContexts.emplace_back( graph.getResources() ); } - bool isComputePass = m_callbacks.isComputePass(); - for ( auto & attach : m_pass.images ) - details::registerImage( attach, isComputePass, m_context.separateDepthStencilLayouts, m_imageLayouts ); - for ( auto & attach : m_pass.buffers ) - details::registerBuffer( attach, isComputePass, m_bufferAccesses ); + details::registerResources( pass, m_callbacks, m_context + , m_imageLayouts, m_bufferAccesses ); } RunnablePass::~RunnablePass()noexcept @@ -501,11 +559,8 @@ namespace crg #pragma GCC diagnostic pop m_timer.beginPass( commandBuffer ); - for ( auto & attach : m_pass.images ) - details::prepareImage( commandBuffer, index, attach, m_context.separateDepthStencilLayouts, m_graph, context ); - - for ( auto & attach : m_pass.buffers ) - details::prepareBuffer( commandBuffer, index, attach, m_callbacks.isComputePass(), context ); + details::prepareResources( commandBuffer, index, context + , m_graph, m_pass, m_callbacks, m_context ); for ( auto const & action : m_ruConfig.prePassActions ) { @@ -523,7 +578,12 @@ namespace crg m_context.vkCmdEndDebugBlock( commandBuffer ); } - for ( auto const & [view, action] : m_ruConfig.implicitActions ) + for ( auto const & [view, action] : m_ruConfig.implicitImageActions ) + { + context.registerImplicitTransition( *this, view, action ); + } + + for ( auto const & [view, action] : m_ruConfig.implicitBufferActions ) { context.registerImplicitTransition( *this, view, action ); } diff --git a/source/RenderGraph/RunnablePasses/BufferCopy.cpp b/source/RenderGraph/RunnablePasses/BufferCopy.cpp index 6e189b7..aef2b6d 100644 --- a/source/RenderGraph/RunnablePasses/BufferCopy.cpp +++ b/source/RenderGraph/RunnablePasses/BufferCopy.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/BufferCopy.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -32,41 +31,49 @@ namespace crg , m_copyOffset{ copyOffset } , m_copyRange{ copyRange } { + assert( m_pass.inputs.size() == m_pass.outputs.size() ); } void BufferCopy::doRecordInto( RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index )const { - auto srcBufferRange{ m_pass.buffers.front().getBufferRange() }; - auto dstBufferRange{ m_pass.buffers.back().getBufferRange() }; - auto srcBuffer{ m_pass.buffers.front().buffer( index ) }; - auto dstBuffer{ m_pass.buffers.back().buffer( index ) }; - // Copy source to target. - VkBufferCopy copyRegion{ srcBufferRange.offset + m_copyOffset - , dstBufferRange.offset + m_copyOffset - , m_copyRange }; - context.memoryBarrier( commandBuffer - , srcBuffer - , srcBufferRange - , { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader } - , { AccessFlags::eTransferRead, PipelineStageFlags::eTransfer } ); - context.memoryBarrier( commandBuffer - , dstBuffer - , dstBufferRange - , { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } ); - context->vkCmdCopyBuffer( commandBuffer - , srcBuffer - , dstBuffer - , 1u - , ©Region ); - context.memoryBarrier( commandBuffer - , dstBuffer - , dstBufferRange - , { AccessFlags::eShaderRead, PipelineStageFlags::eComputeShader } ); - context.memoryBarrier( commandBuffer - , srcBuffer - , srcBufferRange - , { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader } ); + auto srcIt = m_pass.inputs.begin(); + auto dstIt = m_pass.outputs.begin(); + + while ( srcIt != m_pass.inputs.end() + && dstIt != m_pass.outputs.end() ) + { + auto srcView{ srcIt->second->buffer( index ) }; + auto dstView{ dstIt->second->buffer( index ) }; + auto srcBufferRange{ getSubresourceRange( srcView ) }; + auto dstBufferRange{ getSubresourceRange( dstView ) }; + auto srcBuffer{ m_graph.createBuffer( srcView.data->buffer ) }; + auto dstBuffer{ m_graph.createBuffer( dstView.data->buffer ) }; + // Copy source to target. + VkBufferCopy copyRegion{ srcBufferRange.offset + m_copyOffset + , dstBufferRange.offset + m_copyOffset + , m_copyRange }; + context.memoryBarrier( commandBuffer + , srcView + , { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader } + , { AccessFlags::eTransferRead, PipelineStageFlags::eTransfer } ); + context.memoryBarrier( commandBuffer + , dstView + , { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } ); + context->vkCmdCopyBuffer( commandBuffer + , srcBuffer + , dstBuffer + , 1u + , ©Region ); + context.memoryBarrier( commandBuffer + , dstView + , { AccessFlags::eShaderRead, PipelineStageFlags::eComputeShader } ); + context.memoryBarrier( commandBuffer + , srcView + , { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader } ); + ++srcIt; + ++dstIt; + } } } diff --git a/source/RenderGraph/RunnablePasses/BufferToImageCopy.cpp b/source/RenderGraph/RunnablePasses/BufferToImageCopy.cpp index 96b74e8..62d894c 100644 --- a/source/RenderGraph/RunnablePasses/BufferToImageCopy.cpp +++ b/source/RenderGraph/RunnablePasses/BufferToImageCopy.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/BufferToImageCopy.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -32,28 +31,39 @@ namespace crg , m_copyOffset{ convert( copyOffset ) } , m_copySize{ convert( copySize ) } { + assert( m_pass.inputs.size() == m_pass.outputs.size() ); } void BufferToImageCopy::doRecordInto( RecordContext const & context , VkCommandBuffer commandBuffer , uint32_t index )const { - auto dstAttach{ m_pass.images.back().view( index ) }; - auto srcBuffer{ m_pass.buffers.front().buffer( index ) }; - auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; - // Copy source to target. - auto range = getSubresourceLayers( dstAttach.data->info.subresourceRange ); - VkBufferImageCopy copyRegion{ 0ULL - , 0u - , 0u - , range - , m_copyOffset - , m_copySize }; - context->vkCmdCopyBufferToImage( commandBuffer - , srcBuffer - , dstImage - , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , 1u - , ©Region ); + auto srcIt = m_pass.inputs.begin(); + auto dstIt = m_pass.outputs.begin(); + + while ( srcIt != m_pass.inputs.end() + && dstIt != m_pass.outputs.end() ) + { + auto srcAttach{ srcIt->second->buffer( index ) }; + auto dstAttach{ dstIt->second->view( index ) }; + auto srcBuffer{ m_graph.createBuffer( srcAttach.data->buffer ) }; + auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; + // Copy source to target. + auto range = getSubresourceLayers( getSubresourceRange( dstAttach ) ); + VkBufferImageCopy copyRegion{ 0ULL + , 0u + , 0u + , range + , m_copyOffset + , m_copySize }; + context->vkCmdCopyBufferToImage( commandBuffer + , srcBuffer + , dstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , 1u + , ©Region ); + ++srcIt; + ++dstIt; + } } } diff --git a/source/RenderGraph/RunnablePasses/ComputePass.cpp b/source/RenderGraph/RunnablePasses/ComputePass.cpp index 47ce882..4d5ad44 100644 --- a/source/RenderGraph/RunnablePasses/ComputePass.cpp +++ b/source/RenderGraph/RunnablePasses/ComputePass.cpp @@ -4,13 +4,20 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/ComputePass.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include namespace crg { + namespace cppss + { + static bool isPtrEnabled( bool const * v ) + { + return v ? *v : true; + } + } + ComputePass::ComputePass( FramePass const & pass , GraphContext & context , RunnableGraph & graph @@ -27,14 +34,14 @@ namespace crg , IsComputePassCallback( [](){ return true; } ) } , ruConfig } , m_cpConfig{ cpConfig.m_initialise ? std::move( *cpConfig.m_initialise ) : getDefaultV< RunnablePass::InitialiseCallback >() - , cpConfig.m_enabled ? std::move( *cpConfig.m_enabled ) : getDefaultV< bool const * >() + , cpConfig.m_enabled.has_value() ? std::move( *cpConfig.m_enabled ) : getDefaultV< bool const * >() , cpConfig.m_isEnabled , cpConfig.m_getPassIndex ? std::move( *cpConfig.m_getPassIndex ) : getDefaultV< RunnablePass::GetPassIndexCallback >() , cpConfig.m_recordInto ? std::move( *cpConfig.m_recordInto ) : getDefaultV< RunnablePass::RecordCallback >() , cpConfig.m_end ? std::move( *cpConfig.m_end ) : getDefaultV< RunnablePass::RecordCallback >() - , cpConfig.m_groupCountX ? *cpConfig.m_groupCountX : 1u - , cpConfig.m_groupCountY ? *cpConfig.m_groupCountY : 1u - , cpConfig.m_groupCountZ ? *cpConfig.m_groupCountZ : 1u + , cpConfig.m_groupCountX.has_value() ? *cpConfig.m_groupCountX : 1u + , cpConfig.m_groupCountY.has_value() ? *cpConfig.m_groupCountY : 1u + , cpConfig.m_groupCountZ.has_value() ? *cpConfig.m_groupCountZ : 1u , cpConfig.m_getGroupCountX ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountX ) ) : std::nullopt , cpConfig.m_getGroupCountY ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountY ) ) : std::nullopt , cpConfig.m_getGroupCountZ ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountZ ) ) : std::nullopt @@ -78,7 +85,7 @@ namespace crg { return ( m_cpConfig.isEnabled ? ( *m_cpConfig.isEnabled )() - : ( m_cpConfig.enabled ? *m_cpConfig.enabled : true ) ); + : cppss::isPtrEnabled( m_cpConfig.enabled ) ); } void ComputePass::doRecordInto( RecordContext & context @@ -88,9 +95,10 @@ namespace crg m_pipeline.recordInto( context, commandBuffer, index ); m_cpConfig.recordInto( context, commandBuffer, index ); - if ( auto indirectBuffer = m_cpConfig.indirectBuffer.buffer.buffer( index ) ) - { - context->vkCmdDispatchIndirect( commandBuffer, indirectBuffer, m_cpConfig.indirectBuffer.offset ); + if ( m_cpConfig.indirectBuffer != defaultV< IndirectBuffer > ) + { + auto indirectBuffer = m_graph.createBuffer( m_cpConfig.indirectBuffer.buffer.data->buffer ); + context->vkCmdDispatchIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_cpConfig.indirectBuffer.buffer ).offset ); } else { diff --git a/source/RenderGraph/RunnablePasses/GenerateMipmaps.cpp b/source/RenderGraph/RunnablePasses/GenerateMipmaps.cpp index 2191a87..a868454 100644 --- a/source/RenderGraph/RunnablePasses/GenerateMipmaps.cpp +++ b/source/RenderGraph/RunnablePasses/GenerateMipmaps.cpp @@ -4,7 +4,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/GenerateMipmaps.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -45,13 +44,20 @@ namespace crg , VkCommandBuffer commandBuffer , uint32_t index ) { - auto viewId{ m_pass.images.front().view( index ) }; + for ( auto [_, view] : m_pass.inouts ) + doProcessImageView( context, commandBuffer, view->view( index ) ); + } + + void GenerateMipmaps::doProcessImageView( RecordContext & context + , VkCommandBuffer commandBuffer + , ImageViewId viewId ) + { auto imageId{ viewId.data->image }; auto image{ m_graph.createImage( imageId ) }; auto extent = getExtent( imageId ); auto format = getFormat( imageId ); - auto baseArrayLayer = viewId.data->info.subresourceRange.baseArrayLayer; - auto layerCount = viewId.data->info.subresourceRange.layerCount; + auto baseArrayLayer = getSubresourceRange( viewId ).baseArrayLayer; + auto layerCount = getSubresourceRange( viewId ).layerCount; auto mipLevels = imageId.data->info.mipLevels; auto nextLayoutState = m_graph.getNextLayoutState( context , *this diff --git a/source/RenderGraph/RunnablePasses/ImageBlit.cpp b/source/RenderGraph/RunnablePasses/ImageBlit.cpp index 3e3009f..6ea06d7 100644 --- a/source/RenderGraph/RunnablePasses/ImageBlit.cpp +++ b/source/RenderGraph/RunnablePasses/ImageBlit.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/ImageBlit.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -15,10 +14,8 @@ namespace crg ImageBlit::ImageBlit( FramePass const & pass , GraphContext & context , RunnableGraph & graph - , Offset3D const & blitSrcOffset - , Extent3D const & blitSrcSize - , Offset3D const & blitDstOffset - , Extent3D const & blitDstSize + , Rect3D const & blitSrc + , Rect3D const & blitDst , FilterMode filter , ru::Config ruConfig , GetPassIndexCallback passIndex @@ -32,34 +29,43 @@ namespace crg , std::move( passIndex ) , std::move( isEnabled ) } , std::move( ruConfig ) } - , m_srcOffset{ convert( blitSrcOffset ) } - , m_srcSize{ convert( blitSrcSize ) } - , m_dstOffset{ convert( blitDstOffset ) } - , m_dstSize{ convert( blitDstSize ) } + , m_srcOffset{ convert( blitSrc.offset ) } + , m_srcSize{ convert( blitSrc.extent ) } + , m_dstOffset{ convert( blitDst.offset ) } + , m_dstSize{ convert( blitDst.extent ) } , m_filter{ filter } { - assert( pass.images.size() == 2u ); + assert( m_pass.inputs.size() == m_pass.outputs.size() ); } void ImageBlit::doRecordInto( RecordContext const & context , VkCommandBuffer commandBuffer , uint32_t index ) { - auto srcAttach{ m_pass.images.front().view( index ) }; - auto dstAttach{ m_pass.images.back().view( index ) }; - auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; - auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; - VkImageBlit blitRegion{ getSubresourceLayers( srcAttach.data->info.subresourceRange ) - , { m_srcOffset, VkOffset3D{ int32_t( m_srcSize.width ), int32_t( m_srcSize.height ), int32_t( m_srcSize.depth ) } } - , getSubresourceLayers( dstAttach.data->info.subresourceRange ) - , { m_dstOffset, VkOffset3D{ int32_t( m_dstSize.width ), int32_t( m_dstSize.height ), int32_t( m_dstSize.depth ) } } }; - context->vkCmdBlitImage( commandBuffer - , srcImage - , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL - , dstImage - , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - , 1u - , &blitRegion - , convert( m_filter ) ); + auto srcIt = m_pass.inputs.begin(); + auto dstIt = m_pass.outputs.begin(); + + while ( srcIt != m_pass.inputs.end() + && dstIt != m_pass.outputs.end() ) + { + auto srcAttach{ srcIt->second->view( index ) }; + auto dstAttach{ dstIt->second->view( index ) }; + auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; + auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; + VkImageBlit blitRegion{ getSubresourceLayers( getSubresourceRange( srcAttach ) ) + , { m_srcOffset, VkOffset3D{ int32_t( m_srcSize.width ), int32_t( m_srcSize.height ), int32_t( m_srcSize.depth ) } } + , getSubresourceLayers( getSubresourceRange( dstAttach ) ) + , { m_dstOffset, VkOffset3D{ int32_t( m_dstSize.width ), int32_t( m_dstSize.height ), int32_t( m_dstSize.depth ) } } }; + context->vkCmdBlitImage( commandBuffer + , srcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , dstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , 1u + , &blitRegion + , convert( m_filter ) ); + ++srcIt; + ++dstIt; + } } } diff --git a/source/RenderGraph/RunnablePasses/ImageCopy.cpp b/source/RenderGraph/RunnablePasses/ImageCopy.cpp index bff16bf..0ff9159 100644 --- a/source/RenderGraph/RunnablePasses/ImageCopy.cpp +++ b/source/RenderGraph/RunnablePasses/ImageCopy.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/ImageCopy.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -32,7 +31,7 @@ namespace crg , m_copySize{ convert( copySize ) } , m_finalOutputLayout{ finalOutputLayout } { - assert( ( pass.images.size() % 2u ) == 0u ); + assert( m_pass.inputs.size() == m_pass.outputs.size() || m_pass.inputs.size() == 1u || m_pass.outputs.size() == 1u ); } ImageCopy::ImageCopy( FramePass const & pass @@ -51,28 +50,47 @@ namespace crg , std::move( passIndex ) , std::move( isEnabled ) } { - assert( ( pass.images.size() % 2u ) == 0u ); + assert( m_pass.inputs.size() == m_pass.outputs.size() || m_pass.inputs.size() == 1u || m_pass.outputs.size() == 1u ); } void ImageCopy::doRecordInto( RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index ) { - auto srcIt = m_pass.images.begin(); - auto dstIt = std::next( srcIt ); + if ( m_pass.inputs.size() == m_pass.outputs.size() ) + { + doRecordMultiToMulti( context, commandBuffer, index ); + } + else if ( m_pass.outputs.size() == 1u ) + { + doRecordMultiToSingle( context, commandBuffer, index ); + } + else if ( m_pass.inputs.size() == 1u ) + { + doRecordSingleToMulti( context, commandBuffer, index ); + } + } + + void ImageCopy::doRecordMultiToMulti( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + auto srcIt = m_pass.inputs.begin(); + auto dstIt = m_pass.outputs.begin(); - while ( srcIt != m_pass.images.end() ) + while ( srcIt != m_pass.inputs.end() + && dstIt != m_pass.outputs.end() ) { - auto srcAttach{ srcIt->view( index ) }; - auto dstAttach{ dstIt->view( index ) }; + auto srcAttach{ srcIt->second->view( index ) }; + auto dstAttach{ dstIt->second->view( index ) }; auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; // Copy source to target. - VkImageCopy copyRegion{ getSubresourceLayers( srcAttach.data->info.subresourceRange ) + VkImageCopy copyRegion{ getSubresourceLayers( getSubresourceRange( srcAttach ) ) , {} - , getSubresourceLayers( dstAttach.data->info.subresourceRange ) + , getSubresourceLayers( getSubresourceRange( dstAttach ) ) , {} - , m_copySize }; + , m_copySize }; context->vkCmdCopyImage( commandBuffer , srcImage , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL @@ -88,11 +106,121 @@ namespace crg , crg::makeLayoutState( m_finalOutputLayout ) ); } - srcIt = std::next( dstIt ); + ++srcIt; + ++dstIt; + } + } - if ( srcIt != m_pass.images.end() ) + void ImageCopy::doRecordMultiToSingle( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + std::vector< VkImageCopy > copyRegions; + auto dstIt = m_pass.outputs.begin(); + auto dstAttach{ dstIt->second->view( index ) }; + auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; + auto dstSubresourceRange = getSubresourceLayers( getSubresourceRange( dstAttach ) ); + auto prvSrcImage{ m_graph.createImage( m_pass.inputs.begin()->second->view( index ).data->image ) }; + + for ( auto const & [_, attach] : m_pass.inputs ) + { + auto srcAttach{ attach->view( index ) }; + + if ( auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; + srcImage != prvSrcImage ) { - dstIt = std::next( srcIt ); + context->vkCmdCopyImage( commandBuffer + , prvSrcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , dstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , uint32_t( copyRegions.size() ) + , copyRegions.data() ); + copyRegions.clear(); + prvSrcImage = srcImage; + } + + copyRegions.push_back( { getSubresourceLayers( getSubresourceRange( srcAttach ) ) + , {} + , dstSubresourceRange + , {} + , m_copySize } ); + } + + if ( !copyRegions.empty() ) + { + context->vkCmdCopyImage( commandBuffer + , prvSrcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , dstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , uint32_t( copyRegions.size() ) + , copyRegions.data() ); + } + + if ( m_finalOutputLayout != ImageLayout::eUndefined ) + { + context.memoryBarrier( commandBuffer + , dstAttach + , crg::makeLayoutState( m_finalOutputLayout ) ); + } + } + + void ImageCopy::doRecordSingleToMulti( RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + std::vector< VkImageCopy > copyRegions; + auto srcIt = m_pass.inputs.begin(); + auto srcAttach{ srcIt->second->view( index ) }; + auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; + auto srcSubresourceRange = getSubresourceLayers( getSubresourceRange( srcAttach ) ); + auto prvDstImage{ m_graph.createImage( m_pass.outputs.begin()->second->view( index ).data->image ) }; + + for ( auto const & [_, attach] : m_pass.outputs ) + { + auto dstAttach{ attach->view( index ) }; + + if ( auto dstImage{ m_graph.createImage( dstAttach.data->image ) }; + dstImage != prvDstImage ) + { + context->vkCmdCopyImage( commandBuffer + , srcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , prvDstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , uint32_t( copyRegions.size() ) + , copyRegions.data() ); + copyRegions.clear(); + prvDstImage = dstImage; + } + + copyRegions.push_back( { srcSubresourceRange + , {} + , getSubresourceLayers( getSubresourceRange( dstAttach ) ) + , {} + , m_copySize } ); + } + + if ( !copyRegions.empty() ) + { + context->vkCmdCopyImage( commandBuffer + , srcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , prvDstImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , uint32_t( copyRegions.size() ) + , copyRegions.data() ); + } + + if ( m_finalOutputLayout != ImageLayout::eUndefined ) + { + for ( auto const & [_, attach] : m_pass.outputs ) + { + auto dstAttach{ attach->view( index ) }; + context.memoryBarrier( commandBuffer + , dstAttach + , crg::makeLayoutState( m_finalOutputLayout ) ); } } } diff --git a/source/RenderGraph/RunnablePasses/ImageToBufferCopy.cpp b/source/RenderGraph/RunnablePasses/ImageToBufferCopy.cpp index 2caa4a5..5feb9ef 100644 --- a/source/RenderGraph/RunnablePasses/ImageToBufferCopy.cpp +++ b/source/RenderGraph/RunnablePasses/ImageToBufferCopy.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/RunnablePasses/ImageToBufferCopy.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -38,22 +37,32 @@ namespace crg , VkCommandBuffer commandBuffer , uint32_t index ) { - auto srcAttach{ m_pass.images.back().view( index ) }; - auto dstBuffer{ m_pass.buffers.front().buffer( index ) }; - auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; - // Copy source to target. - auto range = getSubresourceLayers( srcAttach.data->info.subresourceRange ); - VkBufferImageCopy copyRegion{ 0ULL - , 0u - , 0u - , range - , m_copyOffset - , m_copySize }; - context->vkCmdCopyImageToBuffer( commandBuffer - , srcImage - , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL - , dstBuffer - , 1u - , ©Region ); + auto srcIt = m_pass.inputs.begin(); + auto dstIt = m_pass.outputs.begin(); + + while ( srcIt != m_pass.inputs.end() + && dstIt != m_pass.outputs.end() ) + { + auto srcAttach{ srcIt->second->view( index ) }; + auto dstAttach{ dstIt->second->buffer( index ) }; + auto srcImage{ m_graph.createImage( srcAttach.data->image ) }; + auto dstBuffer{ m_graph.createBuffer( dstAttach.data->buffer ) }; + // Copy source to target. + auto range = getSubresourceLayers( getSubresourceRange( srcAttach ) ); + VkBufferImageCopy copyRegion{ 0ULL + , 0u + , 0u + , range + , m_copyOffset + , m_copySize }; + context->vkCmdCopyImageToBuffer( commandBuffer + , srcImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , dstBuffer + , 1u + , ©Region ); + ++srcIt; + ++dstIt; + } } } diff --git a/source/RenderGraph/RunnablePasses/PipelineHolder.cpp b/source/RenderGraph/RunnablePasses/PipelineHolder.cpp index fae24e0..0fa4124 100644 --- a/source/RenderGraph/RunnablePasses/PipelineHolder.cpp +++ b/source/RenderGraph/RunnablePasses/PipelineHolder.cpp @@ -11,6 +11,64 @@ See LICENSE file in root folder. namespace crg { + namespace pphdr + { + static bool isDescriptor( Attachment const & attach ) + { + return attach.isStorageImageView() || attach.isSampledImageView() + || attach.isUniformBuffer() || attach.isStorageBuffer() + || attach.isUniformBufferView() || attach.isStorageBufferView(); + } + + static void createDescriptorWrites( std::map< uint32_t, FramePass::SampledAttachment > const & attaches + , uint32_t index + , RunnableGraph & graph + , WriteDescriptorSetArray & writes ) + { + for ( auto & [binding, attach] : attaches ) + writes.push_back( graph.getDescriptorWrite( *attach.attach, attach.sampler, binding, index ) ); + } + + static void createDescriptorWrites( std::map< uint32_t, Attachment const * > const & attaches + , uint32_t index + , RunnableGraph & graph + , WriteDescriptorSetArray & writes ) + { + for ( auto & [binding, attach] : attaches ) + { + if ( isDescriptor( *attach ) ) + writes.push_back( graph.getDescriptorWrite( *attach, binding, index ) ); + } + } + + static void createDescriptorBindings( std::map< uint32_t, FramePass::SampledAttachment > const & attaches + , VkShaderStageFlags shaderStage + , RunnableGraph const & graph + , VkDescriptorSetLayoutBindingArray & descriptorBindings ) + { + for ( auto & [binding, attach] : attaches ) + { + descriptorBindings.push_back( { binding + , graph.getDescriptorType( *attach.attach ) + , 1u, shaderStage, nullptr } ); + } + } + + static void createDescriptorBindings( std::map< uint32_t, Attachment const * > const & attaches + , VkShaderStageFlags shaderStage + , RunnableGraph const & graph + , VkDescriptorSetLayoutBindingArray & descriptorBindings ) + { + for ( auto & [binding, attach] : attaches ) + { + if ( isDescriptor( *attach ) ) + descriptorBindings.push_back( { binding + , graph.getDescriptorType( *attach ) + , 1u, shaderStage, nullptr } ); + } + } + } + PipelineHolder::PipelineHolder( FramePass const & pass , GraphContext & context , RunnableGraph & graph @@ -20,10 +78,10 @@ namespace crg : m_pass{ pass } , m_context{ context } , m_graph{ graph } - , m_baseConfig{ config.m_programs ? std::move( *config.m_programs ) : defaultV< std::vector< VkPipelineShaderStageCreateInfoArray > > - , config.m_programCreator ? std::move( *config.m_programCreator ) : defaultV< ProgramCreator > - , config.m_layouts ? std::move( *config.m_layouts ) : defaultV< std::vector< VkDescriptorSetLayout > > - , config.m_pushConstants ? std::move( *config.m_pushConstants ) : defaultV< std::vector< VkPushConstantRange > > } + , m_baseConfig{ config.m_programs ? *config.m_programs : defaultV< std::vector< VkPipelineShaderStageCreateInfoArray > > + , config.m_programCreator ? *config.m_programCreator : defaultV< ProgramCreator > + , config.m_layouts ? *config.m_layouts : defaultV< std::vector< VkDescriptorSetLayout > > + , config.m_pushConstants ? *config.m_pushConstants : defaultV< std::vector< VkPushConstantRange > > } , m_bindingPoint{ bindingPoint } { if ( m_baseConfig.m_programCreator.create ) @@ -239,33 +297,11 @@ namespace crg return; } - for ( auto & attach : m_pass.images ) - { - if ( attach.isSampledView() ) - { - descriptorSet.writes.emplace_back( attach.binding - , 0u - , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER - , VkDescriptorImageInfo{ m_graph.createSampler( attach.getSamplerDesc() ) - , m_graph.createImageView( attach.view( index ) ) - , VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); - } - else if ( attach.isStorageView() ) - { - descriptorSet.writes.emplace_back( attach.binding - , 0u - , VK_DESCRIPTOR_TYPE_STORAGE_IMAGE - , VkDescriptorImageInfo{ VkSampler{} - , m_graph.createImageView( attach.view( index ) ) - , VK_IMAGE_LAYOUT_GENERAL } ); - } - } - - for ( auto & buffer : m_pass.buffers ) - { - if ( buffer.isStorageBuffer() || buffer.isUniformBuffer() ) - descriptorSet.writes.push_back( m_graph.getBufferWrite( buffer, index ) ); - } + pphdr::createDescriptorWrites( m_pass.uniforms, index, m_graph, descriptorSet.writes ); + pphdr::createDescriptorWrites( m_pass.sampled, index, m_graph, descriptorSet.writes ); + pphdr::createDescriptorWrites( m_pass.inputs, index, m_graph, descriptorSet.writes ); + pphdr::createDescriptorWrites( m_pass.inouts, index, m_graph, descriptorSet.writes ); + pphdr::createDescriptorWrites( m_pass.outputs, index, m_graph, descriptorSet.writes ); VkDescriptorSetAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO , nullptr @@ -302,30 +338,11 @@ namespace crg | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT ) ); - for ( auto & attach : m_pass.images ) - { - if ( attach.isSampledView() || attach.isStorageView() ) - { - m_descriptorBindings.push_back( { attach.binding - , m_graph.getDescriptorType( attach ) - , 1u - , shaderStage - , nullptr } ); - } - } - - for ( auto & attach : m_pass.buffers ) - { - if ( attach.isUniformBuffer() || attach.isStorageBuffer() - || attach.isUniformBufferView() || attach.isStorageBufferView() ) - { - m_descriptorBindings.push_back( { attach.binding - , m_graph.getDescriptorType( attach ) - , 1u - , shaderStage - , nullptr } ); - } - } + pphdr::createDescriptorBindings( m_pass.uniforms, shaderStage, m_graph, m_descriptorBindings ); + pphdr::createDescriptorBindings( m_pass.sampled, shaderStage, m_graph, m_descriptorBindings ); + pphdr::createDescriptorBindings( m_pass.inputs, shaderStage, m_graph, m_descriptorBindings ); + pphdr::createDescriptorBindings( m_pass.inouts, shaderStage, m_graph, m_descriptorBindings ); + pphdr::createDescriptorBindings( m_pass.outputs, shaderStage, m_graph, m_descriptorBindings ); } void PipelineHolder::doCreateDescriptorSetLayout() diff --git a/source/RenderGraph/RunnablePasses/RenderMesh.cpp b/source/RenderGraph/RunnablePasses/RenderMesh.cpp index bc3350c..b7728a8 100644 --- a/source/RenderGraph/RunnablePasses/RenderMesh.cpp +++ b/source/RenderGraph/RunnablePasses/RenderMesh.cpp @@ -23,7 +23,8 @@ namespace crg , true /*resettable*/ , ruConfig.prePassActions , ruConfig.postPassActions - , ruConfig.implicitActions } } + , ruConfig.implicitImageActions + , ruConfig.implicitBufferActions } } , m_renderMesh{ pass , context , graph diff --git a/source/RenderGraph/RunnablePasses/RenderMeshHolder.cpp b/source/RenderGraph/RunnablePasses/RenderMeshHolder.cpp index 7d6480c..26e3a65 100644 --- a/source/RenderGraph/RunnablePasses/RenderMeshHolder.cpp +++ b/source/RenderGraph/RunnablePasses/RenderMeshHolder.cpp @@ -13,7 +13,8 @@ namespace crg , RunnableGraph & graph , rm::Config config , uint32_t maxPassCount ) - : m_config{ config.m_renderPosition ? std::move( *config.m_renderPosition ) : getDefaultV< Offset2D >() + : m_graph{ graph } + , m_config{ config.m_renderPosition ? std::move( *config.m_renderPosition ) : getDefaultV< Offset2D >() , config.m_depthStencilState ? std::move( *config.m_depthStencilState ) : getDefaultV< VkPipelineDepthStencilStateCreateInfo >() , config.m_getPassIndex ? std::move( *config.m_getPassIndex ) : getDefaultV< RunnablePass::GetPassIndexCallback >() , config.m_isEnabled ? std::move( *config.m_isEnabled ) : getDefaultV< RunnablePass::IsEnabledCallback >() @@ -115,28 +116,31 @@ namespace crg doCreatePipeline( index ); m_pipeline.recordInto( context, commandBuffer, index ); m_config.recordInto( context, commandBuffer, index ); - DeviceSize offset{}; - if ( m_config.vertexBuffer.buffer.buffer( index ) ) + if ( m_config.vertexBuffer.buffer != BufferViewId{} ) { - context->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u, &m_config.vertexBuffer.buffer.buffer( index ), &offset ); + auto vkBuffer = m_graph.createBuffer( m_config.vertexBuffer.buffer.data->buffer ); + context->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u, &vkBuffer, &getSubresourceRange( m_config.vertexBuffer.buffer ).offset ); } - if ( auto indirectBuffer = m_config.indirectBuffer.buffer.buffer( index ) ) + if ( m_config.indirectBuffer != defaultV< IndirectBuffer > ) { - if ( auto indexBuffer = m_config.indexBuffer.buffer.buffer( index ) ) + auto indirectBuffer = m_graph.createBuffer( m_config.indirectBuffer.buffer.data->buffer ); + if ( m_config.indexBuffer != defaultV< IndexBuffer > ) { - context->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, offset, m_config.getIndexType() ); - context->vkCmdDrawIndexedIndirect( commandBuffer, indirectBuffer, m_config.indirectBuffer.offset, 1u, m_config.indirectBuffer.stride ); + auto indexBuffer = m_graph.createBuffer( m_config.indexBuffer.buffer.data->buffer ); + context->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, getSubresourceRange( m_config.indexBuffer.buffer ).offset, m_config.getIndexType() ); + context->vkCmdDrawIndexedIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride ); } else { - context->vkCmdDrawIndirect( commandBuffer, indirectBuffer, m_config.indirectBuffer.offset, 1u, m_config.indirectBuffer.stride ); + context->vkCmdDrawIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride ); } } - else if ( auto indexBuffer = m_config.indexBuffer.buffer.buffer( index ) ) + else if ( m_config.indexBuffer != defaultV< IndexBuffer > ) { - context->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, offset, m_config.getIndexType() ); + auto indexBuffer = m_graph.createBuffer( m_config.indexBuffer.buffer.data->buffer ); + context->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, getSubresourceRange( m_config.indexBuffer.buffer ).offset, m_config.getIndexType() ); context->vkCmdDrawIndexed( commandBuffer, m_config.getPrimitiveCount(), 1u, 0u, 0u, 0u ); } else diff --git a/source/RenderGraph/RunnablePasses/RenderPass.cpp b/source/RenderGraph/RunnablePasses/RenderPass.cpp index 1785959..a190ba2 100644 --- a/source/RenderGraph/RunnablePasses/RenderPass.cpp +++ b/source/RenderGraph/RunnablePasses/RenderPass.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/Attachment.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/RunnableGraph.hpp" #include @@ -21,21 +20,15 @@ namespace crg for ( auto & binding : bindings ) { - auto it = std::find_if( result.begin() - , result.end() + auto it = std::find_if( result.begin(), result.end() , [&binding]( VkDescriptorPoolSize const & lookup ) { return binding.descriptorType == lookup.type; } ); - if ( it == result.end() ) - { result.push_back( { binding.descriptorType, binding.descriptorCount * maxSets } ); - } else - { it->descriptorCount += binding.descriptorCount * maxSets; - } } return result; diff --git a/source/RenderGraph/RunnablePasses/RenderPassHolder.cpp b/source/RenderGraph/RunnablePasses/RenderPassHolder.cpp index c0871f9..afe076a 100644 --- a/source/RenderGraph/RunnablePasses/RenderPassHolder.cpp +++ b/source/RenderGraph/RunnablePasses/RenderPassHolder.cpp @@ -5,7 +5,6 @@ See LICENSE file in root folder. #include "RenderGraph/Attachment.hpp" #include "RenderGraph/GraphContext.hpp" -#include "RenderGraph/ImageData.hpp" #include "RenderGraph/Log.hpp" #include "RenderGraph/RunnableGraph.hpp" @@ -81,12 +80,6 @@ namespace crg , separateDepthStencilLayouts ); } - static bool operator==( PipelineState const & lhs, PipelineState const & rhs ) - { - return lhs.access == rhs.access - && lhs.pipelineStage == rhs.pipelineStage; - } - static bool operator!=( LayoutState const & lhs, LayoutState const & rhs ) { return lhs.layout != rhs.layout @@ -98,8 +91,7 @@ namespace crg , std::vector< RenderPassHolder::Entry > const & attaches , uint32_t passIndex ) { - auto it = std::find_if( attaches.begin() - , attaches.end() + auto it = std::find_if( attaches.begin(), attaches.end() , [&context, passIndex]( RenderPassHolder::Entry const & lookup ) { auto layout = context.getLayoutState( resolveView( lookup.view, passIndex ) ); @@ -163,8 +155,6 @@ namespace crg , crg::RunnablePass const & runnable , uint32_t passIndex ) { - using rpHolder::operator==; - auto & data = m_passes[passIndex]; auto previousState = context.getPrevPipelineState(); auto nextState = context.getNextPipelineState(); @@ -245,46 +235,41 @@ namespace crg auto & data = m_passes[passIndex]; m_blendAttachs.clear(); - for ( auto & attach : m_pass.images ) + for ( auto attach : m_pass.targets ) { - if ( attach.isDepthAttach() - || attach.isStencilAttach() - || attach.isColourAttach() ) + auto view = attach->view( passIndex ); + auto resolved = resolveView( view, passIndex ); + auto currentLayout = m_graph.getCurrentLayoutState( context, resolved ); + auto nextLayout = m_graph.getNextLayoutState( context, runnable, resolved ); + auto from = ( !attach->isInput() + ? crg::makeLayoutState( ImageLayout::eUndefined ) + : currentLayout ); + checkUndefinedInput( "RenderPass", *attach, resolved, from.layout ); + + if ( attach->isDepthImageTarget() || attach->isStencilImageTarget() ) { - auto view = attach.view( passIndex ); - auto resolved = resolveView( view, passIndex ); - auto currentLayout = m_graph.getCurrentLayoutState( context, resolved ); - auto nextLayout = m_graph.getNextLayoutState( context, runnable, resolved ); - auto from = ( !attach.isInput() - ? crg::makeLayoutState( ImageLayout::eUndefined ) - : currentLayout ); - checkUndefinedInput( "RenderPass", attach, resolved, from.layout ); - - if ( attach.isDepthAttach() || attach.isStencilAttach() ) - { - depthReference = rpHolder::addAttach( context - , attach - , view - , attaches - , data.attaches - , data.clearValues - , from - , nextLayout - , m_context.separateDepthStencilLayouts ); - } - else if ( attach.isColourAttach() ) - { - colorReferences.push_back( rpHolder::addAttach( context - , attach - , view - , attaches - , data.attaches - , data.clearValues - , m_blendAttachs - , from - , nextLayout - , m_context.separateDepthStencilLayouts ) ); - } + depthReference = rpHolder::addAttach( context + , *attach + , view + , attaches + , data.attaches + , data.clearValues + , from + , nextLayout + , m_context.separateDepthStencilLayouts ); + } + else if ( attach->isColourImageTarget() ) + { + colorReferences.push_back( rpHolder::addAttach( context + , *attach + , view + , attaches + , data.attaches + , data.clearValues + , m_blendAttachs + , from + , nextLayout + , m_context.separateDepthStencilLayouts ) ); } } @@ -356,21 +341,16 @@ namespace crg m_passes[index].attachments.clear(); m_layers = 1u; - for ( auto & attach : m_pass.images ) + for ( auto attach : m_pass.targets ) { - if ( attach.isColourAttach() - || attach.isDepthAttach() - || attach.isStencilAttach() ) - { - auto view = attach.view(); - m_passes[index].attachments.push_back( &attach ); - width = std::max( width - , view.data->image.data->info.extent.width >> view.data->info.subresourceRange.baseMipLevel ); - height = std::max( height - , view.data->image.data->info.extent.height >> view.data->info.subresourceRange.baseMipLevel ); - m_layers = std::max( m_layers - , view.data->info.subresourceRange.layerCount ); - } + auto view = attach->view(); + m_passes[index].attachments.push_back( attach ); + width = std::max( width + , view.data->image.data->info.extent.width >> getSubresourceRange( view ).baseMipLevel ); + height = std::max( height + , view.data->image.data->info.extent.height >> getSubresourceRange( view ).baseMipLevel ); + m_layers = std::max( m_layers + , getSubresourceRange( view ).layerCount ); } m_passes[index].renderArea.extent.width = width; diff --git a/source/RenderGraph/RunnablePasses/RenderQuad.cpp b/source/RenderGraph/RunnablePasses/RenderQuad.cpp index a62f69e..701ddff 100644 --- a/source/RenderGraph/RunnablePasses/RenderQuad.cpp +++ b/source/RenderGraph/RunnablePasses/RenderQuad.cpp @@ -23,7 +23,8 @@ namespace crg , true /*resettable*/ , ruConfig.prePassActions , ruConfig.postPassActions - , ruConfig.implicitActions } } + , ruConfig.implicitImageActions + , ruConfig.implicitBufferActions } } , m_renderQuad{ pass , context , graph diff --git a/source/RenderGraph/RunnablePasses/RenderQuadHolder.cpp b/source/RenderGraph/RunnablePasses/RenderQuadHolder.cpp index 5b9eae3..f204888 100644 --- a/source/RenderGraph/RunnablePasses/RenderQuadHolder.cpp +++ b/source/RenderGraph/RunnablePasses/RenderQuadHolder.cpp @@ -8,7 +8,13 @@ See LICENSE file in root folder. namespace crg { - //********************************************************************************************* + namespace rdqdhdr + { + static bool isPtrEnabled( bool const * v ) + { + return v ? *v : true; + } + } RenderQuadHolder::RenderQuadHolder( FramePass const & pass , GraphContext & context @@ -18,12 +24,12 @@ namespace crg : m_config{ config.m_texcoordConfig ? std::move( *config.m_texcoordConfig ) : getDefaultV< Texcoord >() , config.m_renderPosition ? std::move( *config.m_renderPosition ) : getDefaultV< Offset2D >() , config.m_depthStencilState ? std::move( *config.m_depthStencilState ) : getDefaultV< VkPipelineDepthStencilStateCreateInfo >() - , config.m_passIndex ? *config.m_passIndex : getDefaultV< uint32_t const * >() - , config.m_enabled ? *config.m_enabled : getDefaultV< bool const * >() + , config.m_passIndex.has_value() ? *config.m_passIndex : getDefaultV< uint32_t const * >() + , config.m_enabled.has_value() ? *config.m_enabled : getDefaultV< bool const * >() , config.m_isEnabled , config.m_recordInto ? std::move( *config.m_recordInto ) : getDefaultV< RunnablePass::RecordCallback >() , config.m_end ? std::move( *config.m_end ) : getDefaultV< RunnablePass::RecordCallback >() - , config.m_instances ? *config.m_instances : 1u + , config.m_instances.has_value() ? *config.m_instances : 1u , config.m_indirectBuffer ? *config.m_indirectBuffer : getDefaultV < IndirectBuffer >() } , m_graph{ graph } , m_pipeline{ pass @@ -111,17 +117,18 @@ namespace crg doCreatePipeline( index ); m_pipeline.recordInto( context, commandBuffer, index ); m_config.recordInto( context, commandBuffer, index ); - DeviceSize offset{}; - if ( m_vertexBuffer - && m_vertexBuffer->buffer.buffer( index ) ) + if ( m_vertexBuffer ) { - context->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u, &m_vertexBuffer->buffer.buffer( index ), &offset ); + auto vkBuffer = m_graph.createBuffer( m_vertexBuffer->buffer.data->buffer ); + context->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u + , &vkBuffer, &getSubresourceRange( m_vertexBuffer->buffer ).offset ); } - if ( auto indirectBuffer = m_config.indirectBuffer.buffer.buffer( index ) ) + if ( m_config.indirectBuffer != defaultV< IndirectBuffer > ) { - context->vkCmdDrawIndirect( commandBuffer, indirectBuffer, m_config.indirectBuffer.offset, 1u, m_config.indirectBuffer.stride ); + auto indirectBuffer = m_graph.createBuffer( m_config.indirectBuffer.buffer.data->buffer ); + context->vkCmdDrawIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride ); } else { @@ -147,7 +154,7 @@ namespace crg { return ( m_config.isEnabled ? ( *m_config.isEnabled )() - : ( m_config.enabled ? *m_config.enabled : true ) ); + : rdqdhdr::isPtrEnabled( m_config.enabled ) ); } void RenderQuadHolder::doPreparePipelineStates( Extent2D const & renderSize @@ -170,25 +177,13 @@ namespace crg } auto & program = m_pipeline.getProgram( index ); - VkGraphicsPipelineCreateInfo createInfo{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO - , nullptr - , 0u - , uint32_t( program.size() ) - , program.data() - , &getInputState() - , &m_iaState - , nullptr - , &m_vpState - , &m_rsState - , &m_msState - , &m_config.depthStencilState - , &m_blendState - , nullptr - , m_pipeline.getPipelineLayout() - , m_renderPass - , 0u - , VkPipeline{} - , 0u }; + VkGraphicsPipelineCreateInfo createInfo{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, nullptr, 0u + , uint32_t( program.size() ), program.data() + , &getInputState(), &m_iaState, nullptr + , &m_vpState, &m_rsState, &m_msState + , &m_config.depthStencilState, &m_blendState, nullptr + , m_pipeline.getPipelineLayout(), m_renderPass + , 0u, VkPipeline{}, 0u }; m_pipeline.createPipeline( index, createInfo ); } @@ -204,12 +199,8 @@ namespace crg , 1.0f }; scissor = { { m_config.renderPosition.x, m_config.renderPosition.y } , { renderSize.width, renderSize.height } }; - return { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO - , nullptr - , 0u - , 1u - , &viewport - , 1u - , &scissor }; + return { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, nullptr, 0u + , 1u, &viewport + , 1u, &scissor }; } } diff --git a/test/BaseTest.cpp b/test/BaseTest.cpp index a7920a4..378cdd7 100644 --- a/test/BaseTest.cpp +++ b/test/BaseTest.cpp @@ -1,5 +1,7 @@ #include "BaseTest.hpp" +#include + #if defined( _WIN32 ) # include #elif defined( __APPLE__ ) @@ -21,6 +23,8 @@ namespace test { + using StringArray = std::vector< std::string >; + //********************************************************************************************* namespace @@ -159,6 +163,25 @@ namespace test { return path.substr( 0, path.find_last_of( PathSeparator ) ); } + + std::string findMissing( StringArray const & lhsLines + , StringArray const & rhsLines + , std::string const & op ) + { + std::string result; + + for ( auto & lhsLine : lhsLines ) + { + if ( rhsLines.end() == std::find( rhsLines.begin() + , rhsLines.end() + , lhsLine ) ) + { + result += op + lhsLine + "\n"; + } + } + + return result; + } } //********************************************************************************************* @@ -228,47 +251,6 @@ namespace test //********************************************************************************************* - void TestCounts::initialise( std::string const & name ) - { - suiteName = name; - tclog = std::make_unique< test::LogStreambuf< test::DebugLogStreambufTraits > >( name, std::clog ); - tcout = std::make_unique< test::LogStreambuf< test::InfoLogStreambufTraits > >( name, std::cout ); - tcerr = std::make_unique< test::LogStreambuf< test::ErrorLogStreambufTraits > >( name, std::cerr ); - } - - void TestCounts::cleanup() - { - tclog.reset(); - tcout.reset(); - tcerr.reset(); - } - - void TestCounts::updateName( std::string const & name ) - { - std::stringstream stream; - ++testId; - stream << "test" << std::setw( 3 ) << std::setfill( '0' ) << testId << "-" << name; - this->testName = stream.str(); - } - - using StringArray = std::vector< std::string >; - - std::string replace( std::string const & value - , std::string const & lookup - , std::string const & repl ) - { - auto result = value; - size_t startPos = 0u; - - while ( ( startPos = result.find( lookup, startPos ) ) != std::string::npos ) - { - result.replace( startPos, lookup.length(), repl ); - startPos += repl.length(); - } - - return result; - } - StringArray splitInLines( std::string const & value ) { StringArray lines; @@ -284,29 +266,10 @@ namespace test return lines; } - std::string findMissing( StringArray const & lhsLines - , StringArray const & rhsLines - , std::string const & op ) - { - std::string result; - - for ( auto & lhsLine : lhsLines ) - { - if ( rhsLines.end() == std::find( rhsLines.begin() - , rhsLines.end() - , lhsLine ) ) - { - result += op + lhsLine + "\n"; - } - } - - return result; - } - std::string TestCounts::diffLines( std::string const & check , std::string const & ref ) { - auto checkLines = splitInLines( replace( check, testName + "/", "" ) ); + auto checkLines = splitInLines( check ); auto refLines = splitInLines( ref ); std::string result; result += findMissing( checkLines, refLines, "+" ); @@ -314,50 +277,52 @@ namespace test return result; } - int reportTestSuite( TestCounts const & testCounts ) - { - int result; - - if ( testCounts.errorCount ) - { - std::cout << "********************************************************************************" << std::endl; - std::cout << "Test suite ended with some failures." << std::endl; - std::cout << "Total checks count: " << testCounts.totalCount << std::endl; - std::cout << "Failed checks count: " << testCounts.errorCount << std::endl; - result = EXIT_FAILURE; - } - else - { - std::cout << "********************************************************************************" << std::endl; - std::cout << "Test suite ended cleanly." << std::endl; - std::cout << "Total checks count: " << testCounts.totalCount << std::endl; - result = EXIT_SUCCESS; - } - - return result; - } + //********************************************************************************************* - void reportSuccess( TestCounts & testCounts - , MessageData const & data ) + TestSuite::TestSuite( std::string const & name ) + : tclog{ std::make_unique< test::LogStreambuf< test::DebugLogStreambufTraits > >( name, std::clog ) } + , tcout{ std::make_unique< test::LogStreambuf< test::InfoLogStreambufTraits > >( name, std::cout ) } + , tcerr{ std::make_unique< test::LogStreambuf< test::ErrorLogStreambufTraits > >( name, std::cerr ) } { - std::cout << "In " << data.function << ":" << data.line << ":" << std::endl; - std::cout << "Success for " << data.target << "( " << data.message << " )" << std::endl; + crg::Logger::setTraceCallback( []( std::string_view, bool )noexcept + { + // Don't log trace + } ); + crg::Logger::setDebugCallback( []( std::string_view msg, bool newLine )noexcept + { + std::clog << msg.data(); + if ( newLine ) + std::clog << "\n"; + } ); + crg::Logger::setInfoCallback( []( std::string_view msg, bool newLine )noexcept + { + std::cout << msg.data(); + if ( newLine ) + std::cout << "\n"; + } ); + crg::Logger::setWarningCallback( []( std::string_view msg, bool newLine )noexcept + { + std::cout << msg.data(); + if ( newLine ) + std::cout << "\n"; + } ); + crg::Logger::setErrorCallback( []( std::string_view msg, bool newLine )noexcept + { + std::cerr << msg.data(); + if ( newLine ) + std::cerr << "\n"; + } ); } - void reportFailure( TestCounts & testCounts - , MessageData const & data ) - { - std::cout << "In " << data.function << ":" << data.line << ":" << std::endl; - std::cout << "Failure for " << data.target << "( " << data.error << "( " << data.message << " ) )" << std::endl; - ++testCounts.errorCount; - } + //********************************************************************************************* - void reportUnhandled( TestCounts & testCounts - , MessageData const & data ) + int testsMain( int argc, char ** argv, std::string_view testSuiteName ) { - std::cout << "In " << data.function << ":" << data.line << ":" << std::endl; - std::cout << "Unhandled Exception for " << data.target << "( " << data.error << "( " << data.message << " ) )" << std::endl; - ++testCounts.errorCount; + std::locale::global( std::locale{ "C" } ); + testing::InitGoogleTest( &argc, argv ); + auto suite = new test::TestSuite{ std::string{ testSuiteName } }; + testing::AddGlobalTestEnvironment( suite ); + return RUN_ALL_TESTS(); } std::string sortLines( std::string const & value ) diff --git a/test/BaseTest.hpp b/test/BaseTest.hpp index b6e9869..ba3a979 100644 --- a/test/BaseTest.hpp +++ b/test/BaseTest.hpp @@ -7,504 +7,113 @@ #include +#include + namespace test { std::string getExecutableDirectory(); struct TestCounts { - void initialise( std::string const & suiteName ); - void cleanup(); + explicit TestCounts( std::string const & testName ) + : testName{ testName } + { + } + std::string diffLines( std::string const & check , std::string const & ref ); - void updateName( std::string const & testName ); - std::string suiteName; std::string testName; - uint32_t testId = 0u; - uint32_t totalCount = 0u; - uint32_t errorCount = 0u; - - private: - std::unique_ptr< std::streambuf > tclog; - std::unique_ptr< std::streambuf > tcout; - std::unique_ptr< std::streambuf > tcerr; }; - struct MessageData + class Exception + : public std::runtime_error { - std::string target; - std::string error; - std::string message; - std::string function; - int line; + public: + using std::runtime_error::runtime_error; }; - inline MessageData makeMessageData( std::string target - , std::string error - , std::string message - , std::string function - , int line ) - { - return MessageData{ std::move( target ) - , std::move( error ) - , std::move( message ) - , std::move( function ) - , line }; - } - - class Exception - : public std::exception + class TestSuite + : public ::testing::Environment { public: - explicit Exception( MessageData data ) - : data{ std::move( data ) } - { - } - - inline const char * what()const noexcept override - { - return data.message.c_str(); - } + TestSuite( std::string const & name ); - MessageData data; + private: + std::unique_ptr< std::streambuf > tclog; + std::unique_ptr< std::streambuf > tcout; + std::unique_ptr< std::streambuf > tcerr; }; - int reportTestSuite( TestCounts const & testCounts ); - void reportSuccess( TestCounts & testCounts, MessageData const & data ); - void reportFailure( TestCounts & testCounts, MessageData const & data ); - void reportUnhandled( TestCounts & testCounts, MessageData const & data ); + int testsMain( int argc, char ** argv, std::string_view testSuiteName ); + std::string sortLines( std::string const & value ); #define testStringify( x )\ #x -#define testConcat2( x, y )\ - testStringify( x ) testStringify( y ) - -#define testConcat3( x, y, z )\ - testConcat2( x, y ) testStringify( z ) - -#define testConcat4( x, y, z, w )\ - testConcat3( x, y, z ) testStringify( w ) - -#define testSuiteBeginEx2( name, testCounts )\ - testCounts.initialise( name );\ - try\ - {\ - -#define testSuiteBeginEx( name, testCounts )\ - int result;\ - {\ - testSuiteBeginEx2( name, testCounts ) - -#define testSuiteBegin( name )\ - int result;\ - {\ - test::TestCounts testCounts;\ - testSuiteBeginEx2( name, testCounts ) - -#define testSuiteEnd()\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.suiteName\ - , "GLOBAL"\ - , exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.suiteName\ - , "GLOBAL"\ - , "Unknown"\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - result = test::reportTestSuite( testCounts );\ - testCounts.cleanup();\ - }\ - return result; +#define nameConcat( X, Y ) nameConcat_( X, Y ) +#define nameConcat_( X, Y ) X ## Y #define testBegin( name )\ - testCounts.updateName( name );\ - auto testName = testCounts.testName;\ - std::cout << "********************************************************************************" << std::endl;\ - std::cout << "TEST: " << testCounts.testName << std::endl;\ - std::cout << "********************************************************************************" << std::endl;\ - try\ - {\ - -#define testEnd()\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "TEST"\ - , exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "TEST"\ - , "Unknown"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } + test::TestCounts testCounts{ name }; -#define failure( x )\ - ++testCounts.totalCount;\ - test::reportFailure( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "FAILURE"\ - , #x\ - , __FUNCTION__\ - , __LINE__ ) ); +#define testEnd() #define require( x )\ try\ {\ - ++testCounts.totalCount;\ if ( !( x ) )\ {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "COND"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) };\ + throw test::Exception{ std::string{ testStringify( x ) } };\ }\ }\ catch ( test::Exception & exc )\ {\ - test::reportFailure( testCounts, exc.data );\ + GTEST_FATAL_FAILURE_( ( std::string{ testStringify( x )" failed." } + exc.what() ).c_str() );\ }\ catch ( ... )\ {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "COND"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) );\ + GTEST_FATAL_FAILURE_( "Unknown unhandled exception." );\ } #define check( x )\ - try\ - {\ - ++testCounts.totalCount;\ - if ( !( x ) )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "REQCOND"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "REQCOND"\ - , std::string{ #x } + " " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "REQCOND"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) );\ - } + EXPECT_TRUE( x ); #define checkEqual( x, y )\ - try\ - {\ - ++testCounts.totalCount;\ - if ( ( x ) != ( y ) )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } - -#define checkEqualStr( x, y )\ - try\ - {\ - ++testCounts.totalCount;\ - if ( ( x ) != ( y ) )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } - -#define checkEqualLines( x, y )\ - try\ - {\ - ++testCounts.totalCount;\ - auto diff = testCounts.diffLines( x, y );\ - if ( !diff.empty() )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )\nDIFF(\n" + diff + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } + EXPECT_EQ( x, y ); #define checkEqualSortedLines( x, y )\ try\ {\ - ++testCounts.totalCount;\ auto diff = testCounts.diffLines( test::sortLines( x ), test::sortLines( y ) );\ if ( !diff.empty() )\ {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )\nDIFF(\n" + diff + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "EQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } - -#define checkNotEqual( x, y )\ - try\ - {\ - ++testCounts.totalCount;\ - if ( ( x ) == ( y ) )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ #x } + " )\nRHS(\n" + std::string{ #y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ - } - -#define checkNotEqualStr( x, y )\ - try\ - {\ - ++testCounts.totalCount;\ - if ( ( x ) != ( y ) )\ - {\ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) };\ + throw test::Exception{ "LHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )\nDIFF(\n" + diff + " )" };\ }\ }\ catch ( test::Exception & exc )\ {\ - test::reportFailure( testCounts, exc.data );\ + GTEST_FATAL_FAILURE_( ( std::string{ #x" failed." } + exc.what() ).c_str() );\ }\ catch ( crg::Exception & exc )\ {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " ) " + exc.what()\ - , __FUNCTION__\ - , __LINE__ ) );\ + GTEST_FATAL_FAILURE_( ( std::string{ #x" failed." } + exc.what() ).c_str() );\ }\ catch ( ... )\ {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "NEQUAL"\ - , "\nLHS(\n" + std::string{ x } + " )\nRHS(\n" + std::string{ y } + " )"\ - , __FUNCTION__\ - , __LINE__ ) );\ + GTEST_FATAL_FAILURE_( "Unknown unhandled exception." );\ } -#define checkThrow( x )\ - try\ - {\ - ++testCounts.totalCount;\ - ( x ); \ - throw test::Exception{ test::makeMessageData( testCounts.testName\ - , "THROW"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) };\ - }\ - catch ( test::Exception & exc )\ - {\ - test::reportFailure( testCounts, exc.data );\ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportSuccess( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "THROW"\ - , std::string{ #x } + " " + std::string{ exc.what() }\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ - {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "THROW"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) );\ - } +#define checkThrow( x, excType )\ + EXPECT_THROW( x, excType ); #define checkNoThrow( x )\ - try\ - {\ - ++testCounts.totalCount;\ - ( x ); \ - }\ - catch ( crg::Exception & exc )\ - {\ - test::reportFailure( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "THROW"\ - , std::string{ #x } + " " + std::string{ exc.what() }\ - , __FUNCTION__\ - , __LINE__ ) );\ - }\ - catch ( ... )\ + EXPECT_NO_THROW( x ); + +#define testSuiteMain()\ + int main( int argc, char ** argv )\ {\ - test::reportUnhandled( testCounts\ - , test::makeMessageData( testCounts.testName\ - , "NOTHROW"\ - , std::string{ #x }\ - , __FUNCTION__\ - , __LINE__ ) );\ + return test::testsMain( argc, argv, CRG_TestSuiteNameString );\ } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aff9089..dd6d171 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,8 @@ enable_testing() +set( GTest_DIR ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/gtest ) +find_package( GTest CONFIG REQUIRED GTest::gtest GTest::gtest_main ) + set( TEST_NAME TestCommon ) set( ${TEST_NAME}_HEADER_FILES @@ -27,6 +30,7 @@ target_sources( ${TEST_NAME} target_link_libraries( ${TEST_NAME} PUBLIC crg::RenderGraph + GTest::gtest ) target_include_directories( ${TEST_NAME} PUBLIC @@ -60,6 +64,11 @@ foreach ( TEST_FILE ${TEST_FILES} ) CXX_STANDARD 20 FOLDER "Tests/${MAIN_PROJECT_NAME}" ) + target_compile_definitions( ${TEST_NAME} + PRIVATE + CRG_TestSuiteName=${TEST_NAME} + CRG_TestSuiteNameString="${TEST_NAME}" + ) target_include_directories( ${TEST_NAME} PRIVATE ${VULKAN_HEADERS_INCLUDE_DIRS} diff --git a/test/Common.cpp b/test/Common.cpp index 37fef25..1ebe083 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include @@ -40,24 +38,15 @@ namespace test return stream; } - void displayPasses( TestCounts const & testCounts - , std::ostream & stream - , crg::RunnableGraph const & value - , crg::dot::Config const & cfg ) - { - crg::dot::displayPasses( stream, value, cfg ); - std::ofstream file{ testCounts.testName + ".dot" }; - crg::dot::displayPasses( file, value, { true, true, true, false } ); - } - void displayTransitions( TestCounts const & testCounts , std::ostream & stream , crg::RunnableGraph const & value - , crg::dot::Config const & cfg ) + , crg::dot::Config cfg ) { + cfg.toRemove = testCounts.testName + "/"; crg::dot::displayTransitions( stream, value, cfg ); - std::ofstream file{ testCounts.testName + "_transitions.dot" }; - crg::dot::displayTransitions( file, value, { true, true, true, false } ); + std::ofstream file{ testCounts.testName + ".dot" }; + crg::dot::displayTransitions( file, value, { true, true, true, false, cfg.toRemove } ); } crg::ImageViewType getViewType( crg::ImageType type @@ -92,6 +81,48 @@ namespace test } } } + + void checkRunnable( TestCounts const & testCounts + , crg::RunnableGraph * runnable + , std::stringstream & stream ) + { + require( runnable ) + test::display( testCounts, stream, *runnable ); + checkNoThrow( runnable->record() ) + checkNoThrow( runnable->run( VkQueue{} ) ) + } + } + + crg::BufferData createBuffer( std::string name ) + { + return crg::BufferData{ std::move( name ) + , crg::BufferCreateFlags::eNone + , 1024 + , ( crg::BufferUsageFlags::eUniformBuffer + | crg::BufferUsageFlags::eStorageBuffer + | crg::BufferUsageFlags::eUniformTexelBuffer + | crg::BufferUsageFlags::eStorageTexelBuffer ) }; + } + + crg::BufferViewData createView( std::string name + , crg::BufferId buffer + , crg::PixelFormat format ) + { + return createView( std::move( name ) + , buffer + , 0u, buffer.data->info.size + , format ); + } + + crg::BufferViewData createView( std::string name + , crg::BufferId buffer + , crg::DeviceSize offset, crg::DeviceSize size + , crg::PixelFormat format ) + { + return crg::BufferViewData{ std::move( name ) + , buffer + , { offset, size } + , format }; } crg::ImageData createImage( std::string name @@ -126,6 +157,22 @@ namespace test , arrayLayers }; } + crg::ImageData createImage3D( std::string name + , crg::PixelFormat format + , uint32_t mipLevels + , uint32_t arrayLayers ) + { + return crg::ImageData{ std::move( name ) + , crg::ImageCreateFlags::eNone + , crg::ImageType::e3D + , format + , { 1024, 1024u, 64u } + , ( crg::ImageUsageFlags::eColorAttachment + | crg::ImageUsageFlags::eSampled ) + , mipLevels + , arrayLayers }; + } + crg::ImageData createImageCube( std::string name , crg::PixelFormat format , uint32_t mipLevels @@ -399,6 +446,12 @@ namespace test ++counter; return VK_SUCCESS; } ); + context.vkCreateBufferView = PFN_vkCreateBufferView( []( VkDevice, const VkBufferViewCreateInfo *, const VkAllocationCallbacks *, VkBufferView * pBuffer ) + { + *pBuffer = VkBufferView( counter.load() ); + ++counter; + return VK_SUCCESS; + } ); context.vkAllocateMemory = PFN_vkAllocateMemory( []( VkDevice, const VkMemoryAllocateInfo *, const VkAllocationCallbacks *, VkDeviceMemory * pMemory ) { *pMemory = VkDeviceMemory( counter.load() ); @@ -484,6 +537,7 @@ namespace test context.vkDestroyDescriptorPool = PFN_vkDestroyDescriptorPool( []( VkDevice, VkDescriptorPool, const VkAllocationCallbacks * ){} ); context.vkFreeDescriptorSets = PFN_vkFreeDescriptorSets( []( VkDevice, VkDescriptorPool, uint32_t, const VkDescriptorSet * ){ return VK_SUCCESS; } ); context.vkDestroyBuffer = PFN_vkDestroyBuffer( []( VkDevice, VkBuffer, const VkAllocationCallbacks * ){} ); + context.vkDestroyBufferView = PFN_vkDestroyBufferView( []( VkDevice, VkBufferView, const VkAllocationCallbacks * ){} ); context.vkFreeMemory = PFN_vkFreeMemory( []( VkDevice, VkDeviceMemory, const VkAllocationCallbacks * ){} ); context.vkDestroyRenderPass = PFN_vkDestroyRenderPass( []( VkDevice, VkRenderPass, const VkAllocationCallbacks * ){} ); context.vkDestroyFramebuffer = PFN_vkDestroyFramebuffer( []( VkDevice, VkFramebuffer, const VkAllocationCallbacks * ){} ); @@ -581,15 +635,12 @@ namespace test return context; } - std::stringstream checkRunnable( TestCounts & testCounts + std::string checkRunnable( TestCounts & testCounts , crg::RunnableGraph * runnable ) { - require( runnable ) - std::stringstream stream; - test::display( testCounts, stream, *runnable ); - checkNoThrow( runnable->record() ) - checkNoThrow( runnable->run( VkQueue{} ) ) - return stream; + std::stringstream result; + checkRunnable( testCounts, runnable, result ); + return result.str(); } void display( TestCounts const & testCounts @@ -616,25 +667,8 @@ namespace test crg::dot::displayTransitions( tmp, value, { false, false, true, false } ); crg::dot::displayTransitions( tmp, value, { false, false, false, true } ); crg::dot::displayTransitions( tmp, value, { false, false, false, false } ); - crg::dot::displayPasses( tmp, value, { true, true, true, true } ); - crg::dot::displayPasses( tmp, value, { true, true, true, false } ); - crg::dot::displayPasses( tmp, value, { true, true, false, true } ); - crg::dot::displayPasses( tmp, value, { true, true, false, false } ); - crg::dot::displayPasses( tmp, value, { true, false, true, true } ); - crg::dot::displayPasses( tmp, value, { true, false, true, false } ); - crg::dot::displayPasses( tmp, value, { true, false, false, true } ); - crg::dot::displayPasses( tmp, value, { true, false, false, false } ); - crg::dot::displayPasses( tmp, value, { false, true, true, true } ); - crg::dot::displayPasses( tmp, value, { false, true, true, false } ); - crg::dot::displayPasses( tmp, value, { false, true, false, true } ); - crg::dot::displayPasses( tmp, value, { false, true, false, false } ); - crg::dot::displayPasses( tmp, value, { false, false, true, true } ); - crg::dot::displayPasses( tmp, value, { false, false, true, false } ); - crg::dot::displayPasses( tmp, value, { false, false, false, true } ); - crg::dot::displayPasses( tmp, value, { false, false, false, false } ); - - displayTransitions( testCounts, tmp, value, { withColours, withIds, withGroups } ); - displayPasses( testCounts, stream, value, { withColours, withIds, withGroups } ); + + displayTransitions( testCounts, stream, value, { withColours, withIds, withGroups } ); } void display( TestCounts const & testCounts @@ -664,7 +698,7 @@ namespace test , runGraph , { crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) - , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer, uint32_t i ){ doRecordInto( ctx, i ); } ) + , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } ) , crg::RunnablePass::GetPassIndexCallback( [index](){ return index; } ) , crg::RunnablePass::IsEnabledCallback( [enabled](){ return enabled; } ) } , std::move( config ) } @@ -687,7 +721,7 @@ namespace test , runGraph , { crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) - , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer, uint32_t i ){ doRecordInto( ctx, i ); } ) + , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } ) , crg::RunnablePass::GetPassIndexCallback( [index](){ return index; } ) } , std::move( config ) } , m_testCounts{ testCounts } @@ -708,7 +742,7 @@ namespace test , runGraph , { crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) - , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer, uint32_t i ){ doRecordInto( ctx, i ); } ) } + , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } ) } , std::move( config ) } , m_testCounts{ testCounts } , m_pipelineStageFlags{ pipelineStageFlags } @@ -726,7 +760,8 @@ namespace test , context , runGraph , { crg::defaultV< crg::RunnablePass::InitialiseCallback > - , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) } + , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) + , crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordTargetsInto( ctx, cb, i ); } ) } , std::move( config ) } , m_testCounts{ testCounts } , m_pipelineStageFlags{ pipelineStageFlags } @@ -735,13 +770,76 @@ namespace test private: void doRecordInto( crg::RecordContext & context + , VkCommandBuffer commandBuffer , uint32_t index ) { - for ( auto & attach : m_pass.images ) + for ( auto & [binding, attach] : m_pass.uniforms ) + { + auto buffer = crg::resolveView( attach->buffer( index ), index ); + context.setAccessState( buffer + , { attach->getAccessMask(), attach->getPipelineStageFlags( m_pipelineStageFlags == crg::PipelineStageFlags::eComputeShader ) } ); + } + for ( auto & [binding, attach] : m_pass.sampled ) + { + auto view = attach.attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); + context.setLayoutState( crg::resolveView( view, index ) + , crg::makeLayoutState( attach.attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + } + for ( auto & [binding, attach] : m_pass.inputs ) + { + if ( attach->isImage() ) + { + auto view = attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); + context.setLayoutState( crg::resolveView( view, index ) + , crg::makeLayoutState( attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + } + else + { + auto buffer = crg::resolveView( attach->buffer( index ), index ); + context.setAccessState( buffer + , { attach->getAccessMask(), attach->getPipelineStageFlags( m_pipelineStageFlags == crg::PipelineStageFlags::eComputeShader ) } ); + } + } + for ( auto & [binding, attach] : m_pass.inouts ) + { + if ( attach->isImage() ) + { + auto view = attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); + context.setLayoutState( crg::resolveView( view, index ) + , crg::makeLayoutState( attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + } + else + { + auto buffer = crg::resolveView( attach->buffer( index ), index ); + context.setAccessState( buffer + , { attach->getAccessMask(), attach->getPipelineStageFlags( m_pipelineStageFlags == crg::PipelineStageFlags::eComputeShader ) } ); + } + } + for ( auto & [binding, attach] : m_pass.outputs ) + { + if ( attach->isImage() ) + { + auto view = attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); + context.setLayoutState( crg::resolveView( view, index ) + , crg::makeLayoutState( attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + } + else + { + auto buffer = crg::resolveView( attach->buffer( index ), index ); + context.setAccessState( buffer + , { attach->getAccessMask(), attach->getPipelineStageFlags( m_pipelineStageFlags == crg::PipelineStageFlags::eComputeShader ) } ); + } + } + for ( auto attach : m_pass.targets ) { - auto view = attach.view( index ); + auto view = attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); context.setLayoutState( crg::resolveView( view, index ) - , crg::makeLayoutState( attach.getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + , crg::makeLayoutState( attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); } m_checkViews( m_testCounts @@ -751,11 +849,46 @@ namespace test , index ); } + void doRecordTargetsInto( crg::RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + for ( auto attach : m_pass.targets ) + { + auto view = attach->view( index ); + context.runImplicitTransition( commandBuffer, index, view ); + context.setLayoutState( crg::resolveView( view, index ) + , crg::makeLayoutState( attach->getImageLayout( m_context.separateDepthStencilLayouts ) ) ); + } + } + test::TestCounts & m_testCounts; crg::PipelineStageFlags m_pipelineStageFlags; CheckViews m_checkViews; }; + class DummyRunnableNoRecord + : public crg::RunnablePass + { + public: + DummyRunnableNoRecord( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph + , crg::PipelineStageFlags pipelineStageFlags + , crg::ru::Config config ) + : crg::RunnablePass{ framePass + , context + , runGraph + , { crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) } + , std::move( config ) } + , m_pipelineStageFlags{ pipelineStageFlags } + { + } + + crg::PipelineStageFlags m_pipelineStageFlags; + }; + crg::RunnablePassPtr createDummy( test::TestCounts & testCounts , crg::FramePass const & framePass , crg::GraphContext & context @@ -828,6 +961,19 @@ namespace test , std::move( config ) ); } + crg::RunnablePassPtr createDummyNoRecord( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph + , crg::PipelineStageFlags pipelineStageFlags + , crg::ru::Config config ) + { + return std::make_unique< DummyRunnableNoRecord >( framePass + , context + , runGraph + , pipelineStageFlags + , std::move( config ) ); + } + void checkDummy( [[maybe_unused]] test::TestCounts & testCounts , [[maybe_unused]] crg::FramePass const & framePass , [[maybe_unused]] crg::RunnableGraph const & graph @@ -836,4 +982,112 @@ namespace test { // Nothing checked yet... } + + template< typename EnumT > + static void condAppendEnumFlag( std::ostream & stream, std::string & sep, EnumT const & v, EnumT const & t, std::string_view s ) + { + if ( checkFlag( v, t ) ) + { + stream << sep << s; + sep = " | "; + } + } +} + +namespace crg +{ + std::ostream & operator<<( std::ostream & stream, AccessFlags const & v ) + { + std::string sep; + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eIndirectCommandRead, "IndirectCommandRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eIndexRead, "IndexRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eVertexAttributeRead, "VertexAttributeRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eUniformRead, "UniformRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eInputAttachmentRead, "InputAttachmentRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eShaderRead, "ShaderRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eShaderWrite, "ShaderWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentRead, "ColorAttachmentRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentWrite, "ColorAttachmentWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eDepthStencilAttachmentRead, "DepthStencilAttachmentRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eDepthStencilAttachmentWrite, "DepthStencilAttachmentWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransferRead, "TransferRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransferWrite, "TransferWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eHostRead, "HostRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eHostWrite, "HostWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eMemoryRead, "MemoryRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eMemoryWrite, "MemoryWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackWrite, "TransformFeedbackWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackCounterRead, "TransformFeedbackCounterRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackCounterWrite, "TransformFeedbackCounterWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eConditionalRenderingRead, "ConditionalRenderingRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentReadNonCoherent, "ColorAttachmentReadNonCoherent" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eAccelerationStructureRead, "AccelerationStructureRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eAccelerationStructureWrite, "AccelerationStructureWrite" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eFragmentDensityMapRead, "FragmentDensityMapRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eFragmentShadingRateAttachmentRead, "FragmentShadingRateAttachmentRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eCommandPreprocessRead, "CommandPreprocessRead" ); + test::condAppendEnumFlag( stream, sep, v, AccessFlags::eCommandPreprocessWrite, "CommandPreprocessWrite" ); + return stream; + } + + std::ostream & operator<<( std::ostream & stream, ImageLayout const & v ) + { + switch ( v ) + { + case ImageLayout::eUndefined: stream << "Undefined"; break; + case ImageLayout::eGeneral: stream << "General"; break; + case ImageLayout::eColorAttachment: stream << "ColorAttachment"; break; + case ImageLayout::eDepthStencilAttachment: stream << "DepthStencilAttachment"; break; + case ImageLayout::eDepthStencilReadOnly: stream << "DepthStencilReadOnly"; break; + case ImageLayout::eShaderReadOnly: stream << "ShaderReadOnly"; break; + case ImageLayout::eTransferSrc: stream << "TransferSrc"; break; + case ImageLayout::eTransferDst: stream << "TransferDst"; break; + case ImageLayout::ePreinitialized: stream << "Preinitialized"; break; + case ImageLayout::eDepthReadOnlyStencilAttachment: stream << "DepthReadOnlyStencilAttachment"; break; + case ImageLayout::eDepthAttachmentStencilReadOnly: stream << "DepthAttachmentStencilReadOnly"; break; + case ImageLayout::eDepthAttachment: stream << "DepthAttachment"; break; + case ImageLayout::eDepthReadOnly: stream << "DepthReadOnly"; break; + case ImageLayout::eStencilAttachment: stream << "StencilAttachment"; break; + case ImageLayout::eStencilReadOnly: stream << "StencilReadOnly"; break; + case ImageLayout::eReadOnly: stream << "ReadOnly"; break; + case ImageLayout::eAttachment: stream << "Attachment"; break; + case ImageLayout::eRenderingLocalRead: stream << "RenderingLocalRead"; break; + case ImageLayout::ePresentSrc: stream << "PresentSrc"; break; + case ImageLayout::eVideoDecodeDst: stream << "VideoDecodeDst"; break; + case ImageLayout::eVideoDecodeSrc: stream << "VideoDecodeSrc"; break; + case ImageLayout::eVideoDecodeDpb: stream << "VideoDecodeDpb"; break; + case ImageLayout::eSharedPresent: stream << "SharedPresent"; break; + case ImageLayout::eFragmentDensityMap: stream << "FragmentDensityMap"; break; + case ImageLayout::eFragmentShadingRateAttachment: stream << "FragmentShadingRateAttachment"; break; + case ImageLayout::eVideoEncodeDst: stream << "VideoEncodeDst"; break; + case ImageLayout::eVideoEncodeSrc: stream << "VideoEncodeSrc"; break; + case ImageLayout::eVideoEncodeDpb: stream << "VideoEncodeDpb"; break; + case ImageLayout::eAttachmentFeedbackLoop: stream << "AttachmentFeedbackLoop"; break; + case ImageLayout::eVideoEncodeQuantizationMap: stream << "VideoEncodeQuantizationMap"; break; + } + return stream; + } + + std::ostream & operator<<( std::ostream & stream, AttachmentLoadOp const & v ) + { + switch ( v ) + { + case AttachmentLoadOp::eLoad: stream << "Load"; break; + case AttachmentLoadOp::eClear: stream << "Clear"; break; + case AttachmentLoadOp::eDontCare: stream << "DontCare"; break; + case AttachmentLoadOp::eNone: stream << "None"; break; + } + return stream; + } + + std::ostream & operator<<( std::ostream & stream, AttachmentStoreOp const & v ) + { + switch ( v ) + { + case AttachmentStoreOp::eStore: stream << "eStore"; break; + case AttachmentStoreOp::eDontCare: stream << "DontCare"; break; + case AttachmentStoreOp::eNone: stream << "None"; break; + } + return stream; + } } diff --git a/test/Common.hpp b/test/Common.hpp index 82e88e0..dde44e0 100644 --- a/test/Common.hpp +++ b/test/Common.hpp @@ -9,6 +9,14 @@ namespace test { + crg::BufferData createBuffer( std::string name ); + crg::BufferViewData createView( std::string name + , crg::BufferId buffer + , crg::PixelFormat format = crg::PixelFormat::eUNDEFINED ); + crg::BufferViewData createView( std::string name + , crg::BufferId buffer + , crg::DeviceSize offset, crg::DeviceSize size + , crg::PixelFormat format = crg::PixelFormat::eUNDEFINED ); crg::ImageData createImage( std::string name , crg::PixelFormat format , uint32_t mipLevels = 1u @@ -17,6 +25,10 @@ namespace test , crg::PixelFormat format , uint32_t mipLevels = 1u , uint32_t arrayLayers = 1u ); + crg::ImageData createImage3D( std::string name + , crg::PixelFormat format + , uint32_t mipLevels = 1u + , uint32_t arrayLayers = 1u ); crg::ImageData createImageCube( std::string name , crg::PixelFormat format , uint32_t mipLevels = 1u @@ -35,10 +47,10 @@ namespace test , uint32_t baseArrayLayer = 0u , uint32_t layerCount = 1u ); crg::GraphContext & getDummyContext(); - std::stringstream checkRunnable( TestCounts & testCounts + std::string checkRunnable( TestCounts & testCounts , crg::RunnableGraph * runnable ); - inline std::stringstream checkRunnable( TestCounts & testCounts + inline std::string checkRunnable( TestCounts & testCounts , crg::RunnableGraphPtr const & runnable ) { return checkRunnable( testCounts, runnable.get() ); @@ -98,9 +110,22 @@ namespace test , crg::RunnableGraph & runGraph , crg::PipelineStageFlags pipelineStageFlags , crg::ru::Config config = {} ); + crg::RunnablePassPtr createDummyNoRecord( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph + , crg::PipelineStageFlags pipelineStageFlags + , crg::ru::Config config = {} ); void checkDummy( test::TestCounts & testCounts , crg::FramePass const & framePass , crg::RunnableGraph const & graph , crg::RecordContext const & context , uint32_t index ); } + +namespace crg +{ + std::ostream & operator<<( std::ostream & stream, AccessFlags const & v ); + std::ostream & operator<<( std::ostream & stream, ImageLayout const & v ); + std::ostream & operator<<( std::ostream & stream, AttachmentLoadOp const & v ); + std::ostream & operator<<( std::ostream & stream, AttachmentStoreOp const & v ); +} diff --git a/test/TestAttachment.cpp b/test/TestAttachment.cpp index c5f969e..d1f9321 100644 --- a/test/TestAttachment.cpp +++ b/test/TestAttachment.cpp @@ -3,14 +3,13 @@ #include #include #include -#include #include namespace { constexpr crg::SamplerDesc defaultSamplerDesc{}; - void testSampledAttachment( test::TestCounts & testCounts ) + TEST( Attachment, SampledAttachment ) { testBegin( "testSampledAttachment" ) crg::ResourceHandler handler; @@ -18,34 +17,76 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addSampledView( view, 1u ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Spl" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == 1u ) - check( attachment.getSamplerDesc() == defaultSamplerDesc ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eShaderReadOnly ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eShaderReadOnly ) + auto tmpAttach1 = crg::Attachment::createDefault( view ); + auto tmpAttach2 = crg::Attachment::createDefault( view ); + tmpAttach2 = std::move( tmpAttach1 ); + tmpAttach1 = tmpAttach2; + auto viewAttach = std::move( tmpAttach2 ); + pass.addInputSampled( viewAttach, 1u ); + require( pass.sampled.size() == 1u ) + auto attachIt = pass.sampled.begin(); + auto const & attachment = attachIt->second; + check( attachment.attach->isImage() ) + check( attachment.attach->isInput() ) + check( !attachment.attach->isOutput() ) + check( !attachment.attach->isClearable() ) + check( !attachment.attach->isTransitionImageView() ) + check( !attachment.attach->isTransferImageView() ) + check( !attachment.attach->imageAttach.isDepthStencilTarget() ) + check( !attachment.attach->imageAttach.isDepthTarget() ) + check( !attachment.attach->imageAttach.isStencilTarget() ) + check( !attachment.attach->imageAttach.isStencilInputTarget() ) + check( !attachment.attach->imageAttach.isStencilOutputTarget() ) + check( attachment.attach->name == pass.getGroupName() + "/" + view.data->name + "/Spl" ) + checkEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment.attach->view() == view ) + check( attachIt->first == 1u ) + check( attachment.sampler == defaultSamplerDesc ) + checkEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly ) + checkEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly ) testEnd() } - void testImplicitColourAttachment( test::TestCounts & testCounts ) + TEST( Attachment, SampledImage ) + { + testBegin( "testSampledImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputSampledImage( view, 1u ); + require( pass.sampled.size() == 1u ) + auto attachIt = pass.sampled.begin(); + auto const & attachment = attachIt->second; + check( attachment.attach->isImage() ) + check( attachment.attach->isInput() ) + check( !attachment.attach->isOutput() ) + check( !attachment.attach->isClearable() ) + check( !attachment.attach->isTransitionImageView() ) + check( !attachment.attach->isTransferImageView() ) + check( !attachment.attach->imageAttach.isDepthStencilTarget() ) + check( !attachment.attach->imageAttach.isDepthTarget() ) + check( !attachment.attach->imageAttach.isStencilTarget() ) + check( !attachment.attach->imageAttach.isStencilInputTarget() ) + check( !attachment.attach->imageAttach.isStencilOutputTarget() ) + check( attachment.attach->name == pass.getGroupName() + "/" + view.data->name + "/Spl" ) + checkEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment.attach->view() == view ) + check( attachIt->first == 1u ) + check( attachment.sampler == defaultSamplerDesc ) + checkEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly ) + checkEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly ) + testEnd() + } + + TEST( Attachment, ImplicitColourAttachment ) { testBegin( "testImplicitColourAttachment" ) crg::ResourceHandler handler; @@ -55,34 +96,35 @@ namespace check( range.baseArrayLayer == 0 ) auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addImplicitColourView( view, crg::ImageLayout::eShaderReadOnly ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Impl" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getSamplerDesc() == defaultSamplerDesc ) - check( attachment.getImageLayout( false ) == attachment.imageAttach.wantedLayout ) - check( attachment.getImageLayout( true ) == attachment.imageAttach.wantedLayout ) + auto viewAttach = crg::Attachment::createDefault( view ); + auto imageLayout = crg::ImageLayout::eShaderReadOnly; + pass.addImplicit( viewAttach, imageLayout ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/Impl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), imageLayout ) + checkEqual( attachment->getImageLayout( true ), imageLayout ) testEnd() } - void testImplicitDepthAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ImplicitDepthAttachment ) { testBegin( "testImplicitDepthAttachment" ) crg::ResourceHandler handler; @@ -90,35 +132,35 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addImplicitDepthView( view, crg::ImageLayout::ePreinitialized ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.hasFlag( crg::ImageAttachment::Flag::Depth ) ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Impl" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getSamplerDesc() == defaultSamplerDesc ) - check( attachment.getImageLayout( false ) == attachment.imageAttach.wantedLayout ) - check( attachment.getImageLayout( true ) == attachment.imageAttach.wantedLayout ) + auto viewAttach = crg::Attachment::createDefault( view ); + auto imageLayout = crg::ImageLayout::ePreinitialized; + pass.addImplicit( viewAttach, imageLayout ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/Impl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), imageLayout ) + checkEqual( attachment->getImageLayout( true ), imageLayout ) testEnd() } - void testImplicitDepthStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ImplicitDepthStencilAttachment ) { testBegin( "testImplicitDepthStencilAttachment" ) crg::ResourceHandler handler; @@ -126,36 +168,35 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addImplicitDepthStencilView( view, crg::ImageLayout::eShaderReadOnly ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.hasFlag( crg::ImageAttachment::Flag::Depth ) ) - check( attachment.imageAttach.hasFlag( crg::ImageAttachment::Flag::Stencil ) ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Impl" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getSamplerDesc() == defaultSamplerDesc ) - check( attachment.getImageLayout( false ) == attachment.imageAttach.wantedLayout ) - check( attachment.getImageLayout( true ) == attachment.imageAttach.wantedLayout ) + auto viewAttach = crg::Attachment::createDefault( view ); + auto imageLayout = crg::ImageLayout::eShaderReadOnly; + pass.addImplicit( viewAttach, imageLayout ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/Impl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), imageLayout ) + checkEqual( attachment->getImageLayout( true ), imageLayout ) testEnd() } - void testInStorageAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InStorageAttachment ) { testBegin( "testInStorageAttachment" ) crg::ResourceHandler handler; @@ -163,33 +204,96 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInputStorageView( view, 1u ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IStr" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == 1u ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eGeneral ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eGeneral ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputStorage( viewAttach, 1u ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IStr" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + check( attachIt->first == 1u ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral ) + testEnd() + } + + TEST( Attachment, InStorageImage ) + { + testBegin( "testInStorageImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputStorageImage( view, 1u ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IStr" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + check( attachIt->first == 1u ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral ) testEnd() } - void testOutStorageAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InStorageBuffer ) + { + testBegin( "testInStorageBuffer" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto view = graph.createView( test::createView( "Test", buffer ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputStorageBuffer( view, 1u ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->isStorageBuffer() ) + check( attachment->bufferAttach.isStorage() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/SB" ) + check( attachment->buffer() == view ) + check( attachIt->first == 1u ) + testEnd() + } + + TEST( Attachment, OutStorageAttachment ) { testBegin( "testOutStorageAttachment" ) crg::ResourceHandler handler; @@ -197,33 +301,34 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addOutputStorageView( view, 1u ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/OStr" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == 1u ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eGeneral ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eGeneral ) + pass.addOutputStorageImage( view, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/OStr" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + check( attachIt->first == 1u ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral ) testEnd() } - void testClearOutStorageAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ClearOutStorageAttachment ) { testBegin( "testClearOutStorageAttachment" ) crg::ResourceHandler handler; @@ -231,33 +336,34 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addClearableOutputStorageView( view, 1u ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/COStr" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == 1u ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eGeneral ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eGeneral ) + pass.addClearableOutputStorageImage( view, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/COStr" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + check( attachIt->first == 1u ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral ) testEnd() } - void testInOutStorageAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutStorageAttachment ) { testBegin( "testInOutStorageAttachment" ) crg::ResourceHandler handler; @@ -265,33 +371,35 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInOutStorageView( view, 1u ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOStr" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == 1u ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eGeneral ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eGeneral ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutStorage( viewAttach, 1u ); + require( pass.inouts.size() == 1u ) + auto attachIt = pass.inouts.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IOStr" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + check( attachIt->first == 1u ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral ) testEnd() } - void testInTransferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InTransferAttachment ) { testBegin( "testInTransferAttachment" ) crg::ResourceHandler handler; @@ -299,33 +407,92 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addTransferInputView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/It" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eTransferSrc ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eTransferSrc ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputTransfer( viewAttach ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ITrf" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferSrc ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferSrc ) testEnd() } - void testOutTransferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InTransferImage ) + { + testBegin( "testInTransferImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputTransferImage( view ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ITrf" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferSrc ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferSrc ) + testEnd() + } + + TEST( Attachment, InTransferBuffer ) + { + testBegin( "testInTransferBuffer" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto view = graph.createView( test::createView( "Test", buffer ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputTransferBuffer( view ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->isTransferBuffer() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ITrf" ) + check( attachment->buffer() == view ) + testEnd() + } + + TEST( Attachment, OutTransferAttachment ) { testBegin( "testOutTransferAttachment" ) crg::ResourceHandler handler; @@ -333,33 +500,33 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addTransferOutputView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Ot" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eTransferDst ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eTransferDst ) + pass.addOutputTransferImage( view ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/OT" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferDst ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferDst ) testEnd() } - void testInOutTransferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutTransferAttachment ) { testBegin( "testInOutTransferAttachment" ) crg::ResourceHandler handler; @@ -367,33 +534,34 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addTransferInOutView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isTransitionView() ) - check( attachment.isTransferView() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOt" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.binding == crg::InvalidBindingId ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eTransferDst ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eTransferDst ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutTransfer( viewAttach ); + require( pass.inouts.size() == 1u ) + auto attachIt = pass.inouts.begin(); + auto const & attachment = attachIt->second; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isTransitionImageView() ) + check( attachment->isTransferImageView() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IOTrf" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferDst ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferDst ) testEnd() } - void testInColourAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InColourAttachment ) { testBegin( "testInColourAttachment" ) crg::ResourceHandler handler; @@ -401,37 +569,76 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInputColourView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Ic" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputColourTarget( viewAttach ); + require( pass.targets.size() == 1u ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRcl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment ) + testEnd() + } + + TEST( Attachment, InColourImage ) + { + testBegin( "testInColourImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputColourTargetImage( view ); + require( pass.targets.size() == 1u ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRcl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment ) testEnd() } - void testOutColourAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutColourAttachment ) { testBegin( "testOutColourAttachment" ) crg::ResourceHandler handler; @@ -439,37 +646,37 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addOutputColourView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Oc" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eClear ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment ) + pass.addOutputColourTarget( view ); + require( pass.targets.size() == 1u ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ORcl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment ) testEnd() } - void testInOutColourAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutColourAttachment ) { testBegin( "testInOutColourAttachment" ) crg::ResourceHandler handler; @@ -477,37 +684,38 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInOutColourView( view ); - require( pass.images.size() == 1u ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( attachment.isColourAttach() ) - check( attachment.isColourInOutAttach() ) - check( attachment.isColourInputAttach() ) - check( attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOc" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutColourTarget( viewAttach ); + require( pass.targets.size() == 1u ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( attachment->isColourImageTarget() ) + check( attachment->isColourInOutImageTarget() ) + check( attachment->isColourInputImageTarget() ) + check( attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IORcl" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment ) testEnd() } - void testInDepthAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InDepthAttachment ) { testBegin( "testInDepthAttachment" ) crg::ResourceHandler handler; @@ -515,37 +723,76 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInputDepthView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Id" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilReadOnly ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthReadOnly ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputDepthTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRdp" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthReadOnly ) + testEnd() + } + + TEST( Attachment, InDepthImage ) + { + testBegin( "testInDepthImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputDepthTargetImage( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRdp" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthReadOnly ) testEnd() } - void testOutDepthAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutDepthAttachment ) { testBegin( "testOutDepthAttachment" ) crg::ResourceHandler handler; @@ -553,37 +800,37 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addOutputDepthView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Od" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eClear ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthAttachment ) + pass.addOutputDepthTarget( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ORdp" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthAttachment ) testEnd() } - void testInOutDepthAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutDepthAttachment ) { testBegin( "testInOutDepthAttachment" ) crg::ResourceHandler handler; @@ -591,37 +838,38 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInOutDepthView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOd" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthAttachment ) - check( attachment.view() == view ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutDepthTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( !attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IORdp" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthAttachment ) + check( attachment->view() == view ) testEnd() } - void testInDepthStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InDepthStencilAttachment ) { testBegin( "testInDepthStencilAttachment" ) crg::ResourceHandler handler; @@ -629,37 +877,76 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInputDepthStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Ids" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilReadOnly ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthStencilReadOnly ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputDepthStencilTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRds" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilReadOnly ) + testEnd() + } + + TEST( Attachment, InDepthStencilImage ) + { + testBegin( "testInDepthStencilImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputDepthStencilTargetImage( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRds" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilReadOnly ) testEnd() } - void testOutDepthStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutDepthStencilAttachment ) { testBegin( "testOutDepthStencilAttachment" ) crg::ResourceHandler handler; @@ -667,37 +954,37 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addOutputDepthStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Ods" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eClear ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eClear ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthStencilAttachment ) + pass.addOutputDepthStencilTarget( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ORds" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eClear ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilAttachment ) testEnd() } - void testInOutDepthStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutDepthStencilAttachment ) { testBegin( "testInOutDepthStencilAttachment" ) crg::ResourceHandler handler; @@ -705,37 +992,38 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInOutDepthStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( attachment.imageAttach.isDepthStencilAttach() ) - check( attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( attachment.imageAttach.isStencilInputAttach() ) - check( attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOds" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eDepthStencilAttachment ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutDepthStencilTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( attachment->imageAttach.isDepthStencilTarget() ) + check( attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IORds" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilAttachment ) testEnd() } - void testInStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InStencilAttachment ) { testBegin( "testInStencilAttachment" ) crg::ResourceHandler handler; @@ -743,37 +1031,76 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eS8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInputStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Is" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilReadOnly ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eStencilReadOnly ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInputStencilTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRst" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilReadOnly ) testEnd() } - void testOutStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InStencilImage ) + { + testBegin( "testInStencilImage" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eS8_UINT ) ); + auto view = graph.createView( test::createView( "Test", image ) ); + crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); + pass.addInputStencilTargetImage( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( !attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IRst" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilReadOnly ) + testEnd() + } + + TEST( Attachment, OutStencilAttachment ) { testBegin( "testOutStencilAttachment" ) crg::ResourceHandler handler; @@ -781,37 +1108,37 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eS8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addOutputStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/Os" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eClear ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eStencilAttachment ) + pass.addOutputStencilTarget( view ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( !attachment->imageAttach.isStencilInputTarget() ) + check( attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/ORst" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eClear ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilAttachment ) testEnd() } - void testInOutStencilAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutStencilAttachment ) { testBegin( "testInOutStencilAttachment" ) crg::ResourceHandler handler; @@ -819,37 +1146,38 @@ namespace auto image = graph.createImage( test::createImage( "Test", crg::PixelFormat::eS8_UINT ) ); auto view = graph.createView( test::createView( "Test", image ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - pass.addInOutStencilView( view ); - require( !pass.images.empty() ) - auto const & attachment = pass.images[0]; - check( attachment.isImage() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isClearable() ) - check( !attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( !attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( attachment.imageAttach.isStencilAttach() ) - check( attachment.imageAttach.isStencilInputAttach() ) - check( attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.name == pass.getGroupName() + "/" + view.data->name + "/IOs" ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eDontCare ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eDontCare ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eDepthStencilAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eStencilAttachment ) + auto viewAttach = crg::Attachment::createDefault( view ); + pass.addInOutStencilTarget( viewAttach ); + require( !pass.targets.empty() ) + auto const & attachment = pass.targets[0]; + check( attachment->isImage() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isClearable() ) + check( !attachment->isColourImageTarget() ) + check( !attachment->isColourInOutImageTarget() ) + check( !attachment->isColourInputImageTarget() ) + check( !attachment->isColourOutputImageTarget() ) + check( !attachment->isTransitionImageView() ) + check( !attachment->isTransferImageView() ) + check( !attachment->imageAttach.isColourTarget() ) + check( !attachment->imageAttach.isDepthStencilTarget() ) + check( !attachment->imageAttach.isDepthTarget() ) + check( attachment->imageAttach.isStencilTarget() ) + check( attachment->imageAttach.isStencilInputTarget() ) + check( attachment->imageAttach.isStencilOutputTarget() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + view.data->name + "/IORst" ) + checkEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare ) + checkEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare ) + checkEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) + check( attachment->view() == view ) + checkEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment ) + checkEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilAttachment ) testEnd() } - void testImageAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ImageAttachment ) { testBegin( "testImageAttachment" ) crg::ResourceHandler handler; @@ -861,467 +1189,509 @@ namespace check( !attachment.isInput() ) check( !attachment.isOutput() ) check( !attachment.isClearable() ) - check( attachment.isColourAttach() ) - check( !attachment.isColourInOutAttach() ) - check( !attachment.isColourInputAttach() ) - check( !attachment.isColourOutputAttach() ) - check( !attachment.isTransitionView() ) - check( !attachment.isTransferView() ) - check( attachment.imageAttach.isColourAttach() ) - check( !attachment.imageAttach.isDepthStencilAttach() ) - check( !attachment.imageAttach.isDepthAttach() ) - check( !attachment.imageAttach.isStencilAttach() ) - check( !attachment.imageAttach.isStencilInputAttach() ) - check( !attachment.imageAttach.isStencilOutputAttach() ) - check( attachment.getLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStoreOp() == crg::AttachmentStoreOp::eStore ) - check( attachment.getStencilLoadOp() == crg::AttachmentLoadOp::eLoad ) - check( attachment.getStencilStoreOp() == crg::AttachmentStoreOp::eStore ) + check( attachment.isColourImageTarget() ) + check( !attachment.isColourInOutImageTarget() ) + check( !attachment.isColourInputImageTarget() ) + check( !attachment.isColourOutputImageTarget() ) + check( !attachment.isTransitionImageView() ) + check( !attachment.isTransferImageView() ) + check( attachment.imageAttach.isColourTarget() ) + check( !attachment.imageAttach.isDepthStencilTarget() ) + check( !attachment.imageAttach.isDepthTarget() ) + check( !attachment.imageAttach.isStencilTarget() ) + check( !attachment.imageAttach.isStencilInputTarget() ) + check( !attachment.imageAttach.isStencilOutputTarget() ) + checkEqual( attachment.getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment.getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment.getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment.getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) check( attachment.view() == view ) - check( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment ) - check( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment ) + checkEqual( attachment.getImageLayout( false ), crg::ImageLayout::eColorAttachment ) + checkEqual( attachment.getImageLayout( true ), crg::ImageLayout::eColorAttachment ) testEnd() } - void testImplicitBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ImplicitBufferAttachment ) { testBegin( "testImplicitBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addImplicitBuffer( buffer, 0u, VK_WHOLE_SIZE, {} ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/ImplB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + crg::AccessState accessState{}; + pass.addImplicit( bufferAttach, accessState ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + checkEqual( getSize( buffer ), 1024u ) + checkEqual( getSize( bufferv ), 1024u ) + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/Impl" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) + checkEqual( attachment->getAccessMask(), accessState.access ) + checkEqual( attachment->getPipelineStageFlags( true ), accessState.pipelineStage ) testEnd() } - void testUniformBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, UniformBufferAttachment ) { testBegin( "testUniformBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addUniformBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/UB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + pass.addInputUniformBuffer( bufferv, 1u ); + require( pass.uniforms.size() == 1u ) + auto attachIt = pass.uniforms.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/UB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInputStorageBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InputStorageBufferAttachment ) { testBegin( "testInputStorageBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/ISB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInputStorage( bufferAttach, 1u ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/IStr" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testOutputStorageBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutputStorageBufferAttachment ) { testBegin( "testOutputStorageBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/OSB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + pass.addOutputStorageBuffer( bufferv, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/OSB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testClearableOutputStorageBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ClearableOutputStorageBufferAttachment ) { testBegin( "testClearableOutputStorageBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addClearableOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/OSB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + pass.addClearableOutputStorageBuffer( bufferv, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/OSB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInOutStorageBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutStorageBufferAttachment ) { testBegin( "testInOutStorageBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addInOutStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/IOSB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInOutStorage( bufferAttach, 1u ); + require( pass.inouts.size() == 1u ) + auto attachIt = pass.inouts.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/IOStr" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testImplicitBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ImplicitBufferViewAttachment ) { testBegin( "testImplicitBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addImplicitBufferView( buffer, view, 0u, VK_WHOLE_SIZE, {} ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( attachment.isTransitionBuffer() ) - check( attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/ImplBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addImplicit( bufferAttach, crg::AccessState{} ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( attachment->isTransitionBuffer() ) + check( attachment->isTransitionBufferView() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/Impl" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testUniformBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, UniformBufferViewAttachment ) { testBegin( "testUniformBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addUniformBufferView( buffer, view, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( attachment.isUniformBuffer() ) - check( attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/UBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + pass.addInputUniformBuffer( bufferv, 1u ); + require( !pass.uniforms.empty() ) + auto attachIt = pass.uniforms.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( attachment->isUniformBuffer() ) + check( attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/UB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInputStorageBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InputStorageBufferViewAttachment ) { testBegin( "testInputStorageBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addInputStorageBufferView( buffer, view, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/ISBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInputStorage( bufferAttach, 1u ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/IStr" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testOutputStorageBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutputStorageBufferViewAttachment ) { testBegin( "testOutputStorageBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addOutputStorageBufferView( buffer, view, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/OSBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + pass.addOutputStorageBuffer( bufferv, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/OSB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testClearableOutputStorageBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, ClearableOutputStorageBufferViewAttachment ) { testBegin( "testClearableOutputStorageBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addClearableOutputStorageBufferView( buffer, view, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/OSBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + pass.addClearableOutputStorageBuffer( bufferv, 1u ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/OSB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInOutStorageBufferViewAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutStorageBufferViewAttachment ) { testBegin( "testInOutStorageBufferViewAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto view = VkBufferView( 2 ); - pass.addInOutStorageBufferView( buffer, view, 0u, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( attachment.isBufferView() ) - check( !attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( attachment.isStorageBuffer() ) - check( attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/IOSBV" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.view == view ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInOutStorage( bufferAttach, 1u ); + require( pass.inouts.size() == 1u ) + auto attachIt = pass.inouts.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( attachment->isBufferView() ) + check( !attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( attachment->isStorageBuffer() ) + check( attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + check( attachIt->first == 1u ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/IOStr" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInputTransferBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InputTransferBufferAttachment ) { testBegin( "testInputTransferBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addTransferInputBuffer( buffer, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( !attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/ITB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInputTransfer( bufferAttach ); + require( pass.inputs.size() == 1u ) + auto attachIt = pass.inputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( !attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/ITrf" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testOutputTransferBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, OutputTransferBufferAttachment ) { testBegin( "testOutputTransferBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addTransferOutputBuffer( buffer, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( !attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/OTB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + pass.addOutputTransferBuffer( bufferv ); + require( pass.outputs.size() == 1u ) + auto attachIt = pass.outputs.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( !attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/OTB" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testInOutTransferBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, InOutTransferBufferAttachment ) { testBegin( "testInOutTransferBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; crg::FramePass & pass = graph.createPass( "test", crg::RunnablePassCreator{} ); - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - pass.addTransferInOutBuffer( buffer, 0u, VK_WHOLE_SIZE ); - require( !pass.buffers.empty() ) - auto const & attachment = pass.buffers[0]; - check( attachment.isBuffer() ) - check( attachment.isInput() ) - check( attachment.isOutput() ) - check( !attachment.isBufferView() ) - check( attachment.isTransferBuffer() ) - check( !attachment.isClearableBuffer() ) - check( !attachment.isStorageBuffer() ) - check( !attachment.isStorageBufferView() ) - check( !attachment.isUniformBuffer() ) - check( !attachment.isUniformBufferView() ) - check( !attachment.isTransitionBuffer() ) - check( !attachment.isTransitionBufferView() ) - check( attachment.name == pass.getGroupName() + "/" + buffer.name + "/IOTB" ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + auto bufferAttach = crg::Attachment::createDefault( bufferv ); + pass.addInOutTransfer( bufferAttach ); + require( pass.inouts.size() == 1u ) + auto attachIt = pass.inouts.begin(); + auto const & attachment = attachIt->second; + check( attachment->isBuffer() ) + check( attachment->isInput() ) + check( attachment->isOutput() ) + check( !attachment->isBufferView() ) + check( attachment->isTransferBuffer() ) + check( !attachment->isClearableBuffer() ) + check( !attachment->isStorageBuffer() ) + check( !attachment->isStorageBufferView() ) + check( !attachment->isUniformBuffer() ) + check( !attachment->isUniformBufferView() ) + check( !attachment->isTransitionBuffer() ) + check( !attachment->isTransitionBufferView() ) + checkEqual( attachment->name, pass.getGroupName() + "/" + buffer.data->name + "/IOTrf" ) + check( attachment->buffer() == bufferv ) + check( attachment->bufferAttach.buffer() == bufferv ) testEnd() } - void testBufferAttachment( test::TestCounts & testCounts ) + TEST( Attachment, BufferAttachment ) { testBegin( "testBufferAttachment" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; - crg::Buffer buffer{ VkBuffer( 1 ), "buffer" }; - auto const attachment = crg::Attachment::createDefault( buffer ); + auto buffer = graph.createBuffer( test::createBuffer( "Test" ) ); + auto bufferv = graph.createView( test::createView( "Test", buffer ) ); + auto attachment = crg::Attachment::createDefault( bufferv ); check( attachment.isBuffer() ) check( !attachment.isInput() ) check( !attachment.isOutput() ) @@ -1334,54 +1704,132 @@ namespace check( !attachment.isUniformBufferView() ) check( !attachment.isTransitionBuffer() ) check( !attachment.isTransitionBufferView() ) - check( attachment.buffer() == buffer.buffer() ) - check( attachment.bufferAttach.buffer == buffer ) + check( attachment.buffer() == bufferv ) + check( attachment.bufferAttach.buffer() == bufferv ) testEnd() } -} -int main( int argc, char ** argv ) -{ - testSuiteBegin( "TestAttachment" ) - testSampledAttachment( testCounts ); - testImplicitColourAttachment( testCounts ); - testImplicitDepthAttachment( testCounts ); - testImplicitDepthStencilAttachment( testCounts ); - testInStorageAttachment( testCounts ); - testOutStorageAttachment( testCounts ); - testClearOutStorageAttachment( testCounts ); - testInOutStorageAttachment( testCounts ); - testInTransferAttachment( testCounts ); - testOutTransferAttachment( testCounts ); - testInOutTransferAttachment( testCounts ); - testInColourAttachment( testCounts ); - testOutColourAttachment( testCounts ); - testInOutColourAttachment( testCounts ); - testInDepthAttachment( testCounts ); - testOutDepthAttachment( testCounts ); - testInOutDepthAttachment( testCounts ); - testInDepthStencilAttachment( testCounts ); - testOutDepthStencilAttachment( testCounts ); - testInOutDepthStencilAttachment( testCounts ); - testInStencilAttachment( testCounts ); - testOutStencilAttachment( testCounts ); - testInOutStencilAttachment( testCounts ); - testImageAttachment( testCounts ); - testImplicitBufferAttachment( testCounts ); - testUniformBufferAttachment( testCounts ); - testInputStorageBufferAttachment( testCounts ); - testOutputStorageBufferAttachment( testCounts ); - testClearableOutputStorageBufferAttachment( testCounts ); - testInOutStorageBufferAttachment( testCounts ); - testImplicitBufferViewAttachment( testCounts ); - testUniformBufferViewAttachment( testCounts ); - testInputStorageBufferViewAttachment( testCounts ); - testOutputStorageBufferViewAttachment( testCounts ); - testClearableOutputStorageBufferViewAttachment( testCounts ); - testInOutStorageBufferViewAttachment( testCounts ); - testInputTransferBufferAttachment( testCounts ); - testOutputTransferBufferAttachment( testCounts ); - testInOutTransferBufferAttachment( testCounts ); - testBufferAttachment( testCounts ); - testSuiteEnd() + TEST( Attachment, AttachmentMerge ) + { + testBegin( "testAttachmentMerge" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer, 0u, 512u ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer, 512u, 512u ) ); + auto image = graph.createImage( test::createImage( "image1", crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u, 2u ) ); + auto image1v = graph.createView( test::createView( "image1v", image, 0u, 1u, 0u, 1u ) ); + auto image2v = graph.createView( test::createView( "image2v", image, 1u, 1u, 1u, 1u ) ); + { + // Empty attachment list + check( graph.mergeAttachments( {} ) == nullptr ) + } + { + // Single buffer attachment in list + auto attachment = crg::Attachment::createDefault( buffer1v ); + checkThrow( attachment.getSource( 1u ), crg::Exception ); + check( attachment.getSource( 0u ) == &attachment ); + check( graph.mergeAttachments( { &attachment } ) == &attachment ); + } + { + // Single image attachment in list + auto attachment = crg::Attachment::createDefault( image1v ); + check( graph.mergeAttachments( { &attachment } ) == &attachment ); + } + { + // Mixed attachments in list + auto attachment1 = crg::Attachment::createDefault( image1v ); + auto attachment2 = crg::Attachment::createDefault( buffer1v ); + checkThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception ); + } + { + // Empty image attachments in list + auto attachment1 = crg::Attachment::createDefault( image1v ); + attachment1.imageAttach.views.clear(); + auto attachment2 = crg::Attachment::createDefault( image2v ); + attachment2.imageAttach.views.clear(); + checkThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception ); + } + { + // Empty buffer attachments in list + auto attachment1 = crg::Attachment::createDefault( buffer1v ); + attachment1.bufferAttach.buffers.clear(); + auto attachment2 = crg::Attachment::createDefault( buffer2v ); + attachment2.bufferAttach.buffers.clear(); + checkThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception ); + } + { + // Image attachments with different pass count + auto attachment1 = crg::Attachment::createDefault( image1v ); + auto attachment2 = crg::Attachment::createDefault( image2v ); + attachment2.imageAttach.views.clear(); + checkThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception ); + } + { + // Buffer attachments with different pass count + auto attachment1 = crg::Attachment::createDefault( buffer1v ); + auto attachment2 = crg::Attachment::createDefault( buffer2v ); + attachment2.bufferAttach.buffers.clear(); + checkThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception ); + } + { + // Image attachments + auto attachment1 = crg::Attachment::createDefault( image1v ); + auto attachment2 = crg::Attachment::createDefault( image2v ); + checkNoThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ) ); + auto & attachment = *graph.mergeAttachments( { &attachment1, &attachment2 } ); + check( attachment.isImage() ) + check( !attachment.isInput() ) + check( !attachment.isOutput() ) + check( !attachment.isClearable() ) + check( attachment.isColourImageTarget() ) + check( !attachment.isColourInOutImageTarget() ) + check( !attachment.isColourInputImageTarget() ) + check( !attachment.isColourOutputImageTarget() ) + check( !attachment.isTransitionImageView() ) + check( !attachment.isTransferImageView() ) + check( attachment.imageAttach.isColourTarget() ) + check( !attachment.imageAttach.isDepthStencilTarget() ) + check( !attachment.imageAttach.isDepthTarget() ) + check( !attachment.imageAttach.isStencilTarget() ) + check( !attachment.imageAttach.isStencilInputTarget() ) + check( !attachment.imageAttach.isStencilOutputTarget() ) + checkEqual( attachment.getLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment.getStoreOp(), crg::AttachmentStoreOp::eStore ) + checkEqual( attachment.getStencilLoadOp(), crg::AttachmentLoadOp::eLoad ) + checkEqual( attachment.getStencilStoreOp(), crg::AttachmentStoreOp::eStore ) + check( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment ) + check( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment ) + check( attachment.pass == nullptr ) + check( attachment.view().data->source.size() == 2u ) + check( attachment.view().data->source[0] == image1v ) + check( attachment.view().data->source[1] == image2v ) + } + { + // Buffer attachments + auto attachment1 = crg::Attachment::createDefault( buffer1v ); + auto attachment2 = crg::Attachment::createDefault( buffer2v ); + checkNoThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ) ); + auto & attachment = *graph.mergeAttachments( { &attachment1, &attachment2 } ); + check( attachment.isBuffer() ) + check( !attachment.isInput() ) + check( !attachment.isOutput() ) + check( !attachment.isBufferView() ) + check( !attachment.isTransferBuffer() ) + check( !attachment.isClearableBuffer() ) + check( !attachment.isStorageBuffer() ) + check( !attachment.isStorageBufferView() ) + check( !attachment.isUniformBuffer() ) + check( !attachment.isUniformBufferView() ) + check( !attachment.isTransitionBuffer() ) + check( !attachment.isTransitionBufferView() ) + check( attachment.pass == nullptr ) + check( attachment.buffer().data->source.size() == 2u ) + check( attachment.buffer().data->source[0] == buffer1v ) + check( attachment.buffer().data->source[1] == buffer2v ) + } + testEnd() + } } + +testSuiteMain() diff --git a/test/TestBases.cpp b/test/TestBases.cpp index d5cc721..51b6276 100644 --- a/test/TestBases.cpp +++ b/test/TestBases.cpp @@ -18,789 +18,842 @@ namespace { return test::getDummyContext(); } +} - void testBaseFuncs( test::TestCounts & testCounts ) - { - testBegin( "testBaseFuncs" ) - crg::ResourceHandler handler; - auto image = handler.createImageId( test::createImage( "image", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); - auto view = handler.createViewId( test::createView( "view", image, crg::PixelFormat::eR16G16B16A16_SFLOAT, 4u, 2u, 2u, 3u ) ); - getMipExtent( view ); - auto type = getImageType( image ); - check( getImageType( view ) == type ) - check( getImageViewType( view ) == view.data->info.viewType ) - check( getImageCreateFlags( view ) == getImageCreateFlags( image ) ) - check( getMipLevels( image ) == 8u ) - check( getMipLevels( view ) == 2u ) - check( getArrayLayers( image ) == 6u ) - check( getArrayLayers( view ) == 3u ) - check( crg::getAccessMask( crg::ImageLayout::ePresentSrc ) == crg::AccessFlags::eMemoryRead ) - check( crg::getAccessMask( crg::ImageLayout::eSharedPresent ) == crg::AccessFlags::eMemoryRead ) - check( crg::getAccessMask( crg::ImageLayout::eColorAttachment ) == crg::AccessFlags::eColorAttachmentWrite ) - check( crg::getAccessMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::AccessFlags::eDepthStencilAttachmentWrite ) - check( crg::getAccessMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::AccessFlags::eDepthStencilAttachmentRead ) - check( crg::getAccessMask( crg::ImageLayout::eShaderReadOnly ) == crg::AccessFlags::eShaderRead ) - check( crg::getAccessMask( crg::ImageLayout::eTransferSrc ) == crg::AccessFlags::eTransferRead ) - check( crg::getAccessMask( crg::ImageLayout::eTransferDst ) == crg::AccessFlags::eTransferWrite ) - check( crg::getAccessMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) ) - check( crg::getAccessMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) ) +TEST( Bases, BaseFuncs ) +{ + testBegin( "testBaseFuncs" ) + crg::ResourceHandler handler; + auto image = handler.createImageId( test::createImage( "image", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); + auto view = handler.createViewId( test::createView( "view", image, crg::PixelFormat::eR16G16B16A16_SFLOAT, 4u, 2u, 2u, 3u ) ); + getMipExtent( view ); + auto type = getImageType( image ); + check( getImageType( view ) == type ) + check( getImageViewType( view ) == view.data->info.viewType ) + check( getImageCreateFlags( view ) == getImageCreateFlags( image ) ) + check( getMipLevels( image ) == 8u ) + check( getMipLevels( view ) == 2u ) + check( getArrayLayers( image ) == 6u ) + check( getArrayLayers( view ) == 3u ) + check( crg::getAccessMask( crg::ImageLayout::ePresentSrc ) == crg::AccessFlags::eMemoryRead ) + check( crg::getAccessMask( crg::ImageLayout::eSharedPresent ) == crg::AccessFlags::eMemoryRead ) + check( crg::getAccessMask( crg::ImageLayout::eColorAttachment ) == crg::AccessFlags::eColorAttachmentWrite ) + check( crg::getAccessMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::AccessFlags::eDepthStencilAttachmentWrite ) + check( crg::getAccessMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::AccessFlags::eDepthStencilAttachmentRead ) + check( crg::getAccessMask( crg::ImageLayout::eShaderReadOnly ) == crg::AccessFlags::eShaderRead ) + check( crg::getAccessMask( crg::ImageLayout::eTransferSrc ) == crg::AccessFlags::eTransferRead ) + check( crg::getAccessMask( crg::ImageLayout::eTransferDst ) == crg::AccessFlags::eTransferWrite ) + check( crg::getAccessMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) ) + check( crg::getAccessMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) ) #ifdef VK_NV_shading_rate_image - check( crg::getAccessMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::AccessFlags::eFragmentShadingRateAttachmentRead ) - check( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShadingRateAttachment ).access == crg::AccessFlags::eFragmentShadingRateAttachmentRead ) - check( crg::getStageMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::PipelineStageFlags::eFragmentShadingRateAttachment ) + check( crg::getAccessMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::AccessFlags::eFragmentShadingRateAttachmentRead ) + check( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShadingRateAttachment ).access == crg::AccessFlags::eFragmentShadingRateAttachmentRead ) + check( crg::getStageMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::PipelineStageFlags::eFragmentShadingRateAttachment ) #endif #ifdef VK_EXT_fragment_density_map - check( crg::getAccessMask( crg::ImageLayout::eFragmentDensityMap ) == crg::AccessFlags::eFragmentDensityMapRead ) - check( crg::getStageMask( crg::ImageLayout::eFragmentDensityMap ) == crg::PipelineStageFlags::eFragmentShader ) + check( crg::getAccessMask( crg::ImageLayout::eFragmentDensityMap ) == crg::AccessFlags::eFragmentDensityMapRead ) + check( crg::getStageMask( crg::ImageLayout::eFragmentDensityMap ) == crg::PipelineStageFlags::eFragmentShader ) #endif - check( crg::getPipelineState( crg::PipelineStageFlags::eBottomOfPipe ).access == crg::AccessFlags::eMemoryRead ) - check( crg::getPipelineState( crg::PipelineStageFlags::eColorAttachmentOutput ).access == ( crg::AccessFlags::eColorAttachmentWrite | crg::AccessFlags::eColorAttachmentRead ) ) - check( crg::getPipelineState( crg::PipelineStageFlags::eLateFragmentTests ).access == ( crg::AccessFlags::eDepthStencilAttachmentWrite | crg::AccessFlags::eDepthStencilAttachmentRead ) ) - check( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShader ).access == crg::AccessFlags::eShaderRead ) - check( crg::getPipelineState( crg::PipelineStageFlags::eTransfer ).access == ( crg::AccessFlags::eTransferRead | crg::AccessFlags::eTransferWrite ) ) - check( crg::getPipelineState( crg::PipelineStageFlags::eComputeShader ).access == crg::AccessFlags::eShaderRead ) - - check( crg::getStageMask( crg::ImageLayout::eUndefined ) == crg::PipelineStageFlags::eHost ) - check( crg::getStageMask( crg::ImageLayout::eGeneral ) == crg::PipelineStageFlags::eBottomOfPipe ) - check( crg::getStageMask( crg::ImageLayout::ePresentSrc ) == crg::PipelineStageFlags::eBottomOfPipe ) - check( crg::getStageMask( crg::ImageLayout::eSharedPresent ) == crg::PipelineStageFlags::eBottomOfPipe ) - check( crg::getStageMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests ) - check( crg::getStageMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests ) - check( crg::getStageMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests ) - check( crg::getStageMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests ) - check( crg::getStageMask( crg::ImageLayout::eColorAttachment ) == crg::PipelineStageFlags::eColorAttachmentOutput ) - check( crg::getStageMask( crg::ImageLayout::eShaderReadOnly ) == crg::PipelineStageFlags::eFragmentShader ) - check( crg::getStageMask( crg::ImageLayout::eTransferSrc ) == crg::PipelineStageFlags::eTransfer ) - check( crg::getStageMask( crg::ImageLayout::eTransferDst ) == crg::PipelineStageFlags::eTransfer ) - - for ( uint32_t i = 0; i <= uint32_t( crg::PixelFormat::eASTC_12x12_SRGB_BLOCK ); ++i ) - checkNoThrow( getName( crg::PixelFormat( i ) ) ); - - for ( uint32_t i = 0; i <= uint32_t( crg::FilterMode::eLinear ); ++i ) - checkNoThrow( getName( crg::FilterMode( i ) ) ); - - for ( uint32_t i = 0; i <= uint32_t( crg::MipmapMode::eLinear ); ++i ) - checkNoThrow( getName( crg::MipmapMode( i ) ) ); - - for ( uint32_t i = 0; i <= uint32_t( crg::WrapMode::eMirrorClampToEdge ); ++i ) - checkNoThrow( getName( crg::WrapMode( i ) ) ); - - auto vb1 = crg::VertexBuffer{ crg::Buffer{ VkBuffer( 1 ), "vtx1" } }; - auto vb2 = crg::VertexBuffer{ crg::Buffer{ VkBuffer( 2 ), "vtx2" } }; - vb2 = std::move( vb1 ); - - testEnd() - } + check( crg::getPipelineState( crg::PipelineStageFlags::eBottomOfPipe ).access == crg::AccessFlags::eMemoryRead ) + check( crg::getPipelineState( crg::PipelineStageFlags::eColorAttachmentOutput ).access == ( crg::AccessFlags::eColorAttachmentWrite | crg::AccessFlags::eColorAttachmentRead ) ) + check( crg::getPipelineState( crg::PipelineStageFlags::eLateFragmentTests ).access == ( crg::AccessFlags::eDepthStencilAttachmentWrite | crg::AccessFlags::eDepthStencilAttachmentRead ) ) + check( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShader ).access == crg::AccessFlags::eShaderRead ) + check( crg::getPipelineState( crg::PipelineStageFlags::eTransfer ).access == ( crg::AccessFlags::eTransferRead | crg::AccessFlags::eTransferWrite ) ) + check( crg::getPipelineState( crg::PipelineStageFlags::eComputeShader ).access == crg::AccessFlags::eShaderRead ) + + check( crg::getStageMask( crg::ImageLayout::eUndefined ) == crg::PipelineStageFlags::eHost ) + check( crg::getStageMask( crg::ImageLayout::eGeneral ) == crg::PipelineStageFlags::eBottomOfPipe ) + check( crg::getStageMask( crg::ImageLayout::ePresentSrc ) == crg::PipelineStageFlags::eBottomOfPipe ) + check( crg::getStageMask( crg::ImageLayout::eSharedPresent ) == crg::PipelineStageFlags::eBottomOfPipe ) + check( crg::getStageMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests ) + check( crg::getStageMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests ) + check( crg::getStageMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests ) + check( crg::getStageMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests ) + check( crg::getStageMask( crg::ImageLayout::eColorAttachment ) == crg::PipelineStageFlags::eColorAttachmentOutput ) + check( crg::getStageMask( crg::ImageLayout::eShaderReadOnly ) == crg::PipelineStageFlags::eFragmentShader ) + check( crg::getStageMask( crg::ImageLayout::eTransferSrc ) == crg::PipelineStageFlags::eTransfer ) + check( crg::getStageMask( crg::ImageLayout::eTransferDst ) == crg::PipelineStageFlags::eTransfer ) + + for ( uint32_t i = 0; i <= uint32_t( crg::PixelFormat::eASTC_12x12_SRGB_BLOCK ); ++i ) + checkNoThrow( getName( crg::PixelFormat( i ) ) ); + + for ( uint32_t i = 0; i <= uint32_t( crg::FilterMode::eLinear ); ++i ) + checkNoThrow( getName( crg::FilterMode( i ) ) ); + + for ( uint32_t i = 0; i <= uint32_t( crg::MipmapMode::eLinear ); ++i ) + checkNoThrow( getName( crg::MipmapMode( i ) ) ); + + for ( uint32_t i = 0; i <= uint32_t( crg::WrapMode::eMirrorClampToEdge ); ++i ) + checkNoThrow( getName( crg::WrapMode( i ) ) ); + + auto vb1 = crg::VertexBuffer{ handler.createViewId( test::createView( "vtx1", handler.createBufferId( test::createBuffer( "vtx1" ) ) ) ) }; + auto vb2 = crg::VertexBuffer{ handler.createViewId( test::createView( "vtx2", handler.createBufferId( test::createBuffer( "vtx2" ) ) ) ) }; + vb2 = std::move( vb1 ); + + testEnd() +} - void testClearValues( test::TestCounts & testCounts ) +TEST( Bases, ClearValues ) +{ + testBegin( "testClearValues" ) + crg::ClearColorValue clearColorInt32{ std::array< int32_t, 4u >{ 1, 2, 3, 4 } }; + crg::ClearColorValue clearColorUInt32{ std::array< uint32_t, 4u >{ 1u, 2u, 3u, 4u } }; + crg::ClearColorValue clearColorFloat32{ std::array< float, 4u >{ 1.0f, 2.0f, 3.0f, 4.0f } }; + crg::ClearDepthStencilValue clearDepthStencil{ 1.0f, 255u }; + + checkNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearColorFloat32 } ) ); + checkNoThrow( getClearColorValue( crg::ClearValue{ clearDepthStencil } ) ); + checkNoThrow( getClearColorValue( crg::ClearValue{ clearColorFloat32 } ) ); + checkNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearDepthStencil } ) ); + checkNoThrow( convert( crg::ClearValue{ clearColorFloat32 } ) ); + checkNoThrow( convert( crg::ClearValue{ clearDepthStencil } ) ); + check( clearColorFloat32.isFloat32() ); + check( !clearColorFloat32.isInt32() ); + check( !clearColorFloat32.isUInt32() ); + check( !clearColorUInt32.isFloat32() ); + check( !clearColorUInt32.isInt32() ); + check( clearColorUInt32.isUInt32() ); + check( !clearColorInt32.isFloat32() ); + check( clearColorInt32.isInt32() ); + check( !clearColorInt32.isUInt32() ); + check( crg::ClearValue{ clearColorFloat32 }.isColor() ); + check( !crg::ClearValue{ clearColorFloat32 }.isDepthStencil() ); + check( !crg::ClearValue{ clearDepthStencil }.isColor() ); + check( crg::ClearValue{ clearDepthStencil }.isDepthStencil() ); { - testBegin( "testClearValues" ) - crg::ClearColorValue clearColorInt32{ std::array< int32_t, 4u >{ 1, 2, 3, 4 } }; - crg::ClearColorValue clearColorUInt32{ std::array< uint32_t, 4u >{ 1u, 2u, 3u, 4u } }; - crg::ClearColorValue clearColorFloat32{ std::array< float, 4u >{ 1.0f, 2.0f, 3.0f, 4.0f } }; - crg::ClearDepthStencilValue clearDepthStencil{ 1.0f, 255u }; - - checkNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearColorFloat32 } ) ); - checkNoThrow( getClearColorValue( crg::ClearValue{ clearDepthStencil } ) ); - checkNoThrow( getClearColorValue( crg::ClearValue{ clearColorFloat32 } ) ); - checkNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearDepthStencil } ) ); - checkNoThrow( convert( crg::ClearValue{ clearColorFloat32 } ) ); - checkNoThrow( convert( crg::ClearValue{ clearDepthStencil } ) ); - check( clearColorFloat32.isFloat32() ); - check( !clearColorFloat32.isInt32() ); - check( !clearColorFloat32.isUInt32() ); - check( !clearColorUInt32.isFloat32() ); - check( !clearColorUInt32.isInt32() ); - check( clearColorUInt32.isUInt32() ); - check( !clearColorInt32.isFloat32() ); - check( clearColorInt32.isInt32() ); - check( !clearColorInt32.isUInt32() ); - check( crg::ClearValue{ clearColorFloat32 }.isColor() ); - check( !crg::ClearValue{ clearColorFloat32 }.isDepthStencil() ); - check( !crg::ClearValue{ clearDepthStencil }.isColor() ); - check( crg::ClearValue{ clearDepthStencil }.isDepthStencil() ); - { - auto vkClearColorFloat32 = crg::convert( clearColorFloat32 ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorFloat32.float32[i] == clearColorFloat32.float32()[i] ); - } - { - auto vkClearColorFloat32 = crg::convert( crg::ClearValue{ clearColorFloat32 } ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorFloat32.color.float32[i] == clearColorFloat32.float32()[i] ); - } - { - auto vkClearColorInt32 = crg::convert( clearColorInt32 ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorInt32.int32[i] == clearColorInt32.int32()[i] ); - } - { - auto vkClearColorInt32 = crg::convert( crg::ClearValue{ clearColorInt32 } ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorInt32.color.int32[i] == clearColorInt32.int32()[i] ); - } - { - auto vkClearColorUInt32 = crg::convert( clearColorUInt32 ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorUInt32.uint32[i] == clearColorUInt32.uint32()[i] ); - } - { - auto vkClearColorUInt32 = crg::convert( crg::ClearValue{ clearColorUInt32 } ); - for ( uint32_t i = 0; i < 4u; ++i ) - check( vkClearColorUInt32.color.uint32[i] == clearColorUInt32.uint32()[i] ); - } - { - auto vkClearDepthStencil = crg::convert( clearDepthStencil ); - check( vkClearDepthStencil.depth == clearDepthStencil.depth ); - check( vkClearDepthStencil.stencil == clearDepthStencil.stencil ); - } - { - auto vkClearDepthStencil = crg::convert( crg::ClearValue{ clearDepthStencil } ); - check( vkClearDepthStencil.depthStencil.depth == clearDepthStencil.depth ); - check( vkClearDepthStencil.depthStencil.stencil == clearDepthStencil.stencil ); - } - - testEnd() + auto vkClearColorFloat32 = crg::convert( clearColorFloat32 ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorFloat32.float32[i] == clearColorFloat32.float32()[i] ); } - - void testSignal( test::TestCounts & testCounts ) { - testBegin( "testSignal" ) - { - using DummyFunc = std::function< void() >; - using OnDummy = crg::Signal< DummyFunc >; - OnDummy onDummy; - - auto connection = onDummy.connect( []() - { - // Nothing to do here... - } ); - onDummy(); - connection.disconnect(); - onDummy(); - connection = onDummy.connect( []() - { - // Nothing to do here... - } ); - onDummy(); - connection = onDummy.connect( []() - { - // Nothing to do here... - } ); - onDummy(); - auto connection2 = onDummy.connect( []() - { - // Nothing to do here... - } ); - onDummy(); - } - { - using DummyFunc = std::function< void() >; - using OnDummy = crg::Signal< DummyFunc >; - auto onDummy = std::make_unique< OnDummy >(); - - auto connection = onDummy->connect( []() - { - // Nothing to do here... - } ); - ( *onDummy )(); - auto connection2 = onDummy->connect( []() - { - // Nothing to do here... - } ); - ( *onDummy )(); - - onDummy.reset(); - } - { - using DummyFunc = std::function< void( bool ) >; - using OnDummy = crg::Signal< DummyFunc >; - using OnDummyConnection = crg::SignalConnection< OnDummy >; - auto onDummy = std::make_unique< OnDummy >(); - OnDummyConnection tmpConn; - - auto connection = onDummy->connect( []( bool ) - { - // Nothing to do here... - } ); - ( *onDummy )( false ); - auto connection2 = onDummy->connect( [&tmpConn, &onDummy]( bool ) - { - tmpConn = onDummy->connect( []( bool ) - { - // Nothing to do here... - } ); - } ); - ( *onDummy )( true ); - - onDummy.reset(); - } - testEnd() + auto vkClearColorFloat32 = crg::convert( crg::ClearValue{ clearColorFloat32 } ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorFloat32.color.float32[i] == clearColorFloat32.float32()[i] ); } - - void testFence( test::TestCounts & testCounts ) { - testBegin( "testFence" ) - auto & context = getContext(); - { - crg::Fence fence{ context, "test", {} }; - fence.reset(); - fence.wait( 0xFFFFFFFFFFFFFFFFULL ); - fence.reset(); - } - testEnd() + auto vkClearColorInt32 = crg::convert( clearColorInt32 ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorInt32.int32[i] == clearColorInt32.int32()[i] ); } - - void testFramePassTimer( test::TestCounts & testCounts ) { - testBegin( "testFramePassTimer" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - crg::RunnablePass * runPass{}; - graph.createPass( "Mesh" - , [&testCounts, &runPass]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - auto res = createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - runPass = res.get(); - return res; - } ); - checkThrow( crg::checkVkResult( VK_ERROR_VALIDATION_FAILED_EXT, std::string{ "Test" } ) ) - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - { - auto & timer = runPass->getTimer(); - auto save = timer.getCpuTime(); - { - auto block = timer.start(); - std::this_thread::sleep_for( std::chrono::milliseconds{ 10u } ); - } - timer.retrieveGpuTime(); - auto end = timer.getCpuTime(); - auto total = ( end - save ) + timer.getGpuTime(); - check( total >= std::chrono::milliseconds{ 10u } ); - timer.reset(); - check( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } ); - check( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } ); - } - { - crg::FramePassTimer timer{ getContext(), "test", crg::TimerScope::eUpdate }; - auto save = timer.getCpuTime(); - { - auto block = std::make_unique< crg::FramePassTimerBlock >( timer.start() ); - std::this_thread::sleep_for( std::chrono::milliseconds{ 10u } ); - block.reset(); - } - timer.retrieveGpuTime(); - auto end = timer.getCpuTime(); - auto total = ( end - save ) + timer.getGpuTime(); - check( total >= std::chrono::milliseconds{ 10u } ); - timer.reset(); - check( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } ); - check( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } ); - } - { - auto timer = std::make_unique< crg::FramePassTimer >( getContext(), "test", crg::TimerScope::eUpdate ); - auto connection = timer->onDestroy.connect( []( crg::FramePassTimer const & thisTimer ) - { - if ( thisTimer.getScope() == crg::TimerScope::eUpdate ) - { - CRG_Exception( "WTF???" ); - } - } ); - timer.reset(); - } - testEnd() + auto vkClearColorInt32 = crg::convert( crg::ClearValue{ clearColorInt32 } ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorInt32.color.int32[i] == clearColorInt32.int32()[i] ); + } + { + auto vkClearColorUInt32 = crg::convert( clearColorUInt32 ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorUInt32.uint32[i] == clearColorUInt32.uint32()[i] ); + } + { + auto vkClearColorUInt32 = crg::convert( crg::ClearValue{ clearColorUInt32 } ); + for ( uint32_t i = 0; i < 4u; ++i ) + check( vkClearColorUInt32.color.uint32[i] == clearColorUInt32.uint32()[i] ); + } + { + auto vkClearDepthStencil = crg::convert( clearDepthStencil ); + check( vkClearDepthStencil.depth == clearDepthStencil.depth ); + check( vkClearDepthStencil.stencil == clearDepthStencil.stencil ); + } + { + auto vkClearDepthStencil = crg::convert( crg::ClearValue{ clearDepthStencil } ); + check( vkClearDepthStencil.depthStencil.depth == clearDepthStencil.depth ); + check( vkClearDepthStencil.depthStencil.stencil == clearDepthStencil.stencil ); } - void testImplicitActions( test::TestCounts & testCounts ) + testEnd() +} + +TEST( Bases, Signal ) +{ + testBegin( "testSignal" ) { - testBegin( "testImplicitActions" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto & testPass1 = graph.createPass( "Mesh" - , [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + using DummyFunc = std::function< void() >; + using OnDummy = crg::Signal< DummyFunc >; + OnDummy onDummy; + + auto connection = onDummy.connect( []() { - auto depthIt = framePass.images.begin(); - auto colourIt = std::next( depthIt ); - auto extent3D = getExtent( colour2v ); - auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , 0u - , false - , crg::ru::Config{} - .implicitAction( depthIt->view(), crg::RecordContext::clearAttachment( *depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) - .implicitAction( depth2v, crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) - .implicitAction( colourIt->view(), crg::RecordContext::clearAttachment( *colourIt ) ) - .implicitAction( colour4v, crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{}, crg::ImageLayout::eShaderReadOnly ) ) - .implicitAction( colour2v, crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) - .implicitAction( colour3v, crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) ); + // Nothing to do here... } ); - testPass1.addOutputDepthStencilView( depth1v ); - testPass1.addOutputColourView( colour1v ); - testPass1.addOutputColourView( colour2v ); - testPass1.addOutputColourView( colour3v ); - testPass1.addOutputColourView( colour4v ); - testPass1.addOutputStorageView( depth2v, 0u ); - - auto & testPass2 = graph.createPass( "Pass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + onDummy(); + connection.disconnect(); + onDummy(); + connection = onDummy.connect( []() { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , 0u ); + // Nothing to do here... } ); - testPass2.addDependency( testPass1 ); - testPass2.addInOutDepthStencilView( depth1v ); - testPass2.addInOutColourView( colour1v ); - testPass2.addInOutColourView( colour2v ); - testPass2.addInOutColourView( colour3v ); - testPass2.addInOutColourView( colour4v ); - testPass2.addInOutStorageView( depth2v, 0u ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() - } - - void testPrePassActions( test::TestCounts & testCounts ) - { - testBegin( "testPrePassActions" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto & testPass1 = graph.createPass( "Mesh" - , [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + onDummy(); + connection = onDummy.connect( []() { - auto depthIt = framePass.images.begin(); - auto colourIt = std::next( depthIt ); - auto extent3D = getExtent( colour2v ); - auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , crg::ru::Config{} - .prePassAction( crg::RecordContext::clearAttachment( *depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) - .prePassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) - .prePassAction( crg::RecordContext::clearAttachment( *colourIt ) ) - .prePassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) ) - .prePassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) - .prePassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) ); + // Nothing to do here... } ); - testPass1.addOutputDepthStencilView( depth1v ); - testPass1.addOutputColourView( colour1v ); - testPass1.addOutputColourView( colour2v ); - testPass1.addOutputColourView( colour3v ); - testPass1.addOutputColourView( colour4v ); - testPass1.addOutputStorageView( depth2v, 0u ); - - auto & testPass2 = graph.createPass( "Pass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + onDummy(); + auto connection2 = onDummy.connect( []() { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , 0u ); + // Nothing to do here... } ); - testPass2.addDependency( testPass1 ); - testPass2.addInOutDepthStencilView( depth1v ); - testPass2.addInOutColourView( colour1v ); - testPass2.addInOutColourView( colour2v ); - testPass2.addInOutColourView( colour3v ); - testPass2.addInOutColourView( colour4v ); - testPass2.addInOutStorageView( depth2v, 0u ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() + onDummy(); } - - void testPostPassActions( test::TestCounts & testCounts ) { - testBegin( "testPrePassActions" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); - auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - crg::RunnablePass const * runPass{}; - auto & testPass1 = graph.createPass( "Mesh" - , [&runPass , &testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + using DummyFunc = std::function< void() >; + using OnDummy = crg::Signal< DummyFunc >; + auto onDummy = std::make_unique< OnDummy >(); + + auto connection = onDummy->connect( []() { - auto depthIt = framePass.images.begin(); - auto colourIt = std::next( depthIt ); - auto extent3D = getExtent( colour2v ); - auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; - auto res = createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , crg::ru::Config{ 1u, true } - .postPassAction( crg::RecordContext::clearAttachment( *depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) - .postPassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) - .postPassAction( crg::RecordContext::clearAttachment( *colourIt ) ) - .postPassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) ) - .postPassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) - .postPassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) ); - runPass = res.get(); - return res; + // Nothing to do here... } ); - testPass1.addOutputDepthStencilView( depth1v ); - testPass1.addOutputColourView( colour1v ); - testPass1.addOutputColourView( colour2v ); - testPass1.addOutputColourView( colour3v ); - testPass1.addOutputColourView( colour4v ); - testPass1.addOutputStorageView( depth2v, 0u ); - - auto & testPass2 = graph.createPass( "Pass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + ( *onDummy )(); + auto connection2 = onDummy->connect( []() { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy - , 0u ); + // Nothing to do here... } ); - testPass2.addDependency( testPass1 ); - testPass2.addInOutDepthStencilView( depth1v ); - testPass2.addInOutColourView( colour1v ); - testPass2.addInOutColourView( colour2v ); - testPass2.addInOutColourView( colour3v ); - testPass2.addInOutColourView( colour4v ); - testPass2.addInOutStorageView( depth2v, 0u ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() - } + ( *onDummy )(); - void testGraphDeps( test::TestCounts & testCounts ) + onDummy.reset(); + } { - testBegin( "testGraphDeps" ) - crg::ResourceHandler handler; - crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; - auto colour = graph1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colourv = graph1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto iocolour = graph1.createImage( test::createImage( "iocolour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto iocolourv = graph1.createView( test::createView( "iocolourv", iocolour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto & testPass1 = graph1.createPass( "Mesh" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + using DummyFunc = std::function< void( bool ) >; + using OnDummy = crg::Signal< DummyFunc >; + using OnDummyConnection = crg::SignalConnection< OnDummy >; + auto onDummy = std::make_unique< OnDummy >(); + OnDummyConnection tmpConn; + + auto connection = onDummy->connect( []( bool ) { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + // Nothing to do here... } ); - testPass1.addOutputColourView( colourv ); - testPass1.addOutputColourView( iocolourv ); - testPass1.addOutputStorageBuffer( crg::Buffer{ ( VkBuffer )1u, "test" }, 0u, 0u, VK_WHOLE_SIZE ); - graph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - graph1.addOutput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) ); - check( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) - - crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; - graph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - graph2.addInput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) ); - check( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) - graph2.addDependency( graph1 ); - auto & testPass2 = graph2.createPass( "Pass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + ( *onDummy )( false ); + auto connection2 = onDummy->connect( [&tmpConn, &onDummy]( bool ) { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + tmpConn = onDummy->connect( []( bool ) + { + // Nothing to do here... + } ); } ); - testPass2.addSampledView( colourv, 0u ); - testPass2.addInOutColourView( iocolourv ); + ( *onDummy )( true ); - auto runnable1 = graph1.compile( getContext() ); - test::checkRunnable( testCounts, runnable1 ); + onDummy.reset(); + } + testEnd() +} + +TEST( Bases, Exception ) +{ + testBegin( "testException" ) + auto & context = getContext(); + try + { + CRG_Exception( "Coin !!" ); + } + catch ( crg::Exception & exc ) + { + crg::Logger::logInfo( exc.what() ); + } + testEnd() +} - auto runnable2 = graph2.compile( getContext() ); - test::checkRunnable( testCounts, runnable2 ); - testEnd() +TEST( Bases, Fence ) +{ + testBegin( "testFence" ) + auto & context = getContext(); + { + crg::Fence fence{ context, "test", {} }; + fence.reset(); + fence.wait( 0xFFFFFFFFFFFFFFFFULL ); + fence.reset(); } + testEnd() +} - void test2PassGraphDeps( test::TestCounts & testCounts ) +TEST( Bases, FramePassTimer ) +{ + testBegin( "testFramePassTimer" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + crg::RunnablePass * runPass{}; + auto buffer = graph.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = graph.createView( test::createView( "bufferv", buffer ) ); + auto & testPass = graph.createPass( "Mesh" + , [&testCounts, &runPass]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + auto res = createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + runPass = res.get(); + return res; + } ); + testPass.addClearableOutputStorageBuffer( bufferv, 1u ); + checkThrow( crg::checkVkResult( VK_ERROR_VALIDATION_FAILED_EXT, std::string{ "Test" } ), crg::Exception ) + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); { - testBegin( "test2PassGraphDeps" ) - crg::ResourceHandler handler; - crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; - crg::Buffer buffer{ ( VkBuffer )1u, "test" }; - auto colour = graph1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colourv = graph1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto & timer = runPass->getTimer(); + auto save = timer.getCpuTime(); { - auto & testPass11 = graph1.createPass( "Pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass11.addOutputColourView( colourv ); - testPass11.addOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - auto & testPass12 = graph1.createPass( "Pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass12.addDependency( testPass11 ); - testPass12.addInOutStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - testPass12.addInOutStorageView( colourv, 1u ); + auto block = timer.start(); + std::this_thread::sleep_for( std::chrono::milliseconds{ 10u } ); } - graph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - check( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) - - crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; - graph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - check( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) - graph2.addDependency( graph1 ); + timer.retrieveGpuTime(); + auto end = timer.getCpuTime(); + auto total = ( end - save ) + timer.getGpuTime(); + check( total >= std::chrono::milliseconds{ 10u } ); + timer.reset(); + check( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } ); + check( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } ); + } + { + crg::FramePassTimer timer{ getContext(), "test", crg::TimerScope::eUpdate }; + auto save = timer.getCpuTime(); { - auto & testPass21 = graph2.createPass( "Pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass21.addSampledView( colourv, 0u ); - - auto & testPass22 = graph2.createPass( "Pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass22.addDependency( testPass21 ); - testPass22.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); + auto block = std::make_unique< crg::FramePassTimerBlock >( timer.start() ); + std::this_thread::sleep_for( std::chrono::milliseconds{ 10u } ); + block.reset(); } - - auto runnable1 = graph1.compile( getContext() ); - test::checkRunnable( testCounts, runnable1 ); - - auto runnable2 = graph2.compile( getContext() ); - test::checkRunnable( testCounts, runnable2 ); - testEnd() + timer.retrieveGpuTime(); + auto end = timer.getCpuTime(); + auto total = ( end - save ) + timer.getGpuTime(); + check( total >= std::chrono::milliseconds{ 10u } ); + timer.reset(); + check( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } ); + check( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } ); } - - void testPassGroupDeps( test::TestCounts & testCounts ) { - testBegin( "testPassGroupDeps" ) - crg::ResourceHandler handler; - crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; - auto & group1 = graph1.getDefaultGroup(); - auto colour = group1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colourv = group1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto & testPass1 = group1.createPass( "Mesh" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) + auto timer = std::make_unique< crg::FramePassTimer >( getContext(), "test", crg::TimerScope::eUpdate ); + auto connection = timer->onDestroy.connect( []( crg::FramePassTimer const & thisTimer ) { + if ( thisTimer.getScope() == crg::TimerScope::eUpdate ) + { + CRG_Exception( "WTF???" ); + } + } ); + timer.reset(); + } + testEnd() +} + +TEST( Bases, ImplicitActions ) +{ + testBegin( "testImplicitActions" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto buffer1 = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer1 ) ); + auto buffer2 = graph.createBuffer( test::createBuffer( "buffer2" ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer2 ) ); + auto buffer3 = graph.createBuffer( test::createBuffer( "buffer3" ) ); + auto buffer3v = graph.createView( test::createView( "buffer3v", buffer3 ) ); + auto buffer4 = graph.createBuffer( test::createBuffer( "buffer4" ) ); + auto buffer4v = graph.createView( test::createView( "buffer4v", buffer4 ) ); + auto & testPass1 = graph.createPass( "Mesh" + , [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v, buffer1v, buffer2v, buffer3v]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + auto depthIt = framePass.targets.begin(); + auto colourIt = std::next( depthIt ); + auto extent3D = getExtent( colour2v ); + auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , 0u + , false + , crg::ru::Config{} + .implicitAction( ( *depthIt )->view(), crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) + .implicitAction( depth2v, crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) + .implicitAction( ( *colourIt )->view(), crg::RecordContext::clearAttachment( **colourIt ) ) + .implicitAction( colour4v, crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{}, crg::ImageLayout::eShaderReadOnly ) ) + .implicitAction( colour2v, crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) + .implicitAction( colour3v, crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) + .implicitAction( buffer1v, crg::RecordContext::clearBuffer( buffer1v, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) ) + .implicitAction( buffer2v, crg::RecordContext::clearBuffer( buffer2v, 18u, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) ) + .implicitAction( buffer3v, crg::RecordContext::copyBuffer( buffer1v, buffer3v, 0u, 0u, 48u, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) ) ); + } ); + auto depth1a = testPass1.addOutputDepthStencilTarget( depth1v ); + auto colour1a = testPass1.addOutputColourTarget( colour1v ); + auto colour2a = testPass1.addOutputColourTarget( colour2v ); + auto colour3a = testPass1.addOutputColourTarget( colour3v ); + auto colour4a = testPass1.addOutputColourTarget( colour4v ); + auto depth2a = testPass1.addOutputStorageImage( depth2v, 0u ); + auto buffer2a = testPass1.addOutputStorageBuffer( buffer2v, 1 ); + auto buffer3a = testPass1.addOutputStorageBuffer( buffer3v, 2 ); + auto buffer4a = testPass1.addOutputStorageBuffer( buffer4v, 3 ); + auto buffer1a = testPass1.addOutputStorageBuffer( buffer1v, 4 ); + + auto & testPass2 = graph.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , 0u ); + } ); + testPass2.addInOutDepthStencilTarget( *depth1a ); + testPass2.addInOutColourTarget( *colour1a ); + testPass2.addInOutColourTarget( *colour2a ); + testPass2.addInOutColourTarget( *colour3a ); + testPass2.addInOutColourTarget( *colour4a ); + testPass2.addInOutStorage( *depth2a, 0u ); + testPass2.addInOutStorage( *buffer2a, 1 ); + testPass2.addInOutStorage( *buffer3a, 2 ); + testPass2.addInOutStorage( *buffer4a, 3 ); + testPass2.addInOutStorage( *buffer1a, 4 ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} + +TEST( Bases, PrePassActions ) +{ + testBegin( "testPrePassActions" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto & testPass1 = graph.createPass( "Mesh" + , [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + auto depthIt = framePass.targets.begin(); + auto colourIt = std::next( depthIt ); + auto extent3D = getExtent( colour2v ); + auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , crg::ru::Config{} + .prePassAction( crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) + .prePassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) + .prePassAction( crg::RecordContext::clearAttachment( **colourIt ) ) + .prePassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) ) + .prePassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) + .prePassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) ); + } ); + auto depth1a = testPass1.addOutputDepthStencilTarget( depth1v ); + auto colour1a = testPass1.addOutputColourTarget( colour1v ); + auto colour2a = testPass1.addOutputColourTarget( colour2v ); + auto colour3a = testPass1.addOutputColourTarget( colour3v ); + auto colour4a = testPass1.addOutputColourTarget( colour4v ); + auto depth2a = testPass1.addOutputStorageImage( depth2v, 0u ); + + auto & testPass2 = graph.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , 0u ); + } ); + testPass2.addInOutDepthStencilTarget( *depth1a ); + testPass2.addInOutColourTarget( *colour1a ); + testPass2.addInOutColourTarget( *colour2a ); + testPass2.addInOutColourTarget( *colour3a ); + testPass2.addInOutColourTarget( *colour4a ); + testPass2.addInOutStorage( *depth2a, 0u ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} + +TEST( Bases, PostPassActions ) +{ + testBegin( "testPrePassActions" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto depth1 = graph.createImage( test::createImage( "depth1", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth1v = graph.createView( test::createView( "depth1v", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto depth2 = graph.createImage( test::createImage( "depth2", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depth2v = graph.createView( test::createView( "depth2v", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto colour1 = graph.createImage( test::createImage( "colour1", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour1v = graph.createView( test::createView( "colour1v", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour2 = graph.createImage( test::createImage( "colour2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour2v = graph.createView( test::createView( "colour2v", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour3 = graph.createImage( test::createImage( "colour3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour3v = graph.createView( test::createView( "colour3v", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto colour4 = graph.createImage( test::createImage( "colour4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colour4v = graph.createView( test::createView( "colour4v", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + crg::RunnablePass const * runPass{}; + auto & testPass1 = graph.createPass( "Mesh" + , [&runPass , &testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + auto depthIt = framePass.targets.begin(); + auto colourIt = std::next( depthIt ); + auto extent3D = getExtent( colour2v ); + auto extent2D = crg::Extent2D{ extent3D.width, extent3D.height }; + auto res = createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , crg::ru::Config{ 1u, true } + .postPassAction( crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) ) + .postPassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) ) + .postPassAction( crg::RecordContext::clearAttachment( **colourIt ) ) + .postPassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) ) + .postPassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) ) + .postPassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) ); + runPass = res.get(); + return res; + } ); + auto depth1a = testPass1.addOutputDepthStencilTarget( depth1v ); + auto colour1a = testPass1.addOutputColourTarget( colour1v ); + auto colour2a = testPass1.addOutputColourTarget( colour2v ); + auto colour3a = testPass1.addOutputColourTarget( colour3v ); + auto colour4a = testPass1.addOutputColourTarget( colour4v ); + auto depth2a = testPass1.addOutputStorageImage( depth2v, 0u ); + + auto & testPass2 = graph.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy + , 0u ); + } ); + testPass2.addInOutDepthStencilTarget( *depth1a ); + testPass2.addInOutColourTarget( *colour1a ); + testPass2.addInOutColourTarget( *colour2a ); + testPass2.addInOutColourTarget( *colour3a ); + testPass2.addInOutColourTarget( *colour4a ); + testPass2.addInOutStorage( *depth2a, 0u ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} + +TEST( Bases, GraphDeps ) +{ + testBegin( "testGraphDeps" ) + crg::ResourceHandler handler; + crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; + auto colour = graph1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colourv = graph1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto iocolour = graph1.createImage( test::createImage( "iocolour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto iocolourv = graph1.createView( test::createView( "iocolourv", iocolour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto buffer = graph1.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = graph1.createView( test::createView( "bufferv", buffer ) ); + auto & testPass1 = graph1.createPass( "Mesh" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto coloura = testPass1.addOutputColourTarget( colourv ); + auto iocoloura = testPass1.addOutputColourTarget( iocolourv ); + auto bufferAttach = testPass1.addOutputStorageBuffer( bufferv, 0u ); + graph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + graph1.addOutput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) ); + check( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) + + crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; + graph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + graph2.addInput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) ); + check( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) + graph2.addDependency( graph1 ); + auto & testPass2 = graph2.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + testPass2.addInputSampled( *coloura, 0u ); + testPass2.addInOutColourTarget( *iocoloura ); + + auto runnable1 = graph1.compile( getContext() ); + test::checkRunnable( testCounts, runnable1 ); + + auto runnable2 = graph2.compile( getContext() ); + test::checkRunnable( testCounts, runnable2 ); + testEnd() +} + +TEST( Bases, 2PassGraphDeps ) +{ + testBegin( "test2PassGraphDeps" ) + crg::ResourceHandler handler; + crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; + auto buffer = graph1.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = graph1.createView( test::createView( "bufferv", buffer ) ); + auto colour = graph1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colourv = graph1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + + auto & testPass11 = graph1.createPass( "Pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass1.addOutputColourView( colourv ); - testPass1.addOutputStorageBuffer( crg::Buffer{ ( VkBuffer )1u, "test" }, 0u, 0u, VK_WHOLE_SIZE ); - group1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - group1.addGroupOutput( colourv ); - - crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; - auto & group2 = graph2.getDefaultGroup(); - group2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - group2.addGroupInput( colourv ); - graph2.addDependency( graph1 ); - auto & testPass2 = group2.createPass( "Pass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { + } ); + auto coloura = testPass11.addOutputColourTarget( colourv ); + auto bufferAttach = testPass11.addOutputStorageBuffer( bufferv, 0u ); + + auto & testPass12 = graph1.createPass( "Pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - testPass2.addSampledView( colourv, 0u ); + } ); + bufferAttach = testPass12.addInOutStorage( *bufferAttach, 0u ); + coloura = testPass12.addInOutStorage( *coloura, 1u ); - auto runnable1 = graph1.compile( getContext() ); - test::checkRunnable( testCounts, runnable1 ); + graph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + check( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) - auto runnable2 = graph2.compile( getContext() ); - test::checkRunnable( testCounts, runnable2 ); - testEnd() - } - - void testPassGroups( test::TestCounts & testCounts ) + crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; + graph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + check( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly ) + graph2.addDependency( graph1 ); { - testBegin( "testPassGroups" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto & group1 = graph.createPassGroup( "First" ); - auto colour = group1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colourv = group1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - crg::Buffer buffer{ ( VkBuffer )1u, "test" }; - auto & testPass1 = group1.createPass( "Mesh" + auto & testPass21 = graph2.createPass( "Pass1" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - testPass1.addOutputColourView( colourv ); - testPass1.addOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - group1.addGroupOutput( colourv ); + testPass21.addInputSampled( *coloura, 0u ); - auto & group2 = graph.createPassGroup( "Second" ).createPassGroup( "Third" ); - group2.addGroupInput( colourv ); - auto & testPass2 = group2.createPass( "Pass" + auto & testPass22 = graph2.createPass( "Pass2" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - testPass2.addDependency( testPass1 ); - testPass2.addSampledView( colourv, 0u ); - testPass2.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - - auto runnable2 = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable2 ); - testEnd() + testPass22.addInputStorage( *bufferAttach, 0u ); } - void testResourcesCache( test::TestCounts & testCounts ) - { - testBegin( "testResourcesCache" ) - { - crg::ResourceHandler handler; - crg::RecordContext context( handler ); - checkThrow( context.getContext() ) - } - auto & context = getContext(); - crgUnregisterObject( context, VkBuffer( 1 ) ); - checkThrow( context.deduceMemoryType( 0u, 0u ) ) + auto runnable1 = graph1.compile( getContext() ); + test::checkRunnable( testCounts, runnable1 ); + + auto runnable2 = graph2.compile( getContext() ); + test::checkRunnable( testCounts, runnable2 ); + testEnd() +} + +TEST( Bases, PassGroupDeps ) +{ + testBegin( "testPassGroupDeps" ) + crg::ResourceHandler handler; + crg::FrameGraph graph1{ handler, testCounts.testName + "1" }; + auto & group1 = graph1.getDefaultGroup(); + auto colour = group1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colourv = group1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto buffer = graph1.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = graph1.createView( test::createView( "bufferv", buffer ) ); + auto & testPass1 = group1.createPass( "Mesh" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) { - crg::ResourceHandler handler; - auto sampled = handler.createImageId( test::createImage( "sampled", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto sampledv = handler.createViewId( test::createView( "sampledv", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - handler.createImage( context, sampled ); - handler.createImageView( context, sampledv ); - handler.createQuadTriVertexBuffer( context, "test", false, {} ); - handler.createQuadTriVertexBuffer( context, "test", true, {} ); - handler.createSampler( context, "test", crg::SamplerDesc{} ); - } - crg::ResourceHandler handler; - crg::ResourcesCache resources{ handler }; + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto coloura = testPass1.addOutputColourTarget( colourv ); + testPass1.addOutputStorageBuffer( bufferv, 0u ); + group1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + group1.addGroupOutput( colourv ); + + crg::FrameGraph graph2{ handler, testCounts.testName + "2" }; + auto & group2 = graph2.getDefaultGroup(); + group2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + group2.addGroupInput( colourv ); + graph2.addDependency( graph1 ); + auto & testPass2 = group2.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) { - auto sampled = handler.createImageId( test::createImage( "sampled", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto sampledv = handler.createViewId( test::createView( "sampledv", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - resources.createImage( context, sampled ); - resources.createImageView( context, sampledv ); - resources.destroyImageView( context, sampledv ); - resources.destroyImage( context, sampled ); - } + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + testPass2.addInputSampled( *coloura, 0u ); + + auto runnable1 = graph1.compile( getContext() ); + test::checkRunnable( testCounts, runnable1 ); + + auto runnable2 = graph2.compile( getContext() ); + test::checkRunnable( testCounts, runnable2 ); + testEnd() +} + +TEST( Bases, PassGroups ) +{ + testBegin( "testPassGroups" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto & group1 = graph.createPassGroup( "First" ); + auto colour = group1.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colourv = group1.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto buffer = group1.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = group1.createView( test::createView( "bufferv", buffer ) ); + auto & testPass1 = group1.createPass( "Mesh" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) { - auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - resources.createImage( context, result ); - resources.createImageView( context, resultv ); - resources.destroyImageView( resultv ); - resources.destroyImage( result ); - } + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto coloura = testPass1.addOutputColourTarget( colourv ); + auto bufferAttach = testPass1.addOutputStorageBuffer( bufferv, 0u ); + group1.addGroupOutput( colourv ); + + auto & group2 = graph.createPassGroup( "Second" ).createPassGroup( "Third" ); + group2.addGroupInput( colourv ); + auto & testPass2 = group2.createPass( "Pass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) { - auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - resources.createImage( context, result ); - resources.createImageView( context, resultv ); - resources.createSampler( context, crg::SamplerDesc{} ); - resources.createQuadTriVertexBuffer( context, false, {} ); - resources.createQuadTriVertexBuffer( context, true, {} ); - } - testEnd() - } + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + testPass2.addInputSampled( *coloura, 0u ); + testPass2.addInputStorage( *bufferAttach, 0u ); + + auto runnable2 = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable2 ); + testEnd() +} - void testGraphNodes( test::TestCounts & testCounts ) +TEST( Bases, ResourcesCache ) +{ + testBegin( "testResourcesCache" ) { - testBegin( "testGraphNodes" ) crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - crg::RootNode root{ graph }; - check( getFramePass( root ) == nullptr ) - testEnd() + crg::RecordContext context( handler ); + checkThrow( context.getContext(), crg::Exception ) } + auto & context = getContext(); + crgUnregisterObject( context, VkBuffer( 1 ) ); + checkThrow( context.deduceMemoryType( 0u, 0u ), crg::Exception ) + { + crg::ResourceHandler handler; + auto sampled = handler.createImageId( test::createImage( "sampled", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto sampledv = handler.createViewId( test::createView( "sampledv", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto buffer = handler.createBufferId( test::createBuffer( "buffer" ) ); + auto bufferv = handler.createViewId( test::createView( "bufferv", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + handler.createImage( context, sampled ); + handler.createImageView( context, sampledv ); + handler.createBuffer( context, buffer ); + handler.createBufferView( context, bufferv ); + handler.createQuadTriVertexBuffer( context, "test", false, {} ); + handler.createQuadTriVertexBuffer( context, "test", true, {} ); + handler.createSampler( context, "test", crg::SamplerDesc{} ); + } + crg::ResourceHandler handler; + crg::ResourcesCache resources{ handler }; + { + auto sampled = handler.createImageId( test::createImage( "sampled", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto sampledv = handler.createViewId( test::createView( "sampledv", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + resources.createImage( context, sampled ); + resources.createImageView( context, sampledv ); + resources.destroyImageView( context, sampledv ); + resources.destroyImage( context, sampled ); + auto buffer = handler.createBufferId( test::createBuffer( "buffer" ) ); + auto bufferv = handler.createViewId( test::createView( "bufferv", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + resources.createBuffer( context, buffer ); + resources.createBufferView( context, bufferv ); + resources.destroyBufferView( context, bufferv ); + resources.destroyBuffer( context, buffer ); + } + { + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + resources.createImage( context, result ); + resources.createImageView( context, resultv ); + resources.destroyImageView( resultv ); + resources.destroyImage( result ); + auto buffer = handler.createBufferId( test::createBuffer( "resbuffer" ) ); + auto bufferv = handler.createViewId( test::createView( "resbufferv", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + resources.createBuffer( context, buffer ); + resources.createBufferView( context, bufferv ); + resources.destroyBufferView( bufferv ); + resources.destroyBuffer( buffer ); + } + { + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + resources.createImage( context, result ); + resources.createImageView( context, resultv ); + resources.createSampler( context, crg::SamplerDesc{} ); + resources.createQuadTriVertexBuffer( context, false, {} ); + resources.createQuadTriVertexBuffer( context, true, {} ); + auto buffer = handler.createBufferId( test::createBuffer( "resbuffer" ) ); + auto bufferv = handler.createViewId( test::createView( "resbufferv", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + resources.createBuffer( context, buffer ); + resources.createBufferView( context, bufferv ); + resources.destroyBufferView( context, bufferv ); + resources.destroyBuffer( context, buffer ); + } + testEnd() } -int main( int argc, char ** argv ) +TEST( Bases, GraphNodes ) { - testSuiteBegin( "TestBases" ) - testBaseFuncs( testCounts ); - testClearValues( testCounts ); - testSignal( testCounts ); - testFence( testCounts ); - testFramePassTimer( testCounts ); - testImplicitActions( testCounts ); - testPrePassActions( testCounts ); - testPostPassActions( testCounts ); - testGraphDeps( testCounts ); - test2PassGraphDeps( testCounts ); - testPassGroupDeps( testCounts ); - testPassGroups( testCounts ); - testResourcesCache( testCounts ); - testGraphNodes( testCounts ); - testSuiteEnd() + testBegin( "testGraphNodes" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + crg::RootNode root{ graph }; + check( getFramePass( root ) == nullptr ) + + auto & testPass = graph.createPass( "testPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + crg::FramePassNode node{ testPass }; + check( getFramePass( node ) == &testPass ) + testEnd() } + +testSuiteMain() diff --git a/test/TestRenderGraph.cpp b/test/TestRenderGraph.cpp index b526edb..c8a68ea 100644 --- a/test/TestRenderGraph.cpp +++ b/test/TestRenderGraph.cpp @@ -16,967 +16,1067 @@ namespace return test::getDummyContext(); } - void checkOutputColourIsShaderReadOnly( test::TestCounts & testCounts + void checkTargetColourIsShaderReadOnly( [[maybe_unused]] test::TestCounts const & testCounts , crg::FramePass const & framePass , crg::RunnableGraph const & , crg::RecordContext const & context , uint32_t index ) { - for ( auto & attach : framePass.images ) + for ( auto attach : framePass.targets ) { - auto view = attach.view( index ); + auto view = attach->view( index ); - if ( attach.isColourOutputAttach() ) + if ( attach->isColourOutputImageTarget() ) { auto resolved = crg::resolveView( view, index ); - check( context.getNextLayoutState( resolved ).layout == crg::ImageLayout::eShaderReadOnly ) - check( context.getNextLayoutState( resolved.data->image + checkEqual( context.getNextLayoutState( resolved ).layout, crg::ImageLayout::eShaderReadOnly ) + checkEqual( context.getNextLayoutState( resolved.data->image , resolved.data->info.viewType - , resolved.data->info.subresourceRange ).layout == crg::ImageLayout::eShaderReadOnly ) + , getSubresourceRange( resolved ) ).layout, crg::ImageLayout::eShaderReadOnly ) } } } - void checkSampledIsShaderReadOnly( test::TestCounts & testCounts + void checkSampledIsShaderReadOnly( [[maybe_unused]] test::TestCounts const & testCounts , crg::FramePass const & framePass , crg::RunnableGraph const & , crg::RecordContext const & context , uint32_t index ) { - for ( auto & attach : framePass.images ) + for ( auto & [binding, attach] : framePass.sampled ) { - auto view = attach.view( index ); - - if ( attach.isSampledView() ) - { - check( context.getLayoutState( crg::resolveView( view, index ) ).layout == crg::ImageLayout::eShaderReadOnly ) - } + auto view = attach.attach->view( index ); + checkEqual( context.getLayoutState( crg::resolveView( view, index ) ).layout, crg::ImageLayout::eShaderReadOnly ) } } - crg::FrameGraph buildNoPassGraph( test::TestCounts & testCounts + crg::FrameGraph buildNoPassGraph( test::TestCounts const & testCounts , crg::ResourceHandler & handler ) { crg::FrameGraph graph{ handler, testCounts.testName }; - checkThrow( graph.compile( getContext() ) ) + checkThrow( graph.compile( getContext() ), crg::Exception ) return graph; } +} - void testNoPass( test::TestCounts & testCounts ) - { - testBegin( "testNoPass" ) - crg::ResourceHandler handler; - auto graph1 = buildNoPassGraph( testCounts, handler ); - crg::FrameGraph graph{ std::move( graph1 ) }; - - auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto rtv = graph.createView( test::createView( "rtv", rt ) ); - auto & pass = graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass.addOutputColourView( rtv ); - testEnd() - } +TEST( RenderGraph, NoPass ) +{ + testBegin( "testNoPass" ) + crg::ResourceHandler handler; + auto graph1 = buildNoPassGraph( testCounts, handler ); + crg::FrameGraph graph{ std::move( graph1 ) }; + + auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto rtv = graph.createView( test::createView( "rtv", rt ) ); + auto & pass = graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass.addOutputColourTarget( rtv ); + testEnd() +} - void testOnePass( test::TestCounts & testCounts ) - { - testBegin( "testOnePass" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto rtv = graph.createView( test::createView( "rtv", rt ) ); - auto & pass = graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass.addOutputColourView( rtv ); - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { +TEST( RenderGraph, OnePass ) +{ + testBegin( "testOnePass" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto rtv = graph.createView( test::createView( "rtv", rt ) ); + auto & pass = graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass.addOutputColourTarget( rtv ); + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testDuplicateName( test::TestCounts & testCounts ) - { - testBegin( "testDuplicateName" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - checkNoThrow( graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ) ) - checkThrow( graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ) ) - testEnd() - } - - void testOneDependency( test::TestCounts & testCounts ) - { - testBegin( "testOneDependency" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto rtv = graph.createView( test::createView( "rtv", rt ) ); - auto & pass1 = graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addOutputColourView( rtv ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto out = graph.createImage( test::createImage( "out", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto outv = graph.createView( test::createView( "outv", out ) ); - auto & pass2 = graph.createPass( "pass2C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( rtv, 0u ); - pass2.addOutputColourView( outv ); +TEST( RenderGraph, DuplicateName ) +{ + testBegin( "testDuplicateName" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + checkNoThrow( graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ) ) + checkThrow( graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ), crg::Exception ) + testEnd() +} - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\npass2C/rtv/Spl" -> "pass2C" [ label="rtv" ]; - "Transition to\npass2C/rtv/Spl" [ shape=box ]; - "pass1C" -> "Transition to\npass2C/rtv/Spl" [ label="rtv" ]; +TEST( RenderGraph, OneDependency ) +{ + testBegin( "testOneDependency" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u, 4u ) ); + auto dep = graph.createImage( test::createImage( "dep", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto rtv0 = graph.createView( test::createView( "rtv0", rt, 0u, 1u, 0u, 1u ) ); + auto rtv1 = graph.createView( test::createView( "rtv1", rt, 0u, 1u, 1u, 1u ) ); + auto rtv2 = graph.createView( test::createView( "rtv2", rt, 0u, 1u, 2u, 1u ) ); + auto rtv3 = graph.createView( test::createView( "rtv3", rt, 0u, 1u, 3u, 1u ) ); + auto depv = graph.createView( test::createView( "depv", dep ) ); + auto buf = graph.createBuffer( test::createBuffer( "buf" ) ); + auto bufv = graph.createView( test::createView( "bufv", buf ) ); + auto & pass1 = graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputUniformBuffer( bufv, 1u ); + auto rta = pass1.addOutputColourTarget( graph.mergeViews( { rtv0, rtv1, rtv2, rtv3 } ) ); + auto depa = pass1.addOutputDepthStencilTarget( depv ); + + auto out = graph.createImage( test::createImage( "out", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto outv = graph.createView( test::createView( "outv", out ) ); + auto & pass2 = graph.createPass( "pass2C" + , []( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return test::createDummyNoRecord( framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *rta, 0u ); + pass2.addInputUniformBuffer( bufv, 1u ); + pass2.addOutputColourTarget( outv ); + pass2.addInputDepthStencilTarget( *depa ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "pass1C" [ shape=ellipse ]; "pass2C" [ shape=ellipse ]; + "Transition to\npass2C/rt/Spl0" [ shape=box ]; + "pass1C" -> "Transition to\npass2C/rt/Spl0" [ label="rtv0" ]; + "Transition to\npass2C/rt/Spl0" -> "pass2C" [ label="rtv0" ]; + "Transition to\npass2C/rt/Spl1" [ shape=box ]; + "pass1C" -> "Transition to\npass2C/rt/Spl1" [ label="rtv1" ]; + "Transition to\npass2C/rt/Spl1" -> "pass2C" [ label="rtv1" ]; + "Transition to\npass2C/rt/Spl2" [ shape=box ]; + "pass1C" -> "Transition to\npass2C/rt/Spl2" [ label="rtv2" ]; + "Transition to\npass2C/rt/Spl2" -> "pass2C" [ label="rtv2" ]; + "Transition to\npass2C/rt/Spl3" [ shape=box ]; + "pass1C" -> "Transition to\npass2C/rt/Spl3" [ label="rtv3" ]; + "Transition to\npass2C/rt/Spl3" -> "pass2C" [ label="rtv3" ]; + "Transition to\npass2C/depv/IRds" [ shape=box ]; + "pass1C" -> "Transition to\npass2C/depv/IRds" [ label="depv" ]; + "Transition to\npass2C/depv/IRds" -> "pass2C" [ label="depv" ]; + "ExternalSource" [ shape=ellipse ]; + "Transition to\npass1C/bufv/UB" [ shape=box ]; + "ExternalSource" -> "Transition to\npass1C/bufv/UB" [ label="bufv" ]; + "Transition to\npass1C/bufv/UB" -> "pass1C" [ label="bufv" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testCycleDependency( test::TestCounts & testCounts ) - { - testBegin( "testCycleDependency" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto rtv = graph.createView( test::createView( "rtv", rt ) ); - auto & pass1 = graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addOutputColourView( rtv ); - - auto out = graph.createImage( test::createImage( "out", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto outv = graph.createView( test::createView( "outv", out ) ); - auto & pass2 = graph.createPass( "pass2C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( rtv, 0u ); - pass2.addOutputColourView( outv ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto & pass3 = graph.createPass( "pass3C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass3.addDependency( pass2 ); - pass3.addSampledView( rtv, 0u ); - pass3.addInOutColourView( outv ); - - pass1.addDependency( pass3 ); - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { +TEST( RenderGraph, CycleDependency ) +{ + testBegin( "testCycleDependency" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto rtv = graph.createView( test::createView( "rtv", rt ) ); + auto & pass1 = graph.createPass( "pass1C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto rta = pass1.addOutputColourTarget( rtv ); + + auto out = graph.createImage( test::createImage( "out", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto outv = graph.createView( test::createView( "outv", out ) ); + auto & pass2 = graph.createPass( "pass2C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *rta, 0u ); + auto outa = pass2.addOutputColourTarget( outv ); + + auto & pass3 = graph.createPass( "pass3C" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass3.addInputSampled( *rta, 0u ); + pass3.addInOutColourTarget( *outa ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "pass1C" [ shape=ellipse ]; "pass2C" [ shape=ellipse ]; "Transition to\npass2C/rtv/Spl" [ shape=box ]; "pass1C" -> "Transition to\npass2C/rtv/Spl" [ label="rtv" ]; "Transition to\npass2C/rtv/Spl" -> "pass2C" [ label="rtv" ]; "pass3C" [ shape=ellipse ]; - "Transition to\npass3C/outv/IOc" [ shape=box ]; - "pass2C" -> "Transition to\npass3C/outv/IOc" [ label="outv" ]; - "Transition to\npass3C/outv/IOc" -> "pass3C" [ label="outv" ]; + "Transition to\npass3C/outv/IORcl" [ shape=box ]; + "pass2C" -> "Transition to\npass3C/outv/IORcl" [ label="outv" ]; + "Transition to\npass3C/outv/IORcl" -> "pass3C" [ label="outv" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testUnsortableCycleDependency( test::TestCounts & testCounts ) - { - testBegin( "testUnsortableCycleDependency" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto rtv = graph.createView( test::createView( "rtv", rt ) ); - auto & pass1 = graph.createPass( "pass1C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addOutputColourView( rtv ); - - auto out = graph.createImage( test::createImage( "out", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto outv = graph.createView( test::createView( "outv", out ) ); - auto & pass2 = graph.createPass( "pass2C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( rtv, 0u ); - pass2.addOutputColourView( outv ); - - auto & pass3 = graph.createPass( "pass3C" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass3.addDependency( pass2 ); - pass3.addSampledView( rtv, 0u ); - pass3.addInOutColourView( outv ); - - pass1.addDependency( pass3 ); - pass1.addDependency( pass2 ); - pass2.addDependency( pass3 ); - checkThrow( graph.compile( getContext() ) ); - testEnd() - } - - void testChainedDependencies( test::TestCounts & testCounts ) - { - testBegin( "testChainedDependencies" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto d0 = graph.createImage( test::createImage( "d0", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d0v = graph.createView( test::createView( "d0v", d0 ) ); - auto & pass0 = graph.createPass( "pass0" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass0.addOutputColourView( d0v ); - - auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d1v = graph.createView( test::createView( "d1v", d1 ) ); - auto & pass1 = graph.createPass( "pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addDependency( pass0 ); - pass1.addSampledView( d0v, 0u ); - pass1.addOutputColourView( d1v ); - - auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d2v = graph.createView( test::createView( "d2v", d2 ) ); - auto & pass2 = graph.createPass( "pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( d1v, 0u ); - pass2.addOutputColourView( d2v ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\npass1/d0v/Spl" [ shape=box ]; - "pass0" [ shape=ellipse ]; +TEST( RenderGraph, ChainedDependencies ) +{ + testBegin( "testChainedDependencies" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto d0 = graph.createImage( test::createImage( "d0", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto d0v = graph.createView( test::createView( "d0v", d0 ) ); + auto & pass0 = graph.createPass( "pass0" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto d0a = pass0.addOutputColourTarget( d0v ); + + auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto d1v = graph.createView( test::createView( "d1v", d1 ) ); + auto & pass1 = graph.createPass( "pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputSampled( *d0a, 0u ); + auto d1a = pass1.addOutputColourTarget( d1v ); + + auto buf = graph.createBuffer( test::createBuffer( "buf" ) ); + auto bufv = graph.createView( test::createView( "bufv", buf ) ); + auto & pass2 = graph.createPass( "pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *d1a, 0u ); + pass2.addInputUniformBuffer( bufv, 1u ); + pass2.addInputColourTarget( *d1a ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "pass1" [ shape=ellipse ]; - "pass0" -> "Transition to\npass1/d0v/Spl" [ label="d0v" ]; - "Transition to\npass1/d0v/Spl" -> "pass1" [ label="d0v" ]; - "Transition to\npass2/d1v/Spl" [ shape=box ]; "pass2" [ shape=ellipse ]; + "Transition to\npass2/d1v/Spl" [ shape=box ]; "pass1" -> "Transition to\npass2/d1v/Spl" [ label="d1v" ]; "Transition to\npass2/d1v/Spl" -> "pass2" [ label="d1v" ]; + "Transition to\npass2/d1v/IRcl" [ shape=box ]; + "pass1" -> "Transition to\npass2/d1v/IRcl" [ label="d1v" ]; + "Transition to\npass2/d1v/IRcl" -> "pass2" [ label="d1v" ]; + "pass0" [ shape=ellipse ]; + "Transition to\npass1/d0v/Spl" [ shape=box ]; + "pass0" -> "Transition to\npass1/d0v/Spl" [ label="d0v" ]; + "Transition to\npass1/d0v/Spl" -> "pass1" [ label="d0v" ]; + "ExternalSource" [ shape=ellipse ]; + "Transition to\npass2/bufv/UB" [ shape=box ]; + "ExternalSource" -> "Transition to\npass2/bufv/UB" [ label="bufv" ]; + "Transition to\npass2/bufv/UB" -> "pass2" [ label="bufv" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testSharedDependencies( test::TestCounts & testCounts ) - { - testBegin( "testSharedDependencies" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto dstv1 = graph.createView( test::createView( "dstv1", d ) ); - auto d0 = graph.createImage( test::createImage( "d0", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d0v = graph.createView( test::createView( "d0v", d0 ) ); - auto & pass0 = graph.createPass( "pass0" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass0.addOutputDepthView( dstv1 ); - pass0.addOutputColourView( d0v ); - - auto dstv2 = graph.createView( test::createView( "dstv2", d ) ); - auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d1v = graph.createView( test::createView( "d1v", d1 ) ); - auto & pass1 = graph.createPass( "pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addDependency( pass0 ); - pass1.addSampledView( d0v, 0 ); - pass1.addOutputDepthView( dstv2 ); - pass1.addOutputColourView( d1v ); - - auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto d2v = graph.createView( test::createView( "d2v", d2 ) ); - auto & pass2 = graph.createPass( "pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( d1v, 0 ); - pass2.addOutputColourView( d2v ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\npass1/d0v/Spl" [ shape=box ]; - "pass0" [ shape=ellipse ]; +TEST( RenderGraph, SharedDependencies ) +{ + testBegin( "testSharedDependencies" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto dstv1 = graph.createView( test::createView( "dstv1", d ) ); + auto buf = graph.createBuffer( test::createBuffer( "buf" ) ); + auto bufv1 = graph.createView( test::createView( "bufv1", buf ) ); + auto d0 = graph.createImage( test::createImage( "d0", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto d0v = graph.createView( test::createView( "d0v", d0 ) ); + auto & pass0 = graph.createPass( "pass0" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass0.addOutputStorageBuffer( bufv1, 0 ); + pass0.addOutputDepthTarget( dstv1 ); + auto d0a = pass0.addOutputColourTarget( d0v ); + + auto dstv2 = graph.createView( test::createView( "dstv2", d ) ); + auto bufv2 = graph.createView( test::createView( "bufv2", buf ) ); + auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto d1v = graph.createView( test::createView( "d1v", d1 ) ); + auto & pass1 = graph.createPass( "pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputSampled( *d0a, 0 ); + pass0.addOutputStorageBuffer( bufv2, 0 ); + auto dsta = pass1.addOutputDepthTarget ( dstv2 ); + auto d1a = pass1.addOutputColourTarget( d1v ); + + auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto d2v = graph.createView( test::createView( "d2v", d2 ) ); + auto & pass2 = graph.createPass( "pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *d1a, 0 ); + pass2.addInputDepthTarget( *dsta ); + pass2.addOutputColourTarget( d2v ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { + "pass2" [ shape=ellipse ]; "pass1" [ shape=ellipse ]; - "pass0" -> "Transition to\npass1/d0v/Spl" [ label="d0v" ]; - "Transition to\npass1/d0v/Spl" -> "pass1" [ label="d0v" ]; "Transition to\npass2/d1v/Spl" [ shape=box ]; - "pass2" [ shape=ellipse ]; "pass1" -> "Transition to\npass2/d1v/Spl" [ label="d1v" ]; "Transition to\npass2/d1v/Spl" -> "pass2" [ label="d1v" ]; + "Transition to\npass2/dstv1/IRdp" [ shape=box ]; + "pass1" -> "Transition to\npass2/dstv1/IRdp" [ label="dstv1" ]; + "Transition to\npass2/dstv1/IRdp" -> "pass2" [ label="dstv1" ]; + "pass0" [ shape=ellipse ]; + "Transition to\npass1/d0v/Spl" [ shape=box ]; + "pass0" -> "Transition to\npass1/d0v/Spl" [ label="d0v" ]; + "Transition to\npass1/d0v/Spl" -> "pass1" [ label="d0v" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void test2MipDependencies( test::TestCounts & testCounts ) - { - testBegin( "test2MipDependencies" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); - auto m0v = graph.createView( test::createView( "m0v", lp, 0u ) ); - auto m1v = graph.createView( test::createView( "m1v", lp, 1u ) ); - auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass1.addSampledView( m0v, 0 ); - ssaoMinifyPass1.addOutputColourView( m1v ); - - auto m2v = graph.createView( test::createView( "m2v", lp, 2u ) ); - auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass2.addDependency( ssaoMinifyPass1 ); - ssaoMinifyPass2.addSampledView( m1v, 0 ); - ssaoMinifyPass2.addOutputColourView( m2v ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; +TEST( RenderGraph, 2MipDependencies ) +{ + testBegin( "test2MipDependencies" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); + auto m0v = graph.createView( test::createView( "m0v", lp, 0u ) ); + auto m1v = graph.createView( test::createView( "m1v", lp, 1u ) ); + auto m0a = crg::Attachment::createDefault( m0v ); + graph.addInput( m0v, makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass1.addInputSampled( m0a, 0 ); + auto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v ); + + auto m2v = graph.createView( test::createView( "m2v", lp, 2u ) ); + auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass2.addInputSampled( *m1a, 0 ); + ssaoMinifyPass2.addOutputColourTarget( m2v ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "ssaoMinifyPass1" [ shape=ellipse ]; "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ExternalSource" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ExternalSource" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void test3MipDependencies( test::TestCounts & testCounts ) - { - testBegin( "test3MipDependencies" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32G32B32_SFLOAT, 4u ) ); - auto m0v = graph.createView( test::createView( "m0v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 0u ) ); - auto m1v = graph.createView( test::createView( "m1v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 1u ) ); - auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass1.addSampledView( m0v, 0 ); - ssaoMinifyPass1.addOutputColourView( m1v ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto m2v = graph.createView( test::createView( "m2v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) ); - auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass2.addDependency( ssaoMinifyPass1 ); - ssaoMinifyPass2.addSampledView( m1v, 0 ); - ssaoMinifyPass2.addOutputColourView( m2v ); - - auto m3v = graph.createView( test::createView( "m3v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); - auto & ssaoMinifyPass3 = graph.createPass( "ssaoMinifyPass3" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass3.addDependency( ssaoMinifyPass2 ); - ssaoMinifyPass3.addSampledView( m2v, 0 ); - ssaoMinifyPass3.addOutputColourView( m3v ); - - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; +TEST( RenderGraph, 3MipDependencies ) +{ + testBegin( "test3MipDependencies" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32G32B32_SFLOAT, 4u ) ); + auto m0v = graph.createView( test::createView( "m0v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 0u ) ); + auto m1v = graph.createView( test::createView( "m1v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 1u ) ); + auto m0a = crg::Attachment::createDefault( m0v ); + auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass1.addInputSampled( m0a, 0 ); + auto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v ); + + auto m2v = graph.createView( test::createView( "m2v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) ); + auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass2.addInputSampled( *m1a, 0 ); + auto m2a = ssaoMinifyPass2.addOutputColourTarget( m2v ); + + auto m3v = graph.createView( test::createView( "m3v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); + auto & ssaoMinifyPass3 = graph.createPass( "ssaoMinifyPass3" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass3.addInputSampled( *m2a, 0 ); + ssaoMinifyPass3.addOutputColourTarget( m3v ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ExternalSource" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ExternalSource" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testLoopDependencies( test::TestCounts & testCounts ) - { - testBegin( "testLoopDependencies" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & pass1 = graph.createPass( "pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addSampledView( bv, 0 ); - pass1.addOutputColourView( av ); - - auto & pass2 = graph.createPass( "pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( av, 0 ); - pass2.addOutputColourView( bv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() - } - - void testLoopDependenciesWithRoot( test::TestCounts & testCounts ) - { - testBegin( "testLoopDependenciesWithRoot" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & pass0 = graph.createPass( "pass0" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass0.addOutputColourView( bv ); - - auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & pass1 = graph.createPass( "pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addDependency( pass0 ); - pass1.addSampledView( bv, 0 ); - pass1.addOutputColourView( av ); - - auto & pass2 = graph.createPass( "pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( av, 0 ); - pass2.addOutputColourView( bv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() - } - - void testLoopDependenciesWithRootAndLeaf( test::TestCounts & testCounts ) - { - testBegin( "testLoopDependenciesWithRootAndLeaf" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto c = graph.createImage( test::createImage( "c", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto cv = graph.createView( test::createView( "cv", c, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & pass0 = graph.createPass( "pass0" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass0.addOutputColourView( cv ); - - auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & pass1 = graph.createPass( "pass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass1.addDependency( pass0 ); - pass1.addSampledView( bv, 0 ); - pass1.addSampledView( cv, 1 ); - pass1.addOutputColourView( av ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto & pass2 = graph.createPass( "pass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass2.addDependency( pass1 ); - pass2.addSampledView( av, 0 ); - pass2.addSampledView( cv, 1 ); - pass2.addOutputColourView( bv ); +TEST( RenderGraph, LoopDependencies ) +{ + testBegin( "testLoopDependencies" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto ba = crg::Attachment::createDefault( bv ); + auto & pass1 = graph.createPass( "pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputSampled( ba, 0 ); + auto aa = pass1.addOutputColourTarget( av ); + + auto & pass2 = graph.createPass( "pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *aa, 0 ); + pass2.addOutputColourTarget( bv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} - auto & pass3 = graph.createPass( "pass3" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - pass3.addDependency( pass2 ); - pass3.addSampledView( cv, 0 ); +TEST( RenderGraph, LoopDependenciesWithRoot ) +{ + testBegin( "testLoopDependenciesWithRoot" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & pass0 = graph.createPass( "pass0" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto ba = pass0.addOutputColourTarget( bv ); + + auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & pass1 = graph.createPass( "pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputSampled( *ba, 0 ); + auto aa = pass1.addOutputColourTarget( av ); + + auto & pass2 = graph.createPass( "pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *aa, 0 ); + pass2.addOutputColourTarget( bv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\npass1/cv/Spl" [ shape=box ]; - "pass0" [ shape=ellipse ]; +TEST( RenderGraph, LoopDependenciesWithRootAndLeaf ) +{ + testBegin( "testLoopDependenciesWithRootAndLeaf" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto c = graph.createImage( test::createImage( "c", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto cv = graph.createView( test::createView( "cv", c, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & pass0 = graph.createPass( "pass0" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto ca = pass0.addOutputColourTarget( cv ); + + auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto b = graph.createImage( test::createImage( "b", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto bv = graph.createView( test::createView( "bv", b, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto ba = crg::Attachment::createDefault( bv ); + auto & pass1 = graph.createPass( "pass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass1.addInputSampled( ba, 0 ); + pass1.addInputSampled( *ca, 1 ); + auto aa = pass1.addOutputColourTarget( av ); + + auto & pass2 = graph.createPass( "pass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass2.addInputSampled( *aa, 0 ); + pass2.addInputSampled( *ca, 1 ); + pass2.addOutputColourTarget( bv ); + + auto buf = graph.createBuffer( test::createBuffer( "buf" ) ); + auto bufv = graph.createView( test::createView( "bufv", buf ) ); + auto & pass3 = graph.createPass( "pass3" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + pass3.addInputSampled( *ca, 0 ); + pass3.addInputUniformBuffer( bufv, 1 ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "pass1" [ shape=ellipse ]; - "pass0" -> "Transition to\npass1/cv/Spl" [ label="cv" ]; - "Transition to\npass1/cv/Spl" -> "pass1" [ label="cv" ]; - "Transition to\npass2/av/Spl" [ shape=box ]; "pass2" [ shape=ellipse ]; + "Transition to\npass2/av/Spl" [ shape=box ]; "pass1" -> "Transition to\npass2/av/Spl" [ label="av" ]; "Transition to\npass2/av/Spl" -> "pass2" [ label="av" ]; + "pass0" [ shape=ellipse ]; + "Transition to\npass1/cv/Spl" [ shape=box ]; + "pass0" -> "Transition to\npass1/cv/Spl" [ label="cv" ]; + "Transition to\npass1/cv/Spl" -> "pass1" [ label="cv" ]; + "pass3" [ shape=ellipse ]; + "ExternalSource" [ shape=ellipse ]; + "Transition to\npass1/bv/Spl" [ shape=box ]; + "ExternalSource" -> "Transition to\npass1/bv/Spl" [ label="bv" ]; + "Transition to\npass1/bv/Spl" -> "pass1" [ label="bv" ]; + "Transition to\npass3/bufv/UB" [ shape=box ]; + "ExternalSource" -> "Transition to\npass3/bufv/UB" [ label="bufv" ]; + "Transition to\npass3/bufv/UB" -> "pass3" [ label="bufv" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - std::pair< crg::ImageViewId, crg::FramePass * > buildSsaoPass( test::TestCounts & testCounts - , crg::FramePass const & previous - , crg::ImageViewId const & dsv - , crg::FrameGraph & graph ) - { - auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32_SFLOAT, 4u ) ); - auto m0v = graph.createView( test::createView( "m0v", lp, crg::PixelFormat::eR32_SFLOAT, 0u ) ); - auto & ssaoLinearisePass = graph.createPass( "ssaoLinearisePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoLinearisePass.addDependency( previous ); - ssaoLinearisePass.addSampledView( dsv, 0 ); - ssaoLinearisePass.addOutputColourView( m0v ); - - auto m1v = graph.createView( test::createView( "m1v", lp, crg::PixelFormat::eR32_SFLOAT, 1u ) ); - auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass1.addDependency( ssaoLinearisePass ); - ssaoMinifyPass1.addSampledView( m0v, 0 ); - ssaoMinifyPass1.addOutputColourView( m1v ); - - auto m2v = graph.createView( test::createView( "m2v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) ); - auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass2.addDependency( ssaoMinifyPass1 ); - ssaoMinifyPass2.addSampledView( m1v, 0 ); - ssaoMinifyPass2.addOutputColourView( m2v ); - - auto m3v = graph.createView( test::createView( "m3v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); - auto & ssaoMinifyPass3 = graph.createPass( "ssaoMinifyPass3" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoMinifyPass3.addDependency( ssaoMinifyPass2 ); - ssaoMinifyPass3.addSampledView( m2v, 0 ); - ssaoMinifyPass3.addOutputColourView( m3v ); - - auto mv = graph.createView( test::createView("mv", lp, crg::PixelFormat::eR32_SFLOAT, 0u, 4u ) ); - auto rs = graph.createImage( test::createImage( "rs", crg::PixelFormat::eR32_SFLOAT ) ); - auto rsv = graph.createView( test::createView( "rsv", rs, crg::PixelFormat::eR32_SFLOAT ) ); - auto & ssaoRawPass = graph.createPass( "ssaoRawPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoRawPass.addDependency( ssaoMinifyPass3 ); - ssaoRawPass.addSampledView( mv, 0 ); - ssaoRawPass.addSampledView( m3v, 1 ); - ssaoRawPass.addOutputColourView( rsv ); - - auto bl = graph.createImage( test::createImage( "b1", crg::PixelFormat::eR32_SFLOAT ) ); - auto blv = graph.createView( test::createView( "b1v", bl, crg::PixelFormat::eR32_SFLOAT ) ); - auto & ssaoBlurPass = graph.createPass( "ssaoBlurPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ssaoBlurPass.addDependency( ssaoRawPass ); - ssaoBlurPass.addSampledView( rsv, 0 ); - ssaoBlurPass.addSampledView( m3v, 1 ); - ssaoBlurPass.addOutputColourView( blv ); - - return { blv, &ssaoBlurPass }; - } + checkEqualSortedLines( stream, ref ) + testEnd() +} - void testSsaoPass( test::TestCounts & testCounts ) - { - testBegin( "testSsaoPass" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto dtv = graph.createView( test::createView( "dtv", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto v = graph.createImage( test::createImage( "v", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto vv = graph.createView( test::createView( "vv", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto d1v = graph.createView( test::createView( "d1v", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d2v = graph.createView( test::createView( "d2v", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d3 = graph.createImage( test::createImage( "d3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d3v = graph.createView( test::createView( "d3v", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d4 = graph.createImage( test::createImage( "d4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d4v = graph.createView( test::createView( "d4v", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto & geometryPass = graph.createPass( "geometryPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - geometryPass.addOutputColourView( d1v ); - geometryPass.addOutputColourView( d2v ); - geometryPass.addOutputColourView( d3v ); - geometryPass.addOutputColourView( d4v ); - geometryPass.addOutputColourView( vv ); - geometryPass.addOutputDepthStencilView( dtv ); - - auto dsv = graph.createView( test::createView( "dsv", d, crg::PixelFormat::eR32_SFLOAT ) ); - auto [ssaoResult, ssaoPass] = buildSsaoPass( testCounts - , geometryPass - , dsv - , graph ); +crg::Attachment const * buildSsaoPass( test::TestCounts & testCounts + , crg::Attachment const & lda + , crg::FrameGraph & graph ) +{ + auto lp = graph.createImage( test::createImage( "lp", crg::PixelFormat::eR32_SFLOAT, 4u ) ); + auto m0v = graph.createView( test::createView( "m0v", lp, crg::PixelFormat::eR32_SFLOAT, 0u ) ); + auto & ssaoLinearisePass = graph.createPass( "ssaoLinearisePass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoLinearisePass.addInputSampled( lda, 0 ); + auto m0a = ssaoLinearisePass.addOutputColourTarget( m0v ); + + auto m1v = graph.createView( test::createView( "m1v", lp, crg::PixelFormat::eR32_SFLOAT, 1u ) ); + auto & ssaoMinifyPass1 = graph.createPass( "ssaoMinifyPass1" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass1.addInputSampled( *m0a, 0 ); + auto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v ); + + auto m2v = graph.createView( test::createView( "m2v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) ); + auto & ssaoMinifyPass2 = graph.createPass( "ssaoMinifyPass2" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass2.addInputSampled( *m1a, 0 ); + auto m2a = ssaoMinifyPass2.addOutputColourTarget( m2v ); + + auto m3v = graph.createView( test::createView( "m3v", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) ); + auto & ssaoMinifyPass3 = graph.createPass( "ssaoMinifyPass3" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoMinifyPass3.addInputSampled( *m2a, 0 ); + auto m3a = ssaoMinifyPass3.addOutputColourTarget( m3v ); + + auto rs = graph.createImage( test::createImage( "rs", crg::PixelFormat::eR32_SFLOAT ) ); + auto rsv = graph.createView( test::createView( "rsv", rs, crg::PixelFormat::eR32_SFLOAT ) ); + auto & ssaoRawPass = graph.createPass( "ssaoRawPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoRawPass.addInputSampled( *graph.mergeAttachments( { m0a, m1a, m2a, m3a } ), 0 ); + ssaoRawPass.addInputSampled( *m3a, 1 ); + auto rsa = ssaoRawPass.addOutputColourTarget( rsv ); + + auto bl = graph.createImage( test::createImage( "b1", crg::PixelFormat::eR32_SFLOAT ) ); + auto blv = graph.createView( test::createView( "b1v", bl, crg::PixelFormat::eR32_SFLOAT ) ); + auto & ssaoBlurPass = graph.createPass( "ssaoBlurPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ssaoBlurPass.addInputSampled( *rsa, 0 ); + ssaoBlurPass.addInputSampled( *m3a, 1 ); + return ssaoBlurPass.addOutputColourTarget( blv ); +} - auto of = graph.createImage( test::createImage( "of", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto ofv = graph.createView( test::createView( "ofv", of, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & ambientPass = graph.createPass( "ambientPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - ambientPass.addDependency( *ssaoPass ); - ambientPass.addSampledView( dsv, 0 ); - ambientPass.addSampledView( d1v, 1 ); - ambientPass.addSampledView( d2v, 2 ); - ambientPass.addSampledView( d3v, 3 ); - ambientPass.addSampledView( d4v, 4 ); - ambientPass.addSampledView( ssaoResult, 5 ); - ambientPass.addOutputColourView( ofv ); - - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref = R"(digraph { - "Transition to\nssaoLinearisePass/dsv/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "ssaoLinearisePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nssaoLinearisePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" -> "ssaoLinearisePass" [ label="dtv" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; - "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; - "ssaoMinifyPass3" [ shape=ellipse ]; - "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; - "Transition to\nssaoRawPass/m3v/Spl" [ shape=box ]; - "ssaoRawPass" [ shape=ellipse ]; - "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/m3v/Spl" [ label="m3v" ]; - "Transition to\nssaoRawPass/m3v/Spl" -> "ssaoRawPass" [ label="m3v" ]; - "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; - "ssaoBlurPass" [ shape=ellipse ]; - "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; - "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; - "Transition to\nambientPass/b1v/Spl" [ shape=box ]; +TEST( RenderGraph, SsaoPass ) +{ + testBegin( "testSsaoPass" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto dtv = graph.createView( test::createView( "dtv", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto ld = graph.createImage( test::createImage( "ld", crg::PixelFormat::eR32_SFLOAT ) ); + auto ldv = graph.createView( test::createView( "ldv", ld, crg::PixelFormat::eR32_SFLOAT ) ); + auto v = graph.createImage( test::createImage( "v", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto vv = graph.createView( test::createView( "vv", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto d1v = graph.createView( test::createView( "d1v", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d2v = graph.createView( test::createView( "d2v", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d3 = graph.createImage( test::createImage( "d3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d3v = graph.createView( test::createView( "d3v", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d4 = graph.createImage( test::createImage( "d4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d4v = graph.createView( test::createView( "d4v", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto & geometryPass = graph.createPass( "geometryPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto d1a = geometryPass.addOutputColourTarget( d1v ); + auto d2a = geometryPass.addOutputColourTarget( d2v ); + auto d3a = geometryPass.addOutputColourTarget( d3v ); + auto d4a = geometryPass.addOutputColourTarget( d4v ); + auto lda = geometryPass.addOutputColourTarget( ldv ); + geometryPass.addOutputColourTarget( vv ); + geometryPass.addOutputDepthStencilTarget( dtv ); + + auto ssaoa = buildSsaoPass( testCounts + , *lda + , graph ); + + auto of = graph.createImage( test::createImage( "of", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto ofv = graph.createView( test::createView( "ofv", of, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & ambientPass = graph.createPass( "ambientPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + ambientPass.addInputSampled( *lda, 0 ); + ambientPass.addInputSampled( *d1a, 1 ); + ambientPass.addInputSampled( *d2a, 2 ); + ambientPass.addInputSampled( *d3a, 3 ); + ambientPass.addInputSampled( *d4a, 4 ); + ambientPass.addInputSampled( *ssaoa, 5 ); + ambientPass.addOutputColourTarget( ofv ); + + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref = R"(digraph { "ambientPass" [ shape=ellipse ]; - "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; - "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; - "Transition to\nambientPass/d1v/Spl" [ shape=box ]; "geometryPass" [ shape=ellipse ]; - "ambientPass" [ shape=ellipse ]; + "Transition to\nambientPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nambientPass/d1v/Spl" [ label="d1v" ]; "Transition to\nambientPass/d1v/Spl" -> "ambientPass" [ label="d1v" ]; "Transition to\nambientPass/d2v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nambientPass/d2v/Spl" [ label="d2v" ]; "Transition to\nambientPass/d2v/Spl" -> "ambientPass" [ label="d2v" ]; "Transition to\nambientPass/d3v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "ambientPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nambientPass/d3v/Spl" [ label="d3v" ]; "Transition to\nambientPass/d3v/Spl" -> "ambientPass" [ label="d3v" ]; "Transition to\nambientPass/d4v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nambientPass/d4v/Spl" [ label="d4v" ]; "Transition to\nambientPass/d4v/Spl" -> "ambientPass" [ label="d4v" ]; - "Transition to\nambientPass/dsv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/dsv/Spl" [ label="dtv" ]; - "Transition to\nambientPass/dsv/Spl" -> "ambientPass" [ label="dtv" ]; + "ssaoBlurPass" [ shape=ellipse ]; + "Transition to\nambientPass/b1v/Spl" [ shape=box ]; + "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; + "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; + "ssaoRawPass" [ shape=ellipse ]; + "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; + "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; + "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; + "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoRawPass/lp/Spl3" [ shape=box ]; + "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/lp/Spl3" [ label="m3v" ]; + "Transition to\nssaoRawPass/lp/Spl3" -> "ssaoRawPass" [ label="m3v" ]; + "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; + "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ssaoLinearisePass" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; + "Transition to\nssaoLinearisePass/ldv/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nssaoLinearisePass/ldv/Spl" [ label="ldv" ]; + "Transition to\nssaoLinearisePass/ldv/Spl" -> "ssaoLinearisePass" [ label="ldv" ]; } )"; - checkEqualSortedLines( stream.str(), ref ) - testEnd() - } - - void testBloomPostEffect( test::TestCounts & testCounts ) - { - testBegin( "testBloomPostEffect" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto scene = graph.createImage( test::createImage( "scene", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto scenev = graph.createView( test::createView( "scenev", scene, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto output = graph.createImage( test::createImage( "output", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto outputv = graph.createView( test::createView( "outputv", output, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto hi = graph.createImage( test::createImage( "hi", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) ); - auto hi0v = graph.createView( test::createView( "hi0v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) ); - auto hi1v = graph.createView( test::createView( "hi1v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) ); - auto hi2v = graph.createView( test::createView( "hi2v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) ); - auto hi3v = graph.createView( test::createView( "hi3v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) ); - auto bl = graph.createImage( test::createImage( "bl", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) ); - auto bl0v = graph.createView( test::createView( "bl0v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) ); - auto bl1v = graph.createView( test::createView( "bl1v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) ); - auto bl2v = graph.createView( test::createView( "bl2v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) ); - auto bl3v = graph.createView( test::createView( "bl3v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) ); - - auto & hiPass = graph.createPass( "hiPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - hiPass.addSampledView( scenev, 0u ); - hiPass.addOutputColourView( hiPass.mergeViews( { hi0v, hi1v, hi2v, hi3v } ) ); - - auto & blurPass0X = graph.createPass( "blurPass0X" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass0X.addDependency( hiPass ); - blurPass0X.addSampledView( hi0v, 0u ); - blurPass0X.addOutputColourView( bl0v ); - auto & blurPass0Y = graph.createPass( "blurPass0Y" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass0Y.addDependency( blurPass0X ); - blurPass0Y.addSampledView( bl0v, 0u ); - blurPass0Y.addOutputColourView( hi0v ); + checkEqualSortedLines( stream, ref ) + testEnd() +} - auto & blurPass1X = graph.createPass( "blurPass1X" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass1X.addDependency( hiPass ); - blurPass1X.addSampledView( hi1v, 0u ); - blurPass1X.addOutputColourView( bl1v ); - auto & blurPass1Y = graph.createPass( "blurPass1Y" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass1Y.addDependency( blurPass1X ); - blurPass1Y.addSampledView( bl1v, 0u ); - blurPass1Y.addOutputColourView( hi1v ); +TEST( RenderGraph, BloomPostEffect ) +{ + testBegin( "testBloomPostEffect" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto scene = graph.createImage( test::createImage( "scene", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto scenev = graph.createView( test::createView( "scenev", scene, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto scenea = crg::Attachment::createDefault( scenev ); + auto output = graph.createImage( test::createImage( "output", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto outputv = graph.createView( test::createView( "outputv", output, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto hi = graph.createImage( test::createImage( "hi", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) ); + auto hi0v = graph.createView( test::createView( "hi0v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) ); + auto hi1v = graph.createView( test::createView( "hi1v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) ); + auto hi2v = graph.createView( test::createView( "hi2v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) ); + auto hi3v = graph.createView( test::createView( "hi3v", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) ); + auto bl = graph.createImage( test::createImage( "bl", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) ); + auto bl0v = graph.createView( test::createView( "bl0v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) ); + auto bl1v = graph.createView( test::createView( "bl1v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) ); + auto bl2v = graph.createView( test::createView( "bl2v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) ); + auto bl3v = graph.createView( test::createView( "bl3v", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) ); + + auto & hiPass = graph.createPass( "hiPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + hiPass.addInputSampled( scenea, 0u ); + auto hia = hiPass.addOutputColourTarget( graph.mergeViews( { hi0v, hi1v, hi2v, hi3v } ) ); + require( hia->source.size() == 4u ); + + auto & blurPass0X = graph.createPass( "blurPass0X" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass0X.addInputSampled( *hia->getSource( 0 ), 0u ); + auto bl0a = blurPass0X.addOutputColourTarget( bl0v ); + auto & blurPass0Y = graph.createPass( "blurPass0Y" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass0Y.addInputSampled( *bl0a, 0u ); + auto hi0a = blurPass0Y.addOutputColourTarget( hi0v ); + + auto & blurPass1X = graph.createPass( "blurPass1X" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass1X.addInputSampled( *hia->getSource( 1 ), 0u ); + auto bl1a = blurPass1X.addOutputColourTarget( bl1v ); + auto & blurPass1Y = graph.createPass( "blurPass1Y" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass1Y.addInputSampled( *bl1a, 0u ); + auto hi1a = blurPass1Y.addOutputColourTarget( hi1v ); + + auto & blurPass2X = graph.createPass( "blurPass2X" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass2X.addInputSampled( *hia->getSource( 2 ), 0u ); + auto bl2a = blurPass2X.addOutputColourTarget( bl2v ); + auto & blurPass2Y = graph.createPass( "blurPass2Y" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass2Y.addInputSampled( *bl2a, 0u ); + auto hi2a = blurPass2Y.addOutputColourTarget( hi2v ); + + auto & blurPass3X = graph.createPass( "blurPass3X" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass3X.addInputSampled( *hia->getSource( 3 ), 0u ); + auto bl3a = blurPass3X.addOutputColourTarget( bl3v ); + auto & blurPass3Y = graph.createPass( "blurPass3Y" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + blurPass3Y.addInputSampled( *bl3a, 0u ); + auto hi3a = blurPass3Y.addOutputColourTarget( hi3v ); + + auto & combinePass = graph.createPass( "combinePass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + combinePass.addInputSampled( scenea, 0u ); + combinePass.addInputSampled( *graph.mergeAttachments( { hi0a, hi1a, hi2a, hi3a } ), 1u ); + combinePass.addOutputColourTarget( outputv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} - auto & blurPass2X = graph.createPass( "blurPass2X" +template< bool EnableSsao > +crg::Attachment const * buildDeferred( test::TestCounts & testCounts + , crg::Attachment const *& lda + , crg::Attachment const *& dta + , crg::ImageViewId const & ldv + , crg::ImageViewId const & dtv + , crg::ImageViewId const & vtv + , crg::FrameGraph & graph ) +{ + auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto d1v = graph.createView( test::createView( "d1v", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); + auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d2v = graph.createView( test::createView( "d2v", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d3 = graph.createImage( test::createImage( "d3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d3v = graph.createView( test::createView( "d3v", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d4 = graph.createImage( test::createImage( "d4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto d4v = graph.createView( test::createView( "d4v", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto & geometryPass = graph.createPass( "geometryPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + + auto d1a = geometryPass.addOutputColourTarget( d1v ); + auto d2a = geometryPass.addOutputColourTarget( d2v ); + auto d3a = geometryPass.addOutputColourTarget( d3v ); + auto d4a = geometryPass.addOutputColourTarget( d4v ); + if ( !lda ) + lda = geometryPass.addOutputColourTarget( ldv ); + geometryPass.addOutputColourTarget( vtv ); + if ( dta ) + geometryPass.addInputDepthStencilTarget( *dta ); + else + dta = geometryPass.addOutputDepthStencilTarget( dtv ); + + auto df = graph.createImage( test::createImage( "df", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto dfv = graph.createView( test::createView( "dfv", df, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto sp = graph.createImage( test::createImage( "sp", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto spv = graph.createView( test::createView( "spv", sp, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & lightingPass = graph.createPass( "lightingPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + lightingPass.addInputSampled( *lda, 0 ); + lightingPass.addInputSampled( *d1a, 1 ); + lightingPass.addInputSampled( *d2a, 2 ); + lightingPass.addInputSampled( *d3a, 3 ); + lightingPass.addInputSampled( *d4a, 4 ); + auto dfa = lightingPass.addOutputColourTarget( dfv ); + auto spa = lightingPass.addOutputColourTarget( spv ); + + auto of = graph.createImage( test::createImage( "of", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto ofv = graph.createView( test::createView( "ofv", of, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + + if constexpr ( EnableSsao ) + { + auto ssaoa = buildSsaoPass( testCounts + , *lda + , graph ); + auto & ambientPass = graph.createPass( "ambientPass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -984,10 +1084,19 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - blurPass2X.addDependency( hiPass ); - blurPass2X.addSampledView( hi2v, 0u ); - blurPass2X.addOutputColourView( bl2v ); - auto & blurPass2Y = graph.createPass( "blurPass2Y" + ambientPass.addInputSampled( *lda, 0 ); + ambientPass.addInputSampled( *d1a, 1 ); + ambientPass.addInputSampled( *d2a, 2 ); + ambientPass.addInputSampled( *d3a, 3 ); + ambientPass.addInputSampled( *d4a, 4 ); + ambientPass.addInputSampled( *dfa, 5 ); + ambientPass.addInputSampled( *spa, 6 ); + ambientPass.addInputSampled( *ssaoa, 7 ); + return ambientPass.addOutputColourTarget( ofv ); + } + else + { + auto & ambientPass = graph.createPass( "ambientPass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -995,71 +1104,131 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - blurPass2Y.addDependency( blurPass2X ); - blurPass2Y.addSampledView( bl2v, 0u ); - blurPass2Y.addOutputColourView( hi2v ); + ambientPass.addInputSampled( *lda, 0 ); + ambientPass.addInputSampled( *d1a, 1 ); + ambientPass.addInputSampled( *d2a, 2 ); + ambientPass.addInputSampled( *d3a, 3 ); + ambientPass.addInputSampled( *d4a, 4 ); + ambientPass.addInputSampled( *dfa, 5 ); + ambientPass.addInputSampled( *spa, 6 ); + return ambientPass.addOutputColourTarget( ofv ); + } +} - auto & blurPass3X = graph.createPass( "blurPass3X" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass3X.addDependency( hiPass ); - blurPass3X.addSampledView( hi3v, 0u ); - blurPass3X.addOutputColourView( bl3v ); - auto & blurPass3Y = graph.createPass( "blurPass3Y" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - blurPass3Y.addDependency( blurPass3X ); - blurPass3Y.addSampledView( bl3v, 0u ); - blurPass3Y.addOutputColourView( hi3v ); +crg::Attachment const * buildWeightedBlended( test::TestCounts & testCounts + , crg::Attachment const *& dta + , crg::Attachment const * lda + , crg::ImageViewId const & dtv + , crg::FrameGraph & graph ) +{ + auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto r = graph.createImage( test::createImage( "r", crg::PixelFormat::eR16_SFLOAT ) ); + auto rv = graph.createView( test::createView( "rv", r, crg::PixelFormat::eR16_SFLOAT ) ); + auto & accumulationPass = graph.createPass( "accumulationPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto aa = accumulationPass.addOutputColourTarget( av ); + auto ra = accumulationPass.addOutputColourTarget( rv ); + if ( dta ) + accumulationPass.addInputDepthStencilTarget( *dta ); + else + dta = accumulationPass.addOutputDepthStencilTarget( dtv ); + + auto c = graph.createImage( test::createImage( "c", crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto cv = graph.createView( test::createView( "cv", c, crg::PixelFormat::eR32G32B32_SFLOAT ) ); + auto & combinePass = graph.createPass( "combinePass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + if ( lda ) + combinePass.addInputSampled( *lda, 0u ); + combinePass.addInputSampled( *aa, 1u ); + combinePass.addInputSampled( *ra, 2u ); + return combinePass.addOutputColourTarget( cv ); +} - auto & combinePass = graph.createPass( "combinePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - combinePass.addDependency( blurPass0Y ); - combinePass.addDependency( blurPass1Y ); - combinePass.addDependency( blurPass2Y ); - combinePass.addDependency( blurPass3Y ); - combinePass.addSampledView( scenev, 0u ); - combinePass.addSampledView( combinePass.mergeViews( { hi0v, hi1v, hi2v, hi3v } ), 1u ); - combinePass.addOutputColourView( outputv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() +template< bool EnableDepthPrepass + , bool EnableOpaque + , bool EnableSsao + , bool EnableTransparent > +struct ParamsT +{ + static constexpr bool EnableDepthPrepassT = EnableDepthPrepass; + static constexpr bool EnableOpaqueT = EnableOpaque; + static constexpr bool EnableSsaoT = EnableSsao; + static constexpr bool EnableTransparentT = EnableTransparent; +}; + +using ParamTypes = testing::Types< ParamsT< false, false, false, false > + , ParamsT< false, false, false, true > + , ParamsT< false, true, false, false > + , ParamsT< false, true, false, true > + , ParamsT< false, true, true, false > + , ParamsT< false, true, true, true > + , ParamsT< true, false, false, false > + , ParamsT< true, false, false, true > + , ParamsT< true, true, false, false > + , ParamsT< true, true, false, true > + , ParamsT< true, true, true, false > + , ParamsT< true, true, true, true > >; + +class ParamTypeNames +{ +public: + template< typename T > + static std::string GetName( int ) + { + static constexpr bool EnableDepthPrepass = T::EnableDepthPrepassT; + static constexpr bool EnableOpaque = T::EnableOpaqueT; + static constexpr bool EnableSsao = T::EnableSsaoT; + static constexpr bool EnableTransparent = T::EnableTransparentT; + return ( EnableDepthPrepass ? std::string{ "Prepass" } : std::string{} ) + + ( EnableOpaque ? std::string{ "Opaque" } : std::string{} ) + + ( EnableSsao ? std::string{ "Ssao" } : std::string{} ) + + ( EnableTransparent ? std::string{ "Transparent" } : std::string{} ); } +}; - template< bool EnableSsao > - std::pair< crg::ImageViewId, crg::FramePass * > buildDeferred( test::TestCounts & testCounts - , crg::FramePass const * previous - , crg::ImageViewId const & dsv - , crg::ImageViewId const & dtv - , crg::ImageViewId const & vtv - , crg::FrameGraph & graph ) +template< typename ParamT > +struct RenderGraphT : public ::testing::Test +{ +}; + +TYPED_TEST_SUITE( RenderGraphT, ParamTypes, ParamTypeNames ); + +TYPED_TEST( RenderGraphT, Render ) +{ + static constexpr bool EnableDepthPrepass = TypeParam::EnableDepthPrepassT; + static constexpr bool EnableOpaque = TypeParam::EnableOpaqueT; + static constexpr bool EnableSsao = TypeParam::EnableSsaoT; + static constexpr bool EnableTransparent = TypeParam::EnableTransparentT; + testBegin( "testRender" + + ( EnableDepthPrepass ? std::string{ "Prepass" } : std::string{} ) + + ( EnableOpaque ? std::string{ "Opaque" } : std::string{} ) + + ( EnableSsao ? std::string{ "Ssao" } : std::string{} ) + + ( EnableTransparent ? std::string{ "Transparent" } : std::string{} ) ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto dtv = graph.createView( test::createView( "dtv", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto ld = graph.createImage( test::createImage( "ld", crg::PixelFormat::eR32_SFLOAT ) ); + auto ldv = graph.createView( test::createView( "ldv", d, crg::PixelFormat::eR32_SFLOAT ) ); + crg::Attachment const * dta{}; + crg::Attachment const * lda{}; + + if constexpr ( EnableDepthPrepass ) { - auto d1 = graph.createImage( test::createImage( "d1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto d1v = graph.createView( test::createView( "d1v", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); - auto d2 = graph.createImage( test::createImage( "d2", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d2v = graph.createView( test::createView( "d2v", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d3 = graph.createImage( test::createImage( "d3", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d3v = graph.createView( test::createView( "d3v", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d4 = graph.createImage( test::createImage( "d4", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto d4v = graph.createView( test::createView( "d4v", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto & geometryPass = graph.createPass( "geometryPass" + auto & depthPrepass = graph.createPass( "depthPrepass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -1067,50 +1236,33 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); + lda = depthPrepass.addOutputColourTarget ( ldv ); + dta = depthPrepass.addOutputDepthTarget ( dtv ); + } - if ( previous ) - { - geometryPass.addDependency( *previous ); - } + auto o = graph.createImage( test::createImage( "o", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto otv = graph.createView( test::createView( "otv", o, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - geometryPass.addOutputColourView( d1v ); - geometryPass.addOutputColourView( d2v ); - geometryPass.addOutputColourView( d3v ); - geometryPass.addOutputColourView( d4v ); - geometryPass.addOutputColourView( vtv ); - geometryPass.addOutputDepthStencilView( dtv ); - - auto df = graph.createImage( test::createImage( "df", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto dfv = graph.createView( test::createView( "dfv", df, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto sp = graph.createImage( test::createImage( "sp", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto spv = graph.createView( test::createView( "spv", sp, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & lightingPass = graph.createPass( "lightingPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - lightingPass.addDependency( geometryPass ); - lightingPass.addSampledView( dtv, 0 ); - lightingPass.addSampledView( d1v, 1 ); - lightingPass.addSampledView( d2v, 2 ); - lightingPass.addSampledView( d3v, 3 ); - lightingPass.addSampledView( d4v, 4 ); - lightingPass.addOutputColourView( dfv ); - lightingPass.addOutputColourView( spv ); - - auto of = graph.createImage( test::createImage( "of", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto ofv = graph.createView( test::createView( "ofv", of, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - - if constexpr ( EnableSsao ) - { - auto [ssaoResult, ssaoPass] = buildSsaoPass( testCounts - , geometryPass - , dsv + if constexpr ( EnableOpaque ) + { + auto v = graph.createImage( test::createImage( "v", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto vv = graph.createView( test::createView( "vv", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto dca = buildDeferred< EnableSsao >( testCounts + , lda + , dta + , ldv + , dtv + , vv + , graph ); + + if constexpr ( EnableTransparent ) + { + auto wbcsa = buildWeightedBlended( testCounts + , dta + , lda + , dtv , graph ); - auto & ambientPass = graph.createPass( "ambientPass" + auto & finalCombinePass = graph.createPass( "finalCombinePass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -1118,22 +1270,14 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - ambientPass.addDependency( *ssaoPass ); - ambientPass.addDependency( lightingPass ); - ambientPass.addSampledView( dsv, 0 ); - ambientPass.addSampledView( d1v, 1 ); - ambientPass.addSampledView( d2v, 2 ); - ambientPass.addSampledView( d3v, 3 ); - ambientPass.addSampledView( d4v, 4 ); - ambientPass.addSampledView( dfv, 5 ); - ambientPass.addSampledView( spv, 6 ); - ambientPass.addSampledView( ssaoResult, 7 ); - ambientPass.addOutputColourView( ofv ); - return { ofv, &ambientPass }; + finalCombinePass.addInputSampled( *lda, 0 ); + finalCombinePass.addInputSampled( *dca, 1 ); + finalCombinePass.addInputSampled( *wbcsa, 2 ); + finalCombinePass.addOutputColourTarget( otv ); } else { - auto & ambientPass = graph.createPass( "ambientPass" + auto & finalCombinePass = graph.createPass( "finalCombinePass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -1141,31 +1285,20 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - ambientPass.addDependency( lightingPass ); - ambientPass.addSampledView( dsv, 0 ); - ambientPass.addSampledView( d1v, 1 ); - ambientPass.addSampledView( d2v, 2 ); - ambientPass.addSampledView( d3v, 3 ); - ambientPass.addSampledView( d4v, 4 ); - ambientPass.addSampledView( dfv, 5 ); - ambientPass.addSampledView( spv, 6 ); - ambientPass.addOutputColourView( ofv ); - return { ofv, &ambientPass }; + finalCombinePass.addInputSampled( *lda, 0 ); + finalCombinePass.addInputSampled( *dca, 1 ); + finalCombinePass.addOutputColourTarget( otv ); } + } - - std::pair< crg::ImageViewId, crg::FramePass * > buildWeightedBlended( test::TestCounts & testCounts - , crg::FramePass const * previous - , crg::ImageViewId const & dsv - , crg::ImageViewId const & dtv - , crg::ImageViewId const & vtv - , crg::FrameGraph & graph ) + else if constexpr ( EnableTransparent ) { - auto a = graph.createImage( test::createImage( "a", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto av = graph.createView( test::createView( "av", a, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto r = graph.createImage( test::createImage( "r", crg::PixelFormat::eR16_SFLOAT ) ); - auto rv = graph.createView( test::createView( "rv", r, crg::PixelFormat::eR16_SFLOAT ) ); - auto & accumulationPass = graph.createPass( "accumulationPass" + auto wba = buildWeightedBlended( testCounts + , dta + , lda + , dtv + , graph ); + auto & finalCombinePass = graph.createPass( "finalCombinePass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -1173,20 +1306,14 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - - if ( previous ) - { - accumulationPass.addDependency( *previous ); - } - - accumulationPass.addInOutColourView( av ); - accumulationPass.addInOutColourView( rv ); - accumulationPass.addInOutColourView( vtv ); - accumulationPass.addOutputDepthStencilView( dtv ); - - auto c = graph.createImage( test::createImage( "c", crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto cv = graph.createView( test::createView( "cv", c, crg::PixelFormat::eR32G32B32_SFLOAT ) ); - auto & combinePass = graph.createPass( "combinePass" + if ( lda ) + finalCombinePass.addInputSampled( *lda, 0 ); + finalCombinePass.addInputSampled( *wba, 1 ); + finalCombinePass.addOutputColourTarget( otv ); + } + else + { + auto & finalCombinePass = graph.createPass( "finalCombinePass" , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -1194,159 +1321,53 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - combinePass.addDependency( accumulationPass ); - combinePass.addSampledView( dsv, 0u ); - combinePass.addSampledView( av, 1u ); - combinePass.addSampledView( rv, 2u ); - combinePass.addOutputColourView( cv ); - - return { cv, &combinePass }; + if ( lda ) + finalCombinePass.addInputSampled( *lda, 0 ); + finalCombinePass.addOutputColourTarget( otv ); } - template< bool EnableDepthPrepass - , bool EnableOpaque - , bool EnableSsao - , bool EnableTransparent > - void testRender( test::TestCounts & testCounts ) - { - testBegin( "testRender" - + ( EnableDepthPrepass ? std::string{ "Prepass" } : std::string{} ) - + ( EnableOpaque ? std::string{ "Opaque" } : std::string{} ) - + ( EnableSsao ? std::string{ "Ssao" } : std::string{} ) - + ( EnableTransparent ? std::string{ "Transparent" } : std::string{} ) ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto d = graph.createImage( test::createImage( "d", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto dtv = graph.createView( test::createView( "dtv", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - crg::FramePass * previous{}; - - if constexpr ( EnableDepthPrepass ) - { - auto & depthPrepass = graph.createPass( "depthPrepass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - depthPrepass.addOutputDepthView( dtv ); - previous = &depthPrepass; - } - - auto dsv = graph.createView( test::createView( "dsv", d, crg::PixelFormat::eR32_SFLOAT ) ); - auto o = graph.createImage( test::createImage( "o", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto otv = graph.createView( test::createView( "otv", o, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto runnable = graph.compile( getContext() ); + auto stream = test::checkRunnable( testCounts, runnable ); + std::string ref; + if constexpr ( EnableDepthPrepass ) + { if constexpr ( EnableOpaque ) { - auto v = graph.createImage( test::createImage( "v", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto vv = graph.createView( test::createView( "vv", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto dcs = buildDeferred< EnableSsao >( testCounts - , previous - , dsv - , dtv - , vv - , graph ); - - if constexpr ( EnableTransparent ) - { - auto wbcsv = buildWeightedBlended( testCounts - , dcs.second - , dsv - , dtv - , vv - , graph ); - auto & finalCombinePass = graph.createPass( "finalCombinePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - finalCombinePass.addDependency( *wbcsv.second ); - finalCombinePass.addSampledView( dcs.first, 0 ); - finalCombinePass.addSampledView( wbcsv.first, 1 ); - finalCombinePass.addSampledView( vv, 2 ); - finalCombinePass.addOutputColourView( otv ); - } - else - { - auto & finalCombinePass = graph.createPass( "finalCombinePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - finalCombinePass.addDependency( *dcs.second ); - finalCombinePass.addSampledView( dcs.first, 0 ); - finalCombinePass.addSampledView( vv, 1 ); - finalCombinePass.addOutputColourView( otv ); - } - - } - else if constexpr ( EnableTransparent ) - { - auto v = graph.createImage( test::createImage( "v", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto vv = graph.createView( test::createView( "vv", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto [wbResult, wbPass] = buildWeightedBlended( testCounts - , previous - , dsv - , dtv - , vv - , graph ); - auto & finalCombinePass = graph.createPass( "finalCombinePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - finalCombinePass.addDependency( *wbPass ); - finalCombinePass.addSampledView( wbResult, 0 ); - finalCombinePass.addSampledView( vv, 1 ); - finalCombinePass.addOutputColourView( otv ); - } - else - { - auto & finalCombinePass = graph.createPass( "finalCombinePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - - if ( previous ) - { - finalCombinePass.addDependency( *previous ); - } - - finalCombinePass.addSampledView( dsv, 0 ); - finalCombinePass.addOutputColourView( otv ); - } - - auto runnable = graph.compile( getContext() ); - auto stream = test::checkRunnable( testCounts, runnable ); - std::string ref; - - if constexpr ( EnableDepthPrepass ) - { - if constexpr ( EnableOpaque ) + if constexpr ( EnableSsao ) { - if constexpr ( EnableSsao ) + if constexpr ( EnableTransparent ) { - if constexpr ( EnableTransparent ) - { - ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; + ref = R"(digraph { + "depthPrepass" [ shape=ellipse ]; "geometryPass" [ shape=ellipse ]; + "Transition to\ngeometryPass/dtv/IRds" [ shape=box ]; + "depthPrepass" -> "Transition to\ngeometryPass/dtv/IRds" [ label="dtv" ]; + "Transition to\ngeometryPass/dtv/IRds" -> "geometryPass" [ label="dtv" ]; + "ambientPass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "combinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; + "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; + "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; + "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; "lightingPass" [ shape=ellipse ]; + "ssaoBlurPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; + "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; + "Transition to\nambientPass/spv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; + "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; + "Transition to\nambientPass/b1v/Spl" [ shape=box ]; + "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; + "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "depthPrepass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; @@ -1358,91 +1379,64 @@ namespace "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; - "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; - "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; - "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" [ shape=box ]; - "ssaoLinearisePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nssaoLinearisePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" -> "ssaoLinearisePass" [ label="dtv" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; - "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; - "ssaoMinifyPass3" [ shape=ellipse ]; - "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; - "Transition to\nssaoRawPass/m3v/Spl" [ shape=box ]; "ssaoRawPass" [ shape=ellipse ]; - "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/m3v/Spl" [ label="m3v" ]; - "Transition to\nssaoRawPass/m3v/Spl" -> "ssaoRawPass" [ label="m3v" ]; "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; - "ssaoBlurPass" [ shape=ellipse ]; "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; - "Transition to\nambientPass/b1v/Spl" [ shape=box ]; - "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; - "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; - "Transition to\nambientPass/d1v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d1v/Spl" [ label="d1v" ]; - "Transition to\nambientPass/d1v/Spl" -> "ambientPass" [ label="d1v" ]; - "Transition to\nambientPass/d2v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d2v/Spl" [ label="d2v" ]; - "Transition to\nambientPass/d2v/Spl" -> "ambientPass" [ label="d2v" ]; - "Transition to\nambientPass/d3v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d3v/Spl" [ label="d3v" ]; - "Transition to\nambientPass/d3v/Spl" -> "ambientPass" [ label="d3v" ]; - "Transition to\nambientPass/d4v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d4v/Spl" [ label="d4v" ]; - "Transition to\nambientPass/d4v/Spl" -> "ambientPass" [ label="d4v" ]; - "Transition to\nambientPass/dsv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/dsv/Spl" [ label="dtv" ]; - "Transition to\nambientPass/dsv/Spl" -> "ambientPass" [ label="dtv" ]; - "Transition to\naccumulationPass/vv/IOc" [ shape=box ]; + "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoRawPass/lp/Spl3" [ shape=box ]; + "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/lp/Spl3" [ label="m3v" ]; + "Transition to\nssaoRawPass/lp/Spl3" -> "ssaoRawPass" [ label="m3v" ]; + "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; + "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ssaoLinearisePass" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; "accumulationPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\naccumulationPass/vv/IOc" [ label="vv" ]; - "Transition to\naccumulationPass/vv/IOc" -> "accumulationPass" [ label="vv" ]; "Transition to\ncombinePass/av/Spl" [ shape=box ]; - "combinePass" [ shape=ellipse ]; "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; "Transition to\ncombinePass/rv/Spl" [ shape=box ]; "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; - "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; - "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; - "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; } )"; - } - else - { - ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; + } + else + { + ref = R"(digraph { + "depthPrepass" [ shape=ellipse ]; "geometryPass" [ shape=ellipse ]; + "Transition to\ngeometryPass/dtv/IRds" [ shape=box ]; + "depthPrepass" -> "Transition to\ngeometryPass/dtv/IRds" [ label="dtv" ]; + "Transition to\ngeometryPass/dtv/IRds" -> "geometryPass" [ label="dtv" ]; + "ambientPass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; "lightingPass" [ shape=ellipse ]; + "ssaoBlurPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; + "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; + "Transition to\nambientPass/spv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; + "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; + "Transition to\nambientPass/b1v/Spl" [ shape=box ]; + "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; + "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "depthPrepass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; @@ -1454,75 +1448,58 @@ namespace "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; - "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; - "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; - "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" [ shape=box ]; - "ssaoLinearisePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nssaoLinearisePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" -> "ssaoLinearisePass" [ label="dtv" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; - "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; - "ssaoMinifyPass3" [ shape=ellipse ]; - "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; - "Transition to\nssaoRawPass/m3v/Spl" [ shape=box ]; "ssaoRawPass" [ shape=ellipse ]; - "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/m3v/Spl" [ label="m3v" ]; - "Transition to\nssaoRawPass/m3v/Spl" -> "ssaoRawPass" [ label="m3v" ]; "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; - "ssaoBlurPass" [ shape=ellipse ]; "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; - "Transition to\nambientPass/b1v/Spl" [ shape=box ]; - "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; - "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; - "Transition to\nambientPass/d1v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d1v/Spl" [ label="d1v" ]; - "Transition to\nambientPass/d1v/Spl" -> "ambientPass" [ label="d1v" ]; - "Transition to\nambientPass/d2v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d2v/Spl" [ label="d2v" ]; - "Transition to\nambientPass/d2v/Spl" -> "ambientPass" [ label="d2v" ]; - "Transition to\nambientPass/d3v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d3v/Spl" [ label="d3v" ]; - "Transition to\nambientPass/d3v/Spl" -> "ambientPass" [ label="d3v" ]; - "Transition to\nambientPass/d4v/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/d4v/Spl" [ label="d4v" ]; - "Transition to\nambientPass/d4v/Spl" -> "ambientPass" [ label="d4v" ]; - "Transition to\nambientPass/dsv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nambientPass/dsv/Spl" [ label="dtv" ]; - "Transition to\nambientPass/dsv/Spl" -> "ambientPass" [ label="dtv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; + "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoRawPass/lp/Spl3" [ shape=box ]; + "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/lp/Spl3" [ label="m3v" ]; + "Transition to\nssaoRawPass/lp/Spl3" -> "ssaoRawPass" [ label="m3v" ]; + "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; + "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ssaoLinearisePass" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; } )"; - } } - else if constexpr ( EnableTransparent ) - { - ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; + } + else if constexpr ( EnableTransparent ) + { + ref = R"(digraph { + "depthPrepass" [ shape=ellipse ]; "geometryPass" [ shape=ellipse ]; + "Transition to\ngeometryPass/dtv/IRds" [ shape=box ]; + "depthPrepass" -> "Transition to\ngeometryPass/dtv/IRds" [ label="dtv" ]; + "Transition to\ngeometryPass/dtv/IRds" -> "geometryPass" [ label="dtv" ]; + "ambientPass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "combinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; + "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; + "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; + "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; "lightingPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; + "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; + "Transition to\nambientPass/spv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; + "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "depthPrepass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; @@ -1534,49 +1511,40 @@ namespace "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; - "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; - "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; - "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\naccumulationPass/vv/IOc" [ shape=box ]; "accumulationPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\naccumulationPass/vv/IOc" [ label="vv" ]; - "Transition to\naccumulationPass/vv/IOc" -> "accumulationPass" [ label="vv" ]; "Transition to\ncombinePass/av/Spl" [ shape=box ]; - "combinePass" [ shape=ellipse ]; "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; "Transition to\ncombinePass/rv/Spl" [ shape=box ]; "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; - "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; - "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; - "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; } )"; - } - else - { - ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; + } + else + { + ref = R"(digraph { + "depthPrepass" [ shape=ellipse ]; "geometryPass" [ shape=ellipse ]; + "Transition to\ngeometryPass/dtv/IRds" [ shape=box ]; + "depthPrepass" -> "Transition to\ngeometryPass/dtv/IRds" [ label="dtv" ]; + "Transition to\ngeometryPass/dtv/IRds" -> "geometryPass" [ label="dtv" ]; + "ambientPass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; "lightingPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; + "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; + "Transition to\nambientPass/spv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; + "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "depthPrepass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; @@ -1588,284 +1556,142 @@ namespace "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; - "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; - "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; - "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; } )"; - } } - else if constexpr ( EnableTransparent ) - { - ref = R"(digraph { - "Transition to\ncombinePass/av/Spl" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; + } + else if constexpr ( EnableTransparent ) + { + ref = R"(digraph { "combinePass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; + "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; + "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; + "depthPrepass" [ shape=ellipse ]; + "accumulationPass" [ shape=ellipse ]; + "Transition to\ncombinePass/ldv/Spl" [ shape=box ]; + "depthPrepass" -> "Transition to\ncombinePass/ldv/Spl" [ label="ldv" ]; + "Transition to\ncombinePass/ldv/Spl" -> "combinePass" [ label="ldv" ]; + "Transition to\ncombinePass/av/Spl" [ shape=box ]; "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; "Transition to\ncombinePass/rv/Spl" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; - "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; - "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; + "Transition to\naccumulationPass/dtv/IRds" [ shape=box ]; + "depthPrepass" -> "Transition to\naccumulationPass/dtv/IRds" [ label="dtv" ]; + "Transition to\naccumulationPass/dtv/IRds" -> "accumulationPass" [ label="dtv" ]; } )"; - } - else - { - ref = R"(digraph { - "Transition to\nfinalCombinePass/dsv/Spl" [ shape=box ]; + } + else + { + ref = R"(digraph { + "Transition to\nfinalCombinePass/ldv/Spl" [ shape=box ]; "depthPrepass" [ shape=ellipse ]; "finalCombinePass" [ shape=ellipse ]; - "depthPrepass" -> "Transition to\nfinalCombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nfinalCombinePass/dsv/Spl" -> "finalCombinePass" [ label="dtv" ]; + "depthPrepass" -> "Transition to\nfinalCombinePass/ldv/Spl" [ label="ldv" ]; + "Transition to\nfinalCombinePass/ldv/Spl" -> "finalCombinePass" [ label="ldv" ]; } )"; - } } - else + } + else + { + if constexpr ( EnableOpaque ) { - if constexpr ( EnableOpaque ) + if constexpr ( EnableSsao ) { - if constexpr ( EnableSsao ) + if constexpr ( EnableTransparent ) { - if constexpr ( EnableTransparent ) - { - ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; + ref = R"(digraph { + "finalCombinePass" [ shape=ellipse ]; + "ambientPass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; "lightingPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; - "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; - "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/d2v/Spl" [ label="d2v" ]; - "Transition to\nlightingPass/d2v/Spl" -> "lightingPass" [ label="d2v" ]; - "Transition to\nlightingPass/d3v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/d3v/Spl" [ label="d3v" ]; - "Transition to\nlightingPass/d3v/Spl" -> "lightingPass" [ label="d3v" ]; - "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; - "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "ssaoLinearisePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nssaoLinearisePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" -> "ssaoLinearisePass" [ label="dtv" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; - "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; - "ssaoMinifyPass3" [ shape=ellipse ]; - "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; - "Transition to\nssaoRawPass/m3v/Spl" [ shape=box ]; - "ssaoRawPass" [ shape=ellipse ]; - "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/m3v/Spl" [ label="m3v" ]; - "Transition to\nssaoRawPass/m3v/Spl" -> "ssaoRawPass" [ label="m3v" ]; - "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; - "ssaoBlurPass" [ shape=ellipse ]; - "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; - "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; - "Transition to\nambientPass/b1v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; - "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; - "Transition to\nambientPass/d1v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d1v/Spl" [ label="d1v" ]; - "Transition to\nambientPass/d1v/Spl" -> "ambientPass" [ label="d1v" ]; - "Transition to\nambientPass/d2v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d2v/Spl" [ label="d2v" ]; - "Transition to\nambientPass/d2v/Spl" -> "ambientPass" [ label="d2v" ]; - "Transition to\nambientPass/d3v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d3v/Spl" [ label="d3v" ]; - "Transition to\nambientPass/d3v/Spl" -> "ambientPass" [ label="d3v" ]; - "Transition to\nambientPass/d4v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d4v/Spl" [ label="d4v" ]; - "Transition to\nambientPass/d4v/Spl" -> "ambientPass" [ label="d4v" ]; - "Transition to\nambientPass/dsv/Spl" [ shape=box ]; "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/dsv/Spl" [ label="dtv" ]; - "Transition to\nambientPass/dsv/Spl" -> "ambientPass" [ label="dtv" ]; - "Transition to\naccumulationPass/vv/IOc" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\naccumulationPass/vv/IOc" [ label="vv" ]; - "Transition to\naccumulationPass/vv/IOc" -> "accumulationPass" [ label="vv" ]; - "Transition to\ncombinePass/av/Spl" [ shape=box ]; - "combinePass" [ shape=ellipse ]; - "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; - "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; - "Transition to\ncombinePass/rv/Spl" [ shape=box ]; - "accumulationPass" [ shape=ellipse ]; - "combinePass" [ shape=ellipse ]; - "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; - "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; - "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; - "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; -} -)"; - } - else - { - ref = R"(digraph { "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "lightingPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nlightingPass/d2v/Spl" [ label="d2v" ]; "Transition to\nlightingPass/d2v/Spl" -> "lightingPass" [ label="d2v" ]; "Transition to\nlightingPass/d3v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nlightingPass/d3v/Spl" [ label="d3v" ]; "Transition to\nlightingPass/d3v/Spl" -> "lightingPass" [ label="d3v" ]; "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; - "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; - "Transition to\nambientPass/spv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; - "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" [ shape=box ]; - "ssaoLinearisePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nssaoLinearisePass/dsv/Spl" [ label="dtv" ]; - "Transition to\nssaoLinearisePass/dsv/Spl" -> "ssaoLinearisePass" [ label="dtv" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; - "ssaoMinifyPass1" [ shape=ellipse ]; - "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; - "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; - "ssaoMinifyPass2" [ shape=ellipse ]; - "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; - "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; - "ssaoMinifyPass3" [ shape=ellipse ]; - "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; - "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; - "Transition to\nssaoRawPass/m3v/Spl" [ shape=box ]; - "ssaoRawPass" [ shape=ellipse ]; - "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/m3v/Spl" [ label="m3v" ]; - "Transition to\nssaoRawPass/m3v/Spl" -> "ssaoRawPass" [ label="m3v" ]; - "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; "ssaoBlurPass" [ shape=ellipse ]; - "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; - "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; "Transition to\nambientPass/b1v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; - "Transition to\nambientPass/d1v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d1v/Spl" [ label="d1v" ]; - "Transition to\nambientPass/d1v/Spl" -> "ambientPass" [ label="d1v" ]; - "Transition to\nambientPass/d2v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d2v/Spl" [ label="d2v" ]; - "Transition to\nambientPass/d2v/Spl" -> "ambientPass" [ label="d2v" ]; - "Transition to\nambientPass/d3v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d3v/Spl" [ label="d3v" ]; - "Transition to\nambientPass/d3v/Spl" -> "ambientPass" [ label="d3v" ]; - "Transition to\nambientPass/d4v/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/d4v/Spl" [ label="d4v" ]; - "Transition to\nambientPass/d4v/Spl" -> "ambientPass" [ label="d4v" ]; - "Transition to\nambientPass/dsv/Spl" [ shape=box ]; - "ambientPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nambientPass/dsv/Spl" [ label="dtv" ]; - "Transition to\nambientPass/dsv/Spl" -> "ambientPass" [ label="dtv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; + "ssaoRawPass" [ shape=ellipse ]; + "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; + "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; + "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; + "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoRawPass/lp/Spl3" [ shape=box ]; + "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/lp/Spl3" [ label="m3v" ]; + "Transition to\nssaoRawPass/lp/Spl3" -> "ssaoRawPass" [ label="m3v" ]; + "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; + "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ssaoLinearisePass" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; + "combinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; + "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; + "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; + "accumulationPass" [ shape=ellipse ]; + "Transition to\ncombinePass/av/Spl" [ shape=box ]; + "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; + "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; + "Transition to\ncombinePass/rv/Spl" [ shape=box ]; + "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; + "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; + "Transition to\naccumulationPass/dtv/IRds" [ shape=box ]; + "geometryPass" -> "Transition to\naccumulationPass/dtv/IRds" [ label="dtv" ]; + "Transition to\naccumulationPass/dtv/IRds" -> "accumulationPass" [ label="dtv" ]; } )"; - } } - else if constexpr ( EnableTransparent ) + else { ref = R"(digraph { - "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; - "geometryPass" [ shape=ellipse ]; + "finalCombinePass" [ shape=ellipse ]; + "ambientPass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; "lightingPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; + "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; + "Transition to\nambientPass/spv/Spl" [ shape=box ]; + "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; + "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; + "geometryPass" [ shape=ellipse ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; @@ -1877,46 +1703,88 @@ namespace "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; - "Transition to\nambientPass/dfv/Spl" [ shape=box ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "ssaoBlurPass" [ shape=ellipse ]; + "Transition to\nambientPass/b1v/Spl" [ shape=box ]; + "ssaoBlurPass" -> "Transition to\nambientPass/b1v/Spl" [ label="b1v" ]; + "Transition to\nambientPass/b1v/Spl" -> "ambientPass" [ label="b1v" ]; + "ssaoRawPass" [ shape=ellipse ]; + "Transition to\nssaoBlurPass/rsv/Spl" [ shape=box ]; + "ssaoRawPass" -> "Transition to\nssaoBlurPass/rsv/Spl" [ label="rsv" ]; + "Transition to\nssaoBlurPass/rsv/Spl" -> "ssaoBlurPass" [ label="rsv" ]; + "ssaoMinifyPass3" [ shape=ellipse ]; + "Transition to\nssaoRawPass/lp/Spl3" [ shape=box ]; + "ssaoMinifyPass3" -> "Transition to\nssaoRawPass/lp/Spl3" [ label="m3v" ]; + "Transition to\nssaoRawPass/lp/Spl3" -> "ssaoRawPass" [ label="m3v" ]; + "ssaoMinifyPass2" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" [ shape=box ]; + "ssaoMinifyPass2" -> "Transition to\nssaoMinifyPass3/m2v/Spl" [ label="m2v" ]; + "Transition to\nssaoMinifyPass3/m2v/Spl" -> "ssaoMinifyPass3" [ label="m2v" ]; + "ssaoMinifyPass1" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" [ shape=box ]; + "ssaoMinifyPass1" -> "Transition to\nssaoMinifyPass2/m1v/Spl" [ label="m1v" ]; + "Transition to\nssaoMinifyPass2/m1v/Spl" -> "ssaoMinifyPass2" [ label="m1v" ]; + "ssaoLinearisePass" [ shape=ellipse ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" [ shape=box ]; + "ssaoLinearisePass" -> "Transition to\nssaoMinifyPass1/m0v/Spl" [ label="m0v" ]; + "Transition to\nssaoMinifyPass1/m0v/Spl" -> "ssaoMinifyPass1" [ label="m0v" ]; +} +)"; + } + } + else if constexpr ( EnableTransparent ) + { + ref = R"(digraph { + "finalCombinePass" [ shape=ellipse ]; "ambientPass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; + "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; + "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; + "lightingPass" [ shape=ellipse ]; + "Transition to\nambientPass/dfv/Spl" [ shape=box ]; "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; "Transition to\nambientPass/dfv/Spl" -> "ambientPass" [ label="dfv" ]; "Transition to\nambientPass/spv/Spl" [ shape=box ]; "lightingPass" -> "Transition to\nambientPass/spv/Spl" [ label="spv" ]; "Transition to\nambientPass/spv/Spl" -> "ambientPass" [ label="spv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" [ shape=box ]; - "finalCombinePass" [ shape=ellipse ]; - "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; - "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\naccumulationPass/vv/IOc" [ shape=box ]; + "geometryPass" [ shape=ellipse ]; + "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/d1v/Spl" [ label="d1v" ]; + "Transition to\nlightingPass/d1v/Spl" -> "lightingPass" [ label="d1v" ]; + "Transition to\nlightingPass/d2v/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/d2v/Spl" [ label="d2v" ]; + "Transition to\nlightingPass/d2v/Spl" -> "lightingPass" [ label="d2v" ]; + "Transition to\nlightingPass/d3v/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/d3v/Spl" [ label="d3v" ]; + "Transition to\nlightingPass/d3v/Spl" -> "lightingPass" [ label="d3v" ]; + "Transition to\nlightingPass/d4v/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; + "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; + "geometryPass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; + "combinePass" [ shape=ellipse ]; + "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; + "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; + "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; "accumulationPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\naccumulationPass/vv/IOc" [ label="vv" ]; - "Transition to\naccumulationPass/vv/IOc" -> "accumulationPass" [ label="vv" ]; "Transition to\ncombinePass/av/Spl" [ shape=box ]; - "combinePass" [ shape=ellipse ]; "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; "Transition to\ncombinePass/rv/Spl" [ shape=box ]; "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; - "Transition to\nfinalCombinePass/cv/Spl" [ shape=box ]; - "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; - "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; + "Transition to\naccumulationPass/dtv/IRds" [ shape=box ]; + "geometryPass" -> "Transition to\naccumulationPass/dtv/IRds" [ label="dtv" ]; + "Transition to\naccumulationPass/dtv/IRds" -> "accumulationPass" [ label="dtv" ]; } )"; - } - else - { - ref = R"(digraph { + } + else + { + ref = R"(digraph { "Transition to\nlightingPass/d1v/Spl" [ shape=box ]; "geometryPass" [ shape=ellipse ]; "lightingPass" [ shape=ellipse ]; @@ -1932,10 +1800,10 @@ namespace "geometryPass" [ shape=ellipse ]; "geometryPass" -> "Transition to\nlightingPass/d4v/Spl" [ label="d4v" ]; "Transition to\nlightingPass/d4v/Spl" -> "lightingPass" [ label="d4v" ]; - "Transition to\nlightingPass/dtv/Spl" [ shape=box ]; + "Transition to\nlightingPass/ldv/Spl" [ shape=box ]; "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nlightingPass/dtv/Spl" [ label="dtv" ]; - "Transition to\nlightingPass/dtv/Spl" -> "lightingPass" [ label="dtv" ]; + "geometryPass" -> "Transition to\nlightingPass/ldv/Spl" [ label="ldv" ]; + "Transition to\nlightingPass/ldv/Spl" -> "lightingPass" [ label="ldv" ]; "Transition to\nambientPass/dfv/Spl" [ shape=box ]; "ambientPass" [ shape=ellipse ]; "lightingPass" -> "Transition to\nambientPass/dfv/Spl" [ label="dfv" ]; @@ -1947,25 +1815,19 @@ namespace "finalCombinePass" [ shape=ellipse ]; "ambientPass" -> "Transition to\nfinalCombinePass/ofv/Spl" [ label="ofv" ]; "Transition to\nfinalCombinePass/ofv/Spl" -> "finalCombinePass" [ label="ofv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; "geometryPass" [ shape=ellipse ]; - "geometryPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; } )"; - } } - else if constexpr ( EnableTransparent ) - { - ref = R"(digraph { + } + else if constexpr ( EnableTransparent ) + { + ref = R"(digraph { "Transition to\ncombinePass/av/Spl" [ shape=box ]; "accumulationPass" [ shape=ellipse ]; "combinePass" [ shape=ellipse ]; "accumulationPass" -> "Transition to\ncombinePass/av/Spl" [ label="av" ]; "Transition to\ncombinePass/av/Spl" -> "combinePass" [ label="av" ]; - "Transition to\ncombinePass/dsv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\ncombinePass/dsv/Spl" [ label="dtv" ]; - "Transition to\ncombinePass/dsv/Spl" -> "combinePass" [ label="dtv" ]; "Transition to\ncombinePass/rv/Spl" [ shape=box ]; "accumulationPass" -> "Transition to\ncombinePass/rv/Spl" [ label="rv" ]; "Transition to\ncombinePass/rv/Spl" -> "combinePass" [ label="rv" ]; @@ -1973,321 +1835,98 @@ namespace "finalCombinePass" [ shape=ellipse ]; "combinePass" -> "Transition to\nfinalCombinePass/cv/Spl" [ label="cv" ]; "Transition to\nfinalCombinePass/cv/Spl" -> "finalCombinePass" [ label="cv" ]; - "Transition to\nfinalCombinePass/vv/Spl" [ shape=box ]; - "accumulationPass" -> "Transition to\nfinalCombinePass/vv/Spl" [ label="vv" ]; - "Transition to\nfinalCombinePass/vv/Spl" -> "finalCombinePass" [ label="vv" ]; } )"; - } - else - { - ref = R"(digraph { + } + else + { + ref = R"(digraph { } )"; - } } - - checkEqualSortedLines( stream.str(), ref ) - testEnd() } - void testVarianceShadowMap( test::TestCounts & testCounts ) + checkEqualSortedLines( stream, ref ) + testEnd() +} + +TEST( RenderGraph, VarianceShadowMap ) +{ + testBegin( "testVarianceShadowMap" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + + auto & dirGroup = graph.createPassGroup( "Directional" ); + auto dirShadowMap = dirGroup.createImage( test::createImage( "dirShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 4u ) ); + auto dirVarianceMap = dirGroup.createImage( test::createImage( "dirVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 4u ) ); + auto buffer = dirGroup.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = dirGroup.createView( test::createView( "bufferv", buffer ) ); + crg::AttachmentArray dirShadows; + crg::AttachmentArray dirVariances; { - testBegin( "testVarianceShadowMap" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; + auto intermediate = dirGroup.createImage( test::createImage( "dirIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); + auto intermediatev = dirGroup.createView( test::createView( "dirIntermediatev", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); - auto & dirGroup = graph.createPassGroup( "Directional" ); - auto dirShadowMap = dirGroup.createImage( test::createImage( "dirShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 4u ) ); - auto dirVarianceMap = dirGroup.createImage( test::createImage( "dirVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 4u ) ); - auto dirShadowMapv = dirGroup.createView( test::createView( "dirShadowMapv", dirShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, 0u, 4u ) ); - auto dirVarianceMapv = dirGroup.createView( test::createView( "dirVarianceMapv", dirVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, 0u, 4u ) ); - crg::Buffer buffer{ VkBuffer( uintptr_t( 1 ) ), "buffer" }; - crg::ImageViewIdArray dirShadows; - crg::ImageViewIdArray dirVariances; + for ( uint32_t index = 0u; index < 4u; ++index ) { - auto dirIntermediate = dirGroup.createImage( test::createImage( "dirIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); - auto dirIntermediatev = dirGroup.createView( test::createView( "dirIntermediatev", dirIntermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); - - for ( uint32_t index = 0u; index < 4u; ++index ) - { - auto shadowMapv = dirGroup.createView( test::createView( "dirShadowMapv" + std::to_string( index ), dirShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); - dirShadows.push_back( shadowMapv ); - auto varianceMapv = dirGroup.createView( test::createView( "dirVarianceMapv" + std::to_string( index ), dirVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); - dirVariances.push_back( varianceMapv ); - auto & shadowPass = dirGroup.createPass( "dirShadowPass" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - auto previous = &shadowPass; - shadowPass.addClearableOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - shadowPass.addOutputDepthView( shadowMapv ); - shadowPass.addOutputColourView( varianceMapv ); - - auto & blurPassX = dirGroup.createPass( "dirBlurPassX" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassX.addDependency( *previous ); - previous = &blurPassX; - blurPassX.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassX.addSampledView( varianceMapv, 1u ); - blurPassX.addOutputColourView( dirIntermediatev ); - - auto & blurPassY = dirGroup.createPass( "dirBlurPassY" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassY.addDependency( *previous ); - previous = &blurPassY; - blurPassY.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassY.addSampledView( dirIntermediatev, 1u ); - blurPassY.addOutputColourView( varianceMapv ); - dirGroup.addGroupOutput( varianceMapv ); - } - } - auto & pntGroup = graph.createPassGroup( "Point" ); - auto pntShadowMap = pntGroup.createImage( test::createImage( "pntShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 36u ) ); - auto pntVarianceMap = pntGroup.createImage( test::createImage( "pntVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 36u ) ); - auto pntShadowMapv = pntGroup.createView( test::createView( "pntShadowMapv", pntShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, 0u, 36u ) ); - auto pntVarianceMapv = pntGroup.createView( test::createView( "pntVarianceMapv", pntVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, 0u, 36u ) ); - crg::ImageViewIdArray pntShadows; - crg::ImageViewIdArray pntVariances; - { - auto pntIntermediate = pntGroup.createImage( test::createImage( "pntIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); - auto pntIntermediatev = pntGroup.createView( test::createView( "pntIntermediatev", pntIntermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); - - for ( uint32_t index = 0u; index < 36u; ++index ) - { - auto shadowMapv = pntGroup.createView( test::createView( "pntShadowMapv" + std::to_string( index ), pntShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); - pntShadows.push_back( shadowMapv ); - auto varianceMapv = pntGroup.createView( test::createView( "pntVarianceMapv" + std::to_string( index ), pntVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); - pntVariances.push_back( varianceMapv ); - auto & shadowPass = pntGroup.createPass( "pntShadowPass" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - auto previous = &shadowPass; - shadowPass.addClearableOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - shadowPass.addOutputDepthView( shadowMapv ); - shadowPass.addOutputColourView( varianceMapv ); - - auto & blurPassX = pntGroup.createPass( "pntBlurPassX" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassX.addDependency( *previous ); - previous = &blurPassX; - blurPassX.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassX.addSampledView( varianceMapv, 1u ); - blurPassX.addOutputColourView( pntIntermediatev ); - - auto & blurPassY = pntGroup.createPass( "pntBlurPassY" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassY.addDependency( *previous ); - previous = &blurPassY; - blurPassY.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassY.addSampledView( pntIntermediatev, 1u ); - blurPassY.addOutputColourView( varianceMapv ); - pntGroup.addGroupOutput( varianceMapv ); - } - } - auto & sptGroup = graph.createPassGroup( "Spot" ); - auto sptShadowMap = sptGroup.createImage( test::createImage( "sptShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 10u ) ); - auto sptVarianceMap = sptGroup.createImage( test::createImage( "pntVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 10u ) ); - auto sptShadowMapv = sptGroup.createView( test::createView( "sptShadowMapv", sptShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, 0u, 10u ) ); - auto sptVarianceMapv = sptGroup.createView( test::createView( "sptVarianceMapv", sptVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, 0u, 10u ) ); - crg::ImageViewIdArray sptShadows; - crg::ImageViewIdArray sptVariances; - { - auto sptIntermediate = sptGroup.createImage( test::createImage( "sptIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); - auto sptIntermediatev = sptGroup.createView( test::createView( "sptIntermediatev", sptIntermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); - - for ( uint32_t index = 0u; index < 10u; ++index ) - { - auto shadowMapv = sptGroup.createView( test::createView( "sptShadowMapv" + std::to_string( index ), sptShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); - sptShadows.push_back( shadowMapv ); - auto varianceMapv = sptGroup.createView( test::createView( "sptVarianceMapv" + std::to_string( index ), sptVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); - sptVariances.push_back( varianceMapv ); - auto & shadowPass = sptGroup.createPass( "sptShadowPass" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkOutputColourIsShaderReadOnly ); - } ); - auto previous = &shadowPass; - shadowPass.addClearableOutputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - shadowPass.addOutputDepthView( shadowMapv ); - shadowPass.addOutputColourView( varianceMapv ); - - auto & blurPassX = sptGroup.createPass( "sptBlurPassX" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassX.addDependency( *previous ); - previous = &blurPassX; - blurPassX.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassX.addSampledView( varianceMapv, 1u ); - blurPassX.addOutputColourView( sptIntermediatev ); - - auto & blurPassY = sptGroup.createPass( "sptBlurPassY" + std::to_string( index ) - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - blurPassY.addDependency( *previous ); - previous = &blurPassY; - blurPassY.addInputStorageBuffer( buffer, 0u, 0u, VK_WHOLE_SIZE ); - blurPassY.addSampledView( sptIntermediatev, 1u ); - blurPassY.addOutputColourView( varianceMapv ); - sptGroup.addGroupOutput( varianceMapv ); - } - } + auto shadowMapv = dirGroup.createView( test::createView( "dirShadowMapv" + std::to_string( index ), dirShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); + auto varianceMapv = dirGroup.createView( test::createView( "dirVarianceMapv" + std::to_string( index ), dirVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); + auto & shadowPass = dirGroup.createPass( "dirShadowPass" + std::to_string( index ) + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u ); + auto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv ); + auto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv ); + dirShadows.push_back( shadowMapa ); - auto & objGroup = graph.createPassGroup( "Objects" ); - auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto depthv = graph.createView( test::createView( "depthv", depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); - auto & depthPrepass = graph.createPass( "depthPrepass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - depthPrepass.addOutputDepthView( depthv ); - auto previous = &depthPrepass; + auto & blurPassX = dirGroup.createPass( "dirBlurPassX" + std::to_string( index ) + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkSampledIsShaderReadOnly ); + } ); + blurPassX.addInputStorage( *buffera, 0u ); + blurPassX.addInputSampled( *varianceMapa, 1u ); + auto intermediatea = blurPassX.addOutputColourTarget( intermediatev ); - auto colour = graph.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto & backgroundPass = graph.createPass( "backgroundPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - backgroundPass.addDependency( *previous ); - previous = &backgroundPass; - backgroundPass.addInOutDepthView( depthv ); - backgroundPass.addOutputColourView( colourv ); - objGroup.addOutput( colourv - , crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); - - auto & opaquePass = objGroup.createPass( "opaquePass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , checkSampledIsShaderReadOnly ); - } ); - opaquePass.addDependency( *previous ); - previous = &opaquePass; - opaquePass.addSampledView( dirShadowMapv, 0u ); - opaquePass.addSampledView( dirVarianceMapv, 1u ); - opaquePass.addSampledView( opaquePass.mergeViews( dirShadows ), 0u ); - opaquePass.addSampledView( opaquePass.mergeViews( dirVariances ), 1u ); - opaquePass.addSampledView( pntShadowMapv, 2u ); - opaquePass.addSampledView( pntVarianceMapv, 3u ); - opaquePass.addSampledView( opaquePass.mergeViews( pntShadows ), 2u ); - opaquePass.addSampledView( opaquePass.mergeViews( pntVariances ), 3u ); - opaquePass.addSampledView( sptShadowMapv, 4u ); - opaquePass.addSampledView( sptVarianceMapv, 5u ); - opaquePass.addSampledView( opaquePass.mergeViews( sptShadows ), 4u ); - opaquePass.addSampledView( opaquePass.mergeViews( sptVariances ), 5u ); - opaquePass.addInOutDepthView( depthv ); - opaquePass.addInOutColourView( colourv ); - - auto & transparentPass = objGroup.createPass( "transparentPass" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); - } ); - transparentPass.addDependency( *previous ); - previous = &transparentPass; - transparentPass.addInOutDepthView( depthv ); - transparentPass.addInOutColourView( colourv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() + auto & blurPassY = dirGroup.createPass( "dirBlurPassY" + std::to_string( index ) + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkSampledIsShaderReadOnly ); + } ); + blurPassY.addInputStorage( *buffera, 0u ); + blurPassY.addInputSampled( *intermediatea, 1u ); + varianceMapa = blurPassY.addOutputColourTarget( varianceMapv ); + dirGroup.addGroupOutput( varianceMapv ); + dirVariances.push_back( varianceMapa ); + } } - - void testEnvironmentMap( test::TestCounts & testCounts ) + auto & pntGroup = graph.createPassGroup( "Point" ); + auto pntShadowMap = pntGroup.createImage( test::createImage( "pntShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 36u ) ); + auto pntVarianceMap = pntGroup.createImage( test::createImage( "pntVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 36u ) ); + crg::AttachmentArray pntShadows; + crg::AttachmentArray pntVariances; { - testBegin( "testEnvironmentMap" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) ); - auto cube = graph.createImage( test::createImageCube( "cube", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) ); - auto cubev = graph.createView( test::createView( "cubev", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) ); - auto cubes = graph.createImage( test::createImageCube( "cubes", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); - auto cubesv = graph.createView( test::createView( "cubesv", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) ); - auto colour = graph.createImage( test::createImage1D( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); - auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) ); - crg::ImageViewIdArray colourViews; - crg::ImageViewIdArray cubeViews; - crg::ImageViewIdArray cubesViews; - crg::ImageViewIdArray cubesLayersViews; - std::vector< crg::FramePass const * > previouses{}; - crg::FramePass const * previous{}; - - for ( auto index = 0u; index < 6u; ++index ) - { - auto strIndex = std::to_string( index ); - auto colourvn = graph.createView( test::createView( "colourv" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); - auto cubevn = graph.createView( test::createView( "cubev" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); - auto cubesvn = graph.createView( test::createView( "cubesv" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) ); - auto depthvn = graph.createView( test::createView( "depthv" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) ); - auto & opaquePass = graph.createPass( "EnvOpaquePass" + strIndex + auto intermediate = pntGroup.createImage( test::createImage( "pntIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); + auto intermediatev = pntGroup.createView( test::createView( "pntIntermediatev", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); + + for ( uint32_t index = 0u; index < 36u; ++index ) + { + auto shadowMapv = pntGroup.createView( test::createView( "pntShadowMapv" + std::to_string( index ), pntShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); + auto varianceMapv = pntGroup.createView( test::createView( "pntVarianceMapv" + std::to_string( index ), pntVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); + auto & shadowPass = pntGroup.createPass( "pntShadowPass" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -2295,211 +1934,337 @@ namespace return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - colourViews.push_back( colourvn ); - cubeViews.push_back( cubevn ); - cubesViews.push_back( cubesvn ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 0u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 0u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 1u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 1u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 2u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 2u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 3u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 3u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 4u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 4u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 5u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 5u, 1u ) ) ); - previous = &opaquePass; - opaquePass.addOutputDepthView( depthvn ); - opaquePass.addOutputColourView( colourvn ); - opaquePass.addOutputColourView( cubevn ); - opaquePass.addOutputColourView( cubesvn ); - - auto & backgroundPass = graph.createPass( "EnvBackgroundPass" + strIndex + auto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u ); + auto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv ); + auto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv ); + pntShadows.push_back( shadowMapa ); + + auto & blurPassX = pntGroup.createPass( "pntBlurPassX" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkSampledIsShaderReadOnly ); } ); - backgroundPass.addDependency( *previous ); - previous = &backgroundPass; - backgroundPass.addInOutDepthView( depthvn ); - backgroundPass.addInOutColourView( colourvn ); - backgroundPass.addInOutColourView( cubevn ); - backgroundPass.addInOutColourView( cubesvn ); - - auto & transparentPass = graph.createPass( "EnvTransparentPass" + strIndex + blurPassX.addInputStorage( *buffera, 0u ); + blurPassX.addInputSampled( *varianceMapa, 1u ); + auto intermediatea = blurPassX.addOutputColourTarget( intermediatev ); + + auto & blurPassY = pntGroup.createPass( "pntBlurPassY" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkSampledIsShaderReadOnly ); } ); - transparentPass.addDependency( *previous ); - previouses.push_back( &transparentPass ); - transparentPass.addInputDepthView( depthvn ); - transparentPass.addInOutColourView( colourvn ); - transparentPass.addInOutColourView( cubevn ); - transparentPass.addInOutColourView( cubesvn ); + blurPassY.addInputStorage( *buffera, 0u ); + blurPassY.addInputSampled( *intermediatea, 1u ); + varianceMapa = blurPassY.addOutputColourTarget( varianceMapv ); + pntVariances.push_back( varianceMapa ); + pntGroup.addGroupOutput( varianceMapv ); } - - auto & mipsGen = graph.createPass( "EnvMips" - , [&testCounts]( crg::FramePass const & framePass - , crg::GraphContext & context - , crg::RunnableGraph & runGraph ) - { - return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eTransfer ); - } ); - mipsGen.addDependencies( previouses ); - mipsGen.addTransferInputView( mipsGen.mergeViews( colourViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubeViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubesViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubesLayersViews ) ); - mipsGen.addTransferOutputView( colourv ); - mipsGen.addTransferOutputView( cubev ); - mipsGen.addTransferOutputView( cubesv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() } - - void testDisabledPasses( test::TestCounts & testCounts ) + auto & sptGroup = graph.createPassGroup( "Spot" ); + auto sptShadowMap = sptGroup.createImage( test::createImage( "sptShadowMap", crg::PixelFormat::eX8_D24_UNORM, 1u, 10u ) ); + auto sptVarianceMap = sptGroup.createImage( test::createImage( "pntVarianceMap", crg::PixelFormat::eR32G32_SFLOAT, 1u, 10u ) ); + crg::AttachmentArray sptShadows; + crg::AttachmentArray sptVariances; { - testBegin( "testDisabledPasses" ) - crg::ResourceHandler handler; - crg::FrameGraph graph{ handler, testCounts.testName }; - auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) ); - auto cube = graph.createImage( test::createImageCube( "cube", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) ); - auto cubev = graph.createView( test::createView( "cubev", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) ); - auto cubes = graph.createImage( test::createImageCube( "cubes", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); - auto cubesv = graph.createView( test::createView( "cubesv", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) ); - auto colour = graph.createImage( test::createImage1D( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); - auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) ); - crg::ImageViewIdArray colourViews; - crg::ImageViewIdArray cubeViews; - crg::ImageViewIdArray cubesViews; - crg::ImageViewIdArray cubesLayersViews; - std::vector< crg::FramePass const * > previouses{}; - crg::FramePass const * previous{}; - - for ( auto index = 0u; index < 6u; ++index ) - { - auto strIndex = std::to_string( index ); - auto colourvn = graph.createView( test::createView( "colourv" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); - auto cubevn = graph.createView( test::createView( "cubev" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); - auto cubesvn = graph.createView( test::createView( "cubesv" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) ); - auto depthvn = graph.createView( test::createView( "depthv" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) ); - auto & opaquePass = graph.createPass( "EnvOpaquePass" + strIndex + auto intermediate = sptGroup.createImage( test::createImage( "sptIntermediate", crg::PixelFormat::eR32G32_SFLOAT ) ); + auto intermediatev = sptGroup.createView( test::createView( "sptIntermediatev", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) ); + + for ( uint32_t index = 0u; index < 10u; ++index ) + { + auto shadowMapv = sptGroup.createView( test::createView( "sptShadowMapv" + std::to_string( index ), sptShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) ); + auto varianceMapv = sptGroup.createView( test::createView( "sptVarianceMapv" + std::to_string( index ), sptVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) ); + auto & shadowPass = sptGroup.createPass( "sptShadowPass" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkTargetColourIsShaderReadOnly ); } ); - colourViews.push_back( colourvn ); - cubeViews.push_back( cubevn ); - cubesViews.push_back( cubesvn ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 0u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 0u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 1u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 1u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 2u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 2u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 3u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 3u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 4u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 4u, 1u ) ) ); - cubesLayersViews.push_back( graph.createView( test::createView( "cubesv" + strIndex + std::to_string( 5u ), cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u + 5u, 1u ) ) ); - previous = &opaquePass; - opaquePass.addOutputDepthView( depthvn ); - opaquePass.addOutputColourView( colourvn ); - opaquePass.addOutputColourView( cubevn ); - opaquePass.addOutputColourView( cubesvn ); - - auto & backgroundPass = graph.createPass( "EnvBackgroundPass" + strIndex + auto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u ); + auto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv ); + auto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv ); + sptShadows.push_back( shadowMapa ); + + auto & blurPassX = sptGroup.createPass( "sptBlurPassX" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy, 0u, false ); + , checkSampledIsShaderReadOnly ); } ); - backgroundPass.addDependency( *previous ); - previous = &backgroundPass; - backgroundPass.addInOutDepthView( depthvn ); - backgroundPass.addInOutColourView( colourvn ); - backgroundPass.addInOutColourView( cubevn ); - backgroundPass.addInOutColourView( cubesvn ); - - auto & transparentPass = graph.createPass( "EnvTransparentPass" + strIndex + blurPassX.addInputStorage( *buffera, 0u ); + blurPassX.addInputSampled( *varianceMapa, 1u ); + auto intermediatea = blurPassX.addOutputColourTarget( intermediatev ); + + auto & blurPassY = sptGroup.createPass( "sptBlurPassY" + std::to_string( index ) , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader - , test::checkDummy, 0u, false ); + , checkSampledIsShaderReadOnly ); } ); - transparentPass.addDependency( *previous ); - previouses.push_back( &transparentPass ); - transparentPass.addInputDepthView( depthvn ); - transparentPass.addInOutColourView( colourvn ); - transparentPass.addInOutColourView( cubevn ); - transparentPass.addInOutColourView( cubesvn ); + blurPassY.addInputStorage( *buffera, 0u ); + blurPassY.addInputSampled( *intermediatea, 1u ); + varianceMapa = blurPassY.addOutputColourTarget( varianceMapv ); + sptVariances.push_back( varianceMapa ); + sptGroup.addGroupOutput( varianceMapv ); } + } + + auto & objGroup = graph.createPassGroup( "Objects" ); + auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto depthv = graph.createView( test::createView( "depthv", depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto & depthPrepass = graph.createPass( "depthPrepass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto deptha = depthPrepass.addOutputDepthTarget ( depthv ); + + auto colour = graph.createImage( test::createImage( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto & backgroundPass = graph.createPass( "backgroundPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + backgroundPass.addInputDepthTarget( *deptha ); + auto coloura = backgroundPass.addOutputColourTarget( colourv ); + objGroup.addOutput( colourv + , crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) ); + + auto & opaquePass = objGroup.createPass( "opaquePass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , checkSampledIsShaderReadOnly ); + } ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( dirShadows ), 0u ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( dirVariances ), 1u ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( pntShadows ), 2u ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( pntVariances ), 3u ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( sptShadows ), 4u ); + opaquePass.addInputSampled( *objGroup.mergeAttachments( sptVariances ), 5u ); + opaquePass.addInputDepthTarget( *deptha ); + coloura = opaquePass.addInOutColourTarget( *coloura ); + + auto & transparentPass = objGroup.createPass( "transparentPass" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + transparentPass.addInputDepthTarget( *deptha ); + transparentPass.addInOutColourTarget( *coloura ); + + crg::ResourcesCache cache{ handler }; + auto & context = getContext(); + VkDeviceMemory bufferMemory; + cache.createBuffer( context, buffer, bufferMemory ); + cache.createBufferView( context, bufferv ); + VkDeviceMemory imageMemory; + cache.createImage( context, depth, imageMemory ); + cache.createImageView( context, depthv ); + + handler.createBuffer( context, buffer ); + handler.createBufferView( context, bufferv ); + + auto runnable = graph.compile( context ); + test::checkRunnable( testCounts, runnable ); + testEnd() +} + +TEST( RenderGraph, EnvironmentMap ) +{ + testBegin( "testEnvironmentMap" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) ); + auto cube = graph.createImage( test::createImageCube( "cube", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) ); + auto cubev = graph.createView( test::createView( "cubev", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) ); + auto cubes = graph.createImage( test::createImageCube( "cubes", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); + auto cubesv = graph.createView( test::createView( "cubesv", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) ); + auto colour = graph.createImage( test::createImage1D( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); + auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) ); + crg::AttachmentArray colourViews; + crg::AttachmentArray cubeViews; + crg::AttachmentArray cubesViews; + + for ( auto index = 0u; index < 6u; ++index ) + { + auto strIndex = std::to_string( index ); + auto colourvn = graph.createView( test::createView( "colourv" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); + auto cubevn = graph.createView( test::createView( "cubev" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); + auto cubesvn = graph.createView( test::createView( "cubesv" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) ); + auto depthvn = graph.createView( test::createView( "depthv" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) ); + auto & opaquePass = graph.createPass( "EnvOpaquePass" + strIndex + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto depthan = opaquePass.addOutputDepthTarget( depthvn ); + auto colouran = opaquePass.addOutputColourTarget( colourvn ); + auto cubean = opaquePass.addOutputColourTarget( cubevn ); + auto cubesan = opaquePass.addOutputColourTarget( cubesvn ); + + auto & backgroundPass = graph.createPass( "EnvBackgroundPass" + strIndex + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + backgroundPass.addInputDepthTarget( *depthan ); + colouran = backgroundPass.addInOutColourTarget( *colouran ); + cubean = backgroundPass.addInOutColourTarget( *cubean ); + cubesan = backgroundPass.addInOutColourTarget( *cubesan ); - auto & mipsGen = graph.createPass( "EnvMips" + auto & transparentPass = graph.createPass( "EnvTransparentPass" + strIndex , [&testCounts]( crg::FramePass const & framePass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return createDummy( testCounts - , framePass, context, runGraph, crg::PipelineStageFlags::eTransfer ); + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); } ); - mipsGen.addDependencies( previouses ); - mipsGen.addTransferInputView( mipsGen.mergeViews( colourViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubeViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubesViews ) ); - mipsGen.addTransferInputView( mipsGen.mergeViews( cubesLayersViews ) ); - mipsGen.addTransferOutputView( colourv ); - mipsGen.addTransferOutputView( cubev ); - mipsGen.addTransferOutputView( cubesv ); - - auto runnable = graph.compile( getContext() ); - test::checkRunnable( testCounts, runnable ); - testEnd() + transparentPass.addInputDepthTarget( *depthan ); + colourViews.push_back( transparentPass.addInOutColourTarget( *colouran ) ); + cubeViews.push_back( transparentPass.addInOutColourTarget( *cubean ) ); + cubesViews.push_back( transparentPass.addInOutColourTarget( *cubesan ) ); } + + auto & mipsGen = graph.createPass( "EnvMips" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eTransfer ); + } ); + mipsGen.addInputTransfer( *graph.mergeAttachments( colourViews ) ); + mipsGen.addInputTransfer( *graph.mergeAttachments( cubeViews ) ); + mipsGen.addInputTransfer( *graph.mergeAttachments( cubesViews ) ); + mipsGen.addOutputTransferImage( colourv ); + mipsGen.addOutputTransferImage( cubev ); + mipsGen.addOutputTransferImage( cubesv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() } -int main( int argc, char ** argv ) +TEST( RenderGraph, DisabledPasses ) { - testSuiteBegin( "TestRenderGraph" ) - testNoPass( testCounts ); - testOnePass( testCounts ); - testDuplicateName( testCounts ); - testOneDependency( testCounts ); - testCycleDependency( testCounts ); - testUnsortableCycleDependency( testCounts ); - testChainedDependencies( testCounts ); - testSharedDependencies( testCounts ); - test2MipDependencies( testCounts ); - test3MipDependencies( testCounts ); - testLoopDependencies( testCounts ); - testLoopDependenciesWithRoot( testCounts ); - testLoopDependenciesWithRootAndLeaf( testCounts ); - testSsaoPass( testCounts ); - testBloomPostEffect( testCounts ); - testRender< false, false, false, false >( testCounts ); - testRender< false, true, false, false >( testCounts ); - testRender< false, true, true, false >( testCounts ); - testRender< false, false, false, true >( testCounts ); - testRender< false, true, false, true >( testCounts ); - testRender< false, true, true, true >( testCounts ); - testRender< true, false, false, false >( testCounts ); - testRender< true, true, false, false >( testCounts ); - testRender< true, true, true, false >( testCounts ); - testRender< true, false, false, true >( testCounts ); - testRender< true, true, false, true >( testCounts ); - testRender< true, true, true, true >( testCounts ); - testVarianceShadowMap( testCounts ); - testEnvironmentMap( testCounts ); - testDisabledPasses( testCounts ); - testSuiteEnd() + testBegin( "testDisabledPasses" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) ); + auto cube = graph.createImage( test::createImageCube( "cube", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) ); + auto cubev = graph.createView( test::createView( "cubev", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) ); + auto cubes = graph.createImage( test::createImageCube( "cubes", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); + auto cubesv = graph.createView( test::createView( "cubesv", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) ); + auto colour = graph.createImage( test::createImage1D( "colour", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) ); + auto colourv = graph.createView( test::createView( "colourv", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) ); + crg::AttachmentArray colourViews; + crg::AttachmentArray cubeViews; + crg::AttachmentArray cubesViews; + + for ( auto index = 0u; index < 6u; ++index ) + { + auto strIndex = std::to_string( index ); + auto colourvn = graph.createView( test::createView( "colourv" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); + auto cubevn = graph.createView( test::createView( "cubev" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) ); + auto cubesvn = graph.createView( test::createView( "cubesv" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) ); + auto depthvn = graph.createView( test::createView( "depthv" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) ); + auto & opaquePass = graph.createPass( "EnvOpaquePass" + strIndex + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader ); + } ); + auto depthan = opaquePass.addOutputDepthTarget( depthvn ); + auto colouran = opaquePass.addOutputColourTarget( colourvn ); + auto cubean = opaquePass.addOutputColourTarget( cubevn ); + auto cubesan = opaquePass.addOutputColourTarget( cubesvn ); + + auto & backgroundPass = graph.createPass( "EnvBackgroundPass" + strIndex + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy, 0u, false ); + } ); + backgroundPass.addInputDepthTarget( *depthan ); + colouran = backgroundPass.addInOutColourTarget( *colouran ); + cubean = backgroundPass.addInOutColourTarget( *cubean ); + cubesan = backgroundPass.addInOutColourTarget( *cubesan ); + + auto & transparentPass = graph.createPass( "EnvTransparentPass" + strIndex + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader + , test::checkDummy, 0u, false ); + } ); + transparentPass.addInputDepthTarget( *depthan ); + colourViews.push_back( transparentPass.addInOutColourTarget( *colouran ) ); + cubeViews.push_back( transparentPass.addInOutColourTarget( *cubean ) ); + cubesViews.push_back( transparentPass.addInOutColourTarget( *cubesan ) ); + } + + auto & mipsGen = graph.createPass( "EnvMips" + , [&testCounts]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return createDummy( testCounts + , framePass, context, runGraph, crg::PipelineStageFlags::eTransfer ); + } ); + mipsGen.addInputTransfer( *graph.mergeAttachments( colourViews ) ); + mipsGen.addInputTransfer( *graph.mergeAttachments( cubeViews ) ); + mipsGen.addInputTransfer( *graph.mergeAttachments( cubesViews ) ); + mipsGen.addOutputTransferImage( colourv ); + mipsGen.addOutputTransferImage( cubev ); + mipsGen.addOutputTransferImage( cubesv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() } + +testSuiteMain() diff --git a/test/TestRenderPass.cpp b/test/TestRenderPass.cpp index 4ba5ff9..3c72563 100644 --- a/test/TestRenderPass.cpp +++ b/test/TestRenderPass.cpp @@ -9,7 +9,7 @@ namespace { - void testLog( test::TestCounts & testCounts ) + TEST( FramePass, Log ) { testBegin( "testLog" ) auto callback = []( std::string_view msg, bool newLine )noexcept @@ -36,10 +36,28 @@ namespace crg::Logger::logWarning( "warningCoinNL" ); crg::Logger::logError( "errorCoinNoNL ", false ); crg::Logger::logError( "errorCoinNL" ); + + crg::Logger::setTraceCallback( nullptr ); + crg::Logger::setDebugCallback( nullptr ); + crg::Logger::setInfoCallback( nullptr ); + crg::Logger::setWarningCallback( nullptr ); + crg::Logger::setErrorCallback( nullptr ); + + crg::Logger::logTrace( "No callback traceCoinNoNL ", false ); + crg::Logger::logTrace( "No callback traceCoinNL" ); + crg::Logger::logDebug( "No callback debugCoinNoNL ", false ); + crg::Logger::logDebug( "No callback debugCoinNL" ); + crg::Logger::logInfo( "No callback infoCoinNoNL ", false ); + crg::Logger::logInfo( "No callback infoCoinNL" ); + crg::Logger::logWarning( "No callback warningCoinNoNL ", false ); + crg::Logger::logWarning( "No callback warningCoinNL" ); + crg::Logger::logError( "No callback errorCoinNoNL ", false ); + crg::Logger::logError( "No callback errorCoinNL" ); + testEnd() } - void testRenderPass_1C( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C ) { testBegin( "testRenderPass_1C" ) crg::ResourceHandler handler; @@ -47,15 +65,15 @@ namespace auto & pass = graph.createPass( "1C", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); check( pass.getName() == "1C" ) - check( pass.images.size() == 1u ) - check( pass.images[0].view() == rtv ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == rtv ) testEnd() } - void testRenderPass_2C( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C ) { testBegin( "testRenderPass_2C" ) crg::ResourceHandler handler; @@ -63,20 +81,20 @@ namespace auto & pass = graph.createPass( "2C", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); check( pass.getName() == "2C" ) - check( pass.images.size() == 2u ) - check( pass.images[0].view() == rtv1 ) - check( pass.images[1].view() == rtv2 ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == rtv1 ) + check( pass.targets[1]->view() == rtv2 ) testEnd() } - void testRenderPass_0C_1I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_0C_1I ) { testBegin( "testRenderPass_0C_1I" ) crg::ResourceHandler handler; @@ -84,15 +102,16 @@ namespace auto & pass = graph.createPass( "0C_1I", crg::RunnablePassCreator{} ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); check( pass.getName() == "0C_1I" ) - check( pass.images.size() == 1u ) - check( pass.images[0].view() == inv ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_0C_2I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_0C_2I ) { testBegin( "testRenderPass_0C_2I" ) crg::ResourceHandler handler; @@ -100,20 +119,22 @@ namespace auto & pass = graph.createPass( "0C_2I", crg::RunnablePassCreator{} ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); check( pass.getName() == "0C_2I" ) - check( pass.images.size() == 2u ) - check( pass.images[0].view() == inv1 ) - check( pass.images[1].view() == inv2 ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } - void testRenderPass_1C_1I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C_1I ) { testBegin( "testRenderPass_1C_1I" ) crg::ResourceHandler handler; @@ -121,20 +142,22 @@ namespace auto & pass = graph.createPass( "1C_1I", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); check( pass.getName() == "1C_1I" ) - check( pass.images.size() == 2u ) - check( pass.images[0].view() == rtv ) - check( pass.images[1].view() == inv ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == rtv ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_1C_2I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C_2I ) { testBegin( "testRenderPass_1C_2I" ) crg::ResourceHandler handler; @@ -142,25 +165,28 @@ namespace auto & pass = graph.createPass( "1C_2I", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); check( pass.getName() == "1C_2I" ) - check( pass.images.size() == 3u ) - check( pass.images[0].view() == rtv ) - check( pass.images[1].view() == inv1 ) - check( pass.images[2].view() == inv2 ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == rtv ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } - void testRenderPass_2C_1I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C_1I ) { testBegin( "testRenderPass_2C_1I" ) crg::ResourceHandler handler; @@ -168,25 +194,27 @@ namespace auto & pass = graph.createPass( "2C_1I", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); check( pass.getName() == "2C_1I" ) - check( pass.images.size() == 3u ) - check( pass.images[0].view() == rtv1 ) - check( pass.images[1].view() == rtv2 ) - check( pass.images[2].view() == inv ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == rtv1 ) + check( pass.targets[1]->view() == rtv2 ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_2C_2I( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C_2I ) { testBegin( "testRenderPass_2C_2I" ) crg::ResourceHandler handler; @@ -194,30 +222,33 @@ namespace auto & pass = graph.createPass( "2C_2I", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); check( pass.getName() == "2C_2I" ) - check( pass.images.size() == 4u ) - check( pass.images[0].view() == rtv1 ) - check( pass.images[1].view() == rtv2 ) - check( pass.images[2].view() == inv1 ) - check( pass.images[3].view() == inv2 ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == rtv1 ) + check( pass.targets[1]->view() == rtv2 ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } - void testRenderPass_0C_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_0C_DS ) { testBegin( "testRenderPass_0C_DS" ) crg::ResourceHandler handler; @@ -225,15 +256,15 @@ namespace auto & pass = graph.createPass( "0C_DS", crg::RunnablePassCreator{} ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "0C_DS" ) - check( pass.images.size() == 1u ) - check( pass.images[0].view() == dsv ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == dsv ) testEnd() } - void testRenderPass_1C_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C_DS ) { testBegin( "testRenderPass_1C_DS" ) crg::ResourceHandler handler; @@ -241,20 +272,20 @@ namespace auto & pass = graph.createPass( "1C_DS", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "1C_DS" ) - check( pass.images.size() == 2u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv ) testEnd() } - void testRenderPass_2C_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C_DS ) { testBegin( "testRenderPass_2C_DS" ) crg::ResourceHandler handler; @@ -262,25 +293,25 @@ namespace auto & pass = graph.createPass( "2C_DS", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "2C_DS" ) - check( pass.images.size() == 3u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv1 ) - check( pass.images[2].view() == rtv2 ) + check( pass.targets.size() == 3u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv1 ) + check( pass.targets[2]->view() == rtv2 ) testEnd() } - void testRenderPass_0C_1I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_0C_1I_DS ) { testBegin( "testRenderPass_0C_1I_DS" ) crg::ResourceHandler handler; @@ -288,20 +319,22 @@ namespace auto & pass = graph.createPass( "0C_1I_DS", crg::RunnablePassCreator{} ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "0C_1I_DS" ) - check( pass.images.size() == 2u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == inv ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == dsv ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_0C_2I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_0C_2I_DS ) { testBegin( "testRenderPass_0C_2I_DS" ) crg::ResourceHandler handler; @@ -309,25 +342,28 @@ namespace auto & pass = graph.createPass( "0C_2I_DS", crg::RunnablePassCreator{} ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "0C_2I_DS" ) - check( pass.images.size() == 3u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == inv1 ) - check( pass.images[2].view() == inv2 ) + check( pass.targets.size() == 1u ) + check( pass.targets[0]->view() == dsv ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } - void testRenderPass_1C_1I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C_1I_DS ) { testBegin( "testRenderPass_1C_1I_DS" ) crg::ResourceHandler handler; @@ -335,25 +371,27 @@ namespace auto & pass = graph.createPass( "1C_1I_DS", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "1C_1I_DS" ) - check( pass.images.size() == 3u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv ) - check( pass.images[2].view() == inv ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_1C_2I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_1C_2I_DS ) { testBegin( "testRenderPass_1C_2I_DS" ) crg::ResourceHandler handler; @@ -361,30 +399,33 @@ namespace auto & pass = graph.createPass( "1C_2I_DS", crg::RunnablePassCreator{} ); auto rt = graph.createImage( test::createImage( "rt", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv = graph.createView( test::createView( "rtv", rt ) ); - pass.addOutputColourView( rtv ); + pass.addOutputColourTarget( rtv ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "1C_2I_DS" ) - check( pass.images.size() == 4u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv ) - check( pass.images[2].view() == inv1 ) - check( pass.images[3].view() == inv2 ) + check( pass.targets.size() == 2u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } - void testRenderPass_2C_1I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C_1I_DS ) { testBegin( "testRenderPass_2C_1I_DS" ) crg::ResourceHandler handler; @@ -392,30 +433,32 @@ namespace auto & pass = graph.createPass( "2C_1I_DS", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); auto in = graph.createImage( test::createImage( "in", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv = graph.createView( test::createView( "inv", in ) ); - pass.addSampledView( inv, 1u ); + auto attach = crg::Attachment::createDefault( inv ); + pass.addInputSampled( attach, 1u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "2C_1I_DS" ) - check( pass.images.size() == 4u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv1 ) - check( pass.images[2].view() == rtv2 ) - check( pass.images[3].view() == inv ) + check( pass.targets.size() == 3u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv1 ) + check( pass.targets[2]->view() == rtv2 ) + check( pass.sampled.size() == 1u ) + check( pass.sampled.begin()->second.attach->view() == inv ) testEnd() } - void testRenderPass_2C_2I_DS( test::TestCounts & testCounts ) + TEST( FramePass, RenderPass_2C_2I_DS ) { testBegin( "testRenderPass_2C_2I_DS" ) crg::ResourceHandler handler; @@ -423,55 +466,36 @@ namespace auto & pass = graph.createPass( "2C_2I_DS", crg::RunnablePassCreator{} ); auto rt1 = graph.createImage( test::createImage( "rt1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv1 = graph.createView( test::createView( "rtv1", rt1 ) ); - pass.addOutputColourView( rtv1 ); + pass.addOutputColourTarget( rtv1 ); auto rt2 = graph.createImage( test::createImage( "rt2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto rtv2 = graph.createView( test::createView( "rtv2", rt2 ) ); - pass.addOutputColourView( rtv2 ); + pass.addOutputColourTarget( rtv2 ); auto in1 = graph.createImage( test::createImage( "in1", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv1 = graph.createView( test::createView( "inv1", in1 ) ); - pass.addSampledView( inv1, 1u ); + auto attach1 = crg::Attachment::createDefault( inv1 ); + pass.addInputSampled( attach1, 1u ); auto in2 = graph.createImage( test::createImage( "in2", crg::PixelFormat::eR32G32B32A32_SFLOAT ) ); auto inv2 = graph.createView( test::createView( "inv2", in2 ) ); - pass.addSampledView( inv2, 2u ); + auto attach2 = crg::Attachment::createDefault( inv2 ); + pass.addInputSampled( attach2, 2u ); auto ds = graph.createImage( test::createImage( "ds", crg::PixelFormat::eD32_SFLOAT ) ); auto dsv = graph.createView( test::createView( "dsv", ds ) ); - pass.addOutputDepthStencilView( dsv ); + pass.addOutputDepthStencilTarget( dsv ); check( pass.getName() == "2C_2I_DS" ) - check( pass.images.size() == 5u ) - check( pass.images[0].view() == dsv ) - check( pass.images[1].view() == rtv1 ) - check( pass.images[2].view() == rtv2 ) - check( pass.images[3].view() == inv1 ) - check( pass.images[4].view() == inv2 ) + check( pass.targets.size() == 3u ) + check( pass.targets[0]->view() == dsv ) + check( pass.targets[1]->view() == rtv1 ) + check( pass.targets[2]->view() == rtv2 ) + check( pass.sampled.size() == 2u ) + check( pass.sampled.begin()->second.attach->view() == inv1 ) + check( pass.sampled.rbegin()->second.attach->view() == inv2 ) testEnd() } } -int main( int argc, char ** argv ) -{ - testSuiteBegin( "TestRenderPass" ) - testLog( testCounts ); - testRenderPass_1C( testCounts ); - testRenderPass_2C( testCounts ); - testRenderPass_0C_1I( testCounts ); - testRenderPass_0C_2I( testCounts ); - testRenderPass_1C_1I( testCounts ); - testRenderPass_1C_2I( testCounts ); - testRenderPass_2C_1I( testCounts ); - testRenderPass_2C_2I( testCounts ); - testRenderPass_0C_DS( testCounts ); - testRenderPass_1C_DS( testCounts ); - testRenderPass_2C_DS( testCounts ); - testRenderPass_0C_1I_DS( testCounts ); - testRenderPass_0C_2I_DS( testCounts ); - testRenderPass_1C_1I_DS( testCounts ); - testRenderPass_1C_2I_DS( testCounts ); - testRenderPass_2C_1I_DS( testCounts ); - testRenderPass_2C_2I_DS( testCounts ); - testSuiteEnd() -} +testSuiteMain() diff --git a/test/TestRunnablePass.cpp b/test/TestRunnablePass.cpp index 84a7edd..525eb2a 100644 --- a/test/TestRunnablePass.cpp +++ b/test/TestRunnablePass.cpp @@ -25,12 +25,17 @@ namespace return test::getDummyContext(); } - void testBufferCopy( test::TestCounts & testCounts ) + TEST( RunnablePass, BufferCopy_I_O ) { - testBegin( "testBufferCopy" ) - crg::ResourceHandler handler; + testBegin( "testBufferCopy_I_O" ) { + crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer1 = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto buffer2 = graph.createBuffer( test::createBuffer( "buffer2" ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer1 ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer2 ) ); + auto buffer1a = crg::Attachment::createDefault( buffer1v ); auto & testPass = graph.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -39,14 +44,27 @@ namespace return std::make_unique< crg::BufferCopy >( pass, context, runGraph , 0u, 1024u ); } ); - testPass.addTransferInputBuffer( crg::Buffer{ VkBuffer( 1 ), "inBuffer" }, 0u, 1024u ); - testPass.addTransferOutputBuffer( crg::Buffer{ VkBuffer( 1 ), "outBuffer" }, 0u, 1024u ); + testPass.addInputTransfer( buffer1a ); + testPass.addOutputTransferBuffer( buffer2v ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, BufferCopy_IO_IO ) + { + testBegin( "testBufferCopy_IO_IO" ) { + crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer1 = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto buffer2 = graph.createBuffer( test::createBuffer( "buffer2" ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer1 ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer2 ) ); + auto buffer1a = crg::Attachment::createDefault( buffer1v ); + auto buffer2a = crg::Attachment::createDefault( buffer2v ); auto & testPass = graph.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -55,8 +73,8 @@ namespace return std::make_unique< crg::BufferCopy >( pass, context, runGraph , 0u, 512u ); } ); - testPass.addTransferInOutBuffer( crg::Buffer{ VkBuffer( 1 ), "ioBuffer" }, 0u, 512u ); - testPass.addTransferInOutBuffer( crg::Buffer{ VkBuffer( 2 ), "ioBuffer" }, 512u, 1024u ); + testPass.addInOutTransfer( buffer1a ); + testPass.addInOutTransfer( buffer2a ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -64,13 +82,16 @@ namespace testEnd() } - void testBufferToImageCopy( test::TestCounts & testCounts ) + TEST( RunnablePass, BufferToImageCopy ) { testBegin( "testBufferToImageCopy" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer = graph.createBuffer( test::createBuffer( "buffer" ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto bufferv = graph.createView( test::createView( "bufferv", buffer ) ); + auto buffera = crg::Attachment::createDefault( bufferv ); auto & testPass = graph.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -79,21 +100,22 @@ namespace return std::make_unique< crg::BufferToImageCopy >( pass, context, runGraph , crg::Offset3D{}, crg::Extent3D{ 1024, 1024, 1u } ); } ); - testPass.addTransferInputBuffer( crg::Buffer{ VkBuffer( 1 ), "inBuffer" }, 0u, 1024u ); - testPass.addTransferOutputView( resultv ); + testPass.addInputTransfer( buffera ); + testPass.addOutputTransferImage( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); testEnd() } - void testGenerateMipmaps( test::TestCounts & testCounts ) + TEST( RunnablePass, GenerateMipmaps ) { testBegin( "testGenerateMipmaps" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT, 10u ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 10u, 0u, 1u ) ); + auto resulta = crg::Attachment::createDefault( resultv ); auto & testPass = graph.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -101,14 +123,14 @@ namespace { return std::make_unique< crg::GenerateMipmaps >( pass, context, runGraph ); } ); - testPass.addTransferInOutView( resultv ); + testPass.addInOutTransfer( resulta ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); testEnd() } - void testImageBlit( test::TestCounts & testCounts ) + TEST( RunnablePass, ImageBlit ) { testBegin( "testImageBlit" ) crg::ResourceHandler handler; @@ -117,27 +139,56 @@ namespace auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); + auto & testPass = graph.createPass( "Pass" + , [inputv, resultv]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::ImageBlit >( pass, context, runGraph + , crg::Rect3D{ crg::Offset3D{}, getExtent( inputv ) } + , crg::Rect3D{ crg::Offset3D{}, getExtent( resultv ) } + , crg::FilterMode::eLinear ); + } ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + testEnd() + } + + TEST( RunnablePass, Image3DBlit ) + { + testBegin( "testImage3DBlit" ) + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto input = graph.createImage( test::createImage3D( "input", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto result = graph.createImage( test::createImage3D( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); auto & testPass = graph.createPass( "Pass" , [inputv, resultv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { return std::make_unique< crg::ImageBlit >( pass, context, runGraph - , crg::Offset3D{}, getExtent( inputv ) - , crg::Offset3D{}, getExtent( resultv ) + , crg::Rect3D{ crg::Offset3D{}, getExtent( inputv ) } + , crg::Rect3D{ crg::Offset3D{}, getExtent( resultv ) } , crg::FilterMode::eLinear ); } ); - testPass.addTransferInputView( inputv ); - testPass.addTransferOutputView( resultv ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); testEnd() } - void testImageCopy( test::TestCounts & testCounts ) + TEST( RunnablePass, ImageCopy_Base ) { - testBegin( "testImageCopy" ) + testBegin( "testImageCopy_Base" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -145,6 +196,7 @@ namespace auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); auto & testPass = graph.createPass( "Pass" , [inputv]( crg::FramePass const & pass , crg::GraphContext & context @@ -153,12 +205,170 @@ namespace return std::make_unique< crg::ImageCopy >( pass, context, runGraph , getExtent( inputv ) ); } ); - testPass.addTransferInputView( inputv ); - testPass.addTransferOutputView( resultv ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + } + testEnd() + } + + TEST( RunnablePass, ImageCopy_SingleInputMultipleOutputsSameImage ) + { + testBegin( "ImageCopy_SingleInputMultipleOutputsSameImage" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto input = graph.createImage( test::createImage( "input", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 6u ) ); + auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto resultv0 = graph.createView( test::createView( "result0v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto resultv1 = graph.createView( test::createView( "result1v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto resultv2 = graph.createView( test::createView( "result2v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto resultv3 = graph.createView( test::createView( "result3v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 3u, 1u ) ); + auto resultv4 = graph.createView( test::createView( "result4v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 4u, 1u ) ); + auto resultv5 = graph.createView( test::createView( "result5v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 5u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); + auto & testPass = graph.createPass( "Pass" + , [inputv]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::ImageCopy >( pass, context, runGraph + , getExtent( inputv ), crg::ImageLayout::eShaderReadOnly ); + } ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv0 ); + testPass.addOutputTransferImage( resultv1 ); + testPass.addOutputTransferImage( resultv2 ); + testPass.addOutputTransferImage( resultv3 ); + testPass.addOutputTransferImage( resultv4 ); + testPass.addOutputTransferImage( resultv5 ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + } + testEnd() + } + + TEST( RunnablePass, ImageCopy_SingleInputMultipleOutputsDifferentImage ) + { + testBegin( "ImageCopy_SingleInputMultipleOutputsDifferentImage" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto input = graph.createImage( test::createImage( "input", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto result0 = graph.createImage( test::createImage( "result0", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) ); + auto result1 = graph.createImage( test::createImage( "result1", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) ); + auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto result0v0 = graph.createView( test::createView( "result0v", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto result0v1 = graph.createView( test::createView( "result1v", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto result0v2 = graph.createView( test::createView( "result2v", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto result1v0 = graph.createView( test::createView( "result3v", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto result1v1 = graph.createView( test::createView( "result4v", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto result1v2 = graph.createView( test::createView( "result5v", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); + auto & testPass = graph.createPass( "Pass" + , [inputv]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::ImageCopy >( pass, context, runGraph + , getExtent( inputv ) ); + } ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( result0v0 ); + testPass.addOutputTransferImage( result0v1 ); + testPass.addOutputTransferImage( result0v2 ); + testPass.addOutputTransferImage( result1v0 ); + testPass.addOutputTransferImage( result1v1 ); + testPass.addOutputTransferImage( result1v2 ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + } + testEnd() + } + + TEST( RunnablePass, ImageCopy_MultipleInputsSameImageSingleOutput ) + { + testBegin( "ImageCopy_SingleInputMultipleOutputsSameImage" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto input = graph.createImage( test::createImage( "input", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 6u ) ); + auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto inputv0 = graph.createView( test::createView( "inputv0", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputv1 = graph.createView( test::createView( "inputv1", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto inputv2 = graph.createView( test::createView( "inputv2", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto inputv3 = graph.createView( test::createView( "inputv3", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 3u, 1u ) ); + auto inputv4 = graph.createView( test::createView( "inputv4", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 4u, 1u ) ); + auto inputv5 = graph.createView( test::createView( "inputv5", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 5u, 1u ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto & testPass = graph.createPass( "Pass" + , [inputv0]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::ImageCopy >( pass, context, runGraph + , getExtent( inputv0 ), crg::ImageLayout::eShaderReadOnly ); + } ); + testPass.addInputTransferImage( inputv0 ); + testPass.addInputTransferImage( inputv1 ); + testPass.addInputTransferImage( inputv2 ); + testPass.addInputTransferImage( inputv3 ); + testPass.addInputTransferImage( inputv4 ); + testPass.addInputTransferImage( inputv5 ); + testPass.addOutputTransferImage( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, ImageCopy_MultipleInputsDifferentImageSingleOutput ) + { + testBegin( "ImageCopy_MultipleInputsDifferentImageSingleOutput" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto input0 = graph.createImage( test::createImage( "input0", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) ); + auto input1 = graph.createImage( test::createImage( "input1", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) ); + auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto input0v0 = graph.createView( test::createView( "input0v0", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto input0v1 = graph.createView( test::createView( "input0v1", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto input0v2 = graph.createView( test::createView( "input0v2", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto input1v0 = graph.createView( test::createView( "input1v0", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto input1v1 = graph.createView( test::createView( "input1v1", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto input1v2 = graph.createView( test::createView( "input1v2", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto & testPass = graph.createPass( "Pass" + , [result]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::ImageCopy >( pass, context, runGraph + , getExtent( result ) ); + } ); + testPass.addInputTransferImage( input0v0 ); + testPass.addInputTransferImage( input0v1 ); + testPass.addInputTransferImage( input0v2 ); + testPass.addInputTransferImage( input1v0 ); + testPass.addInputTransferImage( input1v1 ); + testPass.addInputTransferImage( input1v2 ); + testPass.addOutputTransferImage( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + } + testEnd() + } + + TEST( RunnablePass, ImageCopy_OutputLayout ) + { + testBegin( "testImageCopy_OutputLayout" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -166,6 +376,7 @@ namespace auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); auto & testPass = graph.createPass( "Pass" , [inputv]( crg::FramePass const & pass , crg::GraphContext & context @@ -175,12 +386,18 @@ namespace , getExtent( inputv ) , crg::ImageLayout::eShaderReadOnly ); } ); - testPass.addTransferInputView( inputv ); - testPass.addTransferOutputView( resultv ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, ImageCopy_BackAndForth ) + { + testBegin( "testImageCopy_BackAndForth" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -188,6 +405,8 @@ namespace auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto inputa = crg::Attachment::createDefault( inputv ); + auto resulta = crg::Attachment::createDefault( resultv ); auto & testPass = graph.createPass( "Pass" , [inputv]( crg::FramePass const & pass , crg::GraphContext & context @@ -197,10 +416,10 @@ namespace , getExtent( inputv ) , crg::ImageLayout::eShaderReadOnly ); } ); - testPass.addTransferInputView( inputv ); - testPass.addTransferOutputView( resultv ); - testPass.addTransferInputView( resultv ); - testPass.addTransferOutputView( inputv ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferImage( resultv ); + testPass.addInputTransfer( resulta ); + testPass.addOutputTransferImage( inputv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -208,13 +427,16 @@ namespace testEnd() } - void testImageToBufferCopy( test::TestCounts & testCounts ) + TEST( RunnablePass, ImageToBufferCopy ) { testBegin( "testImageToBufferCopy" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; auto input = graph.createImage( test::createImage( "input", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer = graph.createBuffer( test::createBuffer( "buffer" ) ); auto inputv = graph.createView( test::createView( "inputv", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto bufferv = graph.createView( test::createView( "bufferv", buffer ) ); + auto inputa = crg::Attachment::createDefault( inputv ); auto & testPass = graph.createPass( "Pass" , [inputv]( crg::FramePass const & pass , crg::GraphContext & context @@ -223,40 +445,46 @@ namespace return std::make_unique< crg::ImageToBufferCopy >( pass, context, runGraph , crg::Offset3D{}, getExtent( inputv ) ); } ); - testPass.addTransferInputView( inputv ); - testPass.addTransferOutputBuffer( crg::Buffer{ VkBuffer( 1 ), "outBuffer" }, 0u, 1024u ); + testPass.addInputTransfer( inputa ); + testPass.addOutputTransferBuffer( bufferv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); testEnd() } - void testComputePass( test::TestCounts & testCounts ) + TEST( RunnablePass, ComputePass ) { testBegin( "testComputePass" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, "/" + testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "buffer" ) ); + auto bufferv = graph.createView( test::createView( "bufferv", buffer ) ); + auto indirect = graph.createBuffer( test::createBuffer( "indirect" ) ); + auto indirectv = graph.createView( test::createView( "indirectv", indirect ) ); auto & testPass1 = graph.createPass( "Pass1" - , []( crg::FramePass const & pass + , [&indirectv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::cp::Config cfg; - cfg.indirectBuffer( crg::IndirectBuffer{ crg::Buffer{ VkBuffer( 1 ), "ind" }, sizeof( VkDrawIndirectCommand ) } ); + cfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } ); cfg.baseConfig( crg::pp::Config{} .programCreator( crg::ProgramCreator{ 1u , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); return std::make_unique< crg::ComputePass >( pass, context, runGraph , crg::ru::Config{}, std::move( cfg ) ); } ); - testPass1.addClearableOutputStorageBuffer( crg::Buffer{ VkBuffer( 1 ), "buffer1" }, 1u, 0u, 1024u ); + auto buffera = testPass1.addClearableOutputStorageBuffer( bufferv, 1u ); auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT ) ); - auto depthv = graph.createView( test::createView( "depthv", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) ); auto depthStencil = graph.createImage( test::createImage( "depthStencil", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) ); + auto buffer1 = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto depthv = graph.createView( test::createView( "depthv", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) ); auto depthStencilv = graph.createView( test::createView( "depthStencilv", depthStencil, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer1 ) ); crg::ComputePass * computePass{}; auto & testPass2 = graph.createPass( "Pass2" , [&computePass]( crg::FramePass const & pass @@ -272,11 +500,28 @@ namespace computePass = res.get(); return res; } ); - testPass2.addDependency( testPass1 ); - testPass2.addUniformBuffer( crg::Buffer{ VkBuffer( 1 ), "buffer1" }, 0u, 0u, 1024u ); - testPass2.addClearableOutputStorageView( resultv, 2u ); - testPass2.addClearableOutputStorageView( depthv, 3u ); + testPass2.addInputUniformBuffer( buffer1v, 0u ); + testPass2.addInputUniform( *buffera, 1u ); + auto resulta = testPass2.addClearableOutputStorageImage( resultv, 2u ); + auto deptha = testPass2.addClearableOutputStorageImage( depthv, 3u ); + auto buffer2 = graph.createBuffer( test::createBuffer( "buffer2" ) ); + auto buffer3 = graph.createBuffer( test::createBuffer( "buffer3" ) ); + auto buffer4 = graph.createBuffer( test::createBuffer( "buffer4" ) ); + auto buffer5 = graph.createBuffer( test::createBuffer( "buffer5" ) ); + auto buffer6 = graph.createBuffer( test::createBuffer( "buffer6" ) ); + auto buffer7 = graph.createBuffer( test::createBuffer( "buffer7" ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer2 ) ); + auto buffer3v = graph.createView( test::createView( "buffer3v", buffer3 ) ); + auto buffer4v = graph.createView( test::createView( "buffer4v", buffer4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer5v = graph.createView( test::createView( "buffer5v", buffer5, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer6v = graph.createView( test::createView( "buffer6v", buffer6, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer7v = graph.createView( test::createView( "buffer7v", buffer7, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer2a = crg::Attachment::createDefault( buffer2v ); + auto buffer3a = crg::Attachment::createDefault( buffer3v ); + auto buffer5a = crg::Attachment::createDefault( buffer5v ); + auto buffer7a = crg::Attachment::createDefault( buffer7v ); + auto depthStencila = crg::Attachment::createDefault( depthStencilv ); auto & testPass3 = graph.createPass( "Pass3" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -289,16 +534,17 @@ namespace return std::make_unique< crg::ComputePass >( pass, context, runGraph , crg::ru::Config{}, std::move( cfg ) ); } ); - testPass3.addDependency( testPass2 ); - testPass3.addInputStorageBuffer( crg::Buffer{ VkBuffer( 2 ), "buffer1" }, 0u, 0u, 1024u ); - testPass3.addInOutStorageBuffer( crg::Buffer{ VkBuffer( 3 ), "buffer2" }, 0u, 0u, 1024u ); - testPass3.addUniformBufferView( crg::Buffer{ VkBuffer( 4 ), "buffer3" }, VkBufferView{}, 0u, 0u, 1024u ); - testPass3.addInputStorageBufferView( crg::Buffer{ VkBuffer( 5 ), "buffer4" }, VkBufferView{}, 0u, 0u, 1024u ); - testPass3.addOutputStorageBufferView( crg::Buffer{ VkBuffer( 6 ), "buffer5" }, VkBufferView{}, 0u, 0u, 1024u ); - testPass3.addInOutStorageBufferView( crg::Buffer{ VkBuffer( 7 ), "buffer6" }, VkBufferView{}, 0u, 0u, 1024u ); - testPass3.addImplicitColourView( resultv, crg::ImageLayout::eShaderReadOnly ); - testPass3.addImplicitDepthView( depthv, crg::ImageLayout::eShaderReadOnly ); - testPass3.addImplicitDepthStencilView( depthStencilv, crg::ImageLayout::eShaderReadOnly ); + testPass3.addInputStorage( buffer2a, 2u ); + testPass3.addInOutStorage( buffer3a, 3u ); + + testPass3.addInputUniformBuffer( buffer4v, 4u ); + testPass3.addInputStorage( buffer5a, 5u ); + testPass3.addOutputStorageBuffer( buffer6v, 6u ); + testPass3.addInOutStorage( buffer7a, 7u ); + + testPass3.addImplicit( *resulta, crg::ImageLayout::eShaderReadOnly ); + testPass3.addImplicit( *deptha, crg::ImageLayout::eShaderReadOnly ); + testPass3.addImplicit( depthStencila, crg::ImageLayout::eShaderReadOnly ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -307,21 +553,23 @@ namespace checkNoThrow( computePass->resetCommandBuffer( 0u ) ) checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) - checkNoThrow( graph.getFinalAccessState( crg::Buffer{ VkBuffer( 1 ), "buffer1" }, 0u ) ) + checkNoThrow( graph.getFinalAccessState( buffer1v ) ) testEnd() } - void testComputePassTransitions( test::TestCounts & testCounts ) + TEST( RunnablePass, ComputePassTransitions ) { testBegin( "testComputePassTransitions" ) crg::ResourceHandler handler; crg::FrameGraph graph{ handler, "/" + testCounts.testName }; auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); - auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto depth = graph.createImage( test::createImage( "depth", crg::PixelFormat::eD32_SFLOAT ) ); + auto buffer1 = graph.createBuffer( test::createBuffer( "buffer1" ) ); + auto buffer2 = graph.createBuffer( test::createBuffer( "buffer2" ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto depthv = graph.createView( test::createView( "depthv", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) ); - crg::Buffer buffer1{ VkBuffer( 1 ), "buffer1" }; - crg::Buffer buffer2{ VkBuffer( 2 ), "buffer2" }; + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer1 ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer2 ) ); auto & testPass1 = graph.createPass( "Pass1" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -334,10 +582,10 @@ namespace return std::make_unique< crg::ComputePass >( pass, context, runGraph , crg::ru::Config{ 1u, true }, std::move( cfg ) ); } ); - testPass1.addClearableOutputStorageView( resultv, 0u ); - testPass1.addClearableOutputStorageView( depthv, 1u ); - testPass1.addClearableOutputStorageBuffer( buffer1, 2u, 0u, 1024u ); - testPass1.addClearableOutputStorageBuffer( buffer2, 3u, 0u, 1024u ); + auto resulta = testPass1.addClearableOutputStorageImage( resultv, 0u ); + auto deptha = testPass1.addClearableOutputStorageImage( depthv, 1u ); + auto buffer1a = testPass1.addClearableOutputStorageBuffer( buffer1v, 2u ); + auto buffer2a = testPass1.addClearableOutputStorageBuffer( buffer2v, 3u ); auto & testPass2 = graph.createPass( "Pass2" , []( crg::FramePass const & pass @@ -351,25 +599,26 @@ namespace return std::make_unique< crg::ComputePass >( pass, context, runGraph , crg::ru::Config{}, std::move( cfg ) ); } ); - testPass2.addDependency( testPass1 ); - testPass2.addImplicitColourView( resultv, crg::ImageLayout::eShaderReadOnly ); - testPass2.addImplicitDepthView( depthv, crg::ImageLayout::eShaderReadOnly ); - testPass2.addImplicitBuffer( buffer1, 0u, 1024u, {} ); - testPass2.addImplicitBuffer( buffer2, 0u, 1024u, {} ); + testPass2.addImplicit( *resulta, crg::ImageLayout::eShaderReadOnly ); + testPass2.addImplicit( *deptha, crg::ImageLayout::eShaderReadOnly ); + testPass2.addInputStorage( *buffer1a, 1u ); + testPass2.addImplicit( *buffer2a, crg::AccessState{} ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); testEnd() } - void testRenderPass( test::TestCounts & testCounts ) + TEST( RunnablePass, RenderPass_ORcl ) { - testBegin( "testRenderPass" ) + testBegin( "testRenderPass_ORcl" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto sampled = graph.createImage( test::createImage( "sampled", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto sampledv = graph.createView( test::createView( "sampledv", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); auto & testPass = graph.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context @@ -379,11 +628,18 @@ namespace , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::defaultV< crg::RunnablePass::RecordCallback > } ); } ); - testPass.addOutputColourView( resultv ); + testPass.addInputSampledImage( sampledv, 0u ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, RenderPass_ORcl_DefCont ) + { + testBegin( "testRenderPass_ORcl_DefCont" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -399,18 +655,26 @@ namespace , crg::defaultV< crg::RunnablePass::RecordCallback > , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, RenderPass_MergedImageViews_ORcl ) + { + testBegin( "testRenderPass_MergedImageViews_ORcl" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; - auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) ); - auto result1v = graph.createView( test::createView( "result1v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); - auto result2v = graph.createView( test::createView( "result2v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); - auto & testPass = graph.createPass( "Pass" + auto & group = graph.createPassGroup( "testGroup" ); + auto result = group.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) ); + auto result1v = group.createView( test::createView( "result1v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto result2v = group.createView( test::createView( "result2v", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto resultv = group.mergeViews( { result1v, result2v } ); + auto & testPass = group.createPass( "Pass" , []( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) @@ -420,12 +684,183 @@ namespace , crg::defaultV< crg::RunnablePass::RecordCallback > , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); } ); - testPass.addOutputColourView( testPass.mergeViews( { result1v, result2v } ) ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); - check( graph.getFinalLayoutState( testPass.mergeViews( { result1v, result2v } ), 0u ).layout == crg::ImageLayout::eColorAttachment ) + checkEqual( graph.getFinalLayoutState( resultv ).layout, crg::ImageLayout::eColorAttachment ) } + testEnd() + } + + TEST( RunnablePass, RenderPass_MergedImageViews_CubeARray_ORcl ) + { + testBegin( "testRenderPass_MergedImageViews_CubeARray_ORcl" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto & group = graph.createPassGroup( "testGroup" ); + auto result = group.createImage( test::createImageCube( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 12u ) ); + auto result1v = group.createView( crg::ImageViewData{ "result1v" + , result + , crg::ImageViewCreateFlags::eNone + , crg::ImageViewType::e2D + , getFormat( result ) + , { getAspectMask( getFormat( result ) ), 0u, 1u, 0u, 6u } } ); + auto result2v = group.createView( crg::ImageViewData{ "result2v" + , result + , crg::ImageViewCreateFlags::eNone + , crg::ImageViewType::e2D + , getFormat( result ) + , { getAspectMask( getFormat( result ) ), 0u, 1u, 6u, 6u } } ); + auto resultv = group.mergeViews( { result1v, result2v } ); + auto & testPass = group.createPass( "Pass" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::RenderPass >( pass, context, runGraph + , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::defaultV< crg::RunnablePass::RecordCallback > + , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); + } ); + testPass.addOutputColourTarget( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + checkEqual( graph.getFinalLayoutState( resultv ).layout, crg::ImageLayout::eColorAttachment ) + } + testEnd() + } + + TEST( RunnablePass, RenderPass_MergedBufferViews_ORcl ) + { + testBegin( "testRenderPass_MergedBufferViews_ORcl" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto & group = graph.createPassGroup( "testGroup" ); + auto result = group.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer = group.createBuffer( test::createBuffer( "buffer" ) ); + auto resultv = group.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto buffer1v = group.createView( test::createView( "buffer1v", buffer, 0, 512u ) ); + auto buffer2v = group.createView( test::createView( "buffer2v", buffer, 512u, 512u ) ); + auto bufferv = group.mergeViews( { buffer1v, buffer2v } ); + auto & testPass = group.createPass( "Pass" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::RenderPass >( pass, context, runGraph + , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::defaultV< crg::RunnablePass::RecordCallback > + , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); + } ); + testPass.addOutputStorageBuffer( bufferv, 0u ); + testPass.addOutputColourTarget( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + checkEqual( graph.getFinalAccessState( bufferv ).access, crg::AccessFlags::eShaderWrite ) + } + testEnd() + } + + TEST( RunnablePass, RenderPass_MergedImageAttachs_ORcl ) + { + testBegin( "testRenderPass_MergedImageAttachs_ORcl" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto intermediate = graph.createImage( test::createImage( "intermediate", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) ); + auto intermediate1v = graph.createView( test::createView( "intermediate1v", intermediate, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); + auto intermediate2v = graph.createView( test::createView( "intermediate2v", intermediate, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) ); + auto & testPass1 = graph.createPass( "Pass1" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::RenderPass >( pass, context, runGraph + , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::defaultV< crg::RunnablePass::RecordCallback > + , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); + } ); + auto intermediate1a = testPass1.addOutputColourTarget( intermediate1v ); + auto intermediate2a = testPass1.addOutputColourTarget( intermediate2v ); + + auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto & testPass2 = graph.createPass( "Pass2" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::RenderPass >( pass, context, runGraph + , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::defaultV< crg::RunnablePass::RecordCallback > + , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); + } ); + auto intermediatea = graph.mergeAttachments( { intermediate1a, intermediate2a } ); + testPass2.addInputSampled( *intermediatea, 0u ); + testPass2.addOutputColourTarget( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + checkEqual( graph.getFinalLayoutState( intermediatea->view() ).layout, crg::ImageLayout::eShaderReadOnly ) + } + testEnd() + } + + TEST( RunnablePass, RenderPass_MergedBufferAttachs_ORcl ) + { + testBegin( "testRenderPass_MergedBufferAttachs_ORcl" ) + { + crg::ResourceHandler handler; + crg::FrameGraph graph{ handler, testCounts.testName }; + auto buffer = graph.createBuffer( test::createBuffer( "buffer" ) ); + auto buffer1v = graph.createView( test::createView( "buffer1v", buffer, 0u, 512u ) ); + auto buffer2v = graph.createView( test::createView( "buffer2v", buffer, 512u, 512u ) ); + auto & testPass1 = graph.createPass( "Pass1" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + crg::cp::Config cfg; + cfg.baseConfig( crg::pp::Config{} + .programCreator( crg::ProgramCreator{ 1u + , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); + return std::make_unique< crg::ComputePass >( pass, context, runGraph + , crg::ru::Config{ 1u, true }, std::move( cfg ) ); + } ); + auto buffer1a = testPass1.addOutputStorageBuffer( buffer1v, 0u ); + auto buffer2a = testPass1.addOutputStorageBuffer( buffer2v, 1u ); + + auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto & testPass2 = graph.createPass( "Pass2" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & runGraph ) + { + return std::make_unique< crg::RenderPass >( pass, context, runGraph + , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > + , crg::defaultV< crg::RunnablePass::RecordCallback > + , crg::defaultV< crg::RenderPass::GetSubpassContentsCallback > } ); + } ); + auto buffera = graph.mergeAttachments( { buffer1a, buffer2a } ); + testPass2.addInputStorage( *buffera, 0u ); + testPass2.addOutputColourTarget( resultv ); + + auto runnable = graph.compile( getContext() ); + test::checkRunnable( testCounts, runnable ); + checkEqual( graph.getFinalAccessState( buffera->buffer() ).access, crg::AccessFlags::eShaderRead ) + } + testEnd() + } + + TEST( RunnablePass, RenderPass_ORdp ) + { + testBegin( "testRenderPass_ORdp" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -440,11 +875,17 @@ namespace , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::defaultV< crg::RunnablePass::RecordCallback > } ); } ); - testPass.addOutputDepthView( depthv ); + testPass.addOutputDepthTarget ( depthv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); } + testEnd() + } + + TEST( RunnablePass, RenderPass_ORcl_ORdp ) + { + testBegin( "testRenderPass_ORcl_ORdp" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -467,8 +908,8 @@ namespace , extent , crg::ru::Config{ 2u } ); } ); - testPass.addOutputColourView( resultv ); - testPass.addOutputDepthView( depthv ); + testPass.addOutputColourTarget( resultv ); + testPass.addOutputDepthTarget ( depthv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -476,6 +917,12 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderPass ) + { + testBegin( "testRenderPass" ) { crg::ResourceHandler handler; crg::FrameGraph graph{ handler, testCounts.testName }; @@ -491,10 +938,10 @@ namespace , crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback > , crg::defaultV< crg::RunnablePass::RecordCallback > } ); } ); - testPass.addOutputColourView( testPass.mergeViews( { result1v, result2v } ) ); - testPass.addOutputColourView( testPass.mergeViews( { result1v, result2v }, false, true ) ); - testPass.addOutputColourView( testPass.mergeViews( { result1v, result2v }, true, false ) ); - testPass.addOutputColourView( testPass.mergeViews( { result1v, result2v }, false, false ) ); + testPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v } ) ); + testPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, false, true ) ); + testPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, true, false ) ); + testPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, false, false ) ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -502,7 +949,7 @@ namespace testEnd() } - void testRenderQuad( test::TestCounts & testCounts ) + TEST( RunnablePass, RenderQuad ) { testBegin( "testRenderQuad" ) crg::ResourceHandler handler; @@ -527,7 +974,7 @@ namespace renderQuad = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -537,16 +984,27 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderQuad_Indirect ) + { + testBegin( "testRenderQuad_Indirect" ) + crg::ResourceHandler handler; + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); { crg::FrameGraph graph{ handler, testCounts.testName }; crg::RenderQuad * renderQuad{}; + auto indirect = graph.createBuffer( test::createBuffer( "indirect" ) ); + auto indirectv = graph.createView( test::createView( "indirectv", indirect ) ); auto & testPass = graph.createPass( "Pass" - , [&renderQuad]( crg::FramePass const & pass + , [&renderQuad, &indirectv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::rq::Config cfg; - cfg.indirectBuffer( crg::IndirectBuffer{ crg::Buffer{ VkBuffer( 1 ), "ind" }, sizeof( VkDrawIndirectCommand ) } ); + cfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } ); cfg.baseConfig( crg::pp::Config{} .programCreator( crg::ProgramCreator{ 1u , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); @@ -555,7 +1013,7 @@ namespace renderQuad = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -567,7 +1025,7 @@ namespace testEnd() } - void testRenderMesh( test::TestCounts & testCounts ) + TEST( RunnablePass, RenderMesh ) { testBegin( "testRenderMesh" ) crg::ResourceHandler handler; @@ -592,7 +1050,7 @@ namespace renderMesh = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -602,16 +1060,27 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderMesh_Vertex ) + { + testBegin( "testRenderMesh_Vertex" ) + crg::ResourceHandler handler; + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); { crg::FrameGraph graph{ handler, testCounts.testName }; crg::RenderMesh * renderMesh{}; + auto vertex = graph.createBuffer( test::createBuffer( "vertex" ) ); + auto vertexv = graph.createView( test::createView( "vertexv", vertex ) ); auto & testPass = graph.createPass( "Pass" - , [&renderMesh]( crg::FramePass const & pass + , [&renderMesh, &vertexv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::rm::Config cfg; - cfg.vertexBuffer( crg::VertexBuffer{ crg::Buffer{ VkBuffer( 1 ), "vtx" } } ); + cfg.vertexBuffer( crg::VertexBuffer{ vertexv } ); cfg.baseConfig( crg::pp::Config{} .programs( { crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} } } ) ); auto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph @@ -619,7 +1088,7 @@ namespace renderMesh = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -628,18 +1097,31 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderMesh_Vertex_Index ) + { + testBegin( "testRenderMesh_Vertex_Index" ) + crg::ResourceHandler handler; + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); { crg::FrameGraph graph{ handler, testCounts.testName }; + auto vertex = graph.createBuffer( test::createBuffer( "vertex" ) ); + auto index = graph.createBuffer( test::createBuffer( "index" ) ); + auto vertexv = graph.createView( test::createView( "vertexv", vertex ) ); + auto indexv = graph.createView( test::createView( "indexv", index ) ); crg::RenderMesh * renderMesh{}; auto & testPass = graph.createPass( "Pass" - , [&renderMesh]( crg::FramePass const & pass + , [&renderMesh, &vertexv, &indexv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::rm::Config cfg; - auto vb = crg::VertexBuffer{ crg::Buffer{ VkBuffer( 1 ), "vtx" } }; + auto vb = crg::VertexBuffer{ vertexv }; cfg.vertexBuffer( std::move( vb ) ); - cfg.indexBuffer( crg::IndexBuffer{ crg::Buffer{ VkBuffer( 2 ), "idx" } } ); + cfg.indexBuffer( crg::IndexBuffer{ indexv } ); cfg.baseConfig( crg::pp::Config{} .programCreator( crg::ProgramCreator{ 1u , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); @@ -648,7 +1130,7 @@ namespace renderMesh = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -657,16 +1139,27 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderMesh_Indirect ) + { + testBegin( "testRenderMesh_Indirect" ) + crg::ResourceHandler handler; + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); { crg::FrameGraph graph{ handler, testCounts.testName }; + auto indirect = graph.createBuffer( test::createBuffer( "indirect" ) ); + auto indirectv = graph.createView( test::createView( "indirectv", indirect ) ); crg::RenderMesh * renderMesh{}; auto & testPass = graph.createPass( "Pass" - , [&renderMesh]( crg::FramePass const & pass + , [&renderMesh, &indirectv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::rm::Config cfg; - cfg.indirectBuffer( crg::IndirectBuffer{ crg::Buffer{ VkBuffer( 1 ), "ind" }, sizeof( VkDrawIndirectCommand ) } ); + cfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } ); cfg.baseConfig( crg::pp::Config{} .programCreator( crg::ProgramCreator{ 1u , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); @@ -675,7 +1168,7 @@ namespace renderMesh = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -684,17 +1177,30 @@ namespace checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( VkQueue{} ) ) } + testEnd() + } + + TEST( RunnablePass, RenderMesh_Indirect_Index ) + { + testBegin( "testRenderMesh_Indirect_Index" ) + crg::ResourceHandler handler; + auto result = handler.createImageId( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); + auto resultv = handler.createViewId( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); { crg::FrameGraph graph{ handler, testCounts.testName }; + auto indirect = graph.createBuffer( test::createBuffer( "indirect" ) ); + auto index = graph.createBuffer( test::createBuffer( "index" ) ); + auto indirectv = graph.createView( test::createView( "indirectv", indirect ) ); + auto indexv = graph.createView( test::createView( "indexv", index ) ); crg::RenderMesh * renderMesh{}; auto & testPass = graph.createPass( "Pass" - , [&renderMesh]( crg::FramePass const & pass + , [&renderMesh, &indirectv, &indexv]( crg::FramePass const & pass , crg::GraphContext & context , crg::RunnableGraph & runGraph ) { crg::rm::Config cfg; - cfg.indirectBuffer( crg::IndirectBuffer{ crg::Buffer{ VkBuffer( 1 ), "ind" }, sizeof( VkDrawIndexedIndirectCommand ) } ); - cfg.indexBuffer( crg::IndexBuffer{ crg::Buffer{ VkBuffer( 2 ), "idx" } } ); + cfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndexedIndirectCommand ) } ); + cfg.indexBuffer( crg::IndexBuffer{ indexv } ); cfg.baseConfig( crg::pp::Config{} .programCreator( crg::ProgramCreator{ 1u , []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) ); @@ -703,7 +1209,7 @@ namespace renderMesh = res.get(); return res; } ); - testPass.addOutputColourView( resultv ); + testPass.addOutputColourTarget( resultv ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -715,7 +1221,7 @@ namespace testEnd() } - void testRenderTexturedMesh( test::TestCounts & testCounts ) + TEST( RunnablePass, RenderTexturedMesh ) { testBegin( "testRenderTexturedMesh" ) crg::ResourceHandler handler; @@ -741,7 +1247,7 @@ namespace renderQuad = res.get(); return res; } ); - testQuad.addOutputColourView( sampledv ); + auto sampledAttach = testQuad.addOutputColourTarget( sampledv ); auto result = graph.createImage( test::createImage( "result", crg::PixelFormat::eR16G16B16A16_SFLOAT ) ); auto resultv = graph.createView( test::createView( "resultv", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) ); @@ -763,9 +1269,8 @@ namespace renderMesh = res.get(); return res; } ); - testMesh.addDependency( testQuad ); - testMesh.addOutputColourView( resultv ); - testMesh.addSampledView( sampledv, 0u ); + testMesh.addOutputColourTarget( resultv ); + testMesh.addInputSampled( *sampledAttach, 0u ); auto runnable = graph.compile( getContext() ); test::checkRunnable( testCounts, runnable ); @@ -775,26 +1280,10 @@ namespace checkNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) ) checkNoThrow( runnable->record() ) checkNoThrow( runnable->run( crg::SemaphoreWait{ VkSemaphore( 1 ), crg::PipelineStageFlags::eAllGraphics }, VkQueue{} ) ) - check( graph.getFinalLayoutState( sampledv, 0u ).layout == crg::ImageLayout::eShaderReadOnly ) - check( graph.getDefaultGroup().getFinalLayoutState( sampledv, 0u ).layout == crg::ImageLayout::eShaderReadOnly ) + checkEqual( graph.getFinalLayoutState( sampledv, 0u ).layout, crg::ImageLayout::eShaderReadOnly ) + checkEqual( graph.getDefaultGroup().getFinalLayoutState( sampledv, 0u ).layout, crg::ImageLayout::eShaderReadOnly ) testEnd() } } -int main( int argc, char ** argv ) -{ - testSuiteBegin( "TestRunnablePass" ) - testBufferCopy( testCounts ); - testBufferToImageCopy( testCounts ); - testGenerateMipmaps( testCounts ); - testImageBlit( testCounts ); - testImageCopy( testCounts ); - testImageToBufferCopy( testCounts ); - testComputePass( testCounts ); - testComputePassTransitions( testCounts ); - testRenderPass( testCounts ); - testRenderQuad( testCounts ); - testRenderMesh( testCounts ); - testRenderTexturedMesh( testCounts ); - testSuiteEnd() -} +testSuiteMain() diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..a85716c --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", + "name": "rendergraph", + "version": "1.4.1", + "builtin-baseline": "e140b1fde236eb682b0d47f905e65008a191800f", + "dependencies": [ + "vulkan-headers" + ], + "features": { + "tests": { + "description": "Unit tests.", + "dependencies": [ + "gtest" + ] + } + } +}