[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = CRLF\nindent_style = tab\nindent_size = 4\ntab_width = 4\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.{c++,cc,cpp,cppm,cu,cuh,cxx,fx,h,h++,hh,hlsl,hpp,hxx,inl,ipp,ixx,tlh,tli}]\n# Visual C++ Code Style settings\ncpp_generate_documentation_comments = doxygen_slash_star\n# Visual C++ Formatting settings\ncpp_indent_braces = false\ncpp_indent_multi_line_relative_to = innermost_parenthesis\ncpp_indent_within_parentheses = indent\ncpp_indent_preserve_within_parentheses = true\ncpp_indent_case_contents = true\ncpp_indent_case_labels = false\ncpp_indent_case_contents_when_block = true\ncpp_indent_lambda_braces_when_parameter = true\ncpp_indent_goto_labels = leftmost_column\ncpp_indent_preprocessor = leftmost_column\ncpp_indent_access_specifiers = false\ncpp_indent_namespace_contents = true\ncpp_indent_preserve_comments = true\ncpp_new_line_before_open_brace_namespace = new_line\ncpp_new_line_before_open_brace_type = new_line\ncpp_new_line_before_open_brace_function = new_line\ncpp_new_line_before_open_brace_block = new_line\ncpp_new_line_before_open_brace_lambda = new_line\ncpp_new_line_scope_braces_on_separate_lines = true\ncpp_new_line_close_brace_same_line_empty_type = false\ncpp_new_line_close_brace_same_line_empty_function = false\ncpp_new_line_before_catch = true\ncpp_new_line_before_else = true\ncpp_new_line_before_while_in_do_while = true\ncpp_space_before_function_open_parenthesis = remove\ncpp_space_within_parameter_list_parentheses = true\ncpp_space_between_empty_parameter_list_parentheses = false\ncpp_space_after_keywords_in_control_flow_statements = true\ncpp_space_within_control_flow_statement_parentheses = true\ncpp_space_before_lambda_open_parenthesis = false\ncpp_space_within_cast_parentheses = true\ncpp_space_after_cast_close_parenthesis = false\ncpp_space_within_expression_parentheses = true\ncpp_space_before_block_open_brace = true\ncpp_space_between_empty_braces = false\ncpp_space_before_initializer_list_open_brace = false\ncpp_space_within_initializer_list_braces = true\ncpp_space_preserve_in_initializer_list = false\ncpp_space_before_open_square_bracket = false\ncpp_space_within_square_brackets = false\ncpp_space_before_empty_square_brackets = false\ncpp_space_between_empty_square_brackets = false\ncpp_space_group_square_brackets = true\ncpp_space_within_lambda_brackets = false\ncpp_space_between_empty_lambda_brackets = false\ncpp_space_before_comma = false\ncpp_space_after_comma = true\ncpp_space_remove_around_member_operators = true\ncpp_space_before_inheritance_colon = true\ncpp_space_before_constructor_colon = true\ncpp_space_remove_before_semicolon = true\ncpp_space_after_semicolon = true\ncpp_space_remove_around_unary_operator = true\ncpp_space_around_binary_operator = insert\ncpp_space_around_assignment_operator = insert\ncpp_space_pointer_reference_alignment = center\ncpp_space_around_ternary_operator = insert\ncpp_use_unreal_engine_macro_formatting = true\ncpp_wrap_preserve_blocks = never\n# Visual C++ Inlcude Cleanup settings\ncpp_include_cleanup_add_missing_error_tag_type = suggestion\ncpp_include_cleanup_remove_unused_error_tag_type = dimmed\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/codecov.yml",
    "content": "codecov:\n  require_ci_to_pass: yes\n\ncoverage:\n  precision: 2\n  round: down\n  range: \"70...100\"\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 100%\n        base: auto\n    patch:\n      default:\n        target: auto\n        threshold: 100%\n        base: auto\n        if_ci_failed: success\n        informational: true\n\nparsers:\n  gcov:\n    branch_detection:\n      conditional: yes\n      loop: yes\n      method: no\n      macro: no\n\ncomment:\n  layout: \"reach,diff,flags,files,footer\"\n  behavior: default\n  require_changes: no\n  require_head: no\n  require_base: no\n\ngithub_checks:\n  annotations: true"
  },
  {
    "path": ".github/workflows/cmake.yml",
    "content": "name: Build\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  release:\n    types:\n      - created\n\njobs:\n  build-windows:\n    strategy:\n      matrix:\n        os: [[windows-latest,x64-windows,msvc]]\n        buildType: [Debug]\n    runs-on: ${{ matrix.os[0] }}\n    steps:\n    - uses: actions/checkout@v4\n    - name: Checkout submodules\n      run: |\n        git submodule update --init -- \"CMake\"\n        git submodule update --init -- \"external/vcpkg\"\n    - name: Setup vcpkg\n      uses: lukka/run-vcpkg@v11\n      with:\n        vcpkgDirectory: '${{ github.workspace }}/external/vcpkg'\n        vcpkgJsonGlob: 'vcpkg.json'\n    - name: Setup OpenCppCoverage\n      id: setup_opencppcoverage\n      run: |\n        choco install OpenCppCoverage -y\n        echo \"C:\\Program Files\\OpenCppCoverage\" >> $env:GITHUB_PATH\n    - name: Create Build Environment\n      run: |\n        cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }}\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        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\n    - name: Build\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --build . --parallel 2 --config ${{ matrix.buildType }}\n    - name: Build coverage report\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --build . --target RenderGraphCoverage --config ${{ matrix.buildType }}\n    - name: Upload coverage reports to Codecov\n      uses: codecov/codecov-action@v4.0.1\n      with:\n        token: ${{ secrets.CODECOV_TOKEN }}\n        file: ${{ github.workspace }}/doc/RenderGraphCoverage.xml\n    - name: Prepare package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --install . --config ${{ matrix.buildType }}\n    - name: Zip package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        7z a $GITHUB_WORKSPACE/RenderGraph-${{ matrix.os[1] }}.zip $GITHUB_WORKSPACE/package/rendergraph/\n    - name: Upload package\n      if: github.event_name == 'push'\n      uses: actions/upload-artifact@v4\n      with:\n        name: RenderGraph-${{ matrix.os[1] }}.zip\n        path: ${{ github.workspace }}/RenderGraph-${{ matrix.os[1] }}.zip\n\n  build-macos:\n    strategy:\n      matrix:\n        os: [[macos-latest,x64-osx,clang]]\n        buildType: [Release]\n    runs-on: ${{ matrix.os[0] }}\n    steps:\n    - uses: actions/checkout@v4\n    - name: Checkout submodules\n      run: |\n        git submodule update --init -- \"CMake\"\n        git submodule update --init -- \"external/vcpkg\"\n    - name: Setup vcpkg\n      uses: lukka/run-vcpkg@v11\n      with:\n        vcpkgDirectory: '${{ github.workspace }}/external/vcpkg'\n        vcpkgJsonGlob: 'vcpkg.json'\n    - name: Create Build Environment\n      run: |\n        cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }}\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        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\n    - name: Build\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --build . --parallel 2 --config ${{ matrix.buildType }}\n    - name: Test\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        ctest -C ${{ matrix.buildType }}\n    - name: Prepare package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --install . --config ${{ matrix.buildType }}\n    - name: Zip package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        7z a $GITHUB_WORKSPACE/RenderGraph-${{ matrix.os[1] }}.zip $GITHUB_WORKSPACE/package/rendergraph/\n    - name: Upload package\n      if: github.event_name == 'push'\n      uses: actions/upload-artifact@v4\n      with:\n        name: RenderGraph-${{ matrix.os[1] }}.zip\n        path: ${{ github.workspace }}/RenderGraph-${{ matrix.os[1] }}.zip\n\n  build-linux-gcc:\n    strategy:\n      matrix:\n        os: [[ubuntu-latest,x64-linux,gcc]]\n        buildType: [Release]\n    runs-on: ${{ matrix.os[0] }}\n    steps:\n    - uses: actions/checkout@v4\n    - name: Checkout submodules\n      run: |\n        git submodule update --init -- \"CMake\"\n        git submodule update --init -- \"external/vcpkg\"\n    - name: Setup vcpkg\n      uses: lukka/run-vcpkg@v11\n      with:\n        vcpkgDirectory: '${{ github.workspace }}/external/vcpkg'\n        vcpkgJsonGlob: 'vcpkg.json'\n    - name: Create Build Environment\n      run: |\n        cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }}\n    - name: Configure GCC version\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        echo \"CC=gcc-12\" >> $GITHUB_ENV\n        echo \"CXX=g++-12\" >> $GITHUB_ENV\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        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\n    - name: Build\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --build . --parallel 2 --config ${{ matrix.buildType }}\n    - name: Test\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        ctest -C ${{ matrix.buildType }}\n    - name: Prepare package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --install . --config ${{ matrix.buildType }}\n    - name: Zip package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        7z a $GITHUB_WORKSPACE/RenderGraph-${{ matrix.os[1] }}-gcc.zip $GITHUB_WORKSPACE/package/rendergraph/\n    - name: Upload package\n      if: github.event_name == 'push'\n      uses: actions/upload-artifact@v4\n      with:\n        name: RenderGraph-${{ matrix.os[1] }}-gcc.zip\n        path: ${{ github.workspace }}/RenderGraph-${{ matrix.os[1] }}-gcc.zip\n\n  build-linux-clang:\n    strategy:\n      matrix:\n        os: [[ubuntu-latest,x64-linux,clang]]\n        buildType: [Release]\n    runs-on: ${{ matrix.os[0] }}\n    steps:\n    - uses: actions/checkout@v4\n    - name: Checkout submodules\n      run: |\n        git submodule update --init -- \"CMake\"\n        git submodule update --init -- \"external/vcpkg\"\n    - name: Setup vcpkg\n      uses: lukka/run-vcpkg@v11\n      with:\n        vcpkgDirectory: '${{ github.workspace }}/external/vcpkg'\n        vcpkgJsonGlob: 'vcpkg.json'\n    - name: Create Build Environment\n      run: |\n        cmake -E make_directory ${{runner.workspace}}/build-${{ matrix.buildType }}\n    - name: Configure Warnings as errors (OFF)\n      if: github.event_name == 'push'\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        echo \"PROJ_WAE=OFF\" >> $GITHUB_ENV\n    - name: Configure Warnings as errors (ON)\n      if: github.event_name == 'pull_request'\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        echo \"PROJ_WAE=ON\" >> $GITHUB_ENV\n    - name: Configure Clang version\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        echo \"CC=clang-16\" >> $GITHUB_ENV\n        echo \"CXX=clang++-16\" >> $GITHUB_ENV\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      run: |\n        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\n    - name: Build\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --build . --parallel 2 --config ${{ matrix.buildType }}\n    - name: Test\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        ctest -C ${{ matrix.buildType }}\n    - name: Prepare package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        cmake --install . --config ${{ matrix.buildType }}\n    - name: Zip package\n      if: github.event_name == 'push'\n      working-directory: ${{runner.workspace}}/build-${{ matrix.buildType }}\n      shell: bash\n      run: |\n        7z a $GITHUB_WORKSPACE/RenderGraph-${{ matrix.os[1] }}-clang.zip $GITHUB_WORKSPACE/package/rendergraph/\n    - name: Upload package\n      if: github.event_name == 'push'\n      uses: actions/upload-artifact@v4\n      with:\n        name: RenderGraph-${{ matrix.os[1] }}-clang.zip\n        path: ${{ github.workspace }}/RenderGraph-${{ matrix.os[1] }}-clang.zip\n"
  },
  {
    "path": ".gitignore",
    "content": "/.vscode\n/binaries\n/build*\n/setup\n/doc/coverage\n/doc/RenderGraphCoverage\n/doc/RenderGraphCoverage.xml\n/doc/x86\n/doc/x64\n/.gitattributes\n*.csproj\n*.user\n*.suo\n*.gch\n*.*~\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"CMake\"]\n\tpath = CMake\n\turl = https://github.com/DragonJoker/CMakeUtils.git\n[submodule \"external/vcpkg\"]\n\tpath = external/vcpkg\n\turl = https://github.com/microsoft/vcpkg.git\n"
  },
  {
    "path": "AUTHORS",
    "content": "Authors of RenderGraph\n\nSylvain Doremus\t\t\tMain author\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required( VERSION 3.10 )\ncmake_policy( VERSION 3.10 )\n\n#--------------------------------------------------------------------------------------------------\n#\tInitial configurations\n#--------------------------------------------------------------------------------------------------\n# Set project name, used in folders and in workspace creation\nset( MAIN_PROJECT_NAME \"RenderGraph\" )\n\n# Set project version numbers\nset( VERSION_MAJOR 2 )\nset( VERSION_MINOR 1 )\nset( VERSION_BUILD 0 )\nset( VERSION_YEAR 2025 )\n\nset( _PROJECT_VERSION \"${VERSION_MAJOR}.${VERSION_MINOR}\" )\nset( _PROJECT_SOVERSION \"${VERSION_BUILD}\" )\n\n# Used to look for external modules\nif ( NOT CMAKE_MODULE_PATH )\n\tset( CMAKE_MODULE_PATH\n\t\t${CMAKE_SOURCE_DIR}/CMake\n\t\t${CMAKE_SOURCE_DIR}/CMake/Modules\n\t\t${CMAKE_SOURCE_DIR}/CMake/Toolchains\n\t)\n\tset( CMAKE_TEMPLATES_DIR ${CMAKE_SOURCE_DIR}/CMake/Templates )\nendif ()\n\nset( CMAKE_POSITION_INDEPENDENT_CODE ON )\nset( CMAKE_CONFIGURATION_TYPES \"Debug;Release;RelWithDebInfo\" CACHE STRING \"The configuration types\" FORCE )\n\n# Experimental Precompiled headers support for GCC\ninclude( PCHSupport )\n\n# Declare the project\nproject( ${MAIN_PROJECT_NAME} )\n\ninclude( Setup )\ninclude( Project )\ninclude( CompilerVersion )\ninclude( UnitTest )\ninclude( CompilationFlags )\ninclude( AStyleUtils )\ninclude( ExternalDependencies )\ninclude( Coverage )\n\n# Organize projects into folders\nset_property( GLOBAL PROPERTY USE_FOLDERS ON )\n\n#--------------------------------------------------------------------------------------------------\n#\tAdding include dirs to include search path\n#--------------------------------------------------------------------------------------------------\nset( CRG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )\nset( CRG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )\n\nset( CRG_EDITORCONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/.editorconfig )\n\nif ( NOT DEFINED CRG_BUILD_STATIC )\n\toption( CRG_BUILD_STATIC \"Build as a static library\" ON )\nendif ()\nif ( NOT DEFINED CRG_BUILD_TESTS )\n\toption( CRG_BUILD_TESTS \"Build RenderGraph test applications\" OFF )\nendif ()\nif ( NOT DEFINED CRG_UNITY_BUILD )\n\toption( CRG_UNITY_BUILD \"Build RenderGraph using Unity (Jumbo) build method\" OFF )\nendif ()\n\nif ( MSVC OR NOT \"${CMAKE_BUILD_TYPE}\" STREQUAL \"\" )\n\tconfigure_file(\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Version.hpp.in\n\t\t${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\tNEWLINE_STYLE LF\n\t)\n\t# RenderGraph library\n\tproject( RenderGraph )\n\tset( ${PROJECT_NAME}_HDR_FILES\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Attachment.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/AttachmentTransition.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferViewData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/DotExport.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Exception.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraph.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphBase.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphEnums.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphFunctions.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphPrerequisites.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphStructs.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePassGroup.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePassTimer.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphContext.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphNode.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphVisitor.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Hash.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Id.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageViewData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/LayerLayoutStatesHandler.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Log.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/PixelFormat.inl\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RecordContext.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ResourceHandler.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnableGraph.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Signal.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/WriteDescriptorSet.hpp\n\t\t${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.hpp\n\t)\n\tset( ${PROJECT_NAME}_SRC_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/Attachment.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/AttachmentTransition.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/DotExport.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraph.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraphPrerequisites.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassGroup.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassTimer.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphContext.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphNode.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/LayerLayoutStatesHandler.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/Log.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RecordContext.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/ResourceHandler.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnableGraph.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePass.cpp\n\t)\n\tset( ${PROJECT_NAME}_NVS_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraph.natvis\n\t)\n\tsource_group( \"Header Files\" FILES ${${PROJECT_NAME}_HDR_FILES} )\n\tsource_group( \"Source Files\" FILES ${${PROJECT_NAME}_SRC_FILES} )\n\tsource_group( \"Visualisation Files\" FILES ${${PROJECT_NAME}_NVS_FILES} )\n\tset( ${PROJECT_NAME}_FOLDER_HDR_FILES\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/BufferCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/BufferToImageCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ComputePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/GenerateMipmaps.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageBlit.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageToBufferCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/PipelineConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/PipelineHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderPass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderPassHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMesh.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMeshConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMeshHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuad.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuadConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuadHolder.hpp\n\t)\n\tset( ${PROJECT_NAME}_FOLDER_SRC_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/BufferCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/BufferToImageCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ComputePass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/GenerateMipmaps.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageBlit.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageToBufferCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/PipelineHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderPass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderPassHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderMesh.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderMeshHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderQuad.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderQuadHolder.cpp\n\t)\n\tset( ${PROJECT_NAME}_SRC_FILES\n\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t${${PROJECT_NAME}_FOLDER_SRC_FILES}\n\t)\n\tset( ${PROJECT_NAME}_HDR_FILES\n\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t${${PROJECT_NAME}_FOLDER_HDR_FILES}\n\t)\n\tsource_group( \"Header Files\\\\RunnablePasses\" FILES ${${PROJECT_NAME}_FOLDER_HDR_FILES} )\n\tsource_group( \"Source Files\\\\RunnablePasses\" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} )\n\tif ( ${CRG_UNITY_BUILD} )\n\t\tfile( GLOB ${PROJECT_NAME}_FOLDER_SRC_FILES\n\t\t\t${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/Unity/*.cxx\n\t\t)\n\t\tsource_group( \"Source Files\\\\Unity\" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} )\n\tendif ()\n\tif ( CRG_BUILD_STATIC )\n\t\tadd_library( ${PROJECT_NAME} STATIC\n\t\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t\t${${PROJECT_NAME}_NVS_FILES}\n\t\t)\n\t\ttarget_compile_definitions( ${PROJECT_NAME}\n\t\t\tPUBLIC\n\t\t\t\tCRG_BUILD_STATIC\n\t\t)\n\telse ()\n\t\tadd_library( ${PROJECT_NAME} SHARED\n\t\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t\t${${PROJECT_NAME}_NVS_FILES}\n\t\t)\n\t\tset_target_properties( ${PROJECT_NAME}\n\t\t\tPROPERTIES\n\t\t\t\tVERSION ${_PROJECT_VERSION}\n\t\t\t\tSOVERSION ${_PROJECT_SOVERSION}\n\t\t)\n\t\tif ( WIN32 )\n\t\t\ttarget_link_libraries( ${PROJECT_NAME}\n\t\t\t\tPUBLIC\n\t\t\t\t\tDbghelp\n\t\t\t)\n\t\telse ()\n\t\t\ttarget_link_libraries( ${PROJECT_NAME}\n\t\t\t\tPRIVATE\n\t\t\t\t\tdl\n\t\t\t)\n\t\tendif ()\n\tendif ()\n\tadd_library( crg::${PROJECT_NAME}\n\t\tALIAS\n\t\t\t${PROJECT_NAME}\n\t)\n\ttarget_add_coverage_flags( ${PROJECT_NAME} )\n\ttarget_sources( ${PROJECT_NAME} \n\t\tPRIVATE\n\t\t\t${CRG_EDITORCONFIG_FILE}\n\t)\n\ttarget_add_compilation_flags( ${PROJECT_NAME} )\n\ttarget_compile_options( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\t$<$<CXX_COMPILER_ID:AppleClang>:-Wno-poison-system-directories>\n\t\t\t$<$<CXX_COMPILER_ID:Clang>:-Wno-poison-system-directories>\n\t)\n\ttarget_compile_definitions( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\tCRG_VERSION_MAJOR=${VERSION_MAJOR}\n\t\t\tCRG_VERSION_MINOR=${VERSION_MINOR}\n\t\t\tCRG_VERSION_BUILD=${VERSION_BUILD}\n\t)\n\ttarget_include_directories( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\t$<BUILD_INTERFACE:${CRG_SOURCE_DIR}/include>\n\t\t\t$<BUILD_INTERFACE:${CRG_BINARY_DIR}>\n\t\t\t$<BUILD_INTERFACE:${Vulkan_INCLUDE_DIR}>\n\t\t\t$<INSTALL_INTERFACE:include>\n\t)\n\tfind_package( VulkanHeaders CONFIG )\n\ttarget_link_libraries( ${PROJECT_NAME}\n\t\tPRIVATE\n\t\t\tVulkan::Headers\n\t)\t\n\tset_target_properties( ${PROJECT_NAME}\n\t\tPROPERTIES\n\t\t\tCXX_STANDARD 20\n\t\t\tFOLDER \"${CRG_BASE_DIR}/Core\"\n\t\t\tDEBUG_POSTFIX \"d\"\n\t\t\tUNITY_BUILD \"${CRG_UNITY_BUILD}\"\n\t)\n\tinstall(\n\t\tTARGETS ${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tEXPORT ${PROJECT_NAME}\n\t\tRUNTIME DESTINATION bin\n\t\tARCHIVE DESTINATION lib\n\t\tLIBRARY DESTINATION lib\n\t)\n\tinstall(\n\t\tFILES ${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\tDESTINATION include/${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tCONFIGURATIONS Release\n\t)\n\ttarget_install_headers( ${PROJECT_NAME}\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}\n\t)\n\tinstall( EXPORT ${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tFILE ${PROJECT_NAME}Config.cmake\n\t\tNAMESPACE crg::\n\t\tDESTINATION share/${PROJECT_NAME}\n\t)\n\tinclude(CMakePackageConfigHelpers)\n\twrite_basic_package_version_file( ${PROJECT_NAME}ConfigVersion.cmake\n\t\tVERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}\n\t\tCOMPATIBILITY AnyNewerVersion\n\t)\n\n\tif ( CRG_BUILD_TESTS )\n\t\tadd_subdirectory( test )\n\tendif ()\nelse()\n\tmessage( SEND_ERROR \"Please select a build type (Debug or Release)\" )\nendif()\n"
  },
  {
    "path": "CMakePresets.json",
    "content": "{\n\t\"version\": 3,\n\t\"cmakeMinimumRequired\": {\n\t\t\"major\": 3,\n\t\t\"minor\": 21,\n\t\t\"patch\": 0\n\t},\n\t\"configurePresets\": [\n\t\t{\n\t\t\t\"name\": \"default-base\",\n\t\t\t\"hidden\": true,\n\t\t\t\"displayName\": \"Default Config\",\n\t\t\t\"description\": \"Default build configuration\",\n\t\t\t\"installDir\": \"${sourceDir}/package/RenderGraph\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CRG_BUILD_STATIC\": false,\n\t\t\t\t\"CRG_BUILD_TESTS\": true\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-base\",\n\t\t\t\"hidden\": true,\n\t\t\t\"displayName\": \"Developer Visual Studio Config\",\n\t\t\t\"description\": \"Developer build configuration using Visual Studio\",\n\t\t\t\"inherits\": \"default-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_TOOLCHAIN_FILE\": \"${sourceDir}/external/vcpkg/scripts/buildsystems/vcpkg.cmake\",\n\t\t\t\t\"PROJECTS_WARNINGS_AS_ERRORS\": true,\n\t\t\t\t\"VCPKG_MANIFEST_FEATURES\": \"tests\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"default-msvc\",\n\t\t\t\"displayName\": \"Default Visual Studio Config\",\n\t\t\t\"description\": \"Default build configuration using Visual Studio\",\n\t\t\t\"inherits\": \"default-base\",\n\t\t\t\"generator\": \"Visual Studio 17 2022\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"default-ninja-base\",\n\t\t\t\"hidden\": true,\n\t\t\t\"displayName\": \"Default Ninja Config\",\n\t\t\t\"description\": \"Default build configuration using Ninja\",\n\t\t\t\"inherits\": \"default-base\",\n\t\t\t\"generator\": \"Ninja\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"default-ninja-debug\",\n\t\t\t\"displayName\": \"Default Ninja Config, Debug\",\n\t\t\t\"description\": \"Default build configuration using Ninja, Debug\",\n\t\t\t\"inherits\": \"default-ninja-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Debug\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"default-ninja-release\",\n\t\t\t\"displayName\": \"Default Ninja Config, Release\",\n\t\t\t\"description\": \"Default build configuration using Ninja, Release\",\n\t\t\t\"inherits\": \"default-ninja-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Release\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-msvc\",\n\t\t\t\"displayName\": \"Developer Visual Studio Config\",\n\t\t\t\"description\": \"Developer build configuration using Visual Studio\",\n\t\t\t\"inherits\": \"dev-base\",\n\t\t\t\"generator\": \"Visual Studio 17 2022\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-ninja-base\",\n\t\t\t\"hidden\": true,\n\t\t\t\"displayName\": \"Developer Ninja Config\",\n\t\t\t\"description\": \"Developer build configuration using Ninja\",\n\t\t\t\"inherits\": \"dev-base\",\n\t\t\t\"generator\": \"Ninja\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-ninja-debug\",\n\t\t\t\"displayName\": \"Developer Ninja Config, Debug\",\n\t\t\t\"description\": \"Developer build configuration using Ninja, Debug\",\n\t\t\t\"inherits\": \"dev-ninja-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Debug\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-ninja-release\",\n\t\t\t\"displayName\": \"Developer Ninja Config, Release\",\n\t\t\t\"description\": \"Developer build configuration using Ninja, Release\",\n\t\t\t\"inherits\": \"dev-ninja-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Release\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-mingw-base\",\n\t\t\t\"hidden\": true,\n\t\t\t\"displayName\": \"Developer MinGW Config\",\n\t\t\t\"description\": \"Developer build configuration using Ninja, on MinGW\",\n\t\t\t\"generator\": \"Ninja\",\n\t\t\t\"inherits\": \"default-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"PROJECTS_WARNINGS_AS_ERRORS\": true,\n\t\t\t\t\"CRG_BUILD_TESTS\": true\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-mingw-debug\",\n\t\t\t\"displayName\": \"Developer MinGW Config, Debug\",\n\t\t\t\"description\": \"Developer build configuration using Ninja, on MinGW, Debug\",\n\t\t\t\"inherits\": \"dev-mingw-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Debug\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-mingw-release\",\n\t\t\t\"displayName\": \"Developer MinGW Config, Release\",\n\t\t\t\"description\": \"Developer build configuration using Ninja, on MinGW, Release\",\n\t\t\t\"inherits\": \"dev-mingw-base\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Release\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"ci\",\n\t\t\t\"installDir\": \"${sourceDir}/package/Castor3D\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_TOOLCHAIN_FILE\": \"${sourceDir}/external/vcpkg/scripts/buildsystems/vcpkg.cmake\",\n\t\t\t\t\"CRG_BUILD_STATIC\": false,\n\t\t\t\t\"CRG_UNITY_BUILD\": true,\n\t\t\t\t\"CRG_BUILD_TESTS\": true,\n\t\t\t\t\"PROJECTS_WARNINGS_AS_ERRORS\": true,\n\t\t\t\t\"VCPKG_MANIFEST_FEATURES\": \"tests\"\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at dragonjoker59@hotmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Sylvain Doremus\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img alt=\"Vcpkg Version\" src=\"https://img.shields.io/vcpkg/v/rendergraph\">\n  <a href=\"https://github.com/DragonJoker/RenderGraph/actions/workflows/cmake.yml\"><img alt=\"Build status\" src=\"https://github.com/DragonJoker/RenderGraph/actions/workflows/cmake.yml/badge.svg\"></a>\n  <a href=\"https://codecov.io/gh/DragonJoker/RenderGraph\" ><img src=\"https://codecov.io/gh/DragonJoker/RenderGraph/graph/badge.svg?token=E0IGAPHLJO\"/></a>\n</p>\n\n\n# RenderGraph\n\nThis library owes to be used to handle Vulkan render passes and image transitions smoothly.\n\nIt allows the user to register its render passes, along with their attachments (input, sampled, colour, depth stencil...), and will generate a runnable graph from that data.\n\n## Current status\n\n- The user can register its passes and their attachments.  \n- The runnable graph is generated, and image layout transitions are handled.  \n- The runnable graph commands can be recorded and submitted to a queue.  \n- Handling of \"variants\" (optional passes, or paths of a single pass that are triggered by specific conditions).  \n\n## Building\n\nRenderGraph uses CMake.\n\nThe only dependency is Vulkan-Headers, and the CMake variable holding its folder is VULKAN_HEADERS_INCLUDE_DIRS, which you need to set on command line, or by editing the CMakeCache.txt.  \n"
  },
  {
    "path": "include/RenderGraph/Attachment.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"BufferViewData.hpp\"\n#include \"ImageViewData.hpp\"\n\n#include <limits>\n\n#ifdef None\n#undef None\n#endif\n\nnamespace crg\n{\n\tstatic constexpr uint32_t InvalidBindingId = std::numeric_limits< uint32_t >::max();\n\n\tstruct SamplerDesc\n\t{\n\t\tFilterMode magFilter{ FilterMode::eNearest };\n\t\tFilterMode minFilter{ FilterMode::eNearest };\n\t\tMipmapMode mipmapMode{ MipmapMode::eNearest };\n\t\tWrapMode addressModeU{ WrapMode::eClampToEdge };\n\t\tWrapMode addressModeV{ WrapMode::eClampToEdge };\n\t\tWrapMode addressModeW{ WrapMode::eClampToEdge };\n\t\tfloat mipLodBias{ 0.0f };\n\t\tfloat minLod{ -500.0f };\n\t\tfloat maxLod{ 500.0f };\n\n\t\texplicit constexpr SamplerDesc( FilterMode magFilter = FilterMode::eNearest\n\t\t\t, FilterMode minFilter = FilterMode::eNearest\n\t\t\t, MipmapMode mipmapMode = MipmapMode::eNearest\n\t\t\t, WrapMode addressModeU = WrapMode::eClampToEdge\n\t\t\t, WrapMode addressModeV = WrapMode::eClampToEdge\n\t\t\t, WrapMode addressModeW = WrapMode::eClampToEdge\n\t\t\t, float mipLodBias = 0.0f\n\t\t\t, float minLod = -500.0f\n\t\t\t, float maxLod = 500.0f )\n\t\t\t: magFilter{ magFilter }\n\t\t\t, minFilter{ minFilter }\n\t\t\t, mipmapMode{ mipmapMode }\n\t\t\t, addressModeU{ addressModeU }\n\t\t\t, addressModeV{ addressModeV }\n\t\t\t, addressModeW{ addressModeW }\n\t\t\t, mipLodBias{ mipLodBias }\n\t\t\t, minLod{ minLod }\n\t\t\t, maxLod{ maxLod }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( SamplerDesc const & lhs, SamplerDesc const & rhs ) = default;\n\t};\n\t/**\n\t*\\brief\n\t*\tAn image attachment.\n\t*/\n\tstruct ImageAttachment\n\t{\n\t\tfriend struct Attachment;\n\t\tfriend struct FramePass;\n\t\t/**\n\t\t*\\brief\n\t\t*\tThe flags qualifying the attachment.\n\t\t*/\n\t\tusing FlagKind = uint16_t;\n\t\tenum class Flag : FlagKind\n\t\t{\n\t\t\tNone = 0x00,\n\t\t\tSampled = 0x01 << 0,\n\t\t\tStorage = 0x01 << 1,\n\t\t\tTransfer = 0x01 << 2,\n\t\t\tDepth = 0x01 << 3,\n\t\t\tStencil = 0x01 << 4,\n\t\t\tStencilClearing = 0x01 << 5,\n\t\t\tStencilInput = 0x01 << 6,\n\t\t\tStencilOutput = 0x01 << 7,\n\t\t\tTransition = 0x01 << 8,\n\t\t\tDepthStencil = Depth | Stencil,\n\t\t\tStencilInOut = StencilInput | StencilOutput,\n\t\t};\n\t\t/**\n\t\t*\\name\n\t\t*\tGetters.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API ImageViewId view( uint32_t index = 0u )const;\n\t\tCRG_API ImageLayout getImageLayout( bool separateDepthStencilLayouts\n\t\t\t, bool isInput\n\t\t\t, bool isOutput )const;\n\t\tCRG_API AccessFlags getAccessMask( bool isInput\n\t\t\t, bool isOutput )const;\n\t\tCRG_API PipelineStageFlags getPipelineStageFlags( bool isCompute )const;\n\n\t\tFlagKind getFlags()const\n\t\t{\n\t\t\treturn flags;\n\t\t}\n\n\t\tFlagKind getFormatFlags()const\n\t\t{\n\t\t\treturn FlagKind( flags & FlagKind( Flag::DepthStencil ) );\n\t\t}\n\n\t\tuint32_t getViewCount()const\n\t\t{\n\t\t\treturn uint32_t( views.size() );\n\t\t}\n\n\t\tbool hasFlag( Flag flag )const\n\t\t{\n\t\t\treturn Flag( flags & FlagKind( flag ) ) == flag;\n\t\t}\n\n\t\tbool isSampledView()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Sampled );\n\t\t}\n\n\t\tbool isStorageView()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Storage );\n\t\t}\n\n\t\tbool isTransferView()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Transfer );\n\t\t}\n\n\t\tbool isTransitionView()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Transition );\n\t\t}\n\n\t\tbool isDepthTarget()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Depth ) && !isTransitionView();\n\t\t}\n\n\t\tbool isStencilTarget()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Stencil ) && !isTransitionView();\n\t\t}\n\n\t\tbool isDepthStencilTarget()const\n\t\t{\n\t\t\treturn isDepthTarget() && isStencilTarget();\n\t\t}\n\n\t\tbool isColourTarget()const\n\t\t{\n\t\t\treturn !isSampledView()\n\t\t\t\t&& !isTransitionView()\n\t\t\t\t&& !isStorageView()\n\t\t\t\t&& !isTransferView()\n\t\t\t\t&& !isDepthTarget()\n\t\t\t\t&& !isStencilTarget();\n\t\t}\n\n\t\tbool isStencilClearingTarget()const\n\t\t{\n\t\t\treturn hasFlag( Flag::StencilClearing );\n\t\t}\n\n\t\tbool isStencilInputTarget()const\n\t\t{\n\t\t\treturn hasFlag( Flag::StencilInput );\n\t\t}\n\n\t\tbool isStencilOutputTarget()const\n\t\t{\n\t\t\treturn hasFlag( Flag::StencilOutput );\n\t\t}\n\t\t/**@}*/\n\n\tpublic:\n\t\tImageViewIdArray views{};\n\t\tAttachmentLoadOp loadOp{};\n\t\tAttachmentStoreOp storeOp{};\n\t\tAttachmentLoadOp stencilLoadOp{};\n\t\tAttachmentStoreOp stencilStoreOp{};\n\t\tClearValue clearValue{};\n\t\tPipelineColorBlendAttachmentState blendState = DefaultBlendState;\n\t\tImageLayout wantedLayout{};\n\t\tFlagKind flags{};\n\n\tprivate:\n\t\tImageAttachment() = default;\n\t\tCRG_API explicit ImageAttachment( ImageViewIdArray view );\n\t\tCRG_API ImageAttachment( FlagKind flags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, AttachmentLoadOp stencilLoadOp\n\t\t\t, AttachmentStoreOp stencilStoreOp\n\t\t\t, ClearValue clearValue\n\t\t\t, PipelineColorBlendAttachmentState blendState\n\t\t\t, ImageLayout wantedLayout );\n\n\t\tfriend bool operator==( ImageAttachment const & lhs\n\t\t\t, ImageAttachment const & rhs )noexcept\n\t\t{\n\t\t\treturn lhs.flags == rhs.flags\n\t\t\t\t&& lhs.views == rhs.views\n\t\t\t\t&& lhs.loadOp == rhs.loadOp\n\t\t\t\t&& lhs.storeOp == rhs.storeOp\n\t\t\t\t&& lhs.stencilLoadOp == rhs.stencilLoadOp\n\t\t\t\t&& lhs.stencilStoreOp == rhs.stencilStoreOp\n\t\t\t\t&& lhs.clearValue == rhs.clearValue\n\t\t\t\t&& lhs.blendState == rhs.blendState;\n\t\t}\n\n\t};\n\t/**\n\t*\\brief\n\t*\tA buffer (uniform or storage) attachment.\n\t*/\n\tstruct BufferAttachment\n\t{\n\t\tfriend struct Attachment;\n\t\tfriend struct FramePass;\n\t\t/**\n\t\t*\\brief\n\t\t*\tThe flags qualifying a buffer attachment.\n\t\t*/\n\t\tusing FlagKind = uint16_t;\n\t\tenum class Flag : FlagKind\n\t\t{\n\t\t\tNone = 0x00,\n\t\t\tUniform = 0x01 << 0,\n\t\t\tStorage = 0x01 << 1,\n\t\t\tTransfer = 0x01 << 2,\n\t\t\tView = 0x01 << 3,\n\t\t\tTransition = 0x01 << 4,\n\t\t\tUniformView = Uniform | View,\n\t\t\tStorageView = Storage | View,\n\t\t\tTransitionView = Transition | View,\n\t\t};\n\n\t\tCRG_API BufferViewId buffer( uint32_t index = 0u )const;\n\t\tCRG_API AccessFlags getAccessMask( bool isInput\n\t\t\t, bool isOutput )const;\n\t\tCRG_API PipelineStageFlags getPipelineStageFlags( bool isCompute )const;\n\n\t\tCRG_API uint32_t getBufferCount()const;\n\n\t\tFlagKind getFlags()const\n\t\t{\n\t\t\treturn flags;\n\t\t}\n\n\t\tFlagKind getFormatFlags()const\n\t\t{\n\t\t\treturn FlagKind( flags & FlagKind( Flag::View ) );\n\t\t}\n\n\t\tbool hasFlag( Flag flag )const\n\t\t{\n\t\t\treturn Flag( flags & FlagKind( flag ) ) == flag;\n\t\t}\n\n\t\tbool isUniform()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Uniform );\n\t\t}\n\n\t\tbool isStorage()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Storage );\n\t\t}\n\n\t\tbool isTransfer()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Transfer );\n\t\t}\n\n\t\tbool isTransition()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Transition );\n\t\t}\n\n\t\tbool isView()const\n\t\t{\n\t\t\treturn hasFlag( Flag::View );\n\t\t}\n\n\t\tbool isUniformView()const\n\t\t{\n\t\t\treturn isUniform() && isView();\n\t\t}\n\n\t\tbool isStorageView()const\n\t\t{\n\t\t\treturn isStorage() && isView();\n\t\t}\n\n\t\tbool isTransitionView()const\n\t\t{\n\t\t\treturn isTransition() && isView();\n\t\t}\n\n\tpublic:\n\t\tBufferViewIdArray buffers;\n\t\tFlagKind flags{};\n\t\tAccessState wantedAccess{};\n\n\tprivate:\n\t\tBufferAttachment() = default;\n\t\tCRG_API explicit BufferAttachment( BufferViewIdArray view );\n\t\tCRG_API BufferAttachment( FlagKind flags\n\t\t\t, BufferViewIdArray views\n\t\t\t, AccessState access = {} );\n\n\t\tfriend bool operator==( BufferAttachment const & lhs\n\t\t\t, BufferAttachment const & rhs )noexcept\n\t\t{\n\t\t\treturn lhs.flags == rhs.flags\n\t\t\t\t&& lhs.buffers == rhs.buffers;\n\t\t}\n\t};\n\t/**\n\t*\\brief\n\t*\tAn attachment to a pass.\n\t*/\n\tstruct Attachment\n\t{\n\t\tfriend struct FramePass;\n\t\tfriend class FrameGraph;\n\n\t\tclass Token\n\t\t{\n\t\t\tfriend struct Attachment;\n\t\t\tfriend struct FramePass;\n\n\t\tprivate:\n\t\t\tToken() noexcept = default;\n\t\t};\n\n\t\tstruct Source\n\t\t{\n\t\t\tSource( Attachment const * parent\n\t\t\t\t, FramePass const * pass\n\t\t\t\t, ImageAttachment const & imgAttach )\n\t\t\t\t: parent{ parent }\n\t\t\t\t, pass{ pass }\n\t\t\t\t, imageAttach{ &imgAttach }\n\t\t\t{\n\t\t\t}\n\n\t\t\tSource( Attachment const * parent\n\t\t\t\t, FramePass const * pass\n\t\t\t\t, BufferAttachment const & bufAttach )\n\t\t\t\t: parent{ parent }\n\t\t\t\t, pass{ pass }\n\t\t\t\t, bufferAttach{ &bufAttach }\n\t\t\t{\n\t\t\t}\n\n\t\t\texplicit Source( AttachmentPtr sourceAttach )\n\t\t\t\t: pass{ sourceAttach->pass }\n\t\t\t\t, imageAttach{ sourceAttach->isImage() ? &sourceAttach->imageAttach : nullptr }\n\t\t\t\t, bufferAttach{ sourceAttach->isBuffer() ? &sourceAttach->bufferAttach : nullptr }\n\t\t\t\t, attach{ std::move( sourceAttach ) }\n\t\t\t{\n\t\t\t}\n\n\t\t\tAttachment const * parent{};\n\t\t\tFramePass const * pass{};\n\t\t\tImageAttachment const * imageAttach{};\n\t\t\tBufferAttachment const * bufferAttach{};\n\t\t\tAttachmentPtr attach;\n\t\t};\n\t\t/**\n\t\t*\\brief\n\t\t*\tThe flags qualifying an Attachment.\n\t\t*/\n\t\tusing FlagKind = uint16_t;\n\t\tenum class Flag : FlagKind\n\t\t{\n\t\t\tNone = 0x00,\n\t\t\tInput = 0x01 << 0,\n\t\t\tOutput = 0x01 << 1,\n\t\t\tImage = 0x01 << 2,\n\t\t\tBuffer = 0x01 << 3,\n\t\t\tNoTransition = 0x01 << 4,\n\t\t\tClearable = 0x01 << 5,\n\t\t\tInOut = Input | Output,\n\t\t};\n\n\t\tCRG_API Attachment( Attachment const & rhs );\n\t\tCRG_API Attachment & operator=( Attachment const & rhs );\n\t\tAttachment( Attachment && rhs )noexcept = default;\n\t\tAttachment & operator=( Attachment && rhs )noexcept = default;\n\t\t/**\n\t\t*\\name\n\t\t*\tGetters.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API uint32_t getViewCount()const;\n\t\tCRG_API uint32_t getBufferCount()const;\n\t\tCRG_API ImageViewId view( uint32_t index = 0u )const;\n\t\tCRG_API BufferViewId buffer( uint32_t index = 0u )const;\n\t\tCRG_API ImageLayout getImageLayout( bool separateDepthStencilLayouts )const;\n\t\tCRG_API AccessFlags getAccessMask()const;\n\t\tCRG_API PipelineStageFlags getPipelineStageFlags( bool isCompute )const;\n\t\tCRG_API Attachment const * getSource( uint32_t index )const;\n\n\t\tFlagKind getFlags()const\n\t\t{\n\t\t\treturn flags;\n\t\t}\n\n\t\tbool hasFlag( Flag flag )const\n\t\t{\n\t\t\treturn Flag( flags & FlagKind( flag ) ) == flag;\n\t\t}\n\n\t\tbool isNoTransition()const\n\t\t{\n\t\t\treturn hasFlag( Flag::NoTransition );\n\t\t}\n\n\t\tbool isInput()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Input );\n\t\t}\n\n\t\tbool isOutput()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Output );\n\t\t}\n\n\t\tbool isInOut()const\n\t\t{\n\t\t\treturn isInput() && isOutput();\n\t\t}\n\n\t\tbool isImage()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Image );\n\t\t}\n\n\t\tbool isBuffer()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Buffer );\n\t\t}\n\n\t\tbool isClearable()const\n\t\t{\n\t\t\treturn hasFlag( Flag::Clearable );\n\t\t}\n\n\t\tbool isUniformBuffer()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isUniform();\n\t\t}\n\n\t\tbool isUniformBufferView()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isUniformView();\n\t\t}\n\n\t\tbool isStorageBuffer()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isStorage();\n\t\t}\n\n\t\tbool isTransferBuffer()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isTransfer();\n\t\t}\n\n\t\tbool isTransferInputBuffer()const\n\t\t{\n\t\t\treturn isInput() && isTransferBuffer();\n\t\t}\n\n\t\tbool isTransferOutputBuffer()const\n\t\t{\n\t\t\treturn isOutput() && isTransferBuffer();\n\t\t}\n\n\t\tbool isClearableBuffer()const\n\t\t{\n\t\t\treturn isBuffer()\n\t\t\t\t&& isOutput()\n\t\t\t\t&& isClearable();\n\t\t}\n\n\t\tbool isClearableImage()const\n\t\t{\n\t\t\treturn isImage()\n\t\t\t\t&& isOutput()\n\t\t\t\t&& isClearable();\n\t\t}\n\n\t\tbool isStorageBufferView()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isStorageView();\n\t\t}\n\n\t\tbool isTransitionBuffer()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isTransition();\n\t\t}\n\n\t\tbool isTransitionBufferView()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isTransitionView();\n\t\t}\n\n\t\tbool isBufferView()const\n\t\t{\n\t\t\treturn isBuffer() && bufferAttach.isView();\n\t\t}\n\n\t\tbool isSampledImageView()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isSampledView();\n\t\t}\n\n\t\tbool isStorageImageView()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isStorageView();\n\t\t}\n\n\t\tbool isTransferImageView()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isTransferView();\n\t\t}\n\n\t\tbool isTransitionImageView()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isTransitionView();\n\t\t}\n\n\t\tbool isDepthImageTarget()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isDepthTarget();\n\t\t}\n\n\t\tbool isStencilImageTarget()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isStencilTarget();\n\t\t}\n\n\t\tbool isColourImageTarget()const\n\t\t{\n\t\t\treturn !isSampledImageView()\n\t\t\t\t&& !isTransitionImageView()\n\t\t\t\t&& !isStorageImageView()\n\t\t\t\t&& !isTransferImageView()\n\t\t\t\t&& !isDepthImageTarget()\n\t\t\t\t&& !isStencilImageTarget();\n\t\t}\n\n\t\tbool isColourInputImageTarget()const\n\t\t{\n\t\t\treturn isInput() && isColourImageTarget();\n\t\t}\n\n\t\tbool isColourOutputImageTarget()const\n\t\t{\n\t\t\treturn isOutput() && isColourImageTarget();\n\t\t}\n\n\t\tbool isColourInOutImageTarget()const\n\t\t{\n\t\t\treturn isInput() && isOutput() && isColourImageTarget();\n\t\t}\n\n\t\tbool isDepthInputImageTarget()const\n\t\t{\n\t\t\treturn isInput() && isDepthImageTarget();\n\t\t}\n\n\t\tbool isDepthOutputImageTarget()const\n\t\t{\n\t\t\treturn isOutput() && isDepthImageTarget();\n\t\t}\n\n\t\tbool isDepthInOutImageTarget()const\n\t\t{\n\t\t\treturn isInput() && isOutput() && isDepthImageTarget();\n\t\t}\n\n\t\tbool isStencilClearingImageTarget()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isStencilClearingTarget();\n\t\t}\n\n\t\tbool isStencilInputImageTarget()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isStencilInputTarget();\n\t\t}\n\n\t\tbool isStencilOutputImageTarget()const\n\t\t{\n\t\t\treturn isImage() && imageAttach.isStencilOutputTarget();\n\t\t}\n\n\t\tbool isStencilInOutImageTarget()const\n\t\t{\n\t\t\treturn isStencilInputImageTarget() && isStencilOutputImageTarget();\n\t\t}\n\n\t\tbool isDepthStencilInputImageTarget()const\n\t\t{\n\t\t\treturn isDepthInputImageTarget() && isStencilInputImageTarget();\n\t\t}\n\n\t\tbool isDepthStencilOutputImageTarget()const\n\t\t{\n\t\t\treturn isDepthOutputImageTarget() && isStencilOutputImageTarget();\n\t\t}\n\n\t\tbool isDepthStencilInOutImageTarget()const\n\t\t{\n\t\t\treturn isDepthInOutImageTarget() && isStencilInOutImageTarget();\n\t\t}\n\n\t\tbool isTransferInputImageView()const\n\t\t{\n\t\t\treturn isInput() && isTransferImageView();\n\t\t}\n\n\t\tbool isTransferOutputImageView()const\n\t\t{\n\t\t\treturn isOutput() && isTransferImageView();\n\t\t}\n\n\t\tbool isStorageInputImageView()const\n\t\t{\n\t\t\treturn isInput() && isStorageImageView();\n\t\t}\n\n\t\tbool isStorageOutputImageView()const\n\t\t{\n\t\t\treturn isOutput() && isStorageImageView();\n\t\t}\n\n\t\tBufferSubresourceRange const & getBufferRange()const\n\t\t{\n\t\t\treturn getSubresourceRange( bufferAttach.buffer() );\n\t\t}\n\n\t\tClearValue const & getClearValue()const\n\t\t{\n\t\t\treturn imageAttach.clearValue;\n\t\t}\n\n\t\tAttachmentLoadOp getLoadOp()const\n\t\t{\n\t\t\treturn imageAttach.loadOp;\n\t\t}\n\n\t\tAttachmentLoadOp getStencilLoadOp()const\n\t\t{\n\t\t\treturn imageAttach.stencilLoadOp;\n\t\t}\n\n\t\tAttachmentStoreOp getStoreOp()const\n\t\t{\n\t\t\treturn imageAttach.storeOp;\n\t\t}\n\n\t\tAttachmentStoreOp getStencilStoreOp()const\n\t\t{\n\t\t\treturn imageAttach.stencilStoreOp;\n\t\t}\n\n\t\tPipelineColorBlendAttachmentState getBlendState()const\n\t\t{\n\t\t\treturn imageAttach.blendState;\n\t\t}\n\t\t/**@}*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a default empty attachment.\n\t\t*/\n\t\tstatic Attachment createDefault( ImageViewIdArray views )\n\t\t{\n\t\t\treturn Attachment{ std::move( views ) };\n\t\t}\n\t\tstatic Attachment createDefault( BufferViewIdArray views )\n\t\t{\n\t\t\treturn Attachment{ std::move( views ) };\n\t\t}\n\t\tstatic Attachment createDefault( ImageViewId view )\n\t\t{\n\t\t\treturn createDefault( ImageViewIdArray{ view } );\n\t\t}\n\t\tstatic Attachment createDefault( BufferViewId view )\n\t\t{\n\t\t\treturn createDefault( BufferViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\name\n\t\t*\tMembers.\n\t\t*/\n\t\t/**@[*/\n\t\tFramePass const * pass{};\n\t\tstd::string name{};\n\t\tImageAttachment imageAttach{};\n\t\tBufferAttachment bufferAttach{};\n\t\tstd::vector< Source > source{};\n\t\tFlagKind flags{};\n\t\t/**@}*/\n\n\t\tCRG_API Attachment( ImageViewId view\n\t\t\t, Attachment const & origin );\n\t\tCRG_API Attachment( BufferViewId view\n\t\t\t, Attachment const & origin );\n\t\tCRG_API explicit Attachment( ImageViewIdArray view );\n\t\tCRG_API explicit Attachment( BufferViewIdArray view );\n\n\t\tAttachment( FlagKind flags\n\t\t\t, std::string name\n\t\t\t, FramePass const * pass\n\t\t\t, ImageAttachment attach\n\t\t\t, Token token );\n\t\tAttachment( FlagKind flags\n\t\t\t, std::string name\n\t\t\t, FramePass const * pass\n\t\t\t, BufferAttachment attach\n\t\t\t, Token token );\n\t\tAttachment( FlagKind flags\n\t\t\t, FramePass const & pass\n\t\t\t, std::string name\n\t\t\t, ImageAttachment::FlagKind imageFlags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, AttachmentLoadOp stencilLoadOp\n\t\t\t, AttachmentStoreOp stencilStoreOp\n\t\t\t, ClearValue clearValue\n\t\t\t, PipelineColorBlendAttachmentState blendState\n\t\t\t, ImageLayout wantedLayout\n\t\t\t, Token token );\n\t\tAttachment( FlagKind flags\n\t\t\t, FramePass const & pass\n\t\t\t, std::string name\n\t\t\t, BufferAttachment::FlagKind bufferFlags\n\t\t\t, BufferViewIdArray views\n\t\t\t, AccessState wantedAccess\n\t\t\t, Token token );\n\n\tprivate:\n\t\tvoid initSources();\n\n\t\tfriend bool operator==( Attachment const & lhs\n\t\t\t, Attachment const & rhs )\n\t\t{\n\t\t\treturn lhs.pass == rhs.pass\n\t\t\t\t&& lhs.flags == rhs.flags\n\t\t\t\t&& lhs.imageAttach == rhs.imageAttach\n\t\t\t\t&& lhs.bufferAttach == rhs.bufferAttach;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/AttachmentTransition.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Attachment.hpp\"\n\n#include <vector>\n\nnamespace crg\n{\n\ttemplate< typename DataT >\n\tstruct DataTransitionT\n\t{\n\t\tDataTransitionT( DataT data, Attachment outputAttach, Attachment inputAttach )noexcept\n\t\t\t: data{ std::move( data ) }\n\t\t\t, outputAttach{ std::move( outputAttach ) }\n\t\t\t, inputAttach{ std::move( inputAttach ) }\n\t\t{\n\t\t}\n\n\t\tDataT data;\n\t\tAttachment outputAttach;\n\t\tAttachment inputAttach;\n\n\tprivate:\n\t\tfriend bool operator==( DataTransitionT const & lhs, DataTransitionT const & rhs )\n\t\t{\n\t\t\treturn match( lhs.data, rhs.data )\n\t\t\t\t&& lhs.outputAttach == rhs.outputAttach\n\t\t\t\t&& lhs.inputAttach == rhs.inputAttach;\n\t\t}\n\t};\n\n\tstruct AttachmentTransitions\n\t{\n\t\tImageTransitionArray imageTransitions;\n\t\tBufferTransitionArray bufferTransitions;\n\t};\n\n\tAttachmentTransitions mergeIdenticalTransitions( AttachmentTransitions value );\n}\n"
  },
  {
    "path": "include/RenderGraph/BufferData.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Id.hpp\"\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tBasic buffer data, from which buffers will be created.\n\t*/\n\tstruct BufferData\n\t{\n\t\tstd::string name;\n\t\tBufferCreateInfo info;\n\n\t\texplicit BufferData( std::string name = {}\n\t\t\t, BufferCreateFlags flags = {}\n\t\t\t, DeviceSize size = {}\n\t\t\t, BufferUsageFlags usage = {}\n\t\t\t, MemoryPropertyFlags memory = MemoryPropertyFlags::eDeviceLocal )\n\t\t\t: name{ std::move( name ) }\n\t\t\t, info{ flags, size, usage, memory }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( BufferData const & lhs, BufferData const & rhs ) = default;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/BufferViewData.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Id.hpp\"\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tBasic buffer view data, from which views will be created.\n\t*/\n\tstruct BufferViewData\n\t{\n\t\tstd::string name;\n\t\tBufferId buffer;\n\t\tBufferViewCreateInfo info;\n\t\tBufferViewIdArray source{};\n\n\t\texplicit BufferViewData( std::string name = {}\n\t\t\t, BufferId buffer = BufferId{}\n\t\t\t, BufferSubresourceRange subresourceRange = {}\n\t\t\t, PixelFormat format = PixelFormat::eUNDEFINED )\n\t\t\t: name{ std::move( name ) }\n\t\t\t, buffer{ std::move( buffer ) }\n\t\t\t, info{ format, subresourceRange }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( BufferViewData const & lhs, BufferViewData const & rhs )\n\t\t{\n\t\t\treturn lhs.buffer == rhs.buffer\n\t\t\t\t&& lhs.info == rhs.info;\n\t\t}\n\t};\n\n\tstruct VertexBuffer\n\t{\n\t\texplicit VertexBuffer( BufferViewId pbuffer = BufferViewId{}\n\t\t\t, VkVertexInputAttributeDescriptionArray pvertexAttribs = {}\n\t\t\t, VkVertexInputBindingDescriptionArray pvertexBindings = {} )\n\t\t\t: buffer{ std::move( pbuffer ) }\n\t\t\t, vertexAttribs{ std::move( pvertexAttribs ) }\n\t\t\t, vertexBindings{ std::move( pvertexBindings ) }\n\t\t{\n\t\t\tdoUpdateState();\n\t\t}\n\n\t\tVertexBuffer( VertexBuffer const & rhs )\n\t\t\t: buffer{ rhs.buffer }\n\t\t\t, vertexAttribs{ rhs.vertexAttribs }\n\t\t\t, vertexBindings{ rhs.vertexBindings }\n\t\t{\n\t\t\tdoUpdateState();\n\t\t}\n\n\t\tVertexBuffer( VertexBuffer && rhs )noexcept\n\t\t\t: buffer{ std::move( rhs.buffer ) }\n\t\t\t, vertexAttribs{ std::move( rhs.vertexAttribs ) }\n\t\t\t, vertexBindings{ std::move( rhs.vertexBindings ) }\n\t\t{\n\t\t\tdoUpdateState();\n\t\t}\n\n\t\tVertexBuffer & operator=( VertexBuffer const & rhs )\n\t\t{\n\t\t\tbuffer = rhs.buffer;\n\t\t\tvertexAttribs = rhs.vertexAttribs;\n\t\t\tvertexBindings = rhs.vertexBindings;\n\t\t\tdoUpdateState();\n\n\t\t\treturn *this;\n\t\t}\n\n\t\tVertexBuffer & operator=( VertexBuffer && rhs )noexcept\n\t\t{\n\t\t\tbuffer = std::move( rhs.buffer );\n\t\t\tvertexAttribs = std::move( rhs.vertexAttribs );\n\t\t\tvertexBindings = std::move( rhs.vertexBindings );\n\t\t\tdoUpdateState();\n\n\t\t\treturn *this;\n\t\t}\n\n\t\tBufferViewId buffer;\n\t\tVkVertexInputAttributeDescriptionArray vertexAttribs;\n\t\tVkVertexInputBindingDescriptionArray vertexBindings;\n\t\tVkPipelineVertexInputStateCreateInfo inputState{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, {}, {}, {}, {}, {} };\n\n\tprivate:\n\t\tvoid doUpdateState()\n\t\t{\n\t\t\tinputState.vertexAttributeDescriptionCount = uint32_t( vertexAttribs.size() );\n\t\t\tinputState.pVertexAttributeDescriptions = vertexAttribs.data();\n\t\t\tinputState.vertexBindingDescriptionCount = uint32_t( vertexBindings.size() );\n\t\t\tinputState.pVertexBindingDescriptions = vertexBindings.data();\n\t\t}\n\t};\n\n\tstruct IndexBuffer\n\t{\n\t\texplicit IndexBuffer( BufferViewId pbuffer = BufferViewId{} )\n\t\t\t: buffer{ std::move( pbuffer ) }\n\t\t{\n\t\t}\n\n\t\tBufferViewId buffer;\n\n\tprivate:\n\t\tfriend bool operator==( IndexBuffer const & lhs, IndexBuffer const & rhs ) = default;\n\t};\n\n\tstruct IndirectBuffer\n\t{\n\t\texplicit IndirectBuffer( BufferViewId pbuffer\n\t\t\t, uint32_t pstride )\n\t\t\t: buffer{ std::move( pbuffer ) }\n\t\t\t, stride{ pstride }\n\t\t{\n\t\t}\n\n\t\tBufferViewId buffer;\n\t\tuint32_t stride;\n\n\tprivate:\n\t\tfriend bool operator==( IndirectBuffer const & lhs, IndirectBuffer const & rhs ) = default;\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< VertexBuffer >\n\t{\n\t\tstatic VertexBuffer get()\n\t\t{\n\t\t\tVertexBuffer const result{};\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< IndexBuffer >\n\t{\n\t\tstatic IndexBuffer get()\n\t\t{\n\t\t\tIndexBuffer const result{ BufferViewId{} };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< IndirectBuffer >\n\t{\n\t\tstatic IndirectBuffer get()\n\t\t{\n\t\t\tIndirectBuffer const result{ BufferViewId{}, 0u };\n\t\t\treturn result;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/DotExport.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 5262 )\n#include <map>\n#include <ostream>\n#include <string>\n#include <sstream>\n#pragma warning( pop )\n\nnamespace crg::dot\n{\n\tstruct Config\n\t{\n\t\tbool withColours{};\n\t\tbool withIds{};\n\t\tbool withGroups{};\n\t\tbool splitGroups{};\n\t\tstd::string toRemove{};\n\t};\n\tusing DisplayResult = std::map< std::string, std::stringstream, std::less<> >;\n\n\tCRG_API DisplayResult displayPasses( RunnableGraph const & value\n\t\t, Config const & config );\n\tCRG_API DisplayResult displayTransitions( RunnableGraph const & value\n\t\t, Config const & config );\n\tCRG_API void displayPasses( std::ostream & stream\n\t\t, RunnableGraph const & value\n\t\t, Config const & config );\n\tCRG_API void displayTransitions( std::ostream & stream\n\t\t, RunnableGraph const & value\n\t\t, Config const & config );\n}\n"
  },
  {
    "path": "include/RenderGraph/Exception.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\n#include <exception>\n\nnamespace crg\n{\n\tclass Exception\n\t\t: public std::exception\n\t{\n\tpublic:\n\t\tException( std::string const & text\n\t\t\t, std::string const & file\n\t\t\t, int line )\n\t\t\t: text{ file + \":\" + std::to_string( line ) + \" - \" + text }\n\t\t{\n\t\t}\n\n\t\tchar const * what()const noexcept override\n\t\t{\n\t\t\treturn text.c_str();\n\t\t}\n\n\tprivate:\n\t\tstd::string text;\n\t};\n\n#define CRG_Exception( text )\\\n\tthrow crg::Exception{ text, __FILE__, __LINE__ }\n}\n"
  },
  {
    "path": "include/RenderGraph/FrameGraph.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Attachment.hpp\"\n#include \"BufferData.hpp\"\n#include \"BufferViewData.hpp\"\n#include \"FramePassGroup.hpp\"\n#include \"GraphNode.hpp\"\n#include \"ImageData.hpp\"\n#include \"ImageViewData.hpp\"\n#include \"RecordContext.hpp\"\n\n#include <map>\n#include <vector>\n\nnamespace crg\n{\n\tclass FrameGraph\n\t{\n\t\tfriend class RunnableGraph;\n\n\tpublic:\n\t\t/**\n\t\t*\\name\n\t\t*\tConstruction/Destruction.\n\t\t*/\n\t\t/**@{*/\n\t\tFrameGraph( FrameGraph const & ) = delete;\n\t\tFrameGraph & operator=( FrameGraph const & ) = delete;\n\t\tFrameGraph & operator=( FrameGraph && )noexcept = delete;\n\t\tFrameGraph( FrameGraph && )noexcept = default;\n\t\t~FrameGraph()noexcept = default;\n\t\tCRG_API explicit FrameGraph( ResourceHandler & handler\n\t\t\t, std::string name = \"FrameGraph\" );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tResource creation.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API BufferId createBuffer( BufferData const & img );\n\t\tCRG_API BufferViewId createView( BufferViewData const & view );\n\t\tCRG_API ImageId createImage( ImageData const & img );\n\t\tCRG_API ImageViewId createView( ImageViewData const & view );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tViews merging.\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a view which represents the given views merging.\n\t\t*/\n\t\tCRG_API ImageViewId mergeViews( ImageViewIdArray const & views\n\t\t\t, bool mergeMipLevels = true\n\t\t\t, bool mergeArrayLayers = true );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a view which represents the given views merging.\n\t\t*/\n\t\tCRG_API BufferViewId mergeViews( BufferViewIdArray const & views );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tAttachments merging.\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a view which represents the given views merging.\n\t\t*/\n\t\tCRG_API Attachment const * mergeAttachments( AttachmentArray const & attachments\n\t\t\t, bool mergeMipLevels = true\n\t\t\t, bool mergeArrayLayers = true );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tPasses and groups.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API FramePass & createPass( std::string const & name\n\t\t\t, RunnablePassCreator runnableCreator );\n\t\tCRG_API FramePassGroup & createPassGroup( std::string const & name );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tCompilation.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API RunnableGraphPtr compile( GraphContext & context );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tDependencies.\n\t\t*/\n\t\t/**@[*/\n\t\tvoid addDependency( FrameGraph const & pgraph )\n\t\t{\n\t\t\tm_depends.push_back( &pgraph );\n\t\t}\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tGetters.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API LayoutState getFinalLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range )const;\n\t\tCRG_API LayoutState getFinalLayoutState( ImageViewId view\n\t\t\t, uint32_t passIndex = 0u )const;\n\t\tCRG_API AccessState const & getFinalAccessState( BufferId buffer\n\t\t\t, BufferSubresourceRange const & range )const;\n\t\tCRG_API AccessState const & getFinalAccessState( BufferViewId view\n\t\t\t, uint32_t passIndex = 0u )const;\n\t\tCRG_API void addInput( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range\n\t\t\t, LayoutState const & outputLayout );\n\t\tCRG_API void addInput( ImageViewId view\n\t\t\t, LayoutState const & outputLayout );\n\t\tCRG_API LayoutState getInputLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range )const;\n\t\tCRG_API LayoutState getInputLayoutState( ImageViewId view )const;\n\t\tCRG_API void addOutput( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range\n\t\t\t, LayoutState const & outputLayout );\n\t\tCRG_API void addOutput( ImageViewId view\n\t\t\t, LayoutState const & outputLayout );\n\t\tCRG_API LayoutState getOutputLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range )const;\n\t\tCRG_API LayoutState getOutputLayoutState( ImageViewId view )const;\n\t\tCRG_API LayerLayoutStatesMap const & getOutputLayoutStates()const;\n\n\t\tResourceHandler & getHandler()noexcept\n\t\t{\n\t\t\treturn m_handler;\n\t\t}\n\n\t\tstd::string const & getName()const noexcept\n\t\t{\n\t\t\treturn m_name;\n\t\t}\n\n\t\tFrameGraphArray const & getDependencies()const noexcept\n\t\t{\n\t\t\treturn m_depends;\n\t\t}\n\n\t\tRecordContext const & getFinalStates()const noexcept\n\t\t{\n\t\t\treturn m_finalState;\n\t\t}\n\n\t\tFramePassGroup & getDefaultGroup()const noexcept\n\t\t{\n\t\t\treturn *m_defaultGroup;\n\t\t}\n\t\t/**@}*/\n\n\tprivate:\n\t\tvoid registerFinalState( RecordContext const & context );\n\n\tprivate:\n\t\tResourceHandler & m_handler;\n\t\tstd::string m_name;\n\t\tFramePassGroupPtr m_defaultGroup;\n\t\tstd::set< BufferId > m_buffers;\n\t\tstd::set< BufferViewId > m_bufferViews;\n\t\tstd::set< ImageId > m_images;\n\t\tstd::set< ImageViewId > m_imageViews;\n\t\tstd::map< std::string, ImageViewId, std::less<> > m_attachViews;\n\t\tRecordContext m_finalState;\n\t\tFrameGraphArray m_depends;\n\t\tLayerLayoutStatesHandler m_inputs;\n\t\tLayerLayoutStatesHandler m_outputs;\n\t\tstd::unordered_map< size_t, AttachmentPtr > m_mergedAttachments;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/FrameGraphBase.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 4865 )\n#pragma warning( disable: 5262 )\n#include <vulkan/vulkan.h>\n\n#include <algorithm>\n#include <bit>\n#include <functional>\n#include <map>\n#include <memory>\n#include <string>\n#include <set>\n#include <unordered_map>\n#include <vector>\n#pragma warning( pop )\n\n#if !defined( _WIN32 ) || defined( CRG_BUILD_STATIC )\n#\tdefine CRG_API\n#else\n#\tif defined( RenderGraph_EXPORTS )\n#\t\tdefine CRG_API __declspec( dllexport )\n#\telse\n#\t\tdefine CRG_API __declspec( dllimport )\n#\tendif\n#endif\n\nnamespace crg\n{\n\tstruct Attachment;\n\tstruct AttachmentTransitions;\n\tstruct BufferData;\n\tstruct BufferViewData;\n\tstruct FramePass;\n\tstruct FramePassGroup;\n\tstruct GraphContext;\n\tstruct GraphNode;\n\tstruct ImageData;\n\tstruct ImageViewData;\n\tstruct IndexBuffer;\n\tstruct IndirectBuffer;\n\tstruct LayoutState;\n\tstruct PipelineState;\n\tstruct RootNode;\n\tstruct SamplerDesc;\n\tstruct SemaphoreWait;\n\tstruct Texcoord;\n\tstruct VertexBuffer;\n\tstruct WriteDescriptorSet;\n\n\tclass ContextResourcesCache;\n\tclass Exception;\n\tclass Fence;\n\tclass FrameGraph;\n\tclass FramePassTimer;\n\tclass GraphVisitor;\n\tclass ImageCopy;\n\tclass PipelinePass;\n\tclass RecordContext;\n\tclass RenderPass;\n\tclass RenderQuad;\n\tclass ResourceHandler;\n\tclass ResourcesCache;\n\tclass RunnableGraph;\n\tclass RunnablePass;\n\n\ttemplate< typename DataT >\n\tstruct Id;\n\ttemplate< typename DataT >\n\tstruct DataTransitionT;\n\ttemplate< typename DataT >\n\tusing DataTransitionArrayT = std::vector< DataTransitionT< DataT > >;\n\ttemplate< typename VkTypeT >\n\tstruct ContextObjectT;\n\ttemplate< typename TypeT >\n\tstruct DefaultValueGetterT;\n\ttemplate< typename TypeT >\n\tstruct RawTyperT;\n\n\tusing BufferId = Id< BufferData >;\n\tusing BufferViewId = Id< BufferViewData >;\n\tusing ImageId = Id< ImageData >;\n\tusing ImageViewId = Id< ImageViewData >;\n\tusing AccessState = PipelineState;\n\tusing DependencyCache = std::unordered_map< size_t, bool >;\n\tusing PassDependencyCache = std::unordered_map< FramePass const *, DependencyCache >;\n\tusing DeviceSize = VkDeviceSize;\n\n\tusing AttachmentPtr = std::unique_ptr< Attachment >;\n\tusing FramePassPtr = std::unique_ptr< FramePass >;\n\tusing FramePassGroupPtr = std::unique_ptr< FramePassGroup >;\n\tusing GraphNodePtr = std::unique_ptr< GraphNode >;\n\tusing RunnableGraphPtr = std::unique_ptr< RunnableGraph >;\n\tusing RunnablePassPtr = std::unique_ptr< RunnablePass >;\n\tusing VertexBufferPtr = std::unique_ptr< VertexBuffer >;\n\n\tusing GraphAdjacentNode = GraphNode *;\n\tusing ConstGraphAdjacentNode = GraphNode const *;\n\n\t/**\n\t*\\brief\n\t*\tThe transition between two states of an image view.\n\t*/\n\tusing ImageTransition = DataTransitionT< ImageViewId >;\n\tusing ImageTransitionArray = DataTransitionArrayT< ImageViewId >;\n\t/**\n\t*\\brief\n\t*\tThe transition between two states of a buffer.\n\t*/\n\tusing BufferTransition = DataTransitionT< BufferViewId >;\n\tusing BufferTransitionArray = DataTransitionArrayT< BufferViewId >;\n\n\tusing AttachmentArray = std::vector< Attachment const * >;\n\tusing BufferViewIdArray = std::vector< BufferViewId >;\n\tusing FramePassPtrArray = std::vector< FramePassPtr >;\n\tusing FramePassGroupPtrArray = std::vector< FramePassGroupPtr >;\n\tusing FrameGraphArray = std::vector< FrameGraph const * >;\n\tusing FramePassArray = std::vector< FramePass const * >;\n\tusing GraphAdjacentNodeArray = std::vector< GraphAdjacentNode >;\n\tusing ConstGraphAdjacentNodeArray = std::vector< ConstGraphAdjacentNode >;\n\tusing GraphNodePtrArray = std::vector< GraphNodePtr >;\n\tusing WriteDescriptorSetArray = std::vector< WriteDescriptorSet >;\n\tusing AttachmentsNodeMap = std::map< ConstGraphAdjacentNode, AttachmentTransitions >;\n\tusing BufferMemoryMap = std::map< BufferId, std::pair< VkBuffer, VkDeviceMemory > >;\n\tusing BufferViewMap = std::map< BufferViewId, VkBufferView >;\n\tusing ImageMemoryMap = std::map< ImageId, std::pair< VkImage, VkDeviceMemory > >;\n\tusing ImageViewMap = std::map< ImageViewId, VkImageView >;\n\tusing ImageViewIdArray = std::vector< ImageViewId >;\n\tusing SemaphoreWaitArray = std::vector< SemaphoreWait >;\n\n\ttemplate< typename DataT >\n\tusing IdDataOwnerCont = std::map< Id< DataT >, std::unique_ptr< DataT > >;\n\tusing BufferIdDataOwnerCont = IdDataOwnerCont< BufferData >;\n\tusing BufferViewIdDataOwnerCont = IdDataOwnerCont< BufferViewData >;\n\tusing ImageIdDataOwnerCont = IdDataOwnerCont< ImageData >;\n\tusing ImageViewIdDataOwnerCont = IdDataOwnerCont< ImageViewData >;\n\n\tusing VkAttachmentDescriptionArray = std::vector< VkAttachmentDescription >;\n\tusing VkAttachmentReferenceArray = std::vector< VkAttachmentReference >;\n\tusing VkBufferArray = std::vector< VkBuffer >;\n\tusing VkBufferViewArray = std::vector< VkBufferView >;\n\tusing VkDescriptorBufferInfoArray = std::vector< VkDescriptorBufferInfo >;\n\tusing VkDescriptorImageInfoArray = std::vector< VkDescriptorImageInfo >;\n\tusing VkDescriptorSetLayoutBindingArray = std::vector< VkDescriptorSetLayoutBinding >;\n\tusing VkDescriptorPoolSizeArray = std::vector< VkDescriptorPoolSize >;\n\tusing VkImageViewArray = std::vector< VkImageView >;\n\tusing VkPipelineColorBlendAttachmentStateArray = std::vector< VkPipelineColorBlendAttachmentState >;\n\tusing VkPipelineShaderStageCreateInfoArray = std::vector< VkPipelineShaderStageCreateInfo >;\n\tusing VkPushConstantRangeArray = std::vector< VkPushConstantRange >;\n\tusing VkScissorArray = std::vector< VkRect2D >;\n\tusing VkSubpassDependencyArray = std::vector< VkSubpassDependency >;\n\tusing VkVertexInputAttributeDescriptionArray = std::vector< VkVertexInputAttributeDescription >;\n\tusing VkVertexInputBindingDescriptionArray = std::vector< VkVertexInputBindingDescription >;\n\tusing VkViewportArray = std::vector< VkViewport >;\n\tusing VkWriteDescriptorSetArray = std::vector< VkWriteDescriptorSet >;\n\n\tusing MipLayoutStates = std::map< uint32_t, LayoutState >;\n\tusing LayerLayoutStates = std::map< uint32_t, MipLayoutStates >;\n\tusing LayoutStateMap = std::unordered_map< uint32_t, LayerLayoutStates >;\n\tusing LayerLayoutStatesMap = std::map< uint32_t, LayerLayoutStates >;\n\tusing AccessStateMap = std::unordered_map< uint32_t, AccessState >;\n\tusing ViewsLayout = LayoutStateMap;\n\tusing BuffersLayout = AccessStateMap;\n\tusing ViewsLayoutPtr = std::unique_ptr< ViewsLayout >;\n\tusing BuffersLayoutPtr = std::unique_ptr< BuffersLayout >;\n\tusing ViewsLayouts = std::vector< ViewsLayoutPtr >;\n\tusing BuffersLayouts = std::vector< BuffersLayoutPtr >;\n\n\tusing ViewLayoutIterators = std::map< uint32_t, ViewsLayouts::iterator >;\n\tusing BufferLayoutIterators = std::map< uint32_t, BuffersLayouts::iterator >;\n}\n"
  },
  {
    "path": "include/RenderGraph/FrameGraphEnums.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphBase.hpp\"\n\n#define CRG_MakeFlags( FlagBits )\\\n\tconstexpr FlagBits operator|( FlagBits lhs, FlagBits rhs ) { return FlagBits( std::underlying_type_t< FlagBits >( lhs ) | std::underlying_type_t< FlagBits >( rhs ) ); }\\\n\tconstexpr FlagBits operator&( FlagBits lhs, FlagBits rhs ) { return FlagBits( std::underlying_type_t< FlagBits >( lhs ) & std::underlying_type_t< FlagBits >( rhs ) ); }\\\n\tconstexpr FlagBits operator^( FlagBits lhs, FlagBits rhs ) { return FlagBits( std::underlying_type_t< FlagBits >( lhs ) ^ std::underlying_type_t< FlagBits >( rhs ) ); }\\\n\tconstexpr FlagBits & operator|=( FlagBits & lhs, FlagBits rhs ) { return lhs = lhs | rhs; }\\\n\tconstexpr FlagBits & operator&=( FlagBits & lhs, FlagBits rhs ) { return lhs = lhs & rhs; }\\\n\tconstexpr FlagBits & operator^=( FlagBits & lhs, FlagBits rhs ) { return lhs = lhs ^ rhs; }\\\n\tconstexpr bool checkFlag( FlagBits lhs, FlagBits rhs ) { return ( lhs & rhs ) == rhs; }\n\nnamespace crg\n{\n\tenum class PixelFormat : int32_t\n\t{\n#define RGPF_ENUM_VALUE( name, value, components, alpha, colour, depth, stencil, compressed ) e##name = value,\n#define RGPF_ENUM_NON_VALUE( name, value ) e##name = value,\n#include \"PixelFormat.inl\"\n\t};\n\n\tenum class ImageType : int32_t\n\t{\n\t\te1D = 0,\n\t\te2D = 1,\n\t\te3D = 2,\n\t};\n\n\tenum class SampleCount : int32_t\n\t{\n\t\te1 = 0x00000001,\n\t\te2 = 0x00000002,\n\t\te4 = 0x00000004,\n\t\te8 = 0x00000008,\n\t\te16 = 0x00000010,\n\t\te32 = 0x00000020,\n\t\te64 = 0x00000040,\n\t};\n\n\tenum class ImageTiling : int32_t\n\t{\n\t\teOptimal = 0,\n\t\teLinear = 1,\n\t\teDRMFormatModifier = 1000158000,\n\t};\n\n\tenum class ImageViewType : int32_t\n\t{\n\t\te1D = 0,\n\t\te2D = 1,\n\t\te3D = 2,\n\t\teCube = 3,\n\t\te1DArray = 4,\n\t\te2DArray = 5,\n\t\teCubeArray = 6,\n\t};\n\n\tenum class ImageLayout : int32_t\n\t{\n\t\teUndefined = 0,\n\t\teGeneral = 1,\n\t\teColorAttachment = 2,\n\t\teDepthStencilAttachment = 3,\n\t\teDepthStencilReadOnly = 4,\n\t\teShaderReadOnly = 5,\n\t\teTransferSrc = 6,\n\t\teTransferDst = 7,\n\t\tePreinitialized = 8,\n\t\teDepthReadOnlyStencilAttachment = 1000117000,\n\t\teDepthAttachmentStencilReadOnly = 1000117001,\n\t\teDepthAttachment = 1000241000,\n\t\teDepthReadOnly = 1000241001,\n\t\teStencilAttachment = 1000241002,\n\t\teStencilReadOnly = 1000241003,\n\t\teReadOnly = 1000314000,\n\t\teAttachment = 1000314001,\n\t\teRenderingLocalRead = 1000232000,\n\t\tePresentSrc = 1000001002,\n\t\teVideoDecodeDst = 1000024000,\n\t\teVideoDecodeSrc = 1000024001,\n\t\teVideoDecodeDpb = 1000024002,\n\t\teSharedPresent = 1000111000,\n\t\teFragmentDensityMap = 1000218000,\n\t\teFragmentShadingRateAttachment = 1000164003,\n\t\teVideoEncodeDst = 1000299000,\n\t\teVideoEncodeSrc = 1000299001,\n\t\teVideoEncodeDpb = 1000299002,\n\t\teAttachmentFeedbackLoop = 1000339000,\n\t\teVideoEncodeQuantizationMap = 1000553000,\n\t};\n\n\tenum class FilterMode : int32_t\n\t{\n\t\teNearest,\n\t\teLinear,\n\t};\n\n\tenum class MipmapMode : int32_t\n\t{\n\t\teNearest,\n\t\teLinear,\n\t};\n\n\tenum class WrapMode : int32_t\n\t{\n\t\teRepeat,\n\t\teMirroredRepeat,\n\t\teClampToEdge,\n\t\teClampToBorder,\n\t\teMirrorClampToEdge,\n\t};\n\n\tenum class AttachmentLoadOp : int32_t\n\t{\n\t\teLoad = 0,\n\t\teClear = 1,\n\t\teDontCare = 2,\n\t\teNone = 1000400000,\n\t};\n\n\tenum class AttachmentStoreOp : int32_t\n\t{\n\t\teStore = 0,\n\t\teDontCare = 1,\n\t\teNone = 1000301000,\n\t};\n\n\tenum class BlendFactor : int32_t\n\t{\n\t\teZero = 0,\n\t\teOne = 1,\n\t\teSrcColor = 2,\n\t\teOneMinusSrcColor = 3,\n\t\teDstColor = 4,\n\t\teOneMinusDstColor = 5,\n\t\teSrcAlpha = 6,\n\t\teOneMinusSrcAlpha = 7,\n\t\teDstAlpha = 8,\n\t\teOneMinusDstAlpha = 9,\n\t\teConstantColor = 10,\n\t\teOneMinusConstantColor = 11,\n\t\teConstantAlpha = 12,\n\t\teOneMinusConstantAlpha = 13,\n\t\teSrcAlphaSaturate = 14,\n\t\teSrc1Color = 15,\n\t\teOneMinusSrc1Color = 16,\n\t\teSrc1Alpha = 17,\n\t\teOneMinusSrc1Alpha = 18,\n\t};\n\n\tenum class BlendOp : int32_t\n\t{\n\t\teAdd = 0,\n\t\teSubtract = 1,\n\t\teReverse_subtract = 2,\n\t\teMin = 3,\n\t\teMax = 4,\n\t\teZero = 1000148000,\n\t\teSrc = 1000148001,\n\t\teDst = 1000148002,\n\t\teSrcOver = 1000148003,\n\t\teDstOver = 1000148004,\n\t\teSrcIn = 1000148005,\n\t\teDstIn = 1000148006,\n\t\teSrcOut = 1000148007,\n\t\teDstOut = 1000148008,\n\t\teSrcAtop = 1000148009,\n\t\teDstAtop = 1000148010,\n\t\teXor = 1000148011,\n\t\teMultiply = 1000148012,\n\t\teScreen = 1000148013,\n\t\teOverlay = 1000148014,\n\t\teDarken = 1000148015,\n\t\teLighten = 1000148016,\n\t\teColordodge = 1000148017,\n\t\teColorburn = 1000148018,\n\t\teHardlight = 1000148019,\n\t\teSoftlight = 1000148020,\n\t\teDifference = 1000148021,\n\t\teExclusion = 1000148022,\n\t\teInvert = 1000148023,\n\t\teInvertRGB = 1000148024,\n\t\teLineardodge = 1000148025,\n\t\teLinearburn = 1000148026,\n\t\teVividlight = 1000148027,\n\t\teLinearlight = 1000148028,\n\t\tePinlight = 1000148029,\n\t\teHardmix = 1000148030,\n\t\teHSLHue = 1000148031,\n\t\teHSLSaturation = 1000148032,\n\t\teHSLColor = 1000148033,\n\t\teHSLLuminosity = 1000148034,\n\t\tePlus = 1000148035,\n\t\tePlusClamped = 1000148036,\n\t\tePlusClamped_alpha = 1000148037,\n\t\tePlusDarker = 1000148038,\n\t\teMinus = 1000148039,\n\t\teMinus_clamped = 1000148040,\n\t\teContrast = 1000148041,\n\t\teInvertOVG = 1000148042,\n\t\teRed = 1000148043,\n\t\teGreen = 1000148044,\n\t\teBlue = 1000148045,\n\t};\n\n\tenum class BufferCreateFlags : int32_t\n\t{\n\t\teNone = 0x00000000,\n\t\teSparseBinding = 0x00000001,\n\t\teSparseResidency = 0x00000002,\n\t\teSparseAliased = 0x00000004,\n\t\teProtected = 0x00000008,\n\t\teDeviceAddressCaptureReplay = 0x00000010,\n\t\teDescriptorBufferCaptureReplay = 0x00000020,\n\t\teVideoProfileIndependent = 0x00000040,\n\t};\n\tCRG_MakeFlags( BufferCreateFlags )\n\n\tenum class BufferUsageFlags : int32_t\n\t{\n\t\teNone = 0x00000000,\n\t\teTransferSrc = 0x00000001,\n\t\teTransferDst = 0x00000002,\n\t\teUniformTexelBuffer = 0x00000004,\n\t\teStorageTexelBuffer = 0x00000008,\n\t\teUniformBuffer = 0x00000010,\n\t\teStorageBuffer = 0x00000020,\n\t\teIndexBuffer = 0x00000040,\n\t\teVertexBuffer = 0x00000080,\n\t\teIndirectBuffer = 0x00000100,\n\t\teShaderDeviceAddress = 0x00020000,\n\t\teVideoDecodeSrc = 0x00002000,\n\t\teVideoDecodeDst = 0x00004000,\n\t\teTransformFeedbackBuffer = 0x00000800,\n\t\teTransformFeedbackCounterBuffer = 0x00001000,\n\t\teConditionalRendering = 0x00000200,\n\t\teAccelerationStructureBuildInputReadOnly = 0x00080000,\n\t\teAccelerationStructureStorage = 0x00100000,\n\t\teShaderBindingTable = 0x00000400,\n\t\teVideoEncodeDst = 0x00008000,\n\t\teVideoEncodeSrc = 0x00010000,\n\t\teSamplerDescriptorBuffer = 0x00200000,\n\t\teResourceDescriptorBuffer = 0x00400000,\n\t\tePushDescriptorsDescriptorBuffer = 0x04000000,\n\t\teMicromapBuildInputReadOnly = 0x00800000,\n\t\teMicromapStorage = 0x01000000,\n\t\teTileMemory = 0x08000000,\n\t};\n\tCRG_MakeFlags( BufferUsageFlags )\n\n\tenum class MemoryPropertyFlags : int32_t\n\t{\n\t\teNone = 0x0000000,\n\t\teDeviceLocal = 0x00000001,\n\t\teHostVisible = 0x00000002,\n\t\teHostCoherent = 0x00000004,\n\t\teHostCached = 0x00000008,\n\t\teLazilyAllocated = 0x00000010,\n\t\teProtected = 0x00000020,\n\t\teDeviceCoherent = 0x00000040,\n\t\teDeviceUncached = 0x00000080,\n\t\teRdmaCapable = 0x00000100,\n\t};\n\tCRG_MakeFlags( MemoryPropertyFlags )\n\n\tenum class ImageCreateFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teSparseBinding = 0x00000001,\n\t\teSparseResidency = 0x00000002,\n\t\teSparseAliased = 0x00000004,\n\t\teMutableFormat = 0x00000008,\n\t\teCubeCompatible = 0x00000010,\n\t\teAlias = 0x00000400,\n\t\teSplitInstanceBindRegions = 0x00000040,\n\t\te2DArrayCompatible = 0x00000020,\n\t\teBlockTexelViewCompatible = 0x00000080,\n\t\teExtendedUsage = 0x00000100,\n\t\teProtected = 0x00000800,\n\t\teDisjoint = 0x00000200,\n\t\teCornerSampled = 0x00002000,\n\t\teSampleLocationsCompatibleDepth = 0x00001000,\n\t\teSubsampled = 0x00004000,\n\t\teDescriptorBufferCaptureReplay = 0x00010000,\n\t\teMultisampledRenderToSingleSampled = 0x00040000,\n\t\te2DViewCompatible = 0x00020000,\n\t\teVideoProfileIndependent = 0x00100000,\n\t\teFragmentDensityMapOffset = 0x00008000,\n\t};\n\tCRG_MakeFlags( ImageCreateFlags )\n\n\tenum class ImageUsageFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teTransferSrc = 0x00000001,\n\t\teTransferDst = 0x00000002,\n\t\teSampled = 0x00000004,\n\t\teStorage = 0x00000008,\n\t\teColorAttachment = 0x00000010,\n\t\teDepthStencilAttachment = 0x00000020,\n\t\teTransientAttachment = 0x00000040,\n\t\teInputAttachment = 0x00000080,\n\t\teHostTransfer = 0x00400000,\n\t\teVideoDecodeDst = 0x00000400,\n\t\teVideoDecodeSrc = 0x00000800,\n\t\teVideoDecodeDpb = 0x00001000,\n\t\teFragmentDensityMap = 0x00000200,\n\t\teFragmentShadingRateAttachment = 0x00000100,\n\t\teVideoEncodeDst = 0x00002000,\n\t\teVideoEncodeSrc = 0x00004000,\n\t\teVideoEncodeDpb = 0x00008000,\n\t\teAttachmentFeedbackLoop = 0x00080000,\n\t\teInvocationMask = 0x00040000,\n\t\teSampleWeight = 0x00100000,\n\t\teSampleBlockMatch = 0x00200000,\n\t\teTileMemory = 0x08000000,\n\t\teVideoEncodeQuantizationDeltaMap = 0x02000000,\n\t\teVideoEncodeEmphasisMap = 0x04000000,\n\t};\n\tCRG_MakeFlags( ImageUsageFlags )\n\n\tenum class ImageViewCreateFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teFragmentDensityMapDynamic = 0x00000001,\n\t\teDescriptorBufferCaptureReplay = 0x00000004,\n\t\teFragmentDensityMapDeferred = 0x00000002,\n\t};\n\tCRG_MakeFlags( ImageViewCreateFlags )\n\n\tenum class ImageAspectFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teColor = 0x00000001,\n\t\teDepth = 0x00000002,\n\t\teStencil = 0x00000004,\n\t\teDepthStencil = eDepth | eStencil,\n\t\teMetadata = 0x00000008,\n\t\tePlane0 = 0x00000010,\n\t\tePlane1 = 0x00000020,\n\t\tePlane2 = 0x00000040,\n\t\teMemoryPlane0 = 0x00000080,\n\t\teMemoryPlane1 = 0x00000100,\n\t\teMemoryPlane2 = 0x00000200,\n\t\teMemoryPlane3 = 0x00000400,\n\t};\n\tCRG_MakeFlags( ImageAspectFlags )\n\n\tenum class PipelineStageFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teTopOfPipe = 0x00000001,\n\t\teDrawIndirect = 0x00000002,\n\t\teVertexInput = 0x00000004,\n\t\teVertexShader = 0x00000008,\n\t\teTessellationControlShader = 0x00000010,\n\t\teTessellationEvaluationShader = 0x00000020,\n\t\teGeometryShader = 0x00000040,\n\t\teFragmentShader = 0x00000080,\n\t\teEarlyFragmentTests = 0x00000100,\n\t\teLateFragmentTests = 0x00000200,\n\t\teColorAttachmentOutput = 0x00000400,\n\t\teComputeShader = 0x00000800,\n\t\teTransfer = 0x00001000,\n\t\teBottomOfPipe = 0x00002000,\n\t\teHost = 0x00004000,\n\t\teAllGraphics = 0x00008000,\n\t\teAllCommands = 0x00010000,\n\t\teTransformFeedback = 0x01000000,\n\t\teConditionalRendering = 0x00040000,\n\t\teAccelerationStructureBuild = 0x02000000,\n\t\teRayTracingShader = 0x00200000,\n\t\teFragmentDensityProcess = 0x00800000,\n\t\teFragmentShadingRateAttachment = 0x00400000,\n\t\teTaskShader = 0x00080000,\n\t\teMeshShader = 0x00100000,\n\t\teCommandPreprocess = 0x00020000,\n\t};\n\tCRG_MakeFlags( PipelineStageFlags )\n\n\tenum class AccessFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teIndirectCommandRead = 0x00000001,\n\t\teIndexRead = 0x00000002,\n\t\teVertexAttributeRead = 0x00000004,\n\t\teUniformRead = 0x00000008,\n\t\teInputAttachmentRead = 0x00000010,\n\t\teShaderRead = 0x00000020,\n\t\teShaderWrite = 0x00000040,\n\t\teColorAttachmentRead = 0x00000080,\n\t\teColorAttachmentWrite = 0x00000100,\n\t\teDepthStencilAttachmentRead = 0x00000200,\n\t\teDepthStencilAttachmentWrite = 0x00000400,\n\t\teTransferRead = 0x00000800,\n\t\teTransferWrite = 0x00001000,\n\t\teHostRead = 0x00002000,\n\t\teHostWrite = 0x00004000,\n\t\teMemoryRead = 0x00008000,\n\t\teMemoryWrite = 0x00010000,\n\t\teTransformFeedbackWrite = 0x02000000,\n\t\teTransformFeedbackCounterRead = 0x04000000,\n\t\teTransformFeedbackCounterWrite = 0x08000000,\n\t\teConditionalRenderingRead = 0x00100000,\n\t\teColorAttachmentReadNonCoherent = 0x00080000,\n\t\teAccelerationStructureRead = 0x00200000,\n\t\teAccelerationStructureWrite = 0x00400000,\n\t\teFragmentDensityMapRead = 0x01000000,\n\t\teFragmentShadingRateAttachmentRead = 0x00800000,\n\t\teCommandPreprocessRead = 0x00020000,\n\t\teCommandPreprocessWrite = 0x00040000,\n\t};\n\tCRG_MakeFlags( AccessFlags )\n\n\tenum class ColorComponentFlags : int32_t\n\t{\n\t\teNone = 0,\n\t\teR = 0x00000001,\n\t\teG = 0x00000002,\n\t\teB = 0x00000004,\n\t\teA = 0x00000008,\n\t};\n\tCRG_MakeFlags( ColorComponentFlags )\n }\n"
  },
  {
    "path": "include/RenderGraph/FrameGraphFunctions.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphStructs.hpp\"\n\n#include <assert.h>\n\nnamespace crg\n{\n\tCRG_API std::string_view getName( PixelFormat v );\n\tCRG_API std::string_view getName( FilterMode v );\n\tCRG_API std::string_view getName( MipmapMode v );\n\tCRG_API std::string_view getName( WrapMode v );\n\n\tCRG_API ImageCreateFlags getImageCreateFlags( ImageId const & image )noexcept;\n\tCRG_API ImageCreateFlags getImageCreateFlags( ImageViewId const & image )noexcept;\n\tCRG_API Extent3D const & getExtent( ImageId const & image )noexcept;\n\tCRG_API Extent3D const & getExtent( ImageViewId const & image )noexcept;\n\tCRG_API DeviceSize getSize( BufferId const & image )noexcept;\n\tCRG_API DeviceSize getSize( BufferViewId const & image )noexcept;\n\tCRG_API Extent3D getMipExtent( ImageViewId const & image )noexcept;\n\tCRG_API PixelFormat getFormat( ImageId const & image )noexcept;\n\tCRG_API PixelFormat getFormat( ImageViewId const & image )noexcept;\n\tCRG_API ImageType getImageType( ImageId const & image )noexcept;\n\tCRG_API ImageType getImageType( ImageViewId const & image )noexcept;\n\tCRG_API ImageViewType getImageViewType( ImageViewId const & image )noexcept;\n\tCRG_API uint32_t getMipLevels( ImageId const & image )noexcept;\n\tCRG_API uint32_t getMipLevels( ImageViewId const & image )noexcept;\n\tCRG_API uint32_t getArrayLayers( ImageId const & image )noexcept;\n\tCRG_API uint32_t getArrayLayers( ImageViewId const & image )noexcept;\n\tCRG_API ImageAspectFlags getAspectFlags( ImageViewId const & image )noexcept;\n\tCRG_API ImageSubresourceRange const & getSubresourceRange( ImageViewId const & image )noexcept;\n\tCRG_API BufferSubresourceRange const & getSubresourceRange( BufferViewId const & buffer )noexcept;\n\tCRG_API AccessFlags getAccessMask( ImageLayout layout )noexcept;\n\tCRG_API PipelineStageFlags getStageMask( ImageLayout layout )noexcept;\n\tCRG_API PipelineState getPipelineState( PipelineStageFlags flags )noexcept;\n\tCRG_API LayoutState makeLayoutState( ImageLayout layout )noexcept;\n\tCRG_API ImageAspectFlags getAspectMask( PixelFormat format )noexcept;\n\tCRG_API LayoutState const & addSubresourceRangeLayout( LayerLayoutStates & ranges\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & newLayout );\n\tCRG_API LayoutState getSubresourceRangeLayout( LayerLayoutStates const & ranges\n\t\t, ImageSubresourceRange const & range );\n\tCRG_API ImageSubresourceRange getVirtualRange( ImageId const & image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range )noexcept;\n\tCRG_API bool match( ImageViewId const & lhs, ImageViewId const & rhs )noexcept;\n\tCRG_API bool match( BufferViewId const & lhs, BufferViewId const & rhs )noexcept;\n\tCRG_API ImageViewId const & resolveView( ImageViewId const & view\n\t\t, uint32_t passIndex );\n\tCRG_API BufferViewId const & resolveView( BufferViewId const & view\n\t\t, uint32_t passIndex );\n\n\tCRG_API void convert( SemaphoreWaitArray const & toWait\n\t\t, std::vector< VkSemaphore > & semaphores\n\t\t, std::vector< VkPipelineStageFlags > & dstStageMasks );\n\tCRG_API std::vector< VkClearValue > convert( std::vector< ClearValue > const & v );\n\tCRG_API VkQueryPool createQueryPool( GraphContext & context\n\t\t, std::string const & name\n\t\t, uint32_t passesCount );\n\n\tCRG_API ClearColorValue getClearColorValue( ClearValue const & v );\n\tCRG_API ClearDepthStencilValue getClearDepthStencilValue( ClearValue const & v );\n\n\tconstexpr VkFormat convert( PixelFormat v )noexcept\n\t{\n\t\treturn VkFormat( v );\n\t}\n\n\tconstexpr PixelFormat convert( VkFormat v )noexcept\n\t{\n\t\treturn PixelFormat( v );\n\t}\n\n\tconstexpr bool isDepthFormat( PixelFormat fmt )noexcept\n\t{\n\t\treturn fmt == PixelFormat::eD16_UNORM\n\t\t\t|| fmt == PixelFormat::eX8_D24_UNORM\n\t\t\t|| fmt == PixelFormat::eD32_SFLOAT\n\t\t\t|| fmt == PixelFormat::eD16_UNORM_S8_UINT\n\t\t\t|| fmt == PixelFormat::eD24_UNORM_S8_UINT\n\t\t\t|| fmt == PixelFormat::eD32_SFLOAT_S8_UINT;\n\t}\n\n\tconstexpr bool isStencilFormat( PixelFormat fmt )noexcept\n\t{\n\t\treturn fmt == PixelFormat::eS8_UINT\n\t\t\t|| fmt == PixelFormat::eD16_UNORM_S8_UINT\n\t\t\t|| fmt == PixelFormat::eD24_UNORM_S8_UINT\n\t\t\t|| fmt == PixelFormat::eD32_SFLOAT_S8_UINT;\n\t}\n\n\tconstexpr bool isColourFormat( PixelFormat fmt )noexcept\n\t{\n\t\treturn !isDepthFormat( fmt ) && !isStencilFormat( fmt );\n\t}\n\n\tconstexpr bool isDepthStencilFormat( PixelFormat fmt )noexcept\n\t{\n\t\treturn isDepthFormat( fmt ) && isStencilFormat( fmt );\n\t}\n\n\tconstexpr bool isDepthOrStencilFormat( PixelFormat fmt )noexcept\n\t{\n\t\treturn isDepthFormat( fmt ) || isStencilFormat( fmt );\n\t}\n\n\tconstexpr VkImageType convert( ImageType v )noexcept\n\t{\n\t\treturn VkImageType( v );\n\t}\n\n\tconstexpr ImageType convert( VkImageType  v )noexcept\n\t{\n\t\treturn ImageType( v );\n\t}\n\n\tconstexpr VkSampleCountFlagBits convert( SampleCount v )noexcept\n\t{\n\t\treturn VkSampleCountFlagBits( v );\n\t}\n\n\tconstexpr SampleCount convert( VkSampleCountFlagBits v )noexcept\n\t{\n\t\treturn SampleCount( v );\n\t}\n\n\tconstexpr VkImageTiling convert( ImageTiling v )noexcept\n\t{\n\t\treturn VkImageTiling( v );\n\t}\n\n\tconstexpr ImageTiling convert( VkImageTiling v )noexcept\n\t{\n\t\treturn ImageTiling( v );\n\t}\n\n\tconstexpr VkImageViewType convert( ImageViewType v )noexcept\n\t{\n\t\treturn VkImageViewType( v );\n\t}\n\n\tconstexpr ImageViewType convert( VkImageViewType  v )noexcept\n\t{\n\t\treturn ImageViewType( v );\n\t}\n\n\tconstexpr VkImageLayout convert( ImageLayout v )noexcept\n\t{\n\t\treturn VkImageLayout( v );\n\t}\n\n\tconstexpr ImageLayout convert( VkImageLayout  v )noexcept\n\t{\n\t\treturn ImageLayout( v );\n\t}\n\n\tconstexpr VkFilter convert( FilterMode v )noexcept\n\t{\n\t\treturn VkFilter( v );\n\t}\n\n\tconstexpr FilterMode convert( VkFilter  v )noexcept\n\t{\n\t\treturn FilterMode( v );\n\t}\n\n\tconstexpr VkSamplerMipmapMode convert( MipmapMode v )noexcept\n\t{\n\t\treturn VkSamplerMipmapMode( v );\n\t}\n\n\tconstexpr MipmapMode convert( VkSamplerMipmapMode v )noexcept\n\t{\n\t\treturn MipmapMode( v );\n\t}\n\n\tconstexpr VkSamplerAddressMode convert( WrapMode v )noexcept\n\t{\n\t\treturn VkSamplerAddressMode( v );\n\t}\n\n\tconstexpr WrapMode convert( VkSamplerAddressMode v )noexcept\n\t{\n\t\treturn WrapMode( v );\n\t}\n\n\tconstexpr VkAttachmentLoadOp convert( AttachmentLoadOp v )noexcept\n\t{\n\t\treturn VkAttachmentLoadOp( v );\n\t}\n\n\tconstexpr AttachmentLoadOp convert( VkAttachmentLoadOp v )noexcept\n\t{\n\t\treturn AttachmentLoadOp( v );\n\t}\n\n\tconstexpr VkBlendFactor convert( BlendFactor v )noexcept\n\t{\n\t\treturn VkBlendFactor( v );\n\t}\n\n\tconstexpr BlendFactor convert( VkBlendFactor v )noexcept\n\t{\n\t\treturn BlendFactor( v );\n\t}\n\n\tconstexpr VkBlendOp convert( BlendOp v )noexcept\n\t{\n\t\treturn VkBlendOp( v );\n\t}\n\n\tconstexpr BlendOp convert( VkBlendOp v )noexcept\n\t{\n\t\treturn BlendOp( v );\n\t}\n\n\tconstexpr VkAttachmentStoreOp convert( AttachmentStoreOp v )noexcept\n\t{\n\t\treturn VkAttachmentStoreOp( v );\n\t}\n\n\tconstexpr AttachmentStoreOp convert( VkAttachmentStoreOp v )noexcept\n\t{\n\t\treturn AttachmentStoreOp( v );\n\t}\n\n\tconstexpr VkBufferCreateFlags getBufferCreateFlags( BufferCreateFlags v )noexcept\n\t{\n\t\treturn VkBufferCreateFlags( v );\n\t}\n\n\tconstexpr BufferCreateFlags getBufferCreateFlags( VkBufferCreateFlags v )noexcept\n\t{\n\t\treturn BufferCreateFlags( v );\n\t}\n\n\tconstexpr VkBufferUsageFlags getBufferUsageFlags( BufferUsageFlags v )noexcept\n\t{\n\t\treturn VkBufferUsageFlags( v );\n\t}\n\n\tconstexpr BufferUsageFlags getBufferUsageFlags( VkBufferUsageFlags v )noexcept\n\t{\n\t\treturn BufferUsageFlags( v );\n\t}\n\n\tconstexpr VkMemoryPropertyFlags getMemoryPropertyFlags( MemoryPropertyFlags v )noexcept\n\t{\n\t\treturn VkMemoryPropertyFlags( v );\n\t}\n\n\tconstexpr MemoryPropertyFlags getMemoryPropertyFlags( VkMemoryPropertyFlags v )noexcept\n\t{\n\t\treturn MemoryPropertyFlags( v );\n\t}\n\n\tconstexpr VkImageCreateFlags getImageCreateFlags( ImageCreateFlags v )noexcept\n\t{\n\t\treturn VkImageCreateFlags( v );\n\t}\n\n\tconstexpr ImageCreateFlags getImageCreateFlags( VkImageCreateFlags v )noexcept\n\t{\n\t\treturn ImageCreateFlags( v );\n\t}\n\n\tconstexpr VkImageUsageFlags getImageUsageFlags( ImageUsageFlags v )noexcept\n\t{\n\t\treturn VkImageUsageFlags( v );\n\t}\n\n\tconstexpr ImageUsageFlags getImageUsageFlags( VkImageUsageFlags v )noexcept\n\t{\n\t\treturn ImageUsageFlags( v );\n\t}\n\n\tconstexpr VkImageViewCreateFlags getImageViewCreateFlags( ImageViewCreateFlags v )noexcept\n\t{\n\t\treturn VkImageViewCreateFlags( v );\n\t}\n\n\tconstexpr ImageViewCreateFlags getImageViewCreateFlags( VkImageViewCreateFlags v )noexcept\n\t{\n\t\treturn ImageViewCreateFlags( v );\n\t}\n\n\tconstexpr VkImageAspectFlags getImageAspectFlags( ImageAspectFlags v )noexcept\n\t{\n\t\treturn VkImageAspectFlags( v );\n\t}\n\n\tconstexpr ImageAspectFlags getImageAspectFlags( VkImageAspectFlags v )noexcept\n\t{\n\t\treturn ImageAspectFlags( v );\n\t}\n\n\tconstexpr VkPipelineStageFlags getPipelineStageFlags( PipelineStageFlags v )noexcept\n\t{\n\t\treturn VkPipelineStageFlags( v );\n\t}\n\n\tconstexpr PipelineStageFlags getPipelineStageFlags( VkPipelineStageFlags v )noexcept\n\t{\n\t\treturn PipelineStageFlags( v );\n\t}\n\n\tconstexpr VkAccessFlags getAccessFlags( AccessFlags v )noexcept\n\t{\n\t\treturn VkAccessFlags( v );\n\t}\n\n\tconstexpr AccessFlags getAccessFlags( VkAccessFlags v )noexcept\n\t{\n\t\treturn AccessFlags( v );\n\t}\n\n\tconstexpr VkColorComponentFlags getColorComponentFlags( ColorComponentFlags v )noexcept\n\t{\n\t\treturn VkColorComponentFlags( v );\n\t}\n\n\tconstexpr ColorComponentFlags getColorComponentFlags( VkColorComponentFlags v )noexcept\n\t{\n\t\treturn ColorComponentFlags( v );\n\t}\n\n\tconstexpr VkExtent2D convert( Extent2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkExtent2D >( v );\n\t}\n\n\tconstexpr Extent2D convert( VkExtent2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< Extent2D >( v );\n\t}\n\n\tconstexpr VkOffset2D convert( Offset2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkOffset2D >( v );\n\t}\n\n\tconstexpr Offset2D convert( VkOffset2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< Offset2D >( v );\n\t}\n\n\tconstexpr VkRect2D convert( Rect2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkRect2D >( v );\n\t}\n\n\tconstexpr Rect2D convert( VkRect2D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< Rect2D >( v );\n\t}\n\n\tconstexpr VkExtent3D convert( Extent3D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkExtent3D >( v );\n\t}\n\n\tconstexpr Extent3D convert( VkExtent3D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< Extent3D >( v );\n\t}\n\n\tconstexpr VkOffset3D convert( Offset3D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkOffset3D >( v );\n\t}\n\n\tconstexpr Offset3D convert( VkOffset3D const & v )noexcept\n\t{\n\t\treturn std::bit_cast< Offset3D >( v );\n\t}\n\n\tconstexpr VkImageSubresourceRange convert( ImageSubresourceRange const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkImageSubresourceRange >( v );\n\t}\n\n\tconstexpr ImageSubresourceRange convert( VkImageSubresourceRange const & v )noexcept\n\t{\n\t\treturn std::bit_cast< ImageSubresourceRange >( v );\n\t}\n\n\tconstexpr VkPipelineColorBlendAttachmentState convert( PipelineColorBlendAttachmentState const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkPipelineColorBlendAttachmentState >( v );\n\t}\n\n\tconstexpr PipelineColorBlendAttachmentState convert( VkPipelineColorBlendAttachmentState const & v )noexcept\n\t{\n\t\treturn std::bit_cast< PipelineColorBlendAttachmentState >( v );\n\t}\n\n\tconstexpr VkClearDepthStencilValue convert( ClearDepthStencilValue const & v )noexcept\n\t{\n\t\treturn std::bit_cast< VkClearDepthStencilValue >( v );\n\t}\n\n\tconstexpr VkClearColorValue convert( ClearColorValue const & v )noexcept\n\t{\n\t\tif ( v.isFloat32() )\n\t\t{\n\t\t\tVkClearColorValue result;\n\t\t\tresult.float32[0] = v.float32()[0];\n\t\t\tresult.float32[1] = v.float32()[1];\n\t\t\tresult.float32[2] = v.float32()[2];\n\t\t\tresult.float32[3] = v.float32()[3];\n\t\t\treturn result;\n\t\t}\n\n\t\tif ( v.isInt32() )\n\t\t{\n\t\t\tVkClearColorValue result;\n\t\t\tresult.int32[0] = v.int32()[0];\n\t\t\tresult.int32[1] = v.int32()[1];\n\t\t\tresult.int32[2] = v.int32()[2];\n\t\t\tresult.int32[3] = v.int32()[3];\n\t\t\treturn result;\n\t\t}\n\n\n\t\tVkClearColorValue result;\n\t\tresult.uint32[0] = v.uint32()[0];\n\t\tresult.uint32[1] = v.uint32()[1];\n\t\tresult.uint32[2] = v.uint32()[2];\n\t\tresult.uint32[3] = v.uint32()[3];\n\t\treturn result;\n\t}\n\n\tconstexpr VkClearValue convert( ClearValue const & v )noexcept\n\t{\n\t\tif ( v.isColor() )\n\t\t{\n\t\t\tVkClearValue result;\n\t\t\tresult.color = convert( v.color() );\n\t\t\treturn result;\n\t\t}\n\n\t\tVkClearValue result;\n\t\tresult.depthStencil = convert( v.depthStencil() );\n\t\treturn result;\n\t}\n\n\tconstexpr VkBufferViewCreateInfo convert( BufferViewCreateInfo const & v )noexcept\n\t{\n\t\treturn VkBufferViewCreateInfo{ VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, nullptr\n\t\t\t, 0, VkBuffer{}, convert( v.format )\n\t\t\t, v.subresourceRange.offset, v.subresourceRange.size };\n\t}\n\n\tconstexpr BufferViewCreateInfo convert( VkBufferViewCreateInfo const & v )noexcept\n\t{\n\t\treturn BufferViewCreateInfo{ convert( v.format )\n\t\t\t, { v.offset, v.range } };\n\t}\n\n\tconstexpr VkBufferCreateInfo convert( BufferCreateInfo const & v )noexcept\n\t{\n\t\treturn VkBufferCreateInfo{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr\n\t\t\t, getBufferCreateFlags( v.flags ), v.size\n\t\t\t, getBufferUsageFlags( v.usage )\n\t\t\t, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr };\n\t}\n\n\tconstexpr BufferCreateInfo convert( VkBufferCreateInfo const & v )noexcept\n\t{\n\t\treturn BufferCreateInfo{ getBufferCreateFlags( v.flags )\n\t\t\t, v.size\n\t\t\t, getBufferUsageFlags( v.usage ) };\n\t}\n\n\tconstexpr VkImageViewCreateInfo convert( ImageViewCreateInfo const & v )noexcept\n\t{\n\t\treturn VkImageViewCreateInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr\n\t\t\t, getImageViewCreateFlags( v.flags ), VkImage{}, convert( v.viewType ), convert( v.format )\n\t\t\t, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }\n\t\t, convert( v.subresourceRange ) };\n\t}\n\n\tconstexpr ImageViewCreateInfo convert( VkImageViewCreateInfo const & v )noexcept\n\t{\n\t\treturn ImageViewCreateInfo{ getImageViewCreateFlags( v.flags ), convert( v.viewType ), convert( v.format )\n\t\t\t, convert( v.subresourceRange ) };\n\t}\n\n\tconstexpr VkImageCreateInfo convert( ImageCreateInfo const & v )noexcept\n\t{\n\t\treturn VkImageCreateInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr\n\t\t\t, getImageCreateFlags( v.flags ), convert( v.imageType ), convert( v.format )\n\t\t\t, convert( v.extent ), v.mipLevels, v.arrayLayers, convert( v.samples )\n\t\t\t, convert( v.tiling ), getImageUsageFlags( v.usage )\n\t\t\t, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr\n\t\t\t, VK_IMAGE_LAYOUT_UNDEFINED };\n\t}\n\n\tconstexpr ImageCreateInfo convert( VkImageCreateInfo const & v )noexcept\n\t{\n\t\treturn ImageCreateInfo{ getImageCreateFlags( v.flags ), convert( v.imageType ), convert( v.format )\n\t\t\t, convert( v.extent ), v.mipLevels, v.arrayLayers, convert( v.samples )\n\t\t\t, convert( v.tiling ), getImageUsageFlags( v.usage ) };\n\t}\n\n\tinline VkImageSubresourceLayers getSubresourceLayers( ImageSubresourceRange const & range\n\t\t, uint32_t layerCount )\n\t{\n\t\treturn VkImageSubresourceLayers{ getImageAspectFlags( range.aspectMask )\n\t\t\t, range.baseMipLevel\n\t\t\t, range.baseArrayLayer\n\t\t\t, layerCount };\n\t}\n\n\tinline VkImageSubresourceLayers getSubresourceLayers( ImageSubresourceRange const & range )\n\t{\n\t\treturn getSubresourceLayers( range, range.layerCount );\n\t}\n\n\tinline VkImageSubresourceLayers getSubresourceLayer( ImageSubresourceRange const & range )\n\t{\n\t\treturn getSubresourceLayers( range, 1u );\n\t}\n}\n"
  },
  {
    "path": "include/RenderGraph/FrameGraphPrerequisites.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphFunctions.hpp\"\n\nnamespace crg\n{\n\tstatic constexpr PipelineColorBlendAttachmentState DefaultBlendState;\n\n\ttemplate< typename TypeT >\n\tstatic inline const TypeT defaultV = DefaultValueGetterT< TypeT >::get();\n\n\ttemplate< typename TypeT >\n\tstatic inline TypeT getDefaultV()\n\t{\n\t\treturn DefaultValueGetterT< TypeT >::get();\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< VkPipelineVertexInputStateCreateInfo >\n\t{\n\t\tstatic VkPipelineVertexInputStateCreateInfo get()\n\t\t{\n\t\t\tVkPipelineVertexInputStateCreateInfo const result{ []()\n\t\t\t\t{\n\t\t\t\t\treturn VkPipelineVertexInputStateCreateInfo{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\n\t\t\t\t\t\t, nullptr\n\t\t\t\t\t\t, {}\n\t\t\t\t\t\t, {}\n\t\t\t\t\t\t, {}\n\t\t\t\t\t\t, {}\n\t\t\t\t\t\t, {} };\n\t\t\t\t}() };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate< typename TypeT >\n\tusing RawTypeT = typename RawTyperT< TypeT >::Type;\n}\n"
  },
  {
    "path": "include/RenderGraph/FrameGraphStructs.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphEnums.hpp\"\n\n#include <array>\n#include <variant>\n\nnamespace crg\n{\n\tstruct Offset2D\n\t{\n\t\tint32_t x{};\n\t\tint32_t y{};\n\n\tprivate:\n\t\tfriend bool operator==( Offset2D const & lhs, Offset2D const & rhs )noexcept = default;\n\t};\n\n\tstruct Extent2D\n\t{\n\t\tuint32_t width{};\n\t\tuint32_t height{};\n\n\tprivate:\n\t\tfriend bool operator==( Extent2D const & lhs, Extent2D const & rhs )noexcept = default;\n\t};\n\n\tstruct Rect2D\n\t{\n\t\tOffset2D offset{};\n\t\tExtent2D extent{};\n\n\tprivate:\n\t\tfriend bool operator==( Rect2D const & lhs, Rect2D const & rhs )noexcept = default;\n\t};\n\n\tstruct Offset3D\n\t{\n\t\tint32_t x{};\n\t\tint32_t y{};\n\t\tint32_t z{};\n\n\tprivate:\n\t\tfriend bool operator==( Offset3D const & lhs, Offset3D const & rhs )noexcept = default;\n\t};\n\n\tstruct Extent3D\n\t{\n\t\tuint32_t width{};\n\t\tuint32_t height{};\n\t\tuint32_t depth{};\n\n\tprivate:\n\t\tfriend bool operator==( Extent3D const & lhs, Extent3D const & rhs )noexcept = default;\n\t};\n\n\tstruct Rect3D\n\t{\n\t\tOffset3D offset{};\n\t\tExtent3D extent{};\n\n\tprivate:\n\t\tfriend bool operator==( Rect3D const & lhs, Rect3D const & rhs )noexcept = default;\n\t};\n\n\tstruct BufferSubresourceRange\n\t{\n\t\tDeviceSize offset{};\n\t\tDeviceSize size{};\n\n\tprivate:\n\t\tfriend bool operator==( BufferSubresourceRange const & lhs, BufferSubresourceRange const & rhs )noexcept = default;\n\n\t\tfriend std::strong_ordering operator<=>( BufferSubresourceRange const & lhs, BufferSubresourceRange const & rhs )noexcept\n\t\t{\n\t\t\tif ( auto c = lhs.offset <=> rhs.offset; c != std::strong_ordering::equal )\n\t\t\t\treturn c;\n\t\t\treturn lhs.size <=> rhs.size;\n\t\t}\n\t};\n\n\tstruct ImageSubresourceRange\n\t{\n\t\tImageAspectFlags aspectMask{};\n\t\tuint32_t baseMipLevel{};\n\t\tuint32_t levelCount{};\n\t\tuint32_t baseArrayLayer{};\n\t\tuint32_t layerCount{};\n\n\tprivate:\n\t\tfriend bool operator==( ImageSubresourceRange const & lhs, ImageSubresourceRange const & rhs )noexcept = default;\n\n\t\tfriend std::strong_ordering operator<=>( ImageSubresourceRange const & lhs, ImageSubresourceRange const & rhs )noexcept\n\t\t{\n\t\t\tif ( auto c = lhs.aspectMask <=> rhs.aspectMask; c != std::strong_ordering::equal )\n\t\t\t\treturn c;\n\t\t\tif ( auto c = lhs.baseArrayLayer <=> rhs.baseArrayLayer; c != std::strong_ordering::equal )\n\t\t\t\treturn c;\n\t\t\tif ( auto c = lhs.layerCount <=> rhs.layerCount; c != std::strong_ordering::equal )\n\t\t\t\treturn c;\n\t\t\tif ( auto c = lhs.baseMipLevel <=> rhs.baseMipLevel; c != std::strong_ordering::equal )\n\t\t\t\treturn c;\n\t\t\treturn lhs.levelCount <=> rhs.levelCount;\n\t\t}\n\t};\n\n\tstruct BufferCreateInfo\n\t{\n\t\tBufferCreateFlags flags{};\n\t\tDeviceSize size{};\n\t\tBufferUsageFlags usage{};\n\t\tMemoryPropertyFlags memory{};\n\n\tprivate:\n\t\tfriend bool operator==( BufferCreateInfo const & lhs, BufferCreateInfo const & rhs )noexcept = default;\n\t};\n\n\tstruct BufferViewCreateInfo\n\t{\n\t\tPixelFormat format{};\n\t\tBufferSubresourceRange subresourceRange{};\n\n\tprivate:\n\t\tfriend bool operator==( BufferViewCreateInfo const & lhs, BufferViewCreateInfo const & rhs )noexcept = default;\n\t};\n\n\tstruct ImageCreateInfo\n\t{\n\t\tImageCreateFlags flags{};\n\t\tImageType imageType{};\n\t\tPixelFormat format{};\n\t\tExtent3D extent{};\n\t\tuint32_t mipLevels{};\n\t\tuint32_t arrayLayers{};\n\t\tSampleCount samples{};\n\t\tImageTiling tiling{};\n\t\tImageUsageFlags usage{};\n\t\tMemoryPropertyFlags memory{};\n\n\tprivate:\n\t\tfriend bool operator==( ImageCreateInfo const & lhs, ImageCreateInfo const & rhs )noexcept = default;\n\t};\n\n\tstruct ImageViewCreateInfo\n\t{\n\t\tImageViewCreateFlags flags{};\n\t\tImageViewType viewType{};\n\t\tPixelFormat format{};\n\t\tImageSubresourceRange subresourceRange{};\n\n\tprivate:\n\t\tfriend bool operator==( ImageViewCreateInfo const & lhs, ImageViewCreateInfo const & rhs )noexcept = default;\n\t};\n\n\tstruct ClearColorValue\n\t{\n\t\tenum class ValueIndex\n\t\t{\n\t\t\teFloat32,\n\t\t\teInt32,\n\t\t\teUInt32,\n\t\t};\n\n\t\ttemplate< typename ValueT >\n\t\tconstexpr ClearColorValue( ValueT r, ValueT g, ValueT b, ValueT a )noexcept\n\t\t\t: m_value{ std::array< ValueT, 4u >{ r, g, b, a } }\n\t\t{\n\t\t}\n\n\t\tconstexpr explicit ClearColorValue( std::array< float, 4u > v = { 0.0f, 0.0f, 0.0f, 0.0f } )noexcept\n\t\t\t: m_value{ std::move( v ) }\n\t\t{\n\t\t}\n\n\t\tconstexpr explicit ClearColorValue( std::array< int32_t, 4u > v )noexcept\n\t\t\t: m_value{ std::move( v ) }\n\t\t{\n\t\t}\n\n\t\tconstexpr explicit ClearColorValue( std::array< uint32_t, 4u > v )noexcept\n\t\t\t: m_value{ std::move( v ) }\n\t\t{\n\t\t}\n\n\t\tconstexpr bool isFloat32()const noexcept\n\t\t{\n\t\t\treturn m_value.index() == uint32_t( ValueIndex::eFloat32 );\n\t\t}\n\n\t\tconstexpr bool isInt32()const noexcept\n\t\t{\n\t\t\treturn m_value.index() == uint32_t( ValueIndex::eInt32 );\n\t\t}\n\n\t\tconstexpr bool isUInt32()const noexcept\n\t\t{\n\t\t\treturn m_value.index() == uint32_t( ValueIndex::eUInt32 );\n\t\t}\n\n\t\tconstexpr std::array< float, 4u > const & float32()const noexcept\n\t\t{\n\t\t\treturn std::get< uint32_t( ValueIndex::eFloat32 ) >( m_value );\n\t\t}\n\n\t\tconstexpr std::array< int32_t, 4u > const & int32()const noexcept\n\t\t{\n\t\t\treturn std::get< uint32_t( ValueIndex::eInt32 ) >( m_value );\n\t\t}\n\n\t\tconstexpr std::array< uint32_t, 4u > const & uint32()const noexcept\n\t\t{\n\t\t\treturn std::get< uint32_t( ValueIndex::eUInt32 ) >( m_value );\n\t\t}\n\n\tprivate:\n\t\tstd::variant< std::array< float, 4u >\n\t\t\t, std::array< int32_t, 4u >\n\t\t\t, std::array< uint32_t, 4u > > m_value;\n\n\t\tfriend bool operator==( ClearColorValue const & lhs, ClearColorValue const & rhs )noexcept = default;\n\t};\n\n\tstruct ClearDepthStencilValue\n\t{\n\t\tfloat depth{};\n\t\tuint32_t stencil{};\n\n\tprivate:\n\t\tfriend bool operator==( ClearDepthStencilValue const & lhs, ClearDepthStencilValue const & rhs )noexcept = default;\n\t};\n\n\tstruct ClearValue\n\t{\n\t\tenum class ValueIndex\n\t\t{\n\t\t\teColor,\n\t\t\teDepthStencil,\n\t\t};\n\n\t\tconstexpr explicit ClearValue( ClearColorValue v = ClearColorValue{} )noexcept\n\t\t\t: m_value{ std::move( v ) }\n\t\t{\n\t\t}\n\n\t\tconstexpr explicit ClearValue( ClearDepthStencilValue v )noexcept\n\t\t\t: m_value{ std::move( v ) }\n\t\t{\n\t\t}\n\n\t\tconstexpr bool isColor()const noexcept\n\t\t{\n\t\t\treturn m_value.index() == uint32_t( ValueIndex::eColor );\n\t\t}\n\n\t\tconstexpr bool isDepthStencil()const noexcept\n\t\t{\n\t\t\treturn m_value.index() == uint32_t( ValueIndex::eDepthStencil );\n\t\t}\n\n\t\tconstexpr ClearColorValue const & color()const noexcept\n\t\t{\n\t\t\treturn std::get< uint32_t( ValueIndex::eColor ) >( m_value );\n\t\t}\n\n\t\tconstexpr ClearDepthStencilValue const & depthStencil()const noexcept\n\t\t{\n\t\t\treturn std::get< uint32_t( ValueIndex::eDepthStencil ) >( m_value );\n\t\t}\n\n\tprivate:\n\t\tstd::variant< ClearColorValue, ClearDepthStencilValue > m_value;\n\n\t\tfriend bool operator==( ClearValue const & lhs, ClearValue const & rhs )noexcept = default;\n\t};\n\n\tstruct PipelineColorBlendAttachmentState\n\t{\n\t\tuint32_t blendEnable{ VK_FALSE };\n\t\tBlendFactor srcColorBlendFactor{ BlendFactor::eOne };\n\t\tBlendFactor dstColorBlendFactor{ BlendFactor::eZero };\n\t\tBlendOp colorBlendOp{ BlendOp::eAdd };\n\t\tBlendFactor srcAlphaBlendFactor{ BlendFactor::eOne };\n\t\tBlendFactor dstAlphaBlendFactor{ BlendFactor::eZero };\n\t\tBlendOp alphaBlendOp{ BlendOp::eAdd };\n\t\tColorComponentFlags colorWriteMask{ ColorComponentFlags::eR | ColorComponentFlags::eG | ColorComponentFlags::eB | ColorComponentFlags::eA };\n\n\tprivate:\n\t\tfriend bool operator==( PipelineColorBlendAttachmentState const & lhs, PipelineColorBlendAttachmentState const & rhs )noexcept = default;\n\t};\n\n\tstruct PipelineState\n\t{\n\t\tAccessFlags access{};\n\t\tPipelineStageFlags pipelineStage{};\n\n\tprivate:\n\t\tfriend bool operator==( PipelineState const & lhs, PipelineState const & rhs )noexcept = default;\n\t};\n\n\tstruct LayoutState\n\t{\n\t\tImageLayout layout{};\n\t\tPipelineState state{};\n\t};\n\n\ttemplate< typename VkTypeT >\n\tstruct ContextObjectT\n\t{\n\t\tContextObjectT( ContextObjectT const & rhs ) = delete;\n\t\tContextObjectT( ContextObjectT && rhs )noexcept = delete;\n\t\tContextObjectT & operator=( ContextObjectT const & rhs ) = delete;\n\t\tContextObjectT & operator=( ContextObjectT && rhs )noexcept = delete;\n\n\t\texplicit ContextObjectT( GraphContext & ctx\n\t\t\t, VkTypeT obj = {}\n\t\t\t, void( *dtor )( GraphContext &, VkTypeT & )noexcept = nullptr )\n\t\t\t: context{ ctx }\n\t\t\t, object{ obj }\n\t\t\t, destroy{ dtor }\n\t\t{\n\t\t}\n\n\t\t~ContextObjectT()noexcept\n\t\t{\n\t\t\tif ( destroy && object )\n\t\t\t{\n\t\t\t\tdestroy( context, object );\n\t\t\t}\n\t\t}\n\n\t\tGraphContext & context;\n\t\tVkTypeT object;\n\t\tvoid ( *destroy )( GraphContext &, VkTypeT & )noexcept;\n\t};\n\n\tstruct SemaphoreWait\n\t{\n\t\tVkSemaphore semaphore{};\n\t\tPipelineStageFlags dstStageMask{};\n\t};\n\n\ttemplate< typename TypeT >\n\tstruct RawTyperT\n\t{\n\t\tusing Type = TypeT;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/FramePass.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/Attachment.hpp\"\n#include \"RenderGraph/WriteDescriptorSet.hpp\"\n\n#include <functional>\n#include <optional>\n#include <unordered_map>\n\nnamespace crg\n{\n\tusing RunnablePassCreator = std::function< RunnablePassPtr( FramePass const &\n\t\t, GraphContext &\n\t\t, RunnableGraph & ) >;\n\n\tstruct FramePass\n\t{\n\tpublic:\n\t\tstruct SampledAttachment\n\t\t{\n\t\t\tSampledAttachment( Attachment const * attach, SamplerDesc sampler )noexcept\n\t\t\t\t: attach{ attach }\n\t\t\t\t, sampler{ std::move( sampler ) }\n\t\t\t{\n\t\t\t}\n\n\t\t\tAttachment const * attach;\n\t\t\tSamplerDesc sampler;\n\t\t};\n\n\tpublic:\n\t\t/**\n\t\t*\\name\n\t\t*\tDependencies.\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tGets the attachment parent from the givent one.\n\t\t*\\param[in] attach\n\t\t*\tThe child attachment.\n\t\t*/\n\t\tCRG_API Attachment const * getParentAttachment( Attachment const & attach )const;\n\t\t/**@}*/\n#pragma region Attachments\n\t\t/**\n\t\t*\\name\n\t\t*\tAttachments\n\t\t*/\n\t\t/**@{*/\n#\tpragma region Uniform\n\t\t/**\n\t\t*\\name\n\t\t*\tUniform\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a uniform buffer multi-pass attachment.\n\t\t*/\n\t\tCRG_API void addInputUniformBuffer( BufferViewIdArray buffers\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a uniform buffer single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputUniformBufferT( BufferViewIdArray buffers\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputUniformBuffer( std::move( buffers ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a uniform buffer single-pass attachment.\n\t\t*/\n\t\tvoid addInputUniformBuffer( BufferViewId buffer\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\taddInputUniformBuffer( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a uniform buffer single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputUniformBufferT( BufferViewId buffer\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputUniformBufferT( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image multi-pass attachment.\n\t\t*/\n\t\tCRG_API void addInputSampledImage( ImageViewIdArray views\n\t\t\t, uint32_t binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputSampledImageT( ImageViewIdArray views\n\t\t\t, EnumT binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} )\n\t\t{\n\t\t\taddInputSampledImage( std::move( views ), uint32_t( binding ), std::move( samplerDesc ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image single-pass attachment.\n\t\t*/\n\t\tvoid addInputSampledImage( ImageViewId view\n\t\t\t, uint32_t binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} )\n\t\t{\n\t\t\taddInputSampledImage( ImageViewIdArray{ view }, binding, std::move( samplerDesc ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputSampledImageT( ImageViewId view\n\t\t\t, EnumT binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} )\n\t\t{\n\t\t\taddInputSampledImageT( ImageViewIdArray{ view }, binding, std::move( samplerDesc ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input uniform attachment.\n\t\t*/\n\t\tCRG_API void addInputUniform( Attachment const & attach\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input uniform attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputUniformT( Attachment const & attach\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputUniform( attach, uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image attachment.\n\t\t*/\n\t\tCRG_API void addInputSampled( Attachment const & attach\n\t\t\t, uint32_t binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a sampled image attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputSampledT( Attachment const & attach\n\t\t\t, EnumT binding\n\t\t\t, SamplerDesc samplerDesc = SamplerDesc{} )\n\t\t{\n\t\t\taddInputSampled( attach, uint32_t( binding ), std::move( samplerDesc ) );\n\t\t}\n\t\t/**@}*/\n#\tpragma endregion\n#\tpragma region Storage\n\t\t/**\n\t\t*\\name\n\t\t*\tStorage\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer multi-pass attachment.\n\t\t*/\n\t\tCRG_API void addInputStorageBuffer( BufferViewIdArray buffers\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer multi-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputStorageBufferT( BufferViewIdArray buffers\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputStorageBuffer( std::move( buffers ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer single-pass attachment.\n\t\t*/\n\t\tvoid addInputStorageBuffer( BufferViewId buffer\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\taddInputStorageBuffer( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputStorageBufferT( BufferViewId buffer\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputStorageBufferT( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\tCRG_API void addInputStorageImage( ImageViewIdArray views\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputStorageImageT( ImageViewIdArray views\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputStorageImage( std::move( views ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\tvoid addInputStorageImage( ImageViewId view\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\taddInputStorageImage( ImageViewIdArray{ view }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputStorageImageT( ImageViewId view\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputStorageImageT( ImageViewIdArray{ view }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\tCRG_API void addInputStorage( Attachment const & attach\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input storage attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tvoid addInputStorageT( Attachment const & attach\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\taddInputStorage( attach, uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input/output storage attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutStorage( Attachment const & attach\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input/output storage attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addInOutStorageT( Attachment const & attach\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addInOutStorage( attach, uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output storage buffer multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputStorageBuffer( BufferViewIdArray buffers\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output storage buffer multi-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addOutputStorageBufferT( BufferViewIdArray buffers\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addOutputStorageBuffer( std::move( buffers ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output storage buffer single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputStorageBuffer( BufferViewId buffer\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\treturn addOutputStorageBuffer( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output storage buffer single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addOutputStorageBufferT( BufferViewId buffer\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addOutputStorageBufferT( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer multi-pass attachment that will be cleared a the beginning of the pass.\n\t\t*/\n\t\tCRG_API Attachment const * addClearableOutputStorageBuffer( BufferViewIdArray buffers\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer multi-pass attachment that will be cleared a the beginning of the pass.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addClearableOutputStorageBufferT( BufferViewIdArray buffers\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addClearableOutputStorageBuffer( std::move( buffers ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer single-pass attachment that will be cleared a the beginning of the pass.\n\t\t*/\n\t\tAttachment const * addClearableOutputStorageBuffer( BufferViewId buffer\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\treturn addClearableOutputStorageBuffer( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage buffer single-pass attachment that will be cleared a the beginning of the pass.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addClearableOutputStorageBufferT( BufferViewId buffer\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addClearableOutputStorageBufferT( BufferViewIdArray{ buffer }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputStorageImage( ImageViewIdArray view\n\t\t\t, uint32_t binding );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image multi-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addOutputStorageImageT( ImageViewIdArray views\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addOutputStorageImage( std::move( views ), uint32_t( binding ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputStorageImage( ImageViewId view\n\t\t\t, uint32_t binding )\n\t\t{\n\t\t\treturn addOutputStorageImage( ImageViewIdArray{ view }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addOutputStorageImageT( ImageViewId view\n\t\t\t, EnumT binding )\n\t\t{\n\t\t\treturn addOutputStorageImageT( ImageViewIdArray{ view }, binding );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addClearableOutputStorageImage( ImageViewIdArray views\n\t\t\t, uint32_t binding\n\t\t\t, ClearValue clearValue = ClearValue{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image multi-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addClearableOutputStorageImageT( ImageViewIdArray views\n\t\t\t, EnumT binding\n\t\t\t, ClearValue clearValue = ClearValue{} )\n\t\t{\n\t\t\treturn addClearableOutputStorageImage( std::move( views )\n\t\t\t\t, uint32_t( binding )\n\t\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image single-pass attachment.\n\t\t*/\n\t\tAttachment const * addClearableOutputStorageImage( ImageViewId view\n\t\t\t, uint32_t binding\n\t\t\t, ClearValue clearValue = ClearValue{} )\n\t\t{\n\t\t\treturn addClearableOutputStorageImage( ImageViewIdArray{ view }\n\t\t\t\t, binding\n\t\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a storage image single-pass attachment.\n\t\t*/\n\t\ttemplate< typename EnumT >\n\t\tAttachment const * addClearableOutputStorageImageT( ImageViewId view\n\t\t\t, EnumT binding\n\t\t\t, ClearValue clearValue = ClearValue{} )\n\t\t{\n\t\t\treturn addClearableOutputStorageImageT( ImageViewIdArray{ view }\n\t\t\t\t, binding\n\t\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**@}*/\n#\tpragma endregion\n#\tpragma region Transfer\n\t\t/**\n\t\t*\\name\n\t\t*\tTransfer\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input external buffer.\n\t\t*/\n\t\tCRG_API void addInputTransferBuffer( BufferViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input external buffer.\n\t\t*/\n\t\tvoid addInputTransferBuffer( BufferViewId view )\n\t\t{\n\t\t\taddInputTransferBuffer( BufferViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input external image.\n\t\t*/\n\t\tCRG_API void addInputTransferImage( ImageViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input external image.\n\t\t*/\n\t\tvoid addInputTransferImage( ImageViewId view )\n\t\t{\n\t\t\taddInputTransferImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input attachment.\n\t\t*/\n\t\tCRG_API void addInputTransfer( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer input/output attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutTransfer( Attachment const & attach\n\t\t\t, Attachment::Flag flag = {} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer output buffer multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputTransferBuffer( BufferViewIdArray buffers );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer output buffer single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputTransferBuffer( BufferViewId buffer )\n\t\t{\n\t\t\treturn addOutputTransferBuffer( BufferViewIdArray{ buffer } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates a transfer output multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputTransferImage( ImageViewIdArray view );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an transfer output single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputTransferImage( ImageViewId view )\n\t\t{\n\t\t\treturn addOutputTransferImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**@}*/\n#\tpragma endregion\n#\tpragma region Target\n\t\t/**\n\t\t*\\name\n\t\t*\tTarget\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input colour attachment.\n\t\t*/\n\t\tCRG_API void addInputColourTargetImage( ImageViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input colour attachment.\n\t\t*/\n\t\tvoid addInputColourTargetImage( ImageViewId view )\n\t\t{\n\t\t\treturn addInputColourTargetImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth attachment.\n\t\t*/\n\t\tCRG_API void addInputDepthTargetImage( ImageViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth attachment.\n\t\t*/\n\t\tvoid addInputDepthTargetImage( ImageViewId view )\n\t\t{\n\t\t\treturn addInputDepthTargetImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input stencil attachment.\n\t\t*/\n\t\tCRG_API void addInputStencilTargetImage( ImageViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input stencil attachment.\n\t\t*/\n\t\tvoid addInputStencilTargetImage( ImageViewId view )\n\t\t{\n\t\t\treturn addInputStencilTargetImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth and stencil attachment.\n\t\t*/\n\t\tCRG_API void addInputDepthStencilTargetImage( ImageViewIdArray views );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth and stencil attachment.\n\t\t*/\n\t\tvoid addInputDepthStencilTargetImage( ImageViewId view )\n\t\t{\n\t\t\treturn addInputDepthStencilTargetImage( ImageViewIdArray{ view } );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input colour attachment.\n\t\t*/\n\t\tCRG_API void addInputColourTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth attachment.\n\t\t*/\n\t\tCRG_API void addInputDepthTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input stencil attachment.\n\t\t*/\n\t\tCRG_API void addInputStencilTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an input depth and stencil attachment.\n\t\t*/\n\t\tCRG_API void addInputDepthStencilTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an in/out colour attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutColourTarget( Attachment const & attach\n\t\t\t, PipelineColorBlendAttachmentState blendState = DefaultBlendState );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an in/out depth attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutDepthTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an in/out stencil attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutStencilTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an in/out depth and stencil attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addInOutDepthStencilTarget( Attachment const & attach );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output colour multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputColourTarget( ImageViewIdArray views\n\t\t\t, ClearColorValue clearValue = ClearColorValue{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output colour single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputColourTarget( ImageViewId view\n\t\t\t, ClearColorValue clearValue = ClearColorValue{} )\n\t\t{\n\t\t\treturn addOutputColourTarget( ImageViewIdArray{ view }\n\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output depth multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputDepthTarget( ImageViewIdArray views\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output depth single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputDepthTarget( ImageViewId view\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} )\n\t\t{\n\t\t\treturn addOutputDepthTarget( ImageViewIdArray{ view }\n\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output stencil multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputStencilTarget( ImageViewIdArray views\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output stencil single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputStencilTarget( ImageViewId view\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} )\n\t\t{\n\t\t\treturn addOutputStencilTarget( ImageViewIdArray{ view }\n\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output depth and stencil multi-pass attachment.\n\t\t*/\n\t\tCRG_API Attachment const * addOutputDepthStencilTarget( ImageViewIdArray views\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an output depth and stencil single-pass attachment.\n\t\t*/\n\t\tAttachment const * addOutputDepthStencilTarget( ImageViewId view\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} )\n\t\t{\n\t\t\treturn addOutputDepthStencilTarget( ImageViewIdArray{ view }\n\t\t\t, std::move( clearValue ) );\n\t\t}\n\t\t/**@}*/\n\t\t/**@}*/\n#\tpragma endregion\n#\tpragma region Implicit\n\t\t/**\n\t\t*\\name\n\t\t*\tImplicit\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an implicit attachment.\n\t\t*\\remarks\n\t\t*\tThis attachment will only be used to compute dependencies, and is considered an input, in that goal.\n\t\t*/\n\t\tCRG_API void addImplicit( Attachment const & attach\n\t\t\t, AccessState wantedAccess );\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates an implicit attachment.\n\t\t*\\remarks\n\t\t*\tThis attachment will only be used to compute dependencies, and is considered an input, in that goal.\n\t\t*/\n\t\tCRG_API void addImplicit( Attachment const & attach\n\t\t\t, ImageLayout wantedLayout );\n\t\t/**@}*/\n#\tpragma endregion\n\t\t/**@}*/\n#pragma endregion\n\t\t/**\n\t\t*\\name\n\t\t*\tGraph compilation.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API RunnablePassPtr createRunnable( GraphContext & context\n\t\t\t, RunnableGraph & graph )const;\n\t\t/**@}*/\n\n\t\tCRG_API std::string getFullName()const;\n\t\tCRG_API std::string getGroupName()const;\n\n\t\tstd::string const & getName()const\n\t\t{\n\t\t\treturn m_name;\n\t\t}\n\n\t\tauto begin()const\n\t\t{\n\t\t\treturn m_ownAttaches.cbegin();\n\t\t}\n\n\t\tauto end()const\n\t\t{\n\t\t\treturn m_ownAttaches.cend();\n\t\t}\n\n\t\tFramePassGroup const & getGroup()const noexcept\n\t\t{\n\t\t\treturn m_group;\n\t\t}\n\n\t\tFrameGraph const & getGraph()const noexcept\n\t\t{\n\t\t\treturn m_graph;\n\t\t}\n\n\t\tuint32_t getId()const noexcept\n\t\t{\n\t\t\treturn m_id;\n\t\t}\n\n\t\tstd::map< uint32_t, Attachment const * > const & getUniforms()const noexcept\n\t\t{\n\t\t\treturn m_uniforms;\n\t\t}\n\n\t\tstd::map< uint32_t, SampledAttachment > const & getSampled()const noexcept\n\t\t{\n\t\t\treturn m_sampled;\n\t\t}\n\n\t\tstd::map< uint32_t, Attachment const * > const & getInputs()const noexcept\n\t\t{\n\t\t\treturn m_inputs;\n\t\t}\n\n\t\tstd::map< uint32_t, Attachment const * > const & getInouts()const noexcept\n\t\t{\n\t\t\treturn m_inouts;\n\t\t}\n\n\t\tstd::map< uint32_t, Attachment const * > const & getOutputs()const noexcept\n\t\t{\n\t\t\treturn m_outputs;\n\t\t}\n\n\t\tstd::vector< Attachment const * > const & getTargets()const noexcept\n\t\t{\n\t\t\treturn m_targets;\n\t\t}\n\n\tprotected:\n\t\tfriend struct FramePassGroup;\n\t\t/**\n\t\t*\\name\n\t\t*\tConstruction.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API FramePass( FramePassGroup const & group\n\t\t\t, FrameGraph & graph\n\t\t\t, uint32_t id\n\t\t\t, std::string const & name\n\t\t\t, RunnablePassCreator runnableCreator );\n\t\t/**@}*/\n\n\tprivate:\n\t\tCRG_API Attachment const * addColourTarget( std::string const & name\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, ImageLayout wantedLayout = ImageLayout::eUndefined\n\t\t\t, ClearColorValue clearValue = ClearColorValue{}\n\t\t\t, PipelineColorBlendAttachmentState blendState = DefaultBlendState );\n\t\tCRG_API Attachment const * addDepthTarget( std::string const & name\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, ImageLayout wantedLayout = ImageLayout::eUndefined\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\t\tCRG_API Attachment const * addStencilTarget( std::string const & name\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, ImageAttachment::FlagKind stencilFlags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp stencilLoadOp\n\t\t\t, AttachmentStoreOp stencilStoreOp\n\t\t\t, ImageLayout wantedLayout = ImageLayout::eUndefined\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\t\tCRG_API Attachment const * addDepthStencilTarget( std::string const & name\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, ImageAttachment::FlagKind stencilFlags\n\t\t\t, ImageViewIdArray views\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, AttachmentLoadOp stencilLoadOp\n\t\t\t, AttachmentStoreOp stencilStoreOp\n\t\t\t, ImageLayout wantedLayout = ImageLayout::eUndefined\n\t\t\t, ClearDepthStencilValue clearValue = ClearDepthStencilValue{} );\n\n\t\tAttachment const * addOwnAttach( ImageViewIdArray views\n\t\t\t, std::string attachName\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, ImageAttachment::FlagKind imageFlags\n\t\t\t, AttachmentLoadOp loadOp\n\t\t\t, AttachmentStoreOp storeOp\n\t\t\t, AttachmentLoadOp stencilLoadOp\n\t\t\t, AttachmentStoreOp stencilStoreOp\n\t\t\t, ClearValue clearValue\n\t\t\t, PipelineColorBlendAttachmentState blendState\n\t\t\t, ImageLayout wantedLayout\n\t\t\t, Attachment const * parent );\n\t\tAttachment const * addOwnAttach( BufferViewIdArray views\n\t\t\t, std::string attachName\n\t\t\t, Attachment::FlagKind flags\n\t\t\t, BufferAttachment::FlagKind bufferFlags\n\t\t\t, AccessState access\n\t\t\t, Attachment const * parent );\n\t\tAttachment * addOwnAttach( Attachment * mine\n\t\t\t, Attachment const * parent );\n\n\tprivate:\n\t\tFramePassGroup const & m_group;\n\t\tFrameGraph & m_graph;\n\t\tuint32_t m_id;\n\t\tstd::map< uint32_t, Attachment const * > m_uniforms;\n\t\tstd::map< uint32_t, SampledAttachment > m_sampled;\n\t\tstd::map< uint32_t, Attachment const * > m_inputs;\n\t\tstd::map< uint32_t, Attachment const * > m_inouts;\n\t\tstd::map< uint32_t, Attachment const * > m_outputs;\n\t\tstd::vector< Attachment const * > m_targets;\n\t\tRunnablePassCreator m_runnableCreator;\n\t\tstd::string m_name;\n\t\tstruct OwnAttachment\n\t\t{\n\t\t\tAttachmentPtr mine{};\n\t\t\tAttachment const * parent{};\n\t\t};\n\t\tstd::unordered_map< Attachment const *, OwnAttachment > m_ownAttaches;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/FramePassGroup.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FramePass.hpp\"\n\n#include <unordered_set>\n\nnamespace crg\n{\n\tstruct FramePassGroup\n\t{\n\t\tfriend class FrameGraph;\n\t\tclass Token\n\t\t{\n\t\t\tfriend class FrameGraph;\n\t\t\tfriend struct FramePassGroup;\n\n\t\tprivate:\n\t\t\tToken() noexcept = default;\n\t\t};\n\t\t/**\n\t\t*\\name\n\t\t*\tConstruction.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API FramePassGroup( FrameGraph & graph\n\t\t\t, uint32_t id\n\t\t\t, std::string const & name\n\t\t\t, Token token );\n\t\tCRG_API FramePassGroup( FramePassGroup & parent\n\t\t\t, uint32_t id\n\t\t\t, std::string const & name\n\t\t\t, Token token );\n\t\t/**@}*/\n\n\tpublic:\n\t\t/**\n\t\t*\\name\n\t\t*\tPasses.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API FramePass & createPass( std::string const & name\n\t\t\t, RunnablePassCreator runnableCreator );\n\t\tCRG_API FramePassGroup & createPassGroup( std::string const & name );\n\t\tCRG_API bool hasPass( std::string const & name )const;\n\t\tCRG_API void listPasses( FramePassArray & result )const;\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tGroup I/O.\n\t\t*/\n\t\t/**@{*/\n\t\tCRG_API void addGroupInput( ImageViewId view );\n\t\tCRG_API void addGroupOutput( ImageViewId view );\n\t\t/**@}*/\n\t\t/**\n\t\t*\\name\n\t\t*\tGraph interface.\n\t\t*/\n\t\t/**@{*/\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::getFinalLayoutState\n\t\t*/\n\t\tCRG_API LayoutState getFinalLayoutState( ImageViewId view\n\t\t\t, uint32_t passIndex = 0u )const;\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::createBuffer\n\t\t*/\n\t\tCRG_API BufferId createBuffer( BufferData const & img )const;\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::createView\n\t\t*/\n\t\tCRG_API BufferViewId createView( BufferViewData const & view )const;\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::createImage\n\t\t*/\n\t\tCRG_API ImageId createImage( ImageData const & img )const;\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::createView\n\t\t*/\n\t\tCRG_API ImageViewId createView( ImageViewData const & view )const;\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::addInput\n\t\t*/\n\t\tCRG_API void addInput( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range\n\t\t\t, LayoutState const & outputLayout );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::addInput\n\t\t*/\n\t\tCRG_API void addInput( ImageViewId view\n\t\t\t, LayoutState const & outputLayout );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::addOutput\n\t\t*/\n\t\tCRG_API void addOutput( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & range\n\t\t\t, LayoutState const & outputLayout );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::addOutput\n\t\t*/\n\t\tCRG_API void addOutput( ImageViewId view\n\t\t\t, LayoutState const & outputLayout );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::mergeViews\n\t\t*/\n\t\tCRG_API ImageViewId mergeViews( ImageViewIdArray const & views\n\t\t\t, bool mergeMipLevels = true\n\t\t\t, bool mergeArrayLayers = true );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::mergeViews\n\t\t*/\n\t\tCRG_API BufferViewId mergeViews( BufferViewIdArray const & views );\n\t\t/**\n\t\t*\\copydoc crg::FrameGraph::mergeAttachments\n\t\t*/\n\t\tCRG_API Attachment const * mergeAttachments( AttachmentArray const & attachments\n\t\t\t, bool mergeMipLevels = true\n\t\t\t, bool mergeArrayLayers = true );\n\t\t/**@}*/\n\n\t\tCRG_API std::string getFullName()const;\n\n\t\tstd::string const & getName()const noexcept\n\t\t{\n\t\t\treturn m_name;\n\t\t}\n\n\t\tFramePassGroupPtrArray const & getGroups()const noexcept\n\t\t{\n\t\t\treturn m_groups;\n\t\t}\n\n\t\tFramePassPtrArray const & getPasses()const noexcept\n\t\t{\n\t\t\treturn m_passes;\n\t\t}\n\n\t\tFramePassGroup const * getParent()const noexcept\n\t\t{\n\t\t\treturn m_parent;\n\t\t}\n\n\t\tuint32_t getId()const noexcept\n\t\t{\n\t\t\treturn m_id;\n\t\t}\n\n\tprivate:\n\t\tuint32_t m_id;\n\t\tFramePassPtrArray m_passes;\n\t\tFramePassGroupPtrArray m_groups;\n\t\tFramePassGroup * m_parent{};\n\t\tstd::string m_name;\n\t\tFrameGraph & m_graph;\n\t\tstd::unordered_set< uint32_t > m_inputs;\n\t\tstd::unordered_set< uint32_t > m_outputs;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/FramePassTimer.hpp",
    "content": "/*\nSee LICENSE file in root folder\n*/\n#ifndef ___CRG_RenderPassTimer_H___\n#define ___CRG_RenderPassTimer_H___\n\n#include \"FrameGraphPrerequisites.hpp\"\n#include \"Signal.hpp\"\n\n#include <array>\n#include <chrono>\n\nnamespace crg\n{\n\tusing Clock = std::chrono::high_resolution_clock;\n\tusing Nanoseconds = std::chrono::nanoseconds;\n\tusing FramePassDestroyFunc = std::function< void( FramePassTimer & ) >;\n\tusing OnFramePassDestroy = Signal< FramePassDestroyFunc >;\n\tusing OnFramePassDestroyConnection = SignalConnection< OnFramePassDestroy >;\n\tusing PassColour = std::array< float, 4u >;\n\n\tenum class TimerScope\n\t{\n\t\teGraph,\n\t\tePass,\n\t\teUpdate,\n\t};\n\n\tclass FramePassTimerBlock\n\t{\n\tpublic:\n\t\tCRG_API explicit FramePassTimerBlock( FramePassTimer & timer );\n\t\tCRG_API FramePassTimerBlock( FramePassTimerBlock && rhs )noexcept;\n\t\tFramePassTimerBlock & operator=( FramePassTimerBlock && rhs )noexcept = delete;\n\t\tFramePassTimerBlock( FramePassTimerBlock const & ) = delete;\n\t\tFramePassTimerBlock & operator=( FramePassTimerBlock const & ) = delete;\n\t\tCRG_API ~FramePassTimerBlock()noexcept;\n\n\t\tFramePassTimer * operator->()const\n\t\t{\n\t\t\treturn m_timer;\n\t\t}\n\n\tprivate:\n\t\tFramePassTimer * m_timer;\n\t};\n\n\tclass FramePassTimer\n\t{\n\t\tfriend class FramePassTimerBlock;\n\n\tpublic:\n\t\tFramePassTimer( FramePassTimer const & rhs ) = delete;\n\t\tFramePassTimer( FramePassTimer && rhs )noexcept = delete;\n\t\tFramePassTimer & operator=( FramePassTimer const & rhs ) = delete;\n\t\tFramePassTimer & operator=( FramePassTimer && rhs )noexcept = delete;\n\t\t/**\n\t\t*\\brief\n\t\t*\tReserves queries from given pool.\n\t\t*\\param[in] device\n\t\t*\tThe GPU device.\n\t\t*\\param[in] category\n\t\t*\tThe render pass category.\n\t\t*\\param[in] name\n\t\t*\tThe timer name.\n\t\t*/\n\t\tCRG_API FramePassTimer( GraphContext & context\n\t\t\t, std::string const & name\n\t\t\t, TimerScope scope\n\t\t\t, VkQueryPool timerQueries\n\t\t\t, uint32_t & baseQueryOffset );\n\t\t/**\n\t\t*\\brief\n\t\t*\tOwns its query pool.\n\t\t*\\param[in] device\n\t\t*\tThe GPU device.\n\t\t*\\param[in] category\n\t\t*\tThe render pass category.\n\t\t*\\param[in] name\n\t\t*\tThe timer name.\n\t\t*/\n\t\tCRG_API FramePassTimer( GraphContext & context\n\t\t\t, std::string const & name\n\t\t\t, TimerScope scope );\n\t\tCRG_API ~FramePassTimer()noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tStarts the CPU timer, resets GPU time.\n\t\t*/\n\t\tCRG_API FramePassTimerBlock start();\n\t\t/**\n\t\t*\\brief\n\t\t*\tNotifies the given pass render.\n\t\t*\\param[in] passIndex\n\t\t*\tThe pass index.\n\t\t*/\n\t\tCRG_API void notifyPassRender( uint32_t passIndex = 0u )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tReset the timer's times.\n\t\t*/\n\t\tCRG_API void reset()noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tWrites the timestamp for the beginning of the pass.\n\t\t*\\param[in] cmd\n\t\t*\tThe command buffer used to record the begin timestamp.\n\t\t*\\param[in] passId\n\t\t*\tThe pass ID.\n\t\t*/\n\t\tCRG_API void beginPass( VkCommandBuffer commandBuffer\n\t\t\t, std::string const & groupName\n\t\t\t, uint32_t passId )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tWrites the timestamp for the end of the pass.\n\t\t*\\param[in] cmd\n\t\t*\tThe command buffer used to record the end timestamp.\n\t\t*\\param[in] passIndex\n\t\t*\tThe pass index.\n\t\t*/\n\t\tCRG_API void endPass( VkCommandBuffer commandBuffer )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tRetrieves GPU time from the query.\n\t\t*/\n\t\tCRG_API void retrieveGpuTime()noexcept;\n\t\t/**\n\t\t*\\name\n\t\t*\tGetters.\n\t\t*/\n\t\t/**@{*/\n\t\tNanoseconds getCpuTime()const noexcept\n\t\t{\n\t\t\treturn m_cpuTime;\n\t\t}\n\n\t\tNanoseconds getGpuTime()const noexcept\n\t\t{\n\t\t\treturn m_gpuTime;\n\t\t}\n\n\t\tstd::string const & getName()const noexcept\n\t\t{\n\t\t\treturn m_name;\n\t\t}\n\n\t\tPassColour const & getColour()const noexcept\n\t\t{\n\t\t\treturn m_colour;\n\t\t}\n\n\t\tTimerScope getScope()const noexcept\n\t\t{\n\t\t\treturn m_scope;\n\t\t}\n\t\t/**@}*/\n\n\t\tOnFramePassDestroy onDestroy;\n\n\tprivate:\n\t\tvoid stop()noexcept;\n\n\tprivate:\n\t\tGraphContext & m_context;\n\t\tTimerScope m_scope{};\n\t\tstd::string m_name{};\n\t\tPassColour m_colour;\n\t\tClock::time_point m_cpuSaveTime{};\n\t\tNanoseconds m_cpuTime{};\n\t\tNanoseconds m_gpuTime{};\n\t\tVkQueryPool m_timerQueries{};\n\t\tbool m_ownPool{};\n\t\tstruct Query\n\t\t{\n\t\t\tuint32_t offset{};\n\t\t\tbool written{};\n\t\t\tbool started{};\n\t\t};\n\t\tstd::array< Query, 2u > m_queries;\n\t};\n}\n\n#endif\n"
  },
  {
    "path": "include/RenderGraph/GraphContext.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphPrerequisites.hpp\"\n\n#include <array>\n#include <functional>\n#include <string>\n#include <unordered_map>\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 5262 )\n#include <mutex>\n#pragma warning( pop )\n\nnamespace crg\n{\n\ttemplate< typename ObjectT >\n\tstruct DebugTypeTraits;\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkBuffer >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_BUFFER;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkBuffer\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkCommandBuffer >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_COMMAND_BUFFER;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkCommandBuffer\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkDevice >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_PHYSICAL_DEVICE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkDevice\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkInstance >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_INSTANCE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkInstance\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkPhysicalDevice >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_PHYSICAL_DEVICE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkPhysicalDevice\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkQueue >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_QUEUE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkQueue\" };\n\t};\n\n#if ( VK_USE_64_BIT_PTR_DEFINES == 1 )\n\ttemplate<>\n\tstruct DebugTypeTraits< VkBufferView >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_BUFFER_VIEW;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkBufferView\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkCommandPool >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_COMMAND_POOL;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkCommandPool\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkDescriptorPool >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_DESCRIPTOR_POOL;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkDescriptorPool\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkDescriptorSet >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_DESCRIPTOR_SET;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkDescriptorSet\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkDescriptorSetLayout >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkDescriptorSetLayout\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkDeviceMemory >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_DEVICE_MEMORY;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkDeviceMemory\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkEvent >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_EVENT;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkEvent\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkFence >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_FENCE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkFence\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkFramebuffer >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_FRAMEBUFFER;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkFramebuffer\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkImage >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_IMAGE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkImage\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkImageView >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_IMAGE_VIEW;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkImageView\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkPipeline >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_PIPELINE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkPipeline\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkPipelineLayout >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_PIPELINE_LAYOUT;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkPipelineLayout\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkQueryPool >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_QUERY_POOL;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkQueryPool\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkRenderPass >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_RENDER_PASS;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkRenderPass\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkSampler >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_SAMPLER;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkSampler\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkSemaphore >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_SEMAPHORE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkSemaphore\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkShaderModule >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_SHADER_MODULE;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkShaderModule\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkSurfaceKHR >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_SURFACE_KHR;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkSurfaceKHR\" };\n\t};\n\n\ttemplate<>\n\tstruct DebugTypeTraits< VkSwapchainKHR >\n\t{\n#if VK_EXT_debug_utils\n\t\tstatic VkObjectType constexpr UtilsValue = VK_OBJECT_TYPE_SWAPCHAIN_KHR;\n#endif\n#if VK_EXT_debug_report || VK_EXT_debug_marker\n\t\tstatic VkDebugReportObjectTypeEXT constexpr ReportValue = VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT;\n#endif\n\t\tstatic inline std::string Name{ \"VkSwapchainKHR\" };\n\t};\n\n#endif // ( VK_USE_64_BIT_PTR_DEFINES == 1 )\n\n\tstruct DebugBlockInfo\n\t{\n\t\tstd::string markerName;\n\t\tstd::array< float, 4 > colour;\n\t};\n\n\tstruct DeletionQueue\n\t{\n\t\tusing CDtorFunc = void( GraphContext & );\n\t\tusing DtorFunc = std::function< CDtorFunc >;\n\t\tusing DtorFuncArray = std::vector< DtorFunc >;\n\n\tpublic:\n\t\tvoid push( DtorFunc func )\n\t\t{\n\t\t\tm_toDelete.push_back( std::move( func ) );\n\t\t}\n\n\t\tvoid clear( GraphContext & context )\n\t\t{\n\t\t\tDtorFuncArray tmp{ std::move( m_toDelete ) };\n\n\t\t\tfor ( DtorFunc const & func : tmp )\n\t\t\t{\n\t\t\t\tfunc( context );\n\t\t\t}\n\t\t}\n\n\tprivate:\n\t\tDtorFuncArray m_toDelete;\n\t};\n\n\tstruct GraphContext\n\t{\n\t\tGraphContext( GraphContext  const & ) = delete;\n\t\tGraphContext( GraphContext  && ) = delete;\n\t\tGraphContext & operator=( GraphContext  const & ) = delete;\n\t\tGraphContext & operator=( GraphContext  && ) = delete;\n\n\t\tCRG_API GraphContext( VkDevice device\n\t\t\t, VkPipelineCache cache\n\t\t\t, VkAllocationCallbacks const * allocator\n\t\t\t, VkPhysicalDeviceMemoryProperties memoryProperties\n\t\t\t, VkPhysicalDeviceProperties properties\n\t\t\t, bool separateDepthStencilLayouts\n\t\t\t, PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr );\n\t\tCRG_API ~GraphContext()noexcept;\n\n\t\tVkDevice device{};\n\t\tVkPipelineCache cache{};\n\t\tVkAllocationCallbacks const * allocator{};\n\t\tVkPhysicalDeviceMemoryProperties memoryProperties{};\n\t\tVkPhysicalDeviceProperties properties{};\n\t\tVkPhysicalDeviceFeatures features{};\n\t\tbool separateDepthStencilLayouts;\n\t\tDeletionQueue delQueue;\n\n#define DECL_vkFunction( name )\\\n\t\tPFN_vk##name vk##name{ nullptr }\n\n\t\tDECL_vkFunction( CreateGraphicsPipelines );\n\t\tDECL_vkFunction( CreateComputePipelines );\n\t\tDECL_vkFunction( DestroyPipeline );\n\t\tDECL_vkFunction( CreatePipelineLayout );\n\t\tDECL_vkFunction( DestroyPipelineLayout );\n\t\tDECL_vkFunction( CreateDescriptorSetLayout );\n\t\tDECL_vkFunction( DestroyDescriptorSetLayout );\n\t\tDECL_vkFunction( CreateDescriptorPool );\n\t\tDECL_vkFunction( DestroyDescriptorPool );\n\t\tDECL_vkFunction( AllocateDescriptorSets );\n\t\tDECL_vkFunction( FreeDescriptorSets );\n\t\tDECL_vkFunction( CreateBuffer );\n\t\tDECL_vkFunction( DestroyBuffer );\n\t\tDECL_vkFunction( CreateBufferView );\n\t\tDECL_vkFunction( DestroyBufferView );\n\t\tDECL_vkFunction( GetBufferMemoryRequirements );\n\t\tDECL_vkFunction( GetImageMemoryRequirements );\n\t\tDECL_vkFunction( AllocateMemory );\n\t\tDECL_vkFunction( FreeMemory );\n\t\tDECL_vkFunction( BindBufferMemory );\n\t\tDECL_vkFunction( BindImageMemory );\n\t\tDECL_vkFunction( MapMemory );\n\t\tDECL_vkFunction( UnmapMemory );\n\t\tDECL_vkFunction( FlushMappedMemoryRanges );\n\t\tDECL_vkFunction( InvalidateMappedMemoryRanges );\n\t\tDECL_vkFunction( CreateRenderPass );\n\t\tDECL_vkFunction( DestroyRenderPass );\n\t\tDECL_vkFunction( CreateFramebuffer );\n\t\tDECL_vkFunction( DestroyFramebuffer );\n\t\tDECL_vkFunction( CreateImage );\n\t\tDECL_vkFunction( DestroyImage );\n\t\tDECL_vkFunction( CreateImageView );\n\t\tDECL_vkFunction( DestroyImageView );\n\t\tDECL_vkFunction( CreateSampler );\n\t\tDECL_vkFunction( DestroySampler );\n\t\tDECL_vkFunction( CreateCommandPool );\n\t\tDECL_vkFunction( DestroyCommandPool );\n\t\tDECL_vkFunction( AllocateCommandBuffers );\n\t\tDECL_vkFunction( FreeCommandBuffers );\n\t\tDECL_vkFunction( CreateSemaphore );\n\t\tDECL_vkFunction( DestroySemaphore );\n\t\tDECL_vkFunction( UpdateDescriptorSets );\n\t\tDECL_vkFunction( BeginCommandBuffer );\n\t\tDECL_vkFunction( EndCommandBuffer );\n\t\tDECL_vkFunction( QueueSubmit );\n\t\tDECL_vkFunction( CreateQueryPool );\n\t\tDECL_vkFunction( DestroyQueryPool );\n\t\tDECL_vkFunction( GetQueryPoolResults );\n\t\tDECL_vkFunction( ResetCommandBuffer );\n\t\tDECL_vkFunction( CreateEvent );\n\t\tDECL_vkFunction( DestroyEvent );\n\t\tDECL_vkFunction( ResetEvent );\n\t\tDECL_vkFunction( SetEvent );\n\t\tDECL_vkFunction( GetEventStatus );\n\t\tDECL_vkFunction( CreateFence );\n\t\tDECL_vkFunction( DestroyFence );\n\t\tDECL_vkFunction( GetFenceStatus );\n\t\tDECL_vkFunction( WaitForFences );\n\t\tDECL_vkFunction( ResetFences );\n\n\t\tDECL_vkFunction( CmdBindPipeline );\n\t\tDECL_vkFunction( CmdBindDescriptorSets );\n\t\tDECL_vkFunction( CmdBindVertexBuffers );\n\t\tDECL_vkFunction( CmdBindIndexBuffer );\n\t\tDECL_vkFunction( CmdClearColorImage );\n\t\tDECL_vkFunction( CmdClearDepthStencilImage );\n\t\tDECL_vkFunction( CmdDispatch );\n\t\tDECL_vkFunction( CmdDispatchIndirect );\n\t\tDECL_vkFunction( CmdDraw );\n\t\tDECL_vkFunction( CmdDrawIndexed );\n\t\tDECL_vkFunction( CmdDrawIndexedIndirect );\n\t\tDECL_vkFunction( CmdDrawIndirect );\n\t\tDECL_vkFunction( CmdBeginRenderPass );\n\t\tDECL_vkFunction( CmdEndRenderPass );\n\t\tDECL_vkFunction( CmdPushConstants );\n\t\tDECL_vkFunction( CmdResetQueryPool );\n\t\tDECL_vkFunction( CmdWriteTimestamp );\n\t\tDECL_vkFunction( CmdPipelineBarrier );\n\t\tDECL_vkFunction( CmdBlitImage );\n\t\tDECL_vkFunction( CmdCopyBuffer );\n\t\tDECL_vkFunction( CmdCopyBufferToImage );\n\t\tDECL_vkFunction( CmdCopyImage );\n\t\tDECL_vkFunction( CmdCopyImageToBuffer );\n\t\tDECL_vkFunction( CmdExecuteCommands );\n\t\tDECL_vkFunction( CmdResetEvent );\n\t\tDECL_vkFunction( CmdSetEvent );\n\t\tDECL_vkFunction( CmdWaitEvents );\n\t\tDECL_vkFunction( CmdFillBuffer );\n\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n#\tif VK_EXT_debug_utils\n\t\tDECL_vkFunction( SetDebugUtilsObjectNameEXT );\n\t\tDECL_vkFunction( CmdBeginDebugUtilsLabelEXT );\n\t\tDECL_vkFunction( CmdEndDebugUtilsLabelEXT );\n#\tendif\n#\tif VK_EXT_debug_marker\n\t\tDECL_vkFunction( DebugMarkerSetObjectNameEXT );\n\t\tDECL_vkFunction( CmdDebugMarkerBeginEXT );\n\t\tDECL_vkFunction( CmdDebugMarkerEndEXT );\n#\tendif\n#undef DECL_vkFunction\n\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n\t\t/**\n\t\t*\\brief\n\t\t*\tBegins a command buffer label.\n\t\t*\\param[in] labelInfo\n\t\t*\tThe parameters of the label to begin.\n\t\t*/\n\t\tCRG_API void vkCmdBeginDebugBlock( VkCommandBuffer commandBuffer\n\t\t\t, DebugBlockInfo const & labelInfo )const;\n\t\t/**\n\t\t*\\brief\n\t\t*\tEnds the command label.\n\t\t*/\n\t\tCRG_API void vkCmdEndDebugBlock( VkCommandBuffer commandBuffer )const;\n#endif\n\t\tCRG_API std::array< float, 4u > getNextRainbowColour()const;\n\t\tCRG_API uint32_t deduceMemoryType( uint32_t typeBits\n\t\t\t, VkMemoryPropertyFlags requirements )const;\n\n\tprivate:\n\t\tfriend class ResourceHandler;\n\t\tstruct ObjectAllocation\n\t\t{\n\t\t\tstd::string type;\n\t\t\tstd::string name;\n\t\t\tstd::string callstack;\n\t\t};\n\n\t\tusing CallstackCallback = std::function< std::string() >;\n\t\tCallstackCallback m_callstackCallback;\n\t\tstd::mutex m_mutex;\n\t\tstd::unordered_map< size_t, ObjectAllocation > m_allocated;\n\n\tpublic:\n\t\tvoid setCallstackCallback( CallstackCallback callback )\n\t\t{\n\t\t\tm_callstackCallback = std::move( callback );\n\t\t}\n\n\t\ttemplate< typename ObjectT >\n\t\tstatic void stRegisterObject( GraphContext & context\n\t\t\t, std::string const & name\n\t\t\t, ObjectT object )\n\t\t{\n\t\t\tusing MyTraits = DebugTypeTraits< ObjectT >;\n\t\t\tcontext.doRegisterObject( uint64_t( object )\n#if VK_EXT_debug_utils\n\t\t\t\t, uint32_t( MyTraits::UtilsValue )\n#elif VK_EXT_debug_marker\n\t\t\t\t, uint32_t( MyTraits::ReportValue )\n#endif\n\t\t\t\t, name\n\t\t\t\t, MyTraits::Name );\n\t\t}\n\n\t\ttemplate< typename ObjectT >\n\t\tstatic void stRegisterObjectName( GraphContext & context\n\t\t\t, std::string const & name\n\t\t\t, ObjectT object )\n\t\t{\n\t\t\tusing MyTraits = DebugTypeTraits< ObjectT >;\n\t\t\tcontext.doRegisterObjectName( uint64_t( object )\n#if VK_EXT_debug_utils\n\t\t\t\t, uint32_t( MyTraits::UtilsValue )\n#elif VK_EXT_debug_marker\n\t\t\t\t, uint32_t( MyTraits::ReportValue )\n#endif\n\t\t\t\t, name );\n\t\t}\n\n\t\ttemplate< typename ObjectT >\n\t\tstatic void stUnregisterObject( GraphContext & context, ObjectT object )\n\t\t{\n\t\t\tcontext.doUnregisterObject( uint64_t( object ) );\n\t\t}\n\n\tprivate:\n#if VK_EXT_debug_utils\n\t\t/**\n\t\t*\\brief\n\t\t*\tBegins a command buffer label.\n\t\t*\\param[in] labelInfo\n\t\t*\tThe parameters of the label to begin.\n\t\t*/\n\t\tvoid doBeginDebugUtilsLabel( VkCommandBuffer commandBuffer\n\t\t\t, VkDebugUtilsLabelEXT const & labelInfo )const;\n\t\t/**\n\t\t*\\brief\n\t\t*\tEnds the command label.\n\t\t*/\n\t\tvoid doEndDebugUtilsLabel( VkCommandBuffer commandBuffer )const;\n#endif\n#if VK_EXT_debug_marker\n\t\t/**\n\t\t*\\brief\n\t\t*\tBegins a command buffer label.\n\t\t*\\param[in] labelInfo\n\t\t*\tThe parameters of the label to begin.\n\t\t*/\n\t\tvoid doDebugMarkerBegin( VkCommandBuffer commandBuffer\n\t\t\t, VkDebugMarkerMarkerInfoEXT const & labelInfo )const;\n\t\t/**\n\t\t*\\brief\n\t\t*\tEnds the command label.\n\t\t*/\n\t\tvoid doDebugMarkerEnd( VkCommandBuffer commandBuffer )const;\n#endif\n\n\t\tCRG_API void doRegisterObject( uint64_t object\n\t\t\t, uint32_t objectType\n\t\t\t, std::string const & name\n\t\t\t, std::string const & typeName );\n\t\tCRG_API void doRegisterObjectName( uint64_t object\n\t\t\t, uint32_t objectType\n\t\t\t, std::string const & name );\n\t\tCRG_API void doUnregisterObject( uint64_t object );\n\n#\tdefine crgRegisterObject( Cont, TypeName, Object )\\\n\t\tcrg::GraphContext::stRegisterObject( Cont, TypeName, Object )\n#\tdefine crgUnregisterObject( Cont, Object )\\\n\t\tcrg::GraphContext::stUnregisterObject( Cont, Object )\n\n#\tdefine crgRegisterObjectName( Cont, TypeName, Object )\\\n\t\tcrg::GraphContext::stRegisterObjectName( Cont, TypeName, Object )\n#else\n#\tdefine crgRegisterObject( Cont, TypeName, Object )\n#\tdefine crgUnregisterObject( Cont, Object )\n#\tdefine crgRegisterObjectName( Cont, TypeName, Object )\n#endif\n\t};\n\n\tCRG_API void checkVkResult( VkResult result, char const * const stepName );\n\tCRG_API void checkVkResult( VkResult result, std::string const & stepName );\n}\n"
  },
  {
    "path": "include/RenderGraph/GraphNode.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/AttachmentTransition.hpp\"\n\n#include <cassert>\n#include <map>\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tBase class for all graph nodes\n\t*\\remarks\n\t*\tIt holds a name, the next nodes, and its dependencies from the previous nodes.\n\t*/\n\tstruct GraphNode\n\t{\n\t\tenum class Kind\n\t\t{\n\t\t\tUndefined,\n\t\t\tRoot,\n\t\t\tFramePass,\n\t\t};\n\n\t\tGraphNode & operator=( GraphNode && rhs )noexcept = default;\n\t\tCRG_API virtual ~GraphNode()noexcept;\n\t\tCRG_API GraphNode( GraphNode && rhs )noexcept;\n\n\t\tCRG_API void attachNode( GraphNode & child );\n\n\t\tCRG_API virtual void accept( GraphVisitor * vis )const = 0;\n\n\t\tvoid setTransitions( AttachmentTransitions transitions )noexcept\n\t\t{\n\t\t\tm_transitions = std::move( transitions );\n\t\t}\n\n\t\ttemplate< typename NodeT >\n\t\tNodeT const & cast()const noexcept\n\t\t{\n\t\t\tassert( kind == NodeT::MyKind );\n\t\t\treturn static_cast< NodeT const & >( *this );\n\t\t}\n\n\t\ttemplate< typename NodeT >\n\t\tNodeT & cast()noexcept\n\t\t{\n\t\t\tassert( kind == NodeT::MyKind );\n\t\t\treturn static_cast< NodeT & >( *this );\n\t\t}\n\n\t\tKind getKind()const noexcept\n\t\t{\n\t\t\treturn kind;\n\t\t}\n\n\t\tstd::string const & getName()const noexcept\n\t\t{\n\t\t\treturn name;\n\t\t}\n\n\t\tFramePassGroup const & getGroup()const noexcept\n\t\t{\n\t\t\treturn *group;\n\t\t}\n\n\t\tuint32_t getId()const noexcept\n\t\t{\n\t\t\treturn id;\n\t\t}\n\n\t\tGraphAdjacentNodeArray const & getPredecessors()const noexcept\n\t\t{\n\t\t\treturn prev;\n\t\t}\n\n\t\tGraphAdjacentNodeArray & getPredecessors()noexcept\n\t\t{\n\t\t\treturn prev;\n\t\t}\n\n\t\tImageTransitionArray const & getImageTransitions()const noexcept\n\t\t{\n\t\t\treturn m_transitions.imageTransitions;\n\t\t}\n\n\t\tBufferTransitionArray const & getBufferTransitions()const noexcept\n\t\t{\n\t\t\treturn m_transitions.bufferTransitions;\n\t\t}\n\n\tprotected:\n\t\tCRG_API GraphNode( Kind kind\n\t\t\t, uint32_t id\n\t\t\t, std::string name\n\t\t\t, FramePassGroup const & group );\n\n\tprivate:\n\t\tGraphNode( GraphNode const & ) = delete;\n\t\tGraphNode & operator=( GraphNode const & ) = delete;\n\n\tprivate:\n\t\tKind kind{};\n\t\tuint32_t id{};\n\t\tstd::string name{};\n\t\tFramePassGroup const * group;\n\t\tGraphAdjacentNodeArray prev{};\n\t\tAttachmentTransitions m_transitions{};\n\t};\n\t/**\n\t*\\brief\n\t*\tGraph node coming from a render pass\n\t*\\remarks\n\t*\tThe node name wil be the FramePass name.\n\t*/\n\tstruct FramePassNode\n\t\t: public GraphNode\n\t{\n\t\tstatic constexpr Kind MyKind = Kind::FramePass;\n\n\t\tFramePassNode & operator=( FramePassNode && rhs )noexcept = default;\n\t\tFramePassNode( FramePassNode && rhs )noexcept = default;\n\t\tCRG_API ~FramePassNode()noexcept override;\n\n\t\tCRG_API explicit FramePassNode( FramePass const & pass );\n\t\tCRG_API void accept( GraphVisitor * vis )const override;\n\n\t\tFramePass const & getFramePass()const\n\t\t{\n\t\t\treturn *pass;\n\t\t}\n\n\tprivate:\n\t\tFramePassNode( FramePassNode const & ) = delete;\n\t\tFramePassNode & operator=( FramePassNode const & ) = delete;\n\n\tprivate:\n\t\tFramePass const * pass;\n\t};\n\t/**\n\t*\\brief\n\t*\tRoot node for the graph.\n\t*\\remarks\n\t*\tLogically, it has no dependency with a previous node.\n\t*/\n\tstruct RootNode\n\t\t: public GraphNode\n\t{\n\t\tstatic constexpr Kind MyKind = Kind::Root;\n\n\t\tRootNode & operator=( RootNode && rhs )noexcept = default;\n\t\tRootNode( RootNode && rhs )noexcept = default;\n\t\tCRG_API ~RootNode()noexcept override;\n\n\t\tCRG_API explicit RootNode( FrameGraph const & graph );\n\t\tCRG_API void accept( GraphVisitor * vis )const override;\n\n\t\tFrameGraph const & getFrameGraph()const\n\t\t{\n\t\t\treturn *graph;\n\t\t}\n\n\tprivate:\n\t\tRootNode( RootNode const & ) = delete;\n\t\tRootNode & operator=( RootNode const & ) = delete;\n\n\tprivate:\n\t\tFrameGraph const * graph;\n\t};\n\n\tCRG_API FramePass const * getFramePass( GraphNode const & node );\n\n\tinline bool isFramePassNode( GraphNode const & node )\n\t{\n\t\treturn node.getKind() == FramePassNode::MyKind;\n\t}\n\n\tinline bool isRootNode( GraphNode const & node )\n\t{\n\t\treturn node.getKind() == RootNode::MyKind;\n\t}\n\n\tinline bool isFramePassNode( ConstGraphAdjacentNode node )\n\t{\n\t\treturn node && isFramePassNode( *node );\n\t}\n\n\tinline bool isRootNode( ConstGraphAdjacentNode node )\n\t{\n\t\treturn node && isRootNode( *node );\n\t}\n\n\ttemplate< typename NodeT >\n\tNodeT const & nodeCast( GraphNode const & node )\n\t{\n\t\treturn node.cast< NodeT >();\n\t}\n\n\ttemplate< typename NodeT >\n\tNodeT & nodeCast( GraphNode & node )\n\t{\n\t\treturn node.cast< NodeT >();\n\t}\n}\n"
  },
  {
    "path": "include/RenderGraph/GraphVisitor.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/GraphNode.hpp\"\n\nnamespace crg\n{\n\tclass GraphVisitor\n\t{\n\tpublic:\n\t\tvirtual ~GraphVisitor()noexcept = default;\n\t\tCRG_API virtual void visitRootNode( RootNode const * node ) = 0;\n\t\tCRG_API virtual void visitFramePassNode( FramePassNode const * node ) = 0;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/Hash.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\nnamespace crg\n{\n\ttemplate< typename T >\n\tinline size_t hashCombine( size_t hash\n\t\t, T const & rhs )\n\t{\n\t\tconst uint64_t kMul = 0x9ddfea08eb382d69ULL;\n\t\tauto seed = hash;\n\n\t\tstd::hash< T > hasher;\n\t\tuint64_t a = ( hasher( rhs ) ^ seed ) * kMul;\n\t\ta ^= ( a >> 47 );\n\n\t\tuint64_t b = ( seed ^ a ) * kMul;\n\t\tb ^= ( b >> 47 );\n\n#pragma warning( push )\n#pragma warning( disable: 4068 )\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wuseless-cast\"\n\t\thash = static_cast< std::size_t >( b * kMul );\n#pragma GCC diagnostic pop\n#pragma clang diagnostic pop\n#pragma warning( pop )\n\t\treturn hash;\n\t}\n\n}\n"
  },
  {
    "path": "include/RenderGraph/Id.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\nnamespace crg\n{\n\ttemplate< typename TypeT >\n\tstruct Id\n\t{\n\t\tuint32_t id;\n\t\tTypeT const * data;\n\n\t\texplicit Id( uint32_t id = 0u\n\t\t\t, TypeT const * data = nullptr )\n\t\t\t: id{ id }\n\t\t\t, data{ data }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( Id const & lhs, Id const & rhs )\n\t\t{\n\t\t\treturn lhs.id == rhs.id;\n\t\t}\n\t};\n\n\ttemplate< typename TypeT >\n\tinline bool operator<( Id< TypeT > const & lhs, Id< TypeT > const & rhs )\n\t{\n\t\treturn lhs.id < rhs.id;\n\t}\n\n\ttemplate< typename TypeT >\n\tinline bool operator>( Id< TypeT > const & lhs, Id< TypeT > const & rhs )\n\t{\n\t\treturn lhs.id > rhs.id;\n\t}\n}\n"
  },
  {
    "path": "include/RenderGraph/ImageData.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Id.hpp\"\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tBasic image data, from which images will be created.\n\t*/\n\tstruct ImageData\n\t{\n\t\tstd::string name;\n\t\tImageCreateInfo info;\n\n\t\texplicit ImageData( std::string name = {}\n\t\t\t, ImageCreateFlags flags = {}\n\t\t\t, ImageType imageType = {}\n\t\t\t, PixelFormat format = {}\n\t\t\t, Extent3D extent = {}\n\t\t\t, ImageUsageFlags usage = {}\n\t\t\t, uint32_t mipLevels = 1u\n\t\t\t, uint32_t arrayLayers = 1u\n\t\t\t, SampleCount samples = SampleCount::e1\n\t\t\t, ImageTiling tiling = ImageTiling::eOptimal\n\t\t\t, MemoryPropertyFlags memory = MemoryPropertyFlags::eDeviceLocal )\n\t\t\t: name{ std::move( name ) }\n\t\t\t, info{ flags, imageType, format\n\t\t\t\t, extent, mipLevels, arrayLayers, samples\n\t\t\t\t, tiling, usage, memory }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( ImageData const & lhs, ImageData const & rhs ) = default;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/ImageViewData.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Id.hpp\"\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tBasic image view data, from which views will be created.\n\t*/\n\tstruct ImageViewData\n\t{\n\t\tstd::string name;\n\t\tImageId image;\n\t\tImageViewCreateInfo info;\n\t\tImageViewIdArray source{};\n\n\t\texplicit ImageViewData( std::string name = {}\n\t\t\t, ImageId image = ImageId{}\n\t\t\t, ImageViewCreateFlags flags = {}\n\t\t\t, ImageViewType viewType = {}\n\t\t\t, PixelFormat format = {}\n\t\t\t, ImageSubresourceRange subresourceRange = {} )\n\t\t\t: name{ std::move( name ) }\n\t\t\t, image{ std::move( image ) }\n\t\t\t, info{ flags, viewType, format, subresourceRange }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tfriend bool operator==( ImageViewData const & lhs, ImageViewData const & rhs )\n\t\t{\n\t\t\treturn lhs.image == rhs.image\n\t\t\t\t&& lhs.info == rhs.info;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/LayerLayoutStatesHandler.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"FrameGraphPrerequisites.hpp\"\n\nnamespace crg\n{\n\tstruct LayerLayoutStatesHandler\n\t{\n\t\tLayerLayoutStatesHandler() = default;\n\t\tCRG_API explicit LayerLayoutStatesHandler( LayerLayoutStatesMap const & rhs );\n\t\tCRG_API void addStates( LayerLayoutStatesHandler const & data );\n\n\t\tCRG_API void setLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, LayoutState const & layoutState );\n\t\tCRG_API void setLayoutState( crg::ImageViewId view\n\t\t\t, LayoutState const & layoutState );\n\t\tCRG_API LayoutState getLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange )const;\n\t\tCRG_API LayoutState getLayoutState( ImageViewId view )const;\n\n\t\tLayerLayoutStatesMap images;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/Log.hpp",
    "content": "/*\nSee LICENSE file in root folder\n*/\n#ifndef ___CRG_Log_H___\n#define ___CRG_Log_H___\n\n#include \"FrameGraphPrerequisites.hpp\"\n\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 5262 )\n#include <functional>\n#include <memory>\n#include <sstream>\n#include <string>\n#pragma warning( pop )\n\nnamespace crg\n{\n\tclass Logger\n\t{\n\tpublic:\n\t\tusing LogCallback = void( * )( std::string_view msg, bool newLine )noexcept;\n\n\tpublic:\n\t\t/**\n\t\t*\\brief\n\t\t*\tLogs a trace message.\n\t\t*/\n\t\tCRG_API static void logTrace( std::string_view message, bool newLine = true )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tLogs a debug message.\n\t\t*/\n\t\tCRG_API static void logDebug( std::string_view message, bool newLine = true )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tLogs an info message.\n\t\t*/\n\t\tCRG_API static void logInfo( std::string_view message, bool newLine = true )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tLogs a warning message.\n\t\t*/\n\t\tCRG_API static void logWarning( std::string_view message, bool newLine = true )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tLogs an error message.\n\t\t*/\n\t\tCRG_API static void logError( std::string_view message, bool newLine = true )noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tSets the trace callback.\n\t\t*/\n\t\tCRG_API static void setTraceCallback( LogCallback callback );\n\t\t/**\n\t\t*\\brief\n\t\t*\tSets the debug callback.\n\t\t*/\n\t\tCRG_API static void setDebugCallback( LogCallback callback );\n\t\t/**\n\t\t*\\brief\n\t\t*\tSets the info callback.\n\t\t*/\n\t\tCRG_API static void setInfoCallback( LogCallback callback );\n\t\t/**\n\t\t*\\brief\n\t\t*\tSets the warning callback.\n\t\t*/\n\t\tCRG_API static void setWarningCallback( LogCallback callback );\n\t\t/**\n\t\t*\\brief\n\t\t*\tSets the error callback.\n\t\t*/\n\t\tCRG_API static void setErrorCallback( LogCallback callback );\n\n\tprivate:\n\t\tLogger();\n\n\t\tstatic Logger & doGetInstance()noexcept;\n\n\tprivate:\n\t\tLogCallback m_trace;\n\t\tLogCallback m_debug;\n\t\tLogCallback m_info;\n\t\tLogCallback m_warning;\n\t\tLogCallback m_error;\n\t};\n}\n\n#endif\n"
  },
  {
    "path": "include/RenderGraph/PixelFormat.inl",
    "content": "/*\nSee LICENSE file in root folder\n*/\n#ifndef RGPF_ENUM_NON_VALUE\n#\tdefine RGPF_ENUM_NON_VALUE( x, y )\n#endif\n\n#ifndef RGPF_ENUM_BEGIN\n#\tdefine RGPF_ENUM_BEGIN( x )\n#endif\n\n#ifndef RGPF_ENUM_END\n#\tdefine RGPF_ENUM_END( x )\n#endif\n\n#ifndef RGPF_ENUM_VALUE\n#\tdefine RGPF_ENUM_VALUE( name, value, components, alpha, colour, depth, stencil, compressed )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_COLOR\n#\tdefine RGPF_ENUM_VALUE_COLOR( name, value, components, alpha ) RGPF_ENUM_VALUE( name, value, components, alpha, true, false, false, false )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_DEPTH_OR_STENCIL\n#\tdefine RGPF_ENUM_VALUE_DEPTH_OR_STENCIL( name, value, components, depth, stencil ) RGPF_ENUM_VALUE( name, value, 1, false, false, depth, stencil, false )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_DEPTH_STENCIL\n#\tdefine RGPF_ENUM_VALUE_DEPTH_STENCIL( name, value ) RGPF_ENUM_VALUE_DEPTH_OR_STENCIL( name, value, 2, true, true )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_DEPTH\n#\tdefine RGPF_ENUM_VALUE_DEPTH( name, value ) RGPF_ENUM_VALUE_DEPTH_OR_STENCIL( name, value, 1, true, false )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_STENCIL\n#\tdefine RGPF_ENUM_VALUE_STENCIL( name, value ) RGPF_ENUM_VALUE_DEPTH_OR_STENCIL( name, value, 1, false, true )\n#endif\n\n#ifndef RGPF_ENUM_VALUE_COMPRESSED\n#\tdefine RGPF_ENUM_VALUE_COMPRESSED( name, value, components, alpha ) RGPF_ENUM_VALUE( name, value, components, alpha, true, false, false, false )\n#endif\n\nRGPF_ENUM_BEGIN( PixelFormat )\nRGPF_ENUM_VALUE( UNDEFINED, 0, 0, false, false, false, false, false )\n\nRGPF_ENUM_VALUE_COLOR( R4G4_UNORM, 1, 2, false )\nRGPF_ENUM_VALUE_COLOR( R4G4B4A4_UNORM, 2, 4, true )\nRGPF_ENUM_VALUE_COLOR( B4G4R4A4_UNORM, 3, 4, true )\nRGPF_ENUM_VALUE_COLOR( R5G6B5_UNORM, 4, 3, false )\nRGPF_ENUM_VALUE_COLOR( B5G6R5_UNORM, 5, 3, false )\nRGPF_ENUM_VALUE_COLOR( R5G5B5A1_UNORM, 6, 4, true )\nRGPF_ENUM_VALUE_COLOR( B5G5R5A1_UNORM, 7, 4, true )\nRGPF_ENUM_VALUE_COLOR( A1R5G5B5_UNORM, 8, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( R8_UNORM, 9, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_SNORM, 10, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_USCALED, 11, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_SSCALED, 12, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_UINT, 13, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_SINT, 14, 1, false )\nRGPF_ENUM_VALUE_COLOR( R8_SRGB, 15, 1, false )\n\nRGPF_ENUM_VALUE_COLOR( R8G8_UNORM, 16, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_SNORM, 17, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_USCALED, 18, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_SSCALED, 19, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_UINT, 20, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_SINT, 21, 2, false )\nRGPF_ENUM_VALUE_COLOR( R8G8_SRGB, 22, 2, false )\n\nRGPF_ENUM_VALUE_COLOR( R8G8B8_UNORM, 23, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_SNORM, 24, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_USCALED, 25, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_SSCALED, 26, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_UINT, 27, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_SINT, 28, 3, false )\nRGPF_ENUM_VALUE_COLOR( R8G8B8_SRGB, 29, 3, false )\n\nRGPF_ENUM_VALUE_COLOR( B8G8R8_UNORM, 30, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_SNORM, 31, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_USCALED, 32, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_SSCALED, 33, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_UINT, 34, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_SINT, 35, 3, false )\nRGPF_ENUM_VALUE_COLOR( B8G8R8_SRGB, 36, 3, false )\n\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_UNORM, 37, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_SNORM, 38, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_USCALED, 39, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_SSCALED, 40, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_UINT, 41, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_SINT, 42, 4, true )\nRGPF_ENUM_VALUE_COLOR( R8G8B8A8_SRGB, 43, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_UNORM, 44, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_SNORM, 45, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_USCALED, 46, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_SSCALED, 47, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_UINT, 48, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_SINT, 49, 4, true )\nRGPF_ENUM_VALUE_COLOR( B8G8R8A8_SRGB, 50, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_UNORM, 51, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_SNORM, 52, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_USCALED, 53, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_SSCALED, 54, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_UINT, 55, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_SINT, 56, 4, true )\nRGPF_ENUM_VALUE_COLOR( A8B8G8R8_SRGB, 57, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_UNORM, 58, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_SNORM, 59, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_USCALED, 60, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_SSCALED, 61, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_UINT, 62, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2R10G10B10_SINT, 63, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_UNORM, 64, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_SNORM, 65, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_USCALED, 66, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_SSCALED, 67, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_UINT, 68, 4, true )\nRGPF_ENUM_VALUE_COLOR( A2B10G10R10_SINT, 69, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( R16_UNORM, 70, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_SNORM, 71, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_USCALED, 72, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_SSCALED, 73, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_UINT, 74, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_SINT, 75, 1, false )\nRGPF_ENUM_VALUE_COLOR( R16_SFLOAT, 76, 1, false )\n\nRGPF_ENUM_VALUE_COLOR( R16G16_UNORM, 77, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_SNORM, 78, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_USCALED, 79, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_SSCALED, 80, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_UINT, 81, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_SINT, 82, 2, false )\nRGPF_ENUM_VALUE_COLOR( R16G16_SFLOAT, 83, 2, false )\n\nRGPF_ENUM_VALUE_COLOR( R16G16B16_UNORM, 84, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_SNORM, 85, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_USCALED, 86, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_SSCALED, 87, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_UINT, 88, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_SINT, 89, 3, false )\nRGPF_ENUM_VALUE_COLOR( R16G16B16_SFLOAT, 90, 3, false )\n\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_UNORM, 91, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_SNORM, 92, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_USCALED, 93, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_SSCALED, 94, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_UINT, 95, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_SINT, 96, 4, true )\nRGPF_ENUM_VALUE_COLOR( R16G16B16A16_SFLOAT, 97, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( R32_UINT, 98, 1, false )\nRGPF_ENUM_VALUE_COLOR( R32_SINT, 99, 1, false )\nRGPF_ENUM_VALUE_COLOR( R32_SFLOAT, 100, 1, false )\n\nRGPF_ENUM_VALUE_COLOR( R32G32_UINT, 101, 2, false )\nRGPF_ENUM_VALUE_COLOR( R32G32_SINT, 102, 2, false )\nRGPF_ENUM_VALUE_COLOR( R32G32_SFLOAT, 103, 2, false )\n\nRGPF_ENUM_VALUE_COLOR( R32G32B32_UINT, 104, 3, false )\nRGPF_ENUM_VALUE_COLOR( R32G32B32_SINT, 105, 3, false )\nRGPF_ENUM_VALUE_COLOR( R32G32B32_SFLOAT, 106, 3, false )\n\nRGPF_ENUM_VALUE_COLOR( R32G32B32A32_UINT, 107, 4, true )\nRGPF_ENUM_VALUE_COLOR( R32G32B32A32_SINT, 108, 4, true )\nRGPF_ENUM_VALUE_COLOR( R32G32B32A32_SFLOAT, 109, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( R64_UINT, 110, 1, false )\nRGPF_ENUM_VALUE_COLOR( R64_SINT, 111, 1, false )\nRGPF_ENUM_VALUE_COLOR( R64_SFLOAT, 112, 1, false )\n\nRGPF_ENUM_VALUE_COLOR( R64G64_UINT, 113, 2, false )\nRGPF_ENUM_VALUE_COLOR( R64G64_SINT, 114, 2, false )\nRGPF_ENUM_VALUE_COLOR( R64G64_SFLOAT, 115, 2, false )\n\nRGPF_ENUM_VALUE_COLOR( R64G64B64_UINT, 116, 3, false )\nRGPF_ENUM_VALUE_COLOR( R64G64B64_SINT, 117, 3, false )\nRGPF_ENUM_VALUE_COLOR( R64G64B64_SFLOAT, 118, 3, false )\n\nRGPF_ENUM_VALUE_COLOR( R64G64B64A64_UINT, 119, 4, true )\nRGPF_ENUM_VALUE_COLOR( R64G64B64A64_SINT, 120, 4, true )\nRGPF_ENUM_VALUE_COLOR( R64G64B64A64_SFLOAT, 121, 4, true )\n\nRGPF_ENUM_VALUE_COLOR( B10G11R11_UFLOAT, 122, 3, false )\nRGPF_ENUM_VALUE_COLOR( E5B9G9R9_UFLOAT, 123, 3, false )\n\nRGPF_ENUM_VALUE_DEPTH( D16_UNORM, 124 )\nRGPF_ENUM_VALUE_DEPTH( X8_D24_UNORM, 125 )\nRGPF_ENUM_VALUE_DEPTH( D32_SFLOAT, 126 )\nRGPF_ENUM_VALUE_STENCIL( S8_UINT, 127 )\nRGPF_ENUM_VALUE_DEPTH_STENCIL( D16_UNORM_S8_UINT, 128 )\nRGPF_ENUM_VALUE_DEPTH_STENCIL( D24_UNORM_S8_UINT, 129 )\nRGPF_ENUM_VALUE_DEPTH_STENCIL( D32_SFLOAT_S8_UINT, 130 )\n\nRGPF_ENUM_VALUE_COMPRESSED( BC1_RGB_UNORM_BLOCK, 131, 3, false ) // RGB_DXT1\nRGPF_ENUM_VALUE_COMPRESSED( BC1_RGB_SRGB_BLOCK, 132, 3, false ) // RGB_DXT1\nRGPF_ENUM_VALUE_COMPRESSED( BC1_RGBA_UNORM_BLOCK, 133, 4, true ) // RGBA_DXT1\nRGPF_ENUM_VALUE_COMPRESSED( BC1_RGBA_SRGB_BLOCK, 134, 4, true ) // RGBA_DXT1\nRGPF_ENUM_VALUE_COMPRESSED( BC2_UNORM_BLOCK, 135, 4, true ) // RGBA_DXT3\nRGPF_ENUM_VALUE_COMPRESSED( BC2_SRGB_BLOCK, 136, 4, true ) // RGBA_DXT3\nRGPF_ENUM_VALUE_COMPRESSED( BC3_UNORM_BLOCK, 137, 4, true ) // RGBA_DXT5\nRGPF_ENUM_VALUE_COMPRESSED( BC3_SRGB_BLOCK, 138, 4, true ) // RGBA_DXT5\nRGPF_ENUM_VALUE_COMPRESSED( BC4_UNORM_BLOCK, 139, 1, false ) // R_ATI1N\nRGPF_ENUM_VALUE_COMPRESSED( BC4_SNORM_BLOCK, 140, 1, false ) // R_ATI1N\nRGPF_ENUM_VALUE_COMPRESSED( BC5_UNORM_BLOCK, 141, 2, false ) // RG_ATI2N\nRGPF_ENUM_VALUE_COMPRESSED( BC5_SNORM_BLOCK, 142, 2, false ) // RG_ATI2N\nRGPF_ENUM_VALUE_COMPRESSED( BC6H_UFLOAT_BLOCK, 143, 3, false ) // RGB_BP\nRGPF_ENUM_VALUE_COMPRESSED( BC6H_SFLOAT_BLOCK, 144, 3, false ) // RGB_BP\nRGPF_ENUM_VALUE_COMPRESSED( BC7_UNORM_BLOCK, 145, 4, true ) // RGBA_BP\nRGPF_ENUM_VALUE_COMPRESSED( BC7_SRGB_BLOCK, 146, 4, true ) // RGBA_BP\n\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8_UNORM_BLOCK, 147, 3, false )\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8_SRGB_BLOCK, 148, 3, false )\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8A1_UNORM_BLOCK, 149, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8A1_SRGB_BLOCK, 150, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8A8_UNORM_BLOCK, 151, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ETC2_R8G8B8A8_SRGB_BLOCK, 152, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( EAC_R11_UNORM_BLOCK, 153, 1, false )\nRGPF_ENUM_VALUE_COMPRESSED( EAC_R11_SNORM_BLOCK, 154, 1, false )\nRGPF_ENUM_VALUE_COMPRESSED( EAC_R11G11_UNORM_BLOCK, 155, 2, false )\nRGPF_ENUM_VALUE_COMPRESSED( EAC_R11G11_SNORM_BLOCK, 156, 2, false )\n\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_4x4_UNORM_BLOCK, 157, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_4x4_SRGB_BLOCK, 158, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_5x4_UNORM_BLOCK, 159, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_5x4_SRGB_BLOCK, 160, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_5x5_UNORM_BLOCK, 161, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_5x5_SRGB_BLOCK, 162, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_6x5_UNORM_BLOCK, 163, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_6x5_SRGB_BLOCK, 164, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_6x6_UNORM_BLOCK, 165, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_6x6_SRGB_BLOCK, 166, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x5_UNORM_BLOCK, 167, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x5_SRGB_BLOCK, 168, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x6_UNORM_BLOCK, 169, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x6_SRGB_BLOCK, 170, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x8_UNORM_BLOCK, 171, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_8x8_SRGB_BLOCK, 172, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x5_UNORM_BLOCK, 173, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x5_SRGB_BLOCK, 174, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x6_UNORM_BLOCK, 175, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x6_SRGB_BLOCK, 176, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x8_UNORM_BLOCK, 177, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x8_SRGB_BLOCK, 178, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x10_UNORM_BLOCK, 179, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_10x10_SRGB_BLOCK, 180, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_12x10_UNORM_BLOCK, 181, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_12x10_SRGB_BLOCK, 182, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_12x12_UNORM_BLOCK, 183, 4, true )\nRGPF_ENUM_VALUE_COMPRESSED( ASTC_12x12_SRGB_BLOCK, 184, 4, true )\n\nRGPF_ENUM_NON_VALUE( COUNT, 185 )\nRGPF_ENUM_END( PixelFormat )\n\n#undef RGPF_ENUM_BEGIN\n#undef RGPF_ENUM_END\n#undef RGPF_ENUM_NON_VALUE\n#undef RGPF_ENUM_VALUE\n#undef RGPF_ENUM_VALUE_COLOR\n#undef RGPF_ENUM_VALUE_DEPTH_OR_STENCIL\n#undef RGPF_ENUM_VALUE_DEPTH_STENCIL\n#undef RGPF_ENUM_VALUE_DEPTH\n#undef RGPF_ENUM_VALUE_STENCIL\n#undef RGPF_ENUM_VALUE_COMPRESSED\n"
  },
  {
    "path": "include/RenderGraph/RecordContext.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"Attachment.hpp\"\n#include \"LayerLayoutStatesHandler.hpp\"\n\n#include <functional>\n#include <map>\n#include <vector>\n\nnamespace crg\n{\n\tclass RecordContext\n\t{\n\tpublic:\n\t\tusing PassIndexArray = std::vector< uint32_t >;\n\t\tusing GraphIndexMap = std::map< FrameGraph const *, PassIndexArray >;\n\t\tusing ImplicitAction = std::function< void( RecordContext &, VkCommandBuffer, uint32_t ) >;\n\n\t\tstruct ImplicitImageTransition\n\t\t{\n\t\t\tRunnablePass const * pass;\n\t\t\tImageViewId view;\n\t\t\tImplicitAction action;\n\t\t};\n\n\t\tstruct ImplicitBufferTransition\n\t\t{\n\t\t\tRunnablePass const * pass;\n\t\t\tBufferViewId view;\n\t\t\tImplicitAction action;\n\t\t};\n\n\tpublic:\n\t\tCRG_API explicit RecordContext( ContextResourcesCache & resources );\n\t\tCRG_API explicit RecordContext( ResourceHandler & handler );\n\t\t/**\n\t\t*\\name\tStates\n\t\t*/\n\t\t//@{\n\t\tCRG_API void addStates( RecordContext const & data );\n\t\t/**\n\t\t*\\name\tPipeline\n\t\t*/\n\t\t//@{\n\t\tCRG_API void setNextPipelineState( PipelineState const & state\n\t\t\t, LayerLayoutStatesMap const & imageLayouts );\n\t\t//@}\n\t\t/**\n\t\t*\\name\tImages\n\t\t*/\n\t\t//@{\n\t\tCRG_API void setLayoutState( crg::ImageViewId view\n\t\t\t, LayoutState const & layoutState );\n\t\tCRG_API LayoutState getLayoutState( ImageViewId view )const;\n\n\t\tCRG_API void setLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, LayoutState const & layoutState );\n\t\tCRG_API LayoutState getLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange )const;\n\n\t\tCRG_API LayoutState getNextLayoutState( ImageViewId view )const;\n\t\tCRG_API LayoutState getNextLayoutState( ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange )const;\n\n\t\tCRG_API void registerImplicitTransition( RunnablePass const & pass\n\t\t\t, crg::ImageViewId view\n\t\t\t, ImplicitAction action = []( RecordContext const &, VkCommandBuffer, uint32_t ){} );\n\t\tCRG_API void registerImplicitTransition( RunnablePass const & pass\n\t\t\t, crg::BufferViewId view\n\t\t\t, ImplicitAction action = []( RecordContext const &, VkCommandBuffer, uint32_t ){} );\n\t\tCRG_API void registerImplicitTransition( ImplicitImageTransition transition );\n\t\tCRG_API void registerImplicitTransition( ImplicitBufferTransition transition );\n\t\tCRG_API void runImplicitTransition( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, crg::ImageViewId view );\n\t\tCRG_API void runImplicitTransition( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, crg::BufferViewId view );\n\t\t//@}\n\t\t/**\n\t\t*\\name\tBuffers\n\t\t*/\n\t\t//@{\n\t\tCRG_API void setAccessState( BufferViewId buffer\n\t\t\t, AccessState const & accessState );\n\t\tCRG_API AccessState getAccessState( BufferViewId view )const;\n\n\t\tCRG_API void setAccessState( BufferId buffer\n\t\t\t, BufferSubresourceRange const & subresourceRange\n\t\t\t, AccessState const & accessState );\n\t\tCRG_API AccessState const & getAccessState( BufferId buffer\n\t\t\t, BufferSubresourceRange const & subresourceRange )const;\n\t\t//@}\n\t\t//@}\n\t\t/**\n\t\t*\\name\tMemory barriers\n\t\t*/\n\t\t//@{\n\t\t/**\n\t\t*\\name\tImages\n\t\t*/\n\t\t//@{\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageViewId const & view\n\t\t\t, ImageLayout initialLayout\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageId const & image\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, ImageLayout initialLayout\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageId const & image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, ImageLayout initialLayout\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageViewId const & view\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageId const & image\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, ImageId const & image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange const & subresourceRange\n\t\t\t, LayoutState const & wantedState\n\t\t\t, bool force = false );\n\t\t//@}\n\t\t/**\n\t\t*\\name\tBuffers\n\t\t*/\n\t\t//@{\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, BufferId buffer\n\t\t\t, BufferSubresourceRange const & subresourceRange\n\t\t\t, AccessState const & initialState\n\t\t\t, AccessState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, BufferViewId view\n\t\t\t, AccessState const & initialState\n\t\t\t, AccessState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, BufferId buffer\n\t\t\t, BufferSubresourceRange const & subresourceRange\n\t\t\t, AccessState const & wantedState\n\t\t\t, bool force = false );\n\t\tCRG_API void memoryBarrier( VkCommandBuffer commandBuffer\n\t\t\t, BufferViewId view\n\t\t\t, AccessState const & wantedState\n\t\t\t, bool force = false );\n\t\t//@}\n\t\t//@}\n\t\tCRG_API GraphContext & getContext()const;\n\t\tCRG_API ContextResourcesCache & getResources()const;\n\n\t\tGraphContext * operator->()const\n\t\t{\n\t\t\treturn &getContext();\n\t\t}\n\n\t\tCRG_API void copyImage( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, ImageViewId srcView\n\t\t\t, ImageViewId dstView\n\t\t\t, Extent2D const & extent\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API void blitImage( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, ImageViewId srcView\n\t\t\t, ImageViewId dstView\n\t\t\t, Rect2D const & srcRect\n\t\t\t, Rect2D const & dstRect\n\t\t\t, FilterMode filter\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API void clearAttachment( VkCommandBuffer commandBuffer\n\t\t\t, ImageViewId dstView\n\t\t\t, ClearColorValue const & clearValue\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API void clearAttachment( VkCommandBuffer commandBuffer\n\t\t\t, ImageViewId dstView\n\t\t\t, ClearDepthStencilValue const & clearValue\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API void copyBuffer( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, BufferViewId srcView\n\t\t\t, BufferViewId dstView\n\t\t\t, DeviceSize srcOffset, DeviceSize dstOffset\n\t\t\t, DeviceSize size\n\t\t\t, AccessState const & finalState = {} );\n\t\tCRG_API void clearBuffer( VkCommandBuffer commandBuffer\n\t\t\t, BufferViewId dstView\n\t\t\t, uint32_t clearValue\n\t\t\t, AccessState const & finalState = {} );\n\n\t\tCRG_API static ImplicitAction copyImage( ImageViewId srcView\n\t\t\t, ImageViewId dstView\n\t\t\t, Extent2D const & extent\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API static ImplicitAction blitImage( ImageViewId srcView\n\t\t\t, ImageViewId dstView\n\t\t\t, Rect2D const & srcRect\n\t\t\t, Rect2D const & dstRect\n\t\t\t, FilterMode filter\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API static ImplicitAction clearAttachment( Attachment const & attach\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API static ImplicitAction clearAttachment( ImageViewId view\n\t\t\t, ClearColorValue const & clearValue\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API static ImplicitAction clearAttachment( ImageViewId view\n\t\t\t, ClearDepthStencilValue const & clearValue\n\t\t\t, ImageLayout finalLayout = ImageLayout::eUndefined );\n\t\tCRG_API static ImplicitAction clearBuffer( BufferViewId dstView\n\t\t\t, AccessState const & finalState = {} );\n\t\tCRG_API static ImplicitAction clearBuffer( BufferViewId dstView\n\t\t\t, uint32_t clearValue\n\t\t\t, AccessState const & finalState = {} );\n\t\tCRG_API static ImplicitAction copyBuffer( BufferViewId srcView\n\t\t\t, BufferViewId dstView\n\t\t\t, DeviceSize srcOffset, DeviceSize dstOffset\n\t\t\t, DeviceSize size\n\t\t\t, AccessState const & finalState = {} );\n\n\t\tResourceHandler & getHandler()const\n\t\t{\n\t\t\treturn *m_handler;\n\t\t}\n\n\t\tPassIndexArray const & getIndexState()const\n\t\t{\n\t\t\treturn m_state;\n\t\t}\n\n\t\tPipelineState const & getPrevPipelineState()const\n\t\t{\n\t\t\treturn m_prevPipelineState;\n\t\t}\n\n\t\tPipelineState const & getCurrPipelineState()const\n\t\t{\n\t\t\treturn m_currPipelineState;\n\t\t}\n\n\t\tPipelineState const & getNextPipelineState()const\n\t\t{\n\t\t\treturn m_nextPipelineState;\n\t\t}\n\n\tprivate:\n\t\tResourceHandler * m_handler;\n\t\tContextResourcesCache * m_resources;\n\t\tLayerLayoutStatesHandler m_images;\n\t\tAccessStateMap m_buffers;\n\t\tstd::vector< ImplicitImageTransition > m_implicitImageTransitions;\n\t\tstd::vector< ImplicitBufferTransition > m_implicitBufferTransitions;\n\t\tPassIndexArray m_state;\n\t\tPipelineState m_prevPipelineState{};\n\t\tPipelineState m_currPipelineState{};\n\t\tPipelineState m_nextPipelineState{};\n\t\tLayerLayoutStatesHandler m_nextImages;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/ResourceHandler.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 5262 )\n#include <mutex>\n#pragma warning( pop )\n#include <unordered_map>\n#include <unordered_set>\n\nnamespace crg\n{\n\tstruct Sampler\n\t{\n\t\tVkSampler sampler;\n\t\tstd::string name;\n\t};\n\n\tclass ResourceHandler\n\t{\n\t\ttemplate< typename ValueT >\n\t\tstruct CreatedT\n\t\t{\n\t\t\tbool created{};\n\t\t\tValueT resource{};\n\t\t\tVkDeviceMemory memory{};\n\t\t};\n\n\t\ttemplate< typename ValueT >\n\t\tstruct CreatedViewT\n\t\t{\n\t\t\tbool created{};\n\t\t\tValueT view{};\n\t\t};\n\n\tpublic:\n\t\tResourceHandler( ResourceHandler const & ) = delete;\n\t\tResourceHandler( ResourceHandler && )noexcept = delete;\n\t\tResourceHandler & operator=( ResourceHandler const & ) = delete;\n\t\tResourceHandler & operator=( ResourceHandler && )noexcept = delete;\n\t\tResourceHandler() = default;\n\t\tCRG_API ~ResourceHandler()noexcept;\n\n\t\tCRG_API BufferId createBufferId( BufferData const & img );\n\t\tCRG_API BufferViewId createViewId( BufferViewData const & view );\n\t\tCRG_API ImageId createImageId( ImageData const & img );\n\t\tCRG_API ImageViewId createViewId( ImageViewData const & view );\n\n\t\tCRG_API CreatedT< VkBuffer > createBuffer( GraphContext & context\n\t\t\t, BufferId bufferId );\n\t\tCRG_API CreatedViewT< VkBufferView > createBufferView( GraphContext & context\n\t\t\t, BufferViewId viewId );\n\t\tCRG_API CreatedT< VkImage > createImage( GraphContext & context\n\t\t\t, ImageId imageId );\n\t\tCRG_API CreatedViewT< VkImageView > createImageView( GraphContext & context\n\t\t\t, ImageViewId viewId );\n\t\tCRG_API VkSampler createSampler( GraphContext & context\n\t\t\t, std::string const & suffix\n\t\t\t, SamplerDesc const & samplerDesc );\n\t\tCRG_API VertexBuffer const * createQuadTriVertexBuffer( GraphContext & context\n\t\t\t, std::string const & suffix\n\t\t\t, bool texCoords\n\t\t\t, Texcoord const & config );\n\t\tCRG_API void destroyBuffer( GraphContext & context\n\t\t\t, BufferId bufferId );\n\t\tCRG_API void destroyBufferView( GraphContext & context\n\t\t\t, BufferViewId viewId );\n\t\tCRG_API void destroyImage( GraphContext & context\n\t\t\t, ImageId imageId );\n\t\tCRG_API void destroyImageView( GraphContext & context\n\t\t\t, ImageViewId viewId );\n\t\tCRG_API void destroySampler( GraphContext & context\n\t\t\t, VkSampler sampler );\n\t\tCRG_API void destroyVertexBuffer( GraphContext & context\n\t\t\t, VertexBuffer const * buffer );\n\n\tprivate:\n\t\tmutable std::mutex m_buffersMutex;\n\t\tBufferIdDataOwnerCont m_bufferIds;\n\t\tmutable std::mutex m_bufferViewsMutex;\n\t\tBufferViewIdDataOwnerCont m_bufferViewIds;\n\t\tBufferMemoryMap m_buffers;\n\t\tBufferViewMap m_bufferViews;\n\t\tmutable std::mutex m_imagesMutex;\n\t\tImageIdDataOwnerCont m_imageIds;\n\t\tmutable std::mutex m_imageViewsMutex;\n\t\tImageViewIdDataOwnerCont m_imageViewIds;\n\t\tImageMemoryMap m_images;\n\t\tImageViewMap m_imageViews;\n\t\tstd::mutex m_samplersMutex;\n\t\tstd::unordered_map< VkSampler, Sampler > m_samplers;\n\t\tstd::mutex m_vertexBuffersMutex;\n\t\tstd::unordered_set< VertexBufferPtr > m_vertexBuffers;\n\t};\n\n\tclass ContextResourcesCache\n\t{\n\tpublic:\n\t\tContextResourcesCache( ContextResourcesCache const & ) = delete;\n\t\tContextResourcesCache & operator=( ContextResourcesCache const & ) = delete;\n\t\tContextResourcesCache( ContextResourcesCache && )noexcept = delete;\n\t\tContextResourcesCache & operator=( ContextResourcesCache && )noexcept = delete;\n\n\t\tCRG_API ContextResourcesCache( ResourceHandler & handler\n\t\t\t, GraphContext & context );\n\t\tCRG_API ~ContextResourcesCache()noexcept;\n\n\t\tCRG_API VkBuffer createBuffer( BufferId const & bufferId );\n\t\tCRG_API VkBuffer createBuffer( BufferId const & bufferId, VkDeviceMemory & memory );\n\t\tCRG_API VkBufferView createBufferView( BufferViewId const & viewId );\n\t\tCRG_API bool destroyBuffer( BufferId const & imageId );\n\t\tCRG_API bool destroyBufferView( BufferViewId const & viewId );\n\n\t\tCRG_API VkImage createImage( ImageId const & imageId );\n\t\tCRG_API VkImage createImage( ImageId const & imageId, VkDeviceMemory & memory );\n\t\tCRG_API VkImageView createImageView( ImageViewId const & viewId );\n\t\tCRG_API bool destroyImage( ImageId const & imageId );\n\t\tCRG_API bool destroyImageView( ImageViewId const & viewId );\n\n\t\tCRG_API VkSampler createSampler( SamplerDesc const & samplerDesc );\n\t\tCRG_API VertexBuffer const & createQuadTriVertexBuffer( bool texCoords\n\t\t\t, Texcoord const & config );\n\n\t\tGraphContext * operator->()const noexcept\n\t\t{\n\t\t\treturn &m_context;\n\t\t}\n\n\t\tGraphContext & getContext()const noexcept\n\t\t{\n\t\t\treturn m_context;\n\t\t}\n\n\t\tResourceHandler & getHandler()const\n\t\t{\n\t\t\treturn m_handler;\n\t\t}\n\n\tprivate:\n\t\tusing VkBufferIdMap = std::map< BufferId, VkBuffer >;\n\t\tusing VkBufferViewIdMap = std::map< BufferViewId, VkBufferView >;\n\t\tusing VkImageIdMap = std::map< ImageId, VkImage >;\n\t\tusing VkImageViewIdMap = std::map< ImageViewId, VkImageView >;\n\n\t\tResourceHandler & m_handler;\n\t\tGraphContext & m_context;\n\t\tVkBufferIdMap m_buffers;\n\t\tVkBufferViewIdMap m_bufferViews;\n\t\tVkImageIdMap m_images;\n\t\tVkImageViewIdMap m_imageViews;\n\t\tstd::unordered_map< size_t, VkSampler > m_samplers;\n\t\tstd::unordered_map< size_t, VertexBuffer const * > m_vertexBuffers;\n\t};\n\n\tclass ResourcesCache\n\t{\n\tpublic:\n\t\tCRG_API explicit ResourcesCache( ResourceHandler & handler );\n\n\t\tCRG_API VkBuffer createBuffer( GraphContext & context\n\t\t\t, BufferId const & bufferId );\n\t\tCRG_API VkBuffer createBuffer( GraphContext & context\n\t\t\t, BufferId const & bufferId\n\t\t\t, VkDeviceMemory & memory );\n\t\tCRG_API VkBufferView createBufferView( GraphContext & context\n\t\t\t, BufferViewId const & viewId );\n\t\tCRG_API bool destroyBuffer( BufferId const & bufferId );\n\t\tCRG_API bool destroyBufferView( BufferViewId const & viewId );\n\t\tCRG_API bool destroyBuffer( GraphContext & context\n\t\t\t, BufferId const & bufferId );\n\t\tCRG_API bool destroyBufferView( GraphContext & context\n\t\t\t, BufferViewId const & viewId );\n\n\t\tCRG_API VkImage createImage( GraphContext & context\n\t\t\t, ImageId const & imageId );\n\t\tCRG_API VkImage createImage( GraphContext & context\n\t\t\t, ImageId const & imageId\n\t\t\t, VkDeviceMemory & memory );\n\t\tCRG_API VkImageView createImageView( GraphContext & context\n\t\t\t, ImageViewId const & viewId );\n\t\tCRG_API bool destroyImage( ImageId const & imageId );\n\t\tCRG_API bool destroyImageView( ImageViewId const & viewId );\n\t\tCRG_API bool destroyImage( GraphContext & context\n\t\t\t, ImageId const & imageId );\n\t\tCRG_API bool destroyImageView( GraphContext & context\n\t\t\t, ImageViewId const & viewId );\n\n\t\tCRG_API VkSampler createSampler( GraphContext & context\n\t\t\t, SamplerDesc const & samplerDesc );\n\t\tCRG_API VertexBuffer const & createQuadTriVertexBuffer( GraphContext & context\n\t\t\t, bool texCoords\n\t\t\t, Texcoord const & config );\n\n\t\tCRG_API ContextResourcesCache & getContextCache( GraphContext & context );\n\n\t\tResourceHandler & getHandler()const\n\t\t{\n\t\t\treturn m_handler;\n\t\t}\n\n\tprivate:\n\t\tusing ContextCacheMap = std::unordered_map< GraphContext *, ContextResourcesCache >;\n\n\t\tResourceHandler & m_handler;\n\t\tContextCacheMap m_caches;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnableGraph.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"GraphContext.hpp\"\n#include \"FrameGraph.hpp\"\n#include \"ResourceHandler.hpp\"\n#include \"RunnablePass.hpp\"\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tTells how the texture coordinates from the vertex buffer are built.\n\t*/\n\tstruct Texcoord\n\t{\n\t\t/**\n\t\t*\\brief\n\t\t*\tTells if the U coordinate of UV must be inverted, thus mirroring vertically the resulting image.\n\t\t*/\n\t\tbool invertU{ false };\n\t\t/**\n\t\t*\\brief\n\t\t*\tTells if the U coordinate of UV must be inverted, thus mirroring horizontally the resulting image.\n\t\t*/\n\t\tbool invertV{ false };\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< Texcoord >\n\t{\n\t\tstatic Texcoord get()\n\t\t{\n\t\t\tstatic Texcoord const result{ false, false };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\tclass RunnableGraph\n\t{\n\tpublic:\n\t\t/**\n\t\t*\\param inputTransitions\n\t\t*\tTransitions for which the pass is the destination.\n\t\t*\\param outputTransitions\n\t\t*\tTransitions for which the pass is the source.\n\t\t*\\param transitions\n\t\t*\tAll transitions.\n\t\t*/\n\t\tCRG_API RunnableGraph( FrameGraph & graph\n\t\t\t, GraphNodePtrArray nodes\n\t\t\t, RootNode rootNode\n\t\t\t, GraphContext & context );\n\t\tCRG_API ~RunnableGraph()noexcept;\n\n\t\tCRG_API void record();\n\n\t\tCRG_API SemaphoreWaitArray run( VkQueue queue );\n\t\tCRG_API SemaphoreWaitArray run( SemaphoreWait toWait\n\t\t\t, VkQueue queue );\n\t\tCRG_API SemaphoreWaitArray run( SemaphoreWaitArray const & toWait\n\t\t\t, VkQueue queue );\n\n\t\tCRG_API VkBuffer createBuffer( BufferId const & buffer );\n\t\tCRG_API VkBufferView createBufferView( BufferViewId const & view );\n\t\tCRG_API VkImage createImage( ImageId const & image );\n\t\tCRG_API VkImageView createImageView( ImageViewId const & view );\n\t\tCRG_API VkSampler createSampler( SamplerDesc const & samplerDesc );\n\t\tCRG_API VertexBuffer const & createQuadTriVertexBuffer( bool texCoords\n\t\t\t, Texcoord const & config );\n\n\t\tCRG_API LayoutState getCurrentLayoutState( RecordContext & context\n\t\t\t, ImageId image\n\t\t\t, ImageViewType viewType\n\t\t\t, ImageSubresourceRange range )const;\n\t\tCRG_API LayoutState getCurrentLayoutState( RecordContext & context\n\t\t\t, ImageViewId view )const;\n\t\tCRG_API LayoutState getNextLayoutState( RecordContext const & context\n\t\t\t, crg::RunnablePass const & runnable\n\t\t\t, ImageViewId view )const;\n\t\tCRG_API LayoutState getOutputLayoutState( ImageViewId view )const;\n\n\t\tCRG_API VkDescriptorType getDescriptorType( Attachment const & attach )const;\n\t\tCRG_API WriteDescriptorSet getDescriptorWrite( Attachment const & attach, uint32_t binding, uint32_t index = 0u );\n\t\tCRG_API WriteDescriptorSet getDescriptorWrite( Attachment const & attach, SamplerDesc const & samplerDesc, uint32_t binding, uint32_t index = 0u );\n\n\t\ttemplate< typename EnumT >\n\t\tWriteDescriptorSet getDescriptorWriteT( Attachment const & attach, EnumT binding, uint32_t index = 0u )\n\t\t{\n\t\t\treturn getDescriptorWrite( attach, uint32_t( binding ), index );\n\t\t}\n\n\t\ttemplate< typename EnumT >\n\t\tWriteDescriptorSet getDescriptorWriteT( Attachment const & attach, SamplerDesc const & samplerDesc, EnumT binding, uint32_t index = 0u )\n\t\t{\n\t\t\treturn getDescriptorWrite( attach, samplerDesc, uint32_t( binding ), index );\n\t\t}\n\n\t\tConstGraphAdjacentNode getNodeGraph()const noexcept\n\t\t{\n\t\t\treturn &m_rootNode;\n\t\t}\n\t\t\n\t\tstd::string const & getName()const noexcept\n\t\t{\n\t\t\treturn m_graph.getName();\n\t\t}\n\n\t\tVkCommandPool getCommandPool()const noexcept\n\t\t{\n\t\t\treturn m_commandPool.object;\n\t\t}\n\n\t\tVkQueryPool getTimerQueryPool()const noexcept\n\t\t{\n\t\t\treturn m_timerQueries.object;\n\t\t}\n\n\t\tuint32_t & getTimerQueryOffset()noexcept\n\t\t{\n\t\t\treturn m_timerQueryOffset;\n\t\t}\n\n\t\tContextResourcesCache & getResources()noexcept\n\t\t{\n\t\t\treturn m_resources;\n\t\t}\n\n\t\tFence & getFence()noexcept\n\t\t{\n\t\t\treturn m_fence;\n\t\t}\n\n\t\tFence const & getFence()const noexcept\n\t\t{\n\t\t\treturn m_fence;\n\t\t}\n\n\t\tFramePassTimer const & getTimer()const noexcept\n\t\t{\n\t\t\treturn m_timer;\n\t\t}\n\n\t\tFramePassTimer & getTimer()noexcept\n\t\t{\n\t\t\treturn m_timer;\n\t\t}\n\n\t\tGraphContext & getContext()const noexcept\n\t\t{\n\t\t\treturn m_context;\n\t\t}\n\n\tprivate:\n\t\tFrameGraph & m_graph;\n\t\tGraphContext & m_context;\n\t\tContextResourcesCache m_resources;\n\t\tGraphNodePtrArray m_nodes;\n\t\tRootNode m_rootNode;\n\t\tContextObjectT< VkQueryPool > m_timerQueries;\n\t\tuint32_t m_timerQueryOffset{};\n\t\tContextObjectT< VkCommandPool > m_commandPool;\n\t\tstd::vector< RunnablePassPtr > m_passes;\n\t\tRecordContext::GraphIndexMap m_states;\n\t\tVkCommandBuffer m_commandBuffer{};\n\t\tVkSemaphore m_semaphore{};\n\t\tFence m_fence;\n\t\tFramePassTimer m_timer;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePass.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FramePass.hpp\"\n#include \"RenderGraph/FramePassTimer.hpp\"\n#include \"RenderGraph/RecordContext.hpp\"\n#include \"RenderGraph/WriteDescriptorSet.hpp\"\n\n#include <optional>\n\nnamespace crg\n{\n\tCRG_API void checkUndefinedInput( std::string const & stepName\n\t\t, Attachment const & attach\n\t\t, ImageViewId const & view\n\t\t, ImageLayout currentLayout );\n\n\ttemplate< typename StrongT, typename ValueT >\n\tstruct GetValueCallbackT\n\t{\n\t\tusing CallbackT = std::function< ValueT() >;\n\n\t\tGetValueCallbackT( GetValueCallbackT && )noexcept = default;\n\t\tGetValueCallbackT & operator=( GetValueCallbackT && )noexcept = default;\n\t\tGetValueCallbackT( GetValueCallbackT const & ) = default;\n\t\tGetValueCallbackT & operator=( GetValueCallbackT const & ) = default;\n\t\texplicit GetValueCallbackT( CallbackT callback = {} )\n\t\t\t: m_callback{ std::move( callback ) }\n\t\t{\n\t\t}\n\n\t\tValueT operator()()const\n\t\t{\n\t\t\treturn m_callback();\n\t\t}\n\n\tprivate:\n\t\tCallbackT m_callback;\n\t};\n\n\ttemplate< typename StrongT, typename ValueT >\n\tGetValueCallbackT< StrongT, ValueT > makeValueCallback( std::function< ValueT() > callback )\n\t{\n\t\treturn GetValueCallbackT< StrongT, ValueT >{ callback };\n\t}\n\n\tclass Fence\n\t{\n\tpublic:\n\t\tCRG_API Fence( GraphContext & context\n\t\t\t, std::string const & name\n\t\t\t, VkFenceCreateInfo create );\n\n\t\tFence( Fence const & ) = delete;\n\t\tFence & operator=( Fence const & ) = delete;\n\t\tFence & operator=( Fence && rhs )noexcept = delete;\n\t\tCRG_API Fence( Fence && rhs )noexcept;\n\t\tCRG_API ~Fence()noexcept;\n\n\t\tCRG_API void reset();\n\t\tCRG_API VkResult wait( uint64_t timeout );\n\n\t\tVkFence getInternal()const noexcept\n\t\t{\n\t\t\treturn m_fence;\n\t\t}\n\n\tprivate:\n\t\tGraphContext * m_context;\n\t\tVkFence m_fence{};\n\t\tbool m_fenceWaited{};\n\t};\n\n\tnamespace ru\n\t{\n\t\tstruct Config\n\t\t{\n\t\t\t/**\n\t\t\t*\\param[in] view\n\t\t\t*\tThe action's target viex.\n\t\t\t*\\param[in] action\n\t\t\t*\tThe implicit action.\n\t\t\t*/\n\t\t\tauto & implicitAction( ImageViewId view\n\t\t\t\t, RecordContext::ImplicitAction action )\n\t\t\t{\n\t\t\t\timplicitImageActions.try_emplace( view, action );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] view\n\t\t\t*\tThe action's target viex.\n\t\t\t*\\param[in] action\n\t\t\t*\tThe implicit action.\n\t\t\t*/\n\t\t\tauto & implicitAction( BufferViewId view\n\t\t\t\t, RecordContext::ImplicitAction action )\n\t\t\t{\n\t\t\t\timplicitBufferActions.try_emplace( view, action );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] action\n\t\t\t*\tThe action to run before the pass recording.\n\t\t\t*/\n\t\t\tauto & prePassAction( RecordContext::ImplicitAction action )\n\t\t\t{\n\t\t\t\tprePassActions.emplace_back( action );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] action\n\t\t\t*\tThe action to run after the pass recording.\n\t\t\t*/\n\t\t\tauto & postPassAction( RecordContext::ImplicitAction action )\n\t\t\t{\n\t\t\t\tpostPassActions.emplace_back( action );\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tuint32_t maxPassCount{ 1u };\n\t\t\tbool resettable{ false };\n\t\t\tstd::vector< RecordContext::ImplicitAction > prePassActions{};\n\t\t\tstd::vector< RecordContext::ImplicitAction > postPassActions{};\n\t\t\tstd::map< ImageViewId, RecordContext::ImplicitAction > implicitImageActions{};\n\t\t\tstd::map< BufferViewId, RecordContext::ImplicitAction > implicitBufferActions{};\n\t\t};\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< ru::Config >\n\t{\n\t\tstatic ru::Config get()\n\t\t{\n\t\t\tru::Config const result{ []()\n\t\t\t\t{\n\t\t\t\t\t\treturn ru::Config{};\n\t\t\t\t}() };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\tclass RunnablePass\n\t{\n\tpublic:\n\t\tstruct LayoutTransition\n\t\t{\n\t\t\t// The layout the view is in, when coming to this pass\n\t\t\tLayoutState from;\n\t\t\t// The layout this pass needs the view to be in\n\t\t\tLayoutState needed;\n\t\t\t// The layout the view needs to be, out from this pass.\n\t\t\tLayoutState to;\n\t\t};\n\n\t\tstruct AccessTransition\n\t\t{\n\t\t\t// The layout the buffer is in, when coming to this pass\n\t\t\tAccessState from;\n\t\t\t// The layout this pass needs the buffer to be in\n\t\t\tAccessState needed;\n\t\t\t// The layout the buffer needs to be, out from this pass.\n\t\t\tAccessState to;\n\t\t};\n\n\t\tstruct PassIndexT\n\t\t{\n\t\t};\n\t\tstruct PipelineStateT\n\t\t{\n\t\t};\n\t\tstruct EnabledT\n\t\t{\n\t\t};\n\t\tstruct ComputePassT\n\t\t{\n\t\t};\n\n\t\tusing InitialiseCallback = std::function< void( uint32_t passIndex ) >;\n\t\tusing RecordCallback = std::function< void( RecordContext &, VkCommandBuffer, uint32_t ) >;\n\t\tusing GetPipelineStateCallback = GetValueCallbackT< PipelineStateT, PipelineState >;\n\t\tusing GetPassIndexCallback = GetValueCallbackT< PassIndexT, uint32_t >;\n\t\tusing IsEnabledCallback = GetValueCallbackT< EnabledT, bool >;\n\t\tusing IsComputePassCallback = GetValueCallbackT< ComputePassT, bool >;\n\n\t\tstruct Callbacks\n\t\t{\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, GetPipelineStateCallback getPipelineState );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, GetPipelineStateCallback getPipelineState\n\t\t\t\t, RecordCallback record );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, GetPipelineStateCallback getPipelineState\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetPassIndexCallback getPassIndex );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, GetPipelineStateCallback getPipelineState\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetPassIndexCallback getPassIndex\n\t\t\t\t, IsEnabledCallback isEnabled );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, GetPipelineStateCallback getPipelineState\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetPassIndexCallback getPassIndex\n\t\t\t\t, IsEnabledCallback isEnabled\n\t\t\t\t, IsComputePassCallback isComputePass );\n\n\t\t\tInitialiseCallback initialise;\n\t\t\tGetPipelineStateCallback getPipelineState;\n\t\t\tRecordCallback record;\n\t\t\tGetPassIndexCallback getPassIndex;\n\t\t\tIsEnabledCallback isEnabled;\n\t\t\tIsComputePassCallback isComputePass;\n\t\t};\n\n\t\tstatic constexpr uint32_t InvalidIndex = ~0u;\n\n\tpublic:\n\t\tCRG_API RunnablePass( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Callbacks callbacks\n\t\t\t, ru::Config config = {} );\n\t\tCRG_API virtual ~RunnablePass()noexcept;\n\t\t/**\n\t\t*\\brief\n\t\t*\tInitialises the pass GPU data for given index.\n\t\t*\\param[in] passIndex\n\t\t*\tThe index of the pass to initialise.\n\t\t*/\n\t\tCRG_API void initialise( uint32_t passIndex );\n\t\t/**\n\t\t*\\brief\n\t\t*\tRecords the pass commands into the given command buffer.\n\t\t*\\param[in,out] context\n\t\t*\tStores the states.\n\t\t*\\param[in] commandBuffer\n\t\t*\tReceives the commands.\n\t\t*/\n\t\tCRG_API uint32_t recordCurrentInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer );\n\t\t/**\n\t\t*\\brief\n\t\t*\tRe-records the pass commands into its command buffer.\n\t\t*/\n\t\tCRG_API uint32_t reRecordCurrent();\n\t\t/**\n\t\t*\\brief\n\t\t*\tResets the command buffer to initial state.\n\t\t*/\n\t\tCRG_API bool resetCommandBuffer( uint32_t passIndex );\n\t\tCRG_API void notifyPassRender();\n\n\t\tLayoutState getLayoutState( crg::ImageViewId view )const\n\t\t{\n\t\t\treturn m_imageLayouts.getLayoutState( view );\n\t\t}\n\n\t\tbool isEnabled()const\n\t\t{\n\t\t\treturn m_callbacks.isEnabled();\n\t\t}\n\n\t\tuint32_t getIndex()const\n\t\t{\n\t\t\treturn isEnabled() ? m_callbacks.getPassIndex() : InvalidIndex;\n\t\t}\n\n\t\tFramePass const & getPass()const\n\t\t{\n\t\t\treturn m_pass;\n\t\t}\n\n\t\tRunnableGraph & getGraph()const\n\t\t{\n\t\t\treturn m_graph;\n\t\t}\n\n\t\tFramePassTimer const & getTimer()const\n\t\t{\n\t\t\treturn m_timer;\n\t\t}\n\n\t\tFramePassTimer & getTimer()\n\t\t{\n\t\t\treturn m_timer;\n\t\t}\n\n\t\tuint32_t getMaxPassCount()const\n\t\t{\n\t\t\treturn uint32_t( m_passes.size() );\n\t\t}\n\n\t\tPipelineState const & getPipelineState()const\n\t\t{\n\t\t\treturn m_pipelineState;\n\t\t}\n\n\t\tLayerLayoutStatesMap const & getImageLayouts()const\n\t\t{\n\t\t\treturn m_imageLayouts.images;\n\t\t}\n\n\tprotected:\n\t\tstruct CommandBuffer\n\t\t{\n\t\t\tVkCommandBuffer commandBuffer{};\n\t\t\tbool recorded{};\n\t\t};\n\n\tprivate:\n\t\tvoid recordOne( CommandBuffer & enabled\n\t\t\t, uint32_t index\n\t\t\t, RecordContext & context );\n\t\tvoid recordInto( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, RecordContext & context );\n\n\t\tVkCommandBuffer doCreateCommandBuffer( std::string const & suffix );\n\n\tprivate:\n\t\tusing LayoutTransitionMap = std::map< ImageViewId, LayoutTransition >;\n\t\tusing AccessTransitionMap = std::map< BufferViewId, AccessTransition >;\n\n\t\tstruct PassData\n\t\t{\n\t\t\tPassData( PassData const & ) = delete;\n\t\t\tPassData & operator=( PassData const & ) = delete;\n\t\t\tPassData & operator=( PassData && )noexcept = delete;\n\t\t\tPassData( PassData && rhs )noexcept\n\t\t\t\t: graph{ rhs.graph }\n\t\t\t\t, context{ rhs.context }\n\t\t\t\t, commandBuffer{ std::move( rhs.commandBuffer ) }\n\t\t\t\t, semaphore{ std::move( rhs.semaphore ) }\n\t\t\t\t, fence{ std::move( rhs.fence ) }\n\t\t\t\t, layoutTransitions{ std::move( rhs.layoutTransitions ) }\n\t\t\t\t, accessTransitions{ std::move( rhs.accessTransitions ) }\n\t\t\t\t, initialised{ rhs.initialised }\n\t\t\t{\n\t\t\t\trhs.commandBuffer.commandBuffer = {};\n\t\t\t\trhs.commandBuffer.recorded = {};\n\t\t\t\trhs.semaphore = {};\n\t\t\t\trhs.initialised = {};\n\t\t\t}\n\n\t\t\tPassData( RunnableGraph & graph\n\t\t\t\t, GraphContext & context\n\t\t\t\t, std::string const & baseName );\n\t\t\t~PassData()noexcept;\n\n\t\t\tRunnableGraph & graph;\n\t\t\tGraphContext & context;\n\t\t\tCommandBuffer commandBuffer;\n\t\t\tVkSemaphore semaphore{};\n\t\t\tFence fence;\n\t\t\tLayoutTransitionMap layoutTransitions;\n\t\t\tAccessTransitionMap accessTransitions;\n\t\t\tbool initialised{};\n\t\t};\n\n\tprivate:\n\t\tFramePass const & m_pass;\n\t\tGraphContext & m_context;\n\t\tRunnableGraph & m_graph;\n\t\tCallbacks m_callbacks;\n\t\tru::Config m_ruConfig;\n\t\tPipelineState m_pipelineState;\n\t\tstd::vector< PassData > m_passes;\n\t\tFramePassTimer m_timer;\n\t\tstd::vector< RecordContext > m_passContexts;\n\t\tLayerLayoutStatesHandler m_imageLayouts;\n\t\tAccessStateMap m_bufferAccesses;\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::InitialiseCallback >\n\t{\n\t\tstatic RunnablePass::InitialiseCallback get()\n\t\t{\n\t\t\tRunnablePass::InitialiseCallback const result{ []( uint32_t ){} };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::GetPipelineStateCallback >\n\t{\n\t\tstatic RunnablePass::GetPipelineStateCallback get()\n\t\t{\n\t\t\tRunnablePass::GetPipelineStateCallback const result{ [](){ return PipelineState{ AccessFlags::eShaderRead, PipelineStageFlags::eFragmentShader }; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::RecordCallback >\n\t{\n\t\tstatic RunnablePass::RecordCallback get()\n\t\t{\n\t\t\tRunnablePass::RecordCallback const result{ []( RecordContext &, VkCommandBuffer, uint32_t ){} };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::GetPassIndexCallback >\n\t{\n\t\tstatic RunnablePass::GetPassIndexCallback get()\n\t\t{\n\t\t\tRunnablePass::GetPassIndexCallback const result{ [](){ return 0u; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::IsEnabledCallback >\n\t{\n\t\tstatic RunnablePass::IsEnabledCallback get()\n\t\t{\n\t\t\tRunnablePass::IsEnabledCallback const result{ [](){ return true; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RunnablePass::IsComputePassCallback >\n\t{\n\t\tstatic RunnablePass::IsComputePassCallback get()\n\t\t{\n\t\t\tRunnablePass::IsComputePassCallback const result{ [](){ return false; } };\n\t\t\treturn result;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/BufferCopy.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass BufferCopy\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API BufferCopy( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, DeviceSize copyOffset\n\t\t\t, DeviceSize copyRange\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\n\tprivate:\n\t\tDeviceSize m_copyOffset;\n\t\tDeviceSize m_copyRange;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/BufferToImageCopy.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass BufferToImageCopy\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API BufferToImageCopy( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Offset3D const & copyOffset\n\t\t\t, Extent3D const & copySize\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext const & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\n\tprivate:\n\t\tVkOffset3D m_copyOffset;\n\t\tVkExtent3D m_copySize;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/ComputePass.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/BufferViewData.hpp\"\n#include \"RenderGraph/RunnablePass.hpp\"\n#include \"RenderGraph/RunnablePasses/PipelineHolder.hpp\"\n\nnamespace crg\n{\n\tnamespace cp\n\t{\n\t\tstruct GroupCountT\n\t\t{\n\t\t};\n\t\tusing GetGroupCountCallback = GetValueCallbackT< GroupCountT, uint32_t >;\n\n\t\ttemplate< template< typename ValueT > typename WrapperT >\n\t\tstruct ConfigT\n\t\t{\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program.\n\t\t\t*/\n\t\t\tauto & program( VkPipelineShaderStageCreateInfoArray const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.program( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline programs.\n\t\t\t*/\n\t\t\tauto & programs( std::vector< VkPipelineShaderStageCreateInfoArray > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programs( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program creator.\n\t\t\t*/\n\t\t\tauto & programCreator( ProgramCreator const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programCreator( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layout.\n\t\t\t*/\n\t\t\tauto & layout( VkDescriptorSetLayout const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layout( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layouts.\n\t\t\t*/\n\t\t\tauto & layouts( std::vector< VkDescriptorSetLayout > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layouts( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRange const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.pushConstants( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRangeArray const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.pushConstants( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tTells if disabled pass should record render pass begin/end.\n\t\t\t*/\n\t\t\tauto & baseConfig( pp::Config const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pass index.\n\t\t\t*/\n\t\t\tauto & passIndex( uint32_t const * config )\n\t\t\t{\n\t\t\t\tm_getPassIndex = [config]()\n\t\t\t\t{\n\t\t\t\t\treturn *config;\n\t\t\t\t};\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe enabled control variable.\n\t\t\t*/\n\t\t\tauto & enabled( bool const * config )\n\t\t\t{\n\t\t\t\tm_enabled = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pass index callback.\n\t\t\t*/\n\t\t\tauto & getPassIndex( RunnablePass::GetPassIndexCallback const & config )\n\t\t\t{\n\t\t\t\tm_getPassIndex = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback checking the enable status of the pass.\n\t\t\t*/\n\t\t\tauto & isEnabled( RunnablePass::IsEnabledCallback const & config )\n\t\t\t{\n\t\t\t\tm_isEnabled = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback recording the pass.\n\t\t\t*/\n\t\t\tauto & recordInto( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_recordInto = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback initialising the pass.\n\t\t\t*/\n\t\t\tauto & initialise( RunnablePass::InitialiseCallback const & config )\n\t\t\t{\n\t\t\t\tm_initialise = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback ending the pass.\n\t\t\t*/\n\t\t\tauto & end( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_end = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe X dispatch groups count.\n\t\t\t*/\n\t\t\tauto & groupCountX( uint32_t config )\n\t\t\t{\n\t\t\t\tm_groupCountX = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe Y dispatch groups count.\n\t\t\t*/\n\t\t\tauto & groupCountY( uint32_t config )\n\t\t\t{\n\t\t\t\tm_groupCountY = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe Z dispatch groups count.\n\t\t\t*/\n\t\t\tauto & groupCountZ( uint32_t config )\n\t\t\t{\n\t\t\t\tm_groupCountZ = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback to retrieve the X dispatch groups count.\n\t\t\t*/\n\t\t\tauto & getGroupCountX( GetGroupCountCallback const & config )\n\t\t\t{\n\t\t\t\tm_getGroupCountX = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback to retrieve the Y dispatch groups count.\n\t\t\t*/\n\t\t\tauto & getGroupCountY( GetGroupCountCallback const & config )\n\t\t\t{\n\t\t\t\tm_getGroupCountY = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback to retrieve the Z dispatch groups count.\n\t\t\t*/\n\t\t\tauto & getGroupCountZ( GetGroupCountCallback const & config )\n\t\t\t{\n\t\t\t\tm_getGroupCountZ = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe buffer used during indirect compute.\n\t\t\t*/\n\t\t\tauto & indirectBuffer( IndirectBuffer const & config )\n\t\t\t{\n\t\t\t\tm_indirectBuffer = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tpp::ConfigT< WrapperT > m_baseConfig{};\n\t\t\tWrapperT< RunnablePass::InitialiseCallback > m_initialise{};\n\t\t\tWrapperT< bool const * > m_enabled{};\n\t\t\tWrapperT< RunnablePass::IsEnabledCallback > m_isEnabled{};\n\t\t\tWrapperT< RunnablePass::GetPassIndexCallback > m_getPassIndex{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_recordInto{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_end{};\n\t\t\tWrapperT< uint32_t > m_groupCountX{};\n\t\t\tWrapperT< uint32_t > m_groupCountY{};\n\t\t\tWrapperT< uint32_t > m_groupCountZ{};\n\t\t\tWrapperT< GetGroupCountCallback > m_getGroupCountX{};\n\t\t\tWrapperT< GetGroupCountCallback > m_getGroupCountY{};\n\t\t\tWrapperT< GetGroupCountCallback > m_getGroupCountZ{};\n\t\t\tWrapperT< IndirectBuffer > m_indirectBuffer{};\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct ConfigT< RawTypeT >\n\t\t{\n\t\t\tRawTypeT< RunnablePass::InitialiseCallback > initialise{};\n\t\t\tRawTypeT< bool const * > enabled{ nullptr };\n\t\t\tstd::optional< RunnablePass::IsEnabledCallback > isEnabled{};\n\t\t\tRawTypeT< RunnablePass::GetPassIndexCallback > getPassIndex{};\n\t\t\tRawTypeT< RunnablePass::RecordCallback > recordInto{};\n\t\t\tRawTypeT< RunnablePass::RecordCallback > end{};\n\t\t\tRawTypeT< uint32_t > groupCountX{ 1u };\n\t\t\tRawTypeT< uint32_t > groupCountY{ 1u };\n\t\t\tRawTypeT< uint32_t > groupCountZ{ 1u };\n\t\t\tstd::optional< GetGroupCountCallback > getGroupCountX{};\n\t\t\tstd::optional< GetGroupCountCallback > getGroupCountY{};\n\t\t\tstd::optional< GetGroupCountCallback > getGroupCountZ{};\n\t\t\tRawTypeT< IndirectBuffer > indirectBuffer{ defaultV< IndirectBuffer > };\n\t\t};\n\n\t\tusing Config = ConfigT< std::optional >;\n\t\tusing ConfigData = ConfigT< RawTypeT >;\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT < cp::GetGroupCountCallback >\n\t{\n\t\tstatic cp::GetGroupCountCallback get()\n\t\t{\n\t\t\tcp::GetGroupCountCallback const result{ []()\n\t\t\t\t{\n\t\t\t\t\treturn 0u;\n\t\t\t\t} };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< cp::Config >\n\t{\n\t\tstatic cp::Config get()\n\t\t{\n\t\t\tcp::Config const result{ []()\n\t\t\t\t{\n\t\t\t\t\treturn cp::Config{};\n\t\t\t\t}() };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\tclass ComputePass\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API ComputePass( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, ru::Config const & ruConfig = {}\n\t\t\t, cp::Config cpConfig = {} );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\t\tCRG_API VkPipelineLayout getPipelineLayout()const;\n\n\tprivate:\n\t\tvoid doInitialise( uint32_t index );\n\t\tuint32_t doGetPassIndex()const;\n\t\tbool doIsEnabled()const;\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\t\tvoid doCreatePipeline( uint32_t index );\n\n\tprivate:\n\t\tcp::ConfigData m_cpConfig;\n\t\tPipelineHolder m_pipeline;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/GenerateMipmaps.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass GenerateMipmaps\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API GenerateMipmaps( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, ImageLayout outputLayout = ImageLayout::eUndefined\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tvoid doProcessImageView( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, ImageViewId viewId )const;\n\n\tprivate:\n\t\tLayoutState m_outputLayout;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/ImageBlit.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass ImageBlit\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API ImageBlit( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Rect3D const & blitSrc\n\t\t\t, Rect3D const & blitDst\n\t\t\t, FilterMode filter\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext const & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\n\tprivate:\n\t\tVkOffset3D m_srcOffset;\n\t\tVkExtent3D m_srcSize;\n\t\tVkOffset3D m_dstOffset;\n\t\tVkExtent3D m_dstSize;\n\t\tFilterMode m_filter;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/ImageCopy.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass ImageCopy\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API ImageCopy( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Extent3D const & copySize\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\t\tCRG_API ImageCopy( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Extent3D const & copySize\n\t\t\t, ImageLayout finalOutputLayout\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tvoid doRecordMultiToMulti( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tvoid doRecordMultiToSingle( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tvoid doRecordSingleToMulti( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\n\tprivate:\n\t\tVkExtent3D m_copySize;\n\t\tImageLayout m_finalOutputLayout;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/ImageToBufferCopy.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass ImageToBufferCopy\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API ImageToBufferCopy( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Offset3D const & copyOffset\n\t\t\t, Extent3D const & copySize\n\t\t\t, ru::Config ruConfig = {}\n\t\t\t, GetPassIndexCallback passIndex = GetPassIndexCallback( [](){ return 0u; } )\n\t\t\t, IsEnabledCallback isEnabled = IsEnabledCallback( [](){ return true; } ) );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext const & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\n\tprivate:\n\t\tVkOffset3D m_copyOffset;\n\t\tVkExtent3D m_copySize;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/PipelineConfig.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n#include \"RenderGraph/WriteDescriptorSet.hpp\"\n\n#include <optional>\n\nnamespace crg\n{\n\tstruct ProgramCreator\n\t{\n\t\tuint32_t maxCount{};\n\t\tstd::function< VkPipelineShaderStageCreateInfoArray( uint32_t ) > create;\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< std::vector< VkPipelineShaderStageCreateInfoArray > >\n\t{\n\t\tstatic inline std::vector< VkPipelineShaderStageCreateInfoArray > const value{};\n\n\t\tstatic std::vector< VkPipelineShaderStageCreateInfoArray > get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\t\n\ttemplate<>\n\tstruct DefaultValueGetterT< std::vector< VkDescriptorSetLayout > >\n\t{\n\t\tstatic inline std::vector< VkDescriptorSetLayout > const value{};\n\n\t\tstatic std::vector< VkDescriptorSetLayout > get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< Extent2D >\n\t{\n\t\tstatic inline Extent2D const value{};\n\n\t\tstatic Extent2D get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< Offset2D >\n\t{\n\t\tstatic inline Offset2D const value{};\n\n\t\tstatic Offset2D get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< ProgramCreator >\n\t{\n\t\tstatic inline ProgramCreator const value{};\n\n\t\tstatic ProgramCreator get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< VkPipelineDepthStencilStateCreateInfo >\n\t{\n\t\tstatic inline VkPipelineDepthStencilStateCreateInfo const value{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_FALSE\n\t\t\t, VK_FALSE\n\t\t\t, {}\n\t\t\t, {}\n\t\t\t, {}\n\t\t\t, {}\n\t\t\t, {}\n\t\t\t, {}\n\t\t\t, {} };\n\n\t\tstatic VkPipelineDepthStencilStateCreateInfo get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< VkPushConstantRangeArray >\n\t{\n\t\tstatic inline VkPushConstantRangeArray const value{};\n\n\t\tstatic VkPushConstantRangeArray get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< uint32_t const * >\n\t{\n\t\tstatic inline uint32_t const * const value{};\n\n\t\tstatic uint32_t const * get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< bool const * >\n\t{\n\t\tstatic inline bool const * const value{};\n\n\t\tstatic bool const * get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n\n\tnamespace pp\n\t{\n\t\ttemplate< template< typename ValueT > typename WrapperT >\n\t\tstruct ConfigT\n\t\t{\n\t\t\tConfigT( ConfigT && )noexcept = default;\n\t\t\tConfigT & operator=( ConfigT && )noexcept = default;\n\t\t\tConfigT( ConfigT const & ) = default;\n\t\t\tConfigT & operator=( ConfigT const & ) = default;\n\t\t\texplicit ConfigT( WrapperT< std::vector< VkPipelineShaderStageCreateInfoArray > > programs = {}\n\t\t\t\t, WrapperT< ProgramCreator > programCreator = {}\n\t\t\t\t, WrapperT< std::vector< VkDescriptorSetLayout > > layouts = {}\n\t\t\t\t, WrapperT< VkPushConstantRangeArray > pushConstants = {} )\n\t\t\t\t: m_programs{ std::move( programs ) }\n\t\t\t\t, m_programCreator{ std::move( programCreator ) }\n\t\t\t\t, m_layouts{ std::move( layouts ) }\n\t\t\t\t, m_pushConstants{ std::move( pushConstants ) }\n\t\t\t{\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program.\n\t\t\t*/\n\t\t\tauto & program( VkPipelineShaderStageCreateInfoArray const & config )\n\t\t\t{\n\t\t\t\tm_programs = { config };\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline programs.\n\t\t\t*/\n\t\t\tauto & programs( std::vector< VkPipelineShaderStageCreateInfoArray > const & config )\n\t\t\t{\n\t\t\t\tm_programs = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program creator.\n\t\t\t*/\n\t\t\tauto & programCreator( ProgramCreator const & config )\n\t\t\t{\n\t\t\t\tm_programCreator = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layout.\n\t\t\t*/\n\t\t\tauto & layout( VkDescriptorSetLayout const & config )\n\t\t\t{\n\t\t\t\tm_layouts = { config };\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layouts.\n\t\t\t*/\n\t\t\tauto & layouts( std::vector< VkDescriptorSetLayout > const & config )\n\t\t\t{\n\t\t\t\tm_layouts = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRange const & config )\n\t\t\t{\n\t\t\t\tpushConstants( VkPushConstantRangeArray{ config } );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRangeArray const & config )\n\t\t\t{\n\t\t\t\tm_pushConstants = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tWrapperT< std::vector< VkPipelineShaderStageCreateInfoArray > > m_programs;\n\t\t\tWrapperT< ProgramCreator > m_programCreator;\n\t\t\tWrapperT< std::vector< VkDescriptorSetLayout > > m_layouts;\n\t\t\tWrapperT< VkPushConstantRangeArray > m_pushConstants;\n\t\t};\n\n\t\tusing Config = ConfigT< std::optional >;\n\t\tusing ConfigData = ConfigT< RawTypeT >;\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< pp::Config >\n\t{\n\t\tstatic inline pp::Config const value{ [](){ return pp::Config{}; }() };\n\n\t\tstatic pp::Config get()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/PipelineHolder.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/PipelineConfig.hpp\"\n\nnamespace crg\n{\n\tclass PipelineHolder\n\t{\n\tpublic:\n\t\tPipelineHolder( PipelineHolder const & )noexcept = delete;\n\t\tPipelineHolder & operator=( PipelineHolder const & )noexcept = delete;\n\t\tPipelineHolder( PipelineHolder && )noexcept = delete;\n\t\tPipelineHolder & operator=( PipelineHolder && )noexcept = delete;\n\t\tCRG_API PipelineHolder( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, pp::Config config\n\t\t\t, VkPipelineBindPoint bindingPoint\n\t\t\t, uint32_t maxPassCount );\n\t\tCRG_API virtual ~PipelineHolder()noexcept;\n\n\t\tCRG_API void initialise();\n\t\tCRG_API void cleanup()noexcept;\n\t\tCRG_API VkPipelineShaderStageCreateInfoArray const & getProgram( uint32_t index );\n\t\tCRG_API VkPipeline & getPipeline( uint32_t index );\n\t\tCRG_API void createPipeline( uint32_t index\n\t\t\t, std::string const & name\n\t\t\t, VkGraphicsPipelineCreateInfo const & createInfo );\n\t\tCRG_API void createPipeline( uint32_t index\n\t\t\t, VkGraphicsPipelineCreateInfo const & createInfo );\n\t\tCRG_API void createPipeline( uint32_t index\n\t\t\t, std::string const & name\n\t\t\t, VkComputePipelineCreateInfo const & createInfo );\n\t\tCRG_API void createPipeline( uint32_t index\n\t\t\t, VkComputePipelineCreateInfo const & createInfo );\n\t\tCRG_API void recordInto( RecordContext const & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t\t, VkPipelineShaderStageCreateInfoArray const & config );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\t\tCRG_API void createDescriptorSet( uint32_t index );\n\n\t\tVkDescriptorSet getDescriptorSet( uint32_t index )\n\t\t{\n\t\t\tcreateDescriptorSet( index );\n\t\t\treturn m_descriptorSets[index].set;\n\t\t}\n\n\t\tVkPipelineLayout getPipelineLayout()const\n\t\t{\n\t\t\treturn m_pipelineLayout;\n\t\t}\n\n\t\tFramePass const & getPass()const\n\t\t{\n\t\t\treturn m_pass;\n\t\t}\n\n\t\tGraphContext & getContext()const\n\t\t{\n\t\t\treturn m_context;\n\t\t}\n\n\tprivate:\n\t\tvoid doFillDescriptorBindings();\n\t\tvoid doCreateDescriptorSetLayout();\n\t\tvoid doCreatePipelineLayout();\n\t\tvoid doCreateDescriptorPool();\n\n\tprotected:\n\t\tstruct DescriptorSet\n\t\t{\n\t\t\tWriteDescriptorSetArray writes{};\n\t\t\tVkDescriptorSet set{};\n\t\t};\n\n\tprivate:\n\t\tFramePass const & m_pass;\n\t\tGraphContext & m_context;\n\t\tRunnableGraph & m_graph;\n\t\tpp::ConfigData m_baseConfig;\n\t\tVkPipelineBindPoint m_bindingPoint;\n\t\tVkDescriptorSetLayoutBindingArray m_descriptorBindings;\n\t\tVkDescriptorSetLayout m_descriptorSetLayout{};\n\t\tVkPipelineLayout m_pipelineLayout{};\n\t\tVkDescriptorPool m_descriptorSetPool{};\n\t\tstd::vector< DescriptorSet > m_descriptorSets;\n\t\tstd::vector< VkPipeline > m_pipelines{};\n\t};\n\n\ttemplate< typename BuilderT >\n\tclass PipelinePassBuilderT\n\t{\n\tpublic:\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe pipeline program.\n\t\t*/\n\t\tBuilderT & program( VkPipelineShaderStageCreateInfoArray const & config )\n\t\t{\n\t\t\tm_baseConfig.programs( { config } );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe pipeline programs.\n\t\t*/\n\t\tBuilderT & programs( std::vector< VkPipelineShaderStageCreateInfoArray > const & config )\n\t\t{\n\t\t\tm_baseConfig.programs( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe pipeline program creator.\n\t\t*/\n\t\tBuilderT & programCreator( ProgramCreator const & config )\n\t\t{\n\t\t\tm_baseConfig.programCreator( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe push constants range for the pipeline.\n\t\t*/\n\t\tauto & pushConstants( VkPushConstantRange const & config )\n\t\t{\n\t\t\tm_baseConfig.pushConstants( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe push constants range for the pipeline.\n\t\t*/\n\t\tauto & pushConstants( VkPushConstantRangeArray const & config )\n\t\t{\n\t\t\tm_baseConfig.pushConstants( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe descriptor set layouts.\n\t\t*/\n\t\tauto & layout( VkDescriptorSetLayout const & config )\n\t\t{\n\t\t\tm_baseConfig.layout( config );\n\t\t\treturn *this;\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe descriptor set layouts.\n\t\t*/\n\t\tauto & layouts( std::vector< VkDescriptorSetLayout > const & config )\n\t\t{\n\t\t\tm_baseConfig.layouts( config );\n\t\t\treturn *this;\n\t\t}\n\n\t\tpp::Config const & getBaseConfig()const noexcept\n\t\t{\n\t\t\treturn m_baseConfig;\n\t\t}\n\n\tprivate:\n\t\tpp::Config m_baseConfig;\n\t};\n\n\tclass PipelinePassBuilder\n\t\t: public PipelinePassBuilderT< PipelinePassBuilder >\n\t{\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderMesh.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/RenderMeshHolder.hpp\"\n#include \"RenderGraph/RunnablePasses/RenderPass.hpp\"\n\nnamespace crg\n{\n\tclass RenderMesh\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\tCRG_API RenderMesh( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, ru::Config const & ruConfig\n\t\t\t, rm::Config rmConfig );\n\t\t~RenderMesh()noexcept override = default;\n\n\t\tCRG_API void resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\n\tprivate:\n\t\tRenderMeshHolder m_renderMesh;\n\t\tRenderPassHolder m_renderPass;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderMeshConfig.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnableGraph.hpp\"\n#include \"RenderGraph/RunnablePasses/PipelineConfig.hpp\"\n\nnamespace crg\n{\n\tstruct PrimitiveCountT\n\t{\n\t};\n\tstruct VertexCountT\n\t{\n\t};\n\tstruct IndexTypeT\n\t{\n\t};\n\tstruct CullModeT\n\t{\n\t};\n\n\tusing GetPrimitiveCountCallback = GetValueCallbackT< PrimitiveCountT, uint32_t >;\n\tusing GetVertexCountCallback = GetValueCallbackT< VertexCountT, uint32_t >;\n\tusing GetIndexTypeCallback = GetValueCallbackT< IndexTypeT, VkIndexType >;\n\tusing GetCullModeCallback = GetValueCallbackT< CullModeT, VkCullModeFlags >;\n\n\tnamespace rm\n\t{\n\t\ttemplate< template< typename ValueT > typename WrapperT >\n\t\tstruct ConfigT\n\t\t{\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program.\n\t\t\t*/\n\t\t\tauto & program( VkPipelineShaderStageCreateInfoArray const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.program( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline programs.\n\t\t\t*/\n\t\t\tauto & programs( std::vector< VkPipelineShaderStageCreateInfoArray > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programs( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program creator.\n\t\t\t*/\n\t\t\tauto & programCreator( ProgramCreator const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programCreator( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layout.\n\t\t\t*/\n\t\t\tauto & layout( VkDescriptorSetLayout const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layout( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layouts.\n\t\t\t*/\n\t\t\tauto & layouts( std::vector< VkDescriptorSetLayout > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layouts( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tTells if disabled pass should record render pass begin/end.\n\t\t\t*/\n\t\t\tauto & baseConfig( pp::Config const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe render area size.\n\t\t\t*/\n\t\t\tauto & renderSize( Extent2D const & config )\n\t\t\t{\n\t\t\t\tm_renderSize = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe render position.\n\t\t\t*/\n\t\t\tauto & renderPosition( Offset2D const & config )\n\t\t\t{\n\t\t\t\tm_renderPosition = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe depth stencil state.\n\t\t\t*/\n\t\t\tauto & depthStencilState( VkPipelineDepthStencilStateCreateInfo const & config )\n\t\t\t{\n\t\t\t\tm_depthStencilState = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pass index callback.\n\t\t\t*/\n\t\t\tauto & getPassIndex( RunnablePass::GetPassIndexCallback const & config )\n\t\t\t{\n\t\t\t\tm_getPassIndex = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback checking the enable status of the pass.\n\t\t\t*/\n\t\t\tauto & isEnabled( RunnablePass::IsEnabledCallback const & config )\n\t\t\t{\n\t\t\t\tm_isEnabled = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback recording the pass.\n\t\t\t*/\n\t\t\tauto & recordInto( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_recordInto = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback ending the pass.\n\t\t\t*/\n\t\t\tauto & end( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_end = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe vertex buffer.\n\t\t\t*/\n\t\t\tauto & vertexBuffer( VertexBuffer const & config )\n\t\t\t{\n\t\t\t\tm_vertexBuffer = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe index buffer.\n\t\t\t*/\n\t\t\tauto & indexBuffer( IndexBuffer const & config )\n\t\t\t{\n\t\t\t\tm_indexBuffer = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe indirect buffer.\n\t\t\t*/\n\t\t\tauto & indirectBuffer( IndirectBuffer const & config )\n\t\t\t{\n\t\t\t\tm_indirectBuffer = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe primitive count retrieval callback.\n\t\t\t*/\n\t\t\tauto & getPrimitiveCount( GetPrimitiveCountCallback const & config )\n\t\t\t{\n\t\t\t\tm_getPrimitiveCount = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe vertex count retrieval callback.\n\t\t\t*/\n\t\t\tauto & getVertexCount( GetVertexCountCallback const & config )\n\t\t\t{\n\t\t\t\tm_getVertexCount = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe index type retrieval callback.\n\t\t\t*/\n\t\t\tauto & getIndexType( GetIndexTypeCallback const & config )\n\t\t\t{\n\t\t\t\tm_getIndexType = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe rasterizer cull mode.\n\t\t\t*/\n\t\t\tauto & getCullMode( GetCullModeCallback const & config )\n\t\t\t{\n\t\t\t\tm_getCullMode = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tpp::ConfigT< WrapperT > m_baseConfig{};\n\t\t\tWrapperT< Offset2D > m_renderPosition{};\n\t\t\tWrapperT< VkPipelineDepthStencilStateCreateInfo > m_depthStencilState{};\n\t\t\tWrapperT< RunnablePass::GetPassIndexCallback > m_getPassIndex{};\n\t\t\tWrapperT< RunnablePass::IsEnabledCallback > m_isEnabled{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_recordInto{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_end{};\n\t\t\tWrapperT< GetPrimitiveCountCallback > m_getPrimitiveCount{};\n\t\t\tWrapperT< GetVertexCountCallback > m_getVertexCount{};\n\t\t\tWrapperT< GetIndexTypeCallback > m_getIndexType{};\n\t\t\tWrapperT< GetCullModeCallback > m_getCullMode{};\n\t\t\tWrapperT< Extent2D > m_renderSize{};\n\t\t\tWrapperT< VertexBuffer > m_vertexBuffer{};\n\t\t\tWrapperT< IndexBuffer > m_indexBuffer{};\n\t\t\tWrapperT< IndirectBuffer > m_indirectBuffer{};\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct ConfigT< RawTypeT >\n\t\t{\n\t\t\tRawTypeT< Offset2D > renderPosition{};\n\t\t\tRawTypeT< VkPipelineDepthStencilStateCreateInfo > depthStencilState{};\n\t\t\tRawTypeT< RunnablePass::GetPassIndexCallback > getPassIndex{};\n\t\t\tRawTypeT< RunnablePass::IsEnabledCallback > isEnabled{};\n\t\t\tRawTypeT< RunnablePass::RecordCallback > recordInto{};\n\t\t\tRawTypeT< RunnablePass::RecordCallback > end{};\n\t\t\tRawTypeT< GetPrimitiveCountCallback > getPrimitiveCount{};\n\t\t\tRawTypeT< GetVertexCountCallback > getVertexCount{};\n\t\t\tRawTypeT< GetIndexTypeCallback > getIndexType{};\n\t\t\tRawTypeT< GetCullModeCallback > getCullMode{};\n\t\t\tRawTypeT< VertexBuffer > vertexBuffer{};\n\t\t\tRawTypeT< IndexBuffer > indexBuffer{};\n\t\t\tRawTypeT< IndirectBuffer > indirectBuffer{ defaultV< IndirectBuffer > };\n\t\t};\n\n\t\tusing Config = ConfigT< std::optional >;\n\t\tusing ConfigData = ConfigT< RawTypeT >;\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< GetPrimitiveCountCallback >\n\t{\n\t\tstatic GetPrimitiveCountCallback get()\n\t\t{\n\t\t\tGetPrimitiveCountCallback const result{ [](){ return 1u; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< GetVertexCountCallback >\n\t{\n\t\tstatic GetVertexCountCallback get()\n\t\t{\n\t\t\tGetVertexCountCallback const result{ [](){ return 1u; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< GetIndexTypeCallback >\n\t{\n\t\tstatic GetIndexTypeCallback get()\n\t\t{\n\t\t\tGetIndexTypeCallback const result{ [](){ return VK_INDEX_TYPE_UINT32; } };\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< GetCullModeCallback >\n\t{\n\t\tstatic GetCullModeCallback get()\n\t\t{\n\t\t\tGetCullModeCallback const result{ [](){ return VK_CULL_MODE_NONE; } };\n\t\t\treturn result;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderMeshHolder.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/RenderMeshConfig.hpp\"\n#include \"RenderGraph/RunnablePasses/PipelineHolder.hpp\"\n\nnamespace crg\n{\n\tclass RenderMeshHolder\n\t{\n\tpublic:\n\t\tCRG_API RenderMeshHolder( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, rm::Config config\n\t\t\t, uint32_t maxPassCount );\n\n\t\tCRG_API void initialise( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t\t, uint32_t index );\n\t\tCRG_API void cleanup();\n\t\tCRG_API void resetRenderPass( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\t\tCRG_API void record( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\t\tCRG_API void end( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tCRG_API uint32_t getPassIndex()const;\n\t\tCRG_API bool isEnabled()const;\n\t\tCRG_API Extent2D getRenderSize()const;\n\n\tprivate:\n\t\tvoid doPreparePipelineStates( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState );\n\t\tvoid doCreatePipeline( uint32_t index );\n\t\tVkPipelineViewportStateCreateInfo doCreateViewportState( Extent2D const & renderSize\n\t\t\t, VkViewport & viewport\n\t\t\t, VkRect2D & scissor )const;\n\n\tprivate:\n\t\tRunnableGraph & m_graph;\n\t\trm::ConfigData m_config;\n\t\tPipelineHolder m_pipeline;\n\t\tVkRenderPass m_renderPass{};\n\t\tExtent2D m_renderSize{};\n\t\tVkViewport m_viewport{};\n\t\tVkRect2D m_scissor{};\n\t\tVkPipelineViewportStateCreateInfo m_vpState{};\n\t\tVkPipelineInputAssemblyStateCreateInfo m_iaState{};\n\t\tVkPipelineMultisampleStateCreateInfo m_msState{};\n\t\tVkPipelineRasterizationStateCreateInfo m_rsState{};\n\t\tVkPipelineColorBlendStateCreateInfo m_blendState{};\n\t\tstd::vector< VkPipelineColorBlendAttachmentState > m_blendAttachs{};\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderPass.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/RenderPassHolder.hpp\"\n\nnamespace crg\n{\n\tCRG_API VkDescriptorPoolSizeArray getBindingsSizes( VkDescriptorSetLayoutBindingArray const & bindings\n\t\t, uint32_t maxSets );\n\n\ttemplate< typename VkType, typename LibType >\n\tinline std::vector< VkType > makeVkArray( std::vector< LibType > const & input )\n\t{\n\t\tstd::vector< VkType > result;\n\t\tresult.reserve( input.size() );\n\n\t\tfor ( auto const & element : input )\n\t\t{\n\t\t\tresult.emplace_back( static_cast< VkType const & >( element ) );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tclass RenderPass\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\ttemplate< typename ConfigT, typename BuilderT >\n\t\tfriend class RenderQuadBuilderT;\n\n\t\tstruct SubpassContentsT;\n\t\tusing GetSubpassContentsCallback = GetValueCallbackT< SubpassContentsT, VkSubpassContents >;\n\n\t\tstruct Callbacks\n\t\t{\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, RecordCallback record );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetSubpassContentsCallback getSubpassContents );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetSubpassContentsCallback getSubpassContents\n\t\t\t\t, GetPassIndexCallback getPassIndex );\n\t\t\tCRG_API Callbacks( InitialiseCallback initialise\n\t\t\t\t, RecordCallback record\n\t\t\t\t, GetSubpassContentsCallback getSubpassContents\n\t\t\t\t, GetPassIndexCallback getPassIndex\n\t\t\t\t, IsEnabledCallback isEnabled );\n\n\t\t\t// RenderPass specifics\n\t\t\tRunnablePass::InitialiseCallback initialise;\n\t\t\tRunnablePass::RecordCallback record;\n\t\t\tGetSubpassContentsCallback getSubpassContents;\n\t\t\t// Passed to RunnablePass\n\t\t\tRunnablePass::GetPassIndexCallback getPassIndex;\n\t\t\tRunnablePass::IsEnabledCallback isEnabled;\n\t\t};\n\n\tpublic:\n\t\tCRG_API RenderPass( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, Callbacks callbacks\n\t\t\t, Extent2D size = {}\n\t\t\t, ru::Config const & ruConfig = {} );\n\n\t\tVkRenderPass getRenderPass( uint32_t passIndex )const\n\t\t{\n\t\t\treturn m_holder.getRenderPass( passIndex );\n\t\t}\n\n\tprotected:\n\t\tVkPipelineColorBlendStateCreateInfo doCreateBlendState()\n\t\t{\n\t\t\treturn m_holder.createBlendState();\n\t\t}\n\n\t\tVkPipelineColorBlendAttachmentStateArray const & doGetBlendAttachs()const\n\t\t{\n\t\t\treturn m_holder.getBlendAttachs();\n\t\t}\n\n\t\tRenderPassHolder const & doGetHolder()const\n\t\t{\n\t\t\treturn m_holder;\n\t\t}\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\n\tprivate:\n\t\tCallbacks m_rpCallbacks;\n\t\tRenderPassHolder m_holder;\n\t};\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< RenderPass::GetSubpassContentsCallback >\n\t{\n\t\tstatic RenderPass::GetSubpassContentsCallback get()\n\t\t{\n\t\t\tRenderPass::GetSubpassContentsCallback const result{ [](){ return VK_SUBPASS_CONTENTS_INLINE; } };\n\t\t\treturn result;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderPassHolder.hpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePass.hpp\"\n\nnamespace crg\n{\n\tclass RenderPassHolder\n\t{\n\tpublic:\n\t\tstruct Entry\n\t\t{\n\t\t\tEntry( crg::ImageViewId pview\n\t\t\t\t, LayoutState pinput\n\t\t\t\t, LayoutState poutput )\n\t\t\t\t: view{ std::move( pview ) }\n\t\t\t\t, input{ std::move( pinput ) }\n\t\t\t\t, output{ std::move( poutput ) }\n\t\t\t{\n\t\t\t}\n\n\t\t\tcrg::ImageViewId view;\n\t\t\tLayoutState input;\n\t\t\tLayoutState output;\n\t\t};\n\n\tpublic:\n\t\tRenderPassHolder( RenderPassHolder const & )noexcept = delete;\n\t\tRenderPassHolder & operator=( RenderPassHolder const & )noexcept = delete;\n\t\tRenderPassHolder( RenderPassHolder && )noexcept = delete;\n\t\tRenderPassHolder & operator=( RenderPassHolder && )noexcept = delete;\n\t\tCRG_API RenderPassHolder( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, uint32_t maxPassCount\n\t\t\t, Extent2D size = {} );\n\t\tCRG_API ~RenderPassHolder()noexcept;\n\n\t\tCRG_API bool initialise( RecordContext & context\n\t\t\t, crg::RunnablePass const & runnable\n\t\t\t, uint32_t passIndex );\n\t\tCRG_API VkRenderPassBeginInfo getBeginInfo( uint32_t index )const;\n\t\tCRG_API void begin( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, VkSubpassContents subpassContents\n\t\t\t, uint32_t index );\n\t\tCRG_API void end( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer );\n\t\tCRG_API VkPipelineColorBlendStateCreateInfo createBlendState();\n\t\tCRG_API VkFramebuffer getFramebuffer( uint32_t index )const;\n\n\t\tVkRenderPass getRenderPass( uint32_t index )const\n\t\t{\n\t\t\treturn m_passes[index].renderPass;\n\t\t}\n\n\t\tExtent2D const & getRenderSize()const\n\t\t{\n\t\t\treturn m_size;\n\t\t}\n\n\t\tRect2D const & getRenderArea( uint32_t index )const\n\t\t{\n\t\t\treturn m_passes[index].renderArea;\n\t\t}\n\n\t\tstd::vector< VkClearValue > const & getClearValues( uint32_t index )const\n\t\t{\n\t\t\treturn m_passes[index].clearValues;\n\t\t}\n\n\t\tVkPipelineColorBlendAttachmentStateArray const & getBlendAttachs()const\n\t\t{\n\t\t\treturn m_blendAttachs;\n\t\t}\n\n\tprivate:\n\t\tvoid doCreateRenderPass( RecordContext & context\n\t\t\t, crg::RunnablePass const & runnable\n\t\t\t, PipelineState const & previousState\n\t\t\t, PipelineState const & nextState\n\t\t\t, uint32_t passIndex );\n\t\tvoid doInitialiseRenderArea( uint32_t index );\n\t\tVkFramebuffer doCreateFramebuffer( uint32_t passIndex )const;\n\n\tprivate:\n\t\tstruct PassData\n\t\t{\n\t\t\tVkRenderPass renderPass{};\n\t\t\tmutable VkFramebuffer frameBuffer{};\n\t\t\tRect2D renderArea{};\n\t\t\tstd::vector< Attachment const * > attachments{};\n\t\t\tstd::vector< VkClearValue > clearValues{};\n\t\t\tstd::vector< Entry > attaches{};\n\t\t\tPipelineState previousState{};\n\t\t\tPipelineState nextState{};\n\n\t\t\tvoid cleanup( crg::GraphContext & context )noexcept;\n\t\t};\n\n\t\tFramePass const & m_pass;\n\t\tGraphContext & m_context;\n\t\tRunnableGraph & m_graph;\n\t\tExtent2D m_size;\n\t\tstd::vector< PassData > m_passes;\n\t\tPassData const * m_currentPass{};\n\t\tVkPipelineColorBlendAttachmentStateArray m_blendAttachs;\n\t\tuint32_t m_layers{};\n\t\tuint32_t m_index{};\n\t\tuint32_t m_count{ 1u };\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderQuad.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/RenderQuadHolder.hpp\"\n#include \"RenderGraph/RunnablePasses/RenderPass.hpp\"\n\nnamespace crg\n{\n\tclass RenderQuad\n\t\t: public RunnablePass\n\t{\n\tpublic:\n\t\ttemplate< typename ConfigT, typename BuilderT >\n\t\tfriend class RenderQuadBuilderT;\n\n\tpublic:\n\t\tCRG_API RenderQuad( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, ru::Config const & ruConfig\n\t\t\t, rq::Config rqConfig );\n\n\t\tCRG_API void resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\n\t\tVkPipelineLayout getPipelineLayout()const\n\t\t{\n\t\t\treturn m_renderQuad.getPipelineLayout();\n\t\t}\n\n\tprivate:\n\t\tvoid doRecordInto( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\t\tuint32_t doGetPassIndex()const;\n\t\tbool doIsEnabled()const;\n\n\tprivate:\n\t\tRenderQuadHolder m_renderQuad;\n\t\tRenderPassHolder m_renderPass;\n\t};\n\n\ttemplate< typename ConfigT, typename BuilderT >\n\tclass RenderQuadBuilderT\n\t\t: public PipelinePassBuilderT< BuilderT >\n\t{\n\t\tstatic_assert( std::is_same_v< ConfigT, rq::Config >\n\t\t\t|| std::is_base_of_v< rq::Config, ConfigT >\n\t\t\t, \"RenderQuadBuilderT::ConfigT must derive from crg::rq::Config\" );\n\n\tpublic:\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe texture coordinates configuration.\n\t\t*/\n\t\tauto & texcoordConfig( Texcoord config )\n\t\t{\n\t\t\tm_config.texcoordConfig( std::move( config ) );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe render area size.\n\t\t*/\n\t\tauto & renderSize( Extent2D config )\n\t\t{\n\t\t\tm_config.renderSize( std::move( config ) );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe render position.\n\t\t*/\n\t\tauto & renderPosition( Offset2D config )\n\t\t{\n\t\t\tm_config.renderPosition( std::move( config ) );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe depth stencil state.\n\t\t*/\n\t\tauto & depthStencilState( VkPipelineDepthStencilStateCreateInfo config )\n\t\t{\n\t\t\tm_config.depthStencilState( std::move( config ) );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe pass index.\n\t\t*/\n\t\tauto & passIndex( uint32_t const * config )\n\t\t{\n\t\t\tm_config.passIndex( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe enabled control variable.\n\t\t*/\n\t\tauto & enabled( bool const * config )\n\t\t{\n\t\t\tm_config.enabled( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe callback checking the enable status of the pass.\n\t\t*/\n\t\tauto & isEnabled( RunnablePass::IsEnabledCallback config )\n\t\t{\n\t\t\tm_config.isEnabled( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe callback to recording the pass.\n\t\t*/\n\t\tauto & recordInto( RunnablePass::RecordCallback config )\n\t\t{\n\t\t\tm_config.recordInto( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\param[in] config\n\t\t*\tThe instances count.\n\t\t*/\n\t\tauto & instances( uint32_t config )\n\t\t{\n\t\t\tm_config.instances( config );\n\t\t\treturn static_cast< BuilderT & >( *this );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tCreates the RenderQuad.\n\t\t*\\param[in] device\n\t\t*\tThe RenderDevice.\n\t\t*\\param[in] pass\n\t\t*\tThe render pass.\n\t\t*/\n\t\tstd::unique_ptr< RenderQuad > build( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, ru::Config ruConfig = {} )\n\t\t{\n\t\t\tm_config.baseConfig( std::move( this->getBaseConfig() ) );\n\t\t\treturn std::make_unique< RenderQuad >( pass\n\t\t\t\t, context\n\t\t\t\t, graph\n\t\t\t\t, std::move( ruConfig )\n\t\t\t\t, m_config );\n\t\t}\n\n\tprivate:\n\t\tConfigT m_config;\n\t};\n\n\tclass RenderQuadBuilder\n\t\t: public RenderQuadBuilderT< rq::Config, RenderQuadBuilder >\n\t{\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderQuadConfig.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/BufferViewData.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n#include \"RenderGraph/RunnablePasses/PipelineConfig.hpp\"\n\nnamespace crg\n{\n\tnamespace rq\n\t{\n\t\ttemplate< template< typename ValueT > typename WrapperT >\n\t\tstruct ConfigT\n\t\t{\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program.\n\t\t\t*/\n\t\t\tauto & program( VkPipelineShaderStageCreateInfoArray const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.program( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline programs.\n\t\t\t*/\n\t\t\tauto & programs( std::vector< VkPipelineShaderStageCreateInfoArray > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programs( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pipeline program creator.\n\t\t\t*/\n\t\t\tauto & programCreator( ProgramCreator const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.programCreator( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layout.\n\t\t\t*/\n\t\t\tauto & layout( VkDescriptorSetLayout const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layout( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe descriptor set layouts.\n\t\t\t*/\n\t\t\tauto & layouts( std::vector< VkDescriptorSetLayout > const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.layouts( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRange const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.pushConstants( VkPushConstantRangeArray{ config } );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe push constants range.\n\t\t\t*/\n\t\t\tauto & pushConstants( VkPushConstantRangeArray const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig.pushConstants( config );\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tTells if disabled pass should record render pass begin/end.\n\t\t\t*/\n\t\t\tauto & baseConfig( pp::Config const & config )\n\t\t\t{\n\t\t\t\tm_baseConfig = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe texture coordinates configuration.\n\t\t\t*/\n\t\t\tauto & texcoordConfig( Texcoord const & config )\n\t\t\t{\n\t\t\t\tm_texcoordConfig = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe render area size.\n\t\t\t*/\n\t\t\tauto & renderSize( Extent2D const & config )\n\t\t\t{\n\t\t\t\tm_renderSize = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe render position.\n\t\t\t*/\n\t\t\tauto & renderPosition( Offset2D const & config )\n\t\t\t{\n\t\t\t\tm_renderPosition = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe depth stencil state.\n\t\t\t*/\n\t\t\tauto & depthStencilState( VkPipelineDepthStencilStateCreateInfo const & config )\n\t\t\t{\n\t\t\t\tm_depthStencilState = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe pass index.\n\t\t\t*/\n\t\t\tauto & passIndex( uint32_t const * config )\n\t\t\t{\n\t\t\t\tm_passIndex = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe enabled control variable.\n\t\t\t*/\n\t\t\tauto & enabled( bool const * config )\n\t\t\t{\n\t\t\t\tm_enabled = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback checking the enable status of the pass.\n\t\t\t*/\n\t\t\tauto & isEnabled( RunnablePass::IsEnabledCallback const & config )\n\t\t\t{\n\t\t\t\tm_isEnabled = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback recording the pass.\n\t\t\t*/\n\t\t\tauto & recordInto( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_recordInto = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe callback ending the pass.\n\t\t\t*/\n\t\t\tauto & end( RunnablePass::RecordCallback const & config )\n\t\t\t{\n\t\t\t\tm_end = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe instances count.\n\t\t\t*/\n\t\t\tauto & instances( uint32_t config )\n\t\t\t{\n\t\t\t\tm_instances = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t/**\n\t\t\t*\\param[in] config\n\t\t\t*\tThe indirect buffer.\n\t\t\t*/\n\t\t\tauto & indirectBuffer( IndirectBuffer const & config )\n\t\t\t{\n\t\t\t\tm_indirectBuffer = config;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tpp::ConfigT< WrapperT > m_baseConfig{};\n\t\t\tWrapperT< Texcoord > m_texcoordConfig{};\n\t\t\tWrapperT< Offset2D > m_renderPosition{};\n\t\t\tWrapperT< VkPipelineDepthStencilStateCreateInfo > m_depthStencilState{};\n\t\t\tWrapperT< uint32_t const * > m_passIndex{};\n\t\t\tWrapperT< bool const * > m_enabled{};\n\t\t\tWrapperT< RunnablePass::IsEnabledCallback > m_isEnabled{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_recordInto{};\n\t\t\tWrapperT< RunnablePass::RecordCallback > m_end{};\n\t\t\tWrapperT< uint32_t > m_instances{};\n\t\t\tWrapperT< Extent2D > m_renderSize{};\n\t\t\tWrapperT< IndirectBuffer > m_indirectBuffer{};\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct ConfigT< RawTypeT >\n\t\t{\n\t\t\tRawTypeT< Texcoord > texcoordConfig;\n\t\t\tRawTypeT< Offset2D > renderPosition;\n\t\t\tRawTypeT< VkPipelineDepthStencilStateCreateInfo > depthStencilState;\n\t\t\tRawTypeT< uint32_t const * > passIndex;\n\t\t\tRawTypeT< bool const * > enabled;\n\t\t\tstd::optional< RunnablePass::IsEnabledCallback > isEnabled;\n\t\t\tRawTypeT< RunnablePass::RecordCallback > recordInto;\n\t\t\tRawTypeT< RunnablePass::RecordCallback > end;\n\t\t\tRawTypeT< uint32_t > m_instances;\n\t\t\tRawTypeT< IndirectBuffer > indirectBuffer{ BufferViewId{}, 0u };\n\t\t};\n\n\t\tusing Config = ConfigT< std::optional >;\n\t\tusing ConfigData = ConfigT< RawTypeT >;\n\t}\n\n\ttemplate<>\n\tstruct DefaultValueGetterT< rq::Config >\n\t{\n\t\tstatic rq::Config get()\n\t\t{\n\t\t\trq::Config const result{ []()\n\t\t\t\t{\n\t\t\t\t\treturn rq::Config{};\n\t\t\t\t}() };\n\t\t\treturn result;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/RunnablePasses/RenderQuadHolder.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/RunnablePasses/RenderQuadConfig.hpp\"\n#include \"RenderGraph/RunnablePasses/PipelineHolder.hpp\"\n\nnamespace crg\n{\n\tclass RenderQuadHolder\n\t{\n\tpublic:\n\t\tCRG_API RenderQuadHolder( FramePass const & pass\n\t\t\t, GraphContext & context\n\t\t\t, RunnableGraph & graph\n\t\t\t, rq::Config config\n\t\t\t, uint32_t maxPassCount );\n\n\t\tCRG_API void initialise( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetRenderPass( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t\t, uint32_t index );\n\t\tCRG_API void resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t\t, uint32_t index );\n\t\tCRG_API void record( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index );\n\t\tCRG_API void end( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const;\n\t\tCRG_API uint32_t getPassIndex()const;\n\t\tCRG_API bool isEnabled()const;\n\n\t\tVkPipelineVertexInputStateCreateInfo const & getInputState()const\n\t\t{\n\t\t\treturn m_vertexBuffer->inputState;\n\t\t}\n\n\t\tVkPipelineLayout getPipelineLayout()const\n\t\t{\n\t\t\treturn m_pipeline.getPipelineLayout();\n\t\t}\n\n\t\tbool isInitialised()const\n\t\t{\n\t\t\treturn m_vertexBuffer != nullptr;\n\t\t}\n\n\tprivate:\n\t\tvoid doPreparePipelineStates( Extent2D const & renderSize\n\t\t\t, VkRenderPass renderPass\n\t\t\t, VkPipelineColorBlendStateCreateInfo blendState );\n\t\tvoid doCreatePipeline( uint32_t passIndex );\n\t\tVkPipelineViewportStateCreateInfo doCreateViewportState( Extent2D const & renderSize\n\t\t\t, VkViewport & viewport\n\t\t\t, VkRect2D & scissor )const;\n\n\tprivate:\n\t\trq::ConfigData m_config;\n\t\tRunnableGraph & m_graph;\n\t\tPipelineHolder m_pipeline;\n\t\tbool m_useTexCoord{ true };\n\t\tVertexBuffer const * m_vertexBuffer{};\n\t\tVkRenderPass m_renderPass{};\n\t\tExtent2D m_renderSize{};\n\t\tVkViewport m_viewport{};\n\t\tVkRect2D m_scissor{};\n\t\tVkPipelineViewportStateCreateInfo m_vpState{};\n\t\tVkPipelineInputAssemblyStateCreateInfo m_iaState{};\n\t\tVkPipelineMultisampleStateCreateInfo m_msState{};\n\t\tVkPipelineRasterizationStateCreateInfo m_rsState{};\n\t\tVkPipelineColorBlendStateCreateInfo m_blendState{};\n\t\tVkPipelineColorBlendAttachmentStateArray m_blendAttachs{};\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/Signal.hpp",
    "content": "/*\nSee LICENSE file in root folder\n*/\n#pragma once\n\n#include <cassert>\n#include <functional>\n#include <set>\n#include <map>\n#pragma warning( push )\n#pragma warning( disable: 4365 )\n#pragma warning( disable: 5262 )\n#include <mutex>\n#pragma warning( pop )\n\nnamespace crg\n{\n\t/**\n\t*\\brief\n\t*\tA connection to a signal.\n\t*/\n\ttemplate< typename SignalT >\n\tclass SignalConnection\n\t{\n\tprivate:\n\t\tSignalConnection( SignalConnection< SignalT > const & ) = delete;\n\t\tSignalConnection & operator=( SignalConnection< SignalT > const & ) = delete;\n\n\t\tSignalConnection( uint32_t connection\n\t\t\t, SignalT * signal )\n\t\t\t: m_connection{ connection }\n\t\t\t, m_signal{ signal }\n\t\t{\n\t\t}\n\n\tpublic:\n\t\t/**\n\t\t*\\name\n\t\t*\tConstruction/Destruction.\n\t\t*/\n\t\t/**\\{*/\n\t\tSignalConnection()\n\t\t\t: SignalConnection{ 0u, nullptr }\n\t\t{\n\t\t}\n\n\t\tSignalConnection( SignalConnection< SignalT > && rhs )noexcept\n\t\t\t: SignalConnection{ 0u, nullptr }\n\t\t{\n\t\t\tswap( *this, rhs );\n\t\t}\n\n\t\tSignalConnection( uint32_t connection, SignalT & signal )\n\t\t\t: SignalConnection{ connection, &signal }\n\t\t{\n\t\t\tsignal.addConnection( *this );\n\t\t}\n\n\t\tSignalConnection & operator=( SignalConnection< SignalT > && rhs )noexcept\n\t\t{\n\t\t\tSignalConnection tmp{ std::move( rhs ) };\n\t\t\tswap( *this, tmp );\n\t\t\treturn *this;\n\t\t}\n\n\t\t~SignalConnection()noexcept\n\t\t{\n\t\t\tdisconnect();\n\t\t}\n\t\t/**\\}*/\n\t\t/**\n\t\t*\\brief\n\t\t*\tDisconnects from the signal.\n\t\t*/\n\t\tvoid disconnect()noexcept\n\t\t{\n\t\t\tif ( m_signal && m_connection )\n\t\t\t{\n\t\t\t\tm_signal->disconnect( m_connection );\n\t\t\t\tm_signal->remConnection( *this );\n\t\t\t\tm_signal = nullptr;\n\t\t\t\tm_connection = 0u;\n\t\t\t}\n\t\t}\n\n\t\tbool isValid()const noexcept\n\t\t{\n\t\t\treturn m_signal && m_connection;\n\t\t}\n\n\tprivate:\n\t\tstatic void swap( SignalConnection & lhs, SignalConnection & rhs )\n\t\t{\n\t\t\tif ( lhs.m_signal )\n\t\t\t\tlhs.m_signal->remConnection( lhs );\n\t\t\tif ( rhs.m_signal )\n\t\t\t\trhs.m_signal->remConnection( rhs );\n\n\t\t\tstd::swap( lhs.m_signal, rhs.m_signal );\n\t\t\tstd::swap( lhs.m_connection, rhs.m_connection );\n\n\t\t\tif ( lhs.m_signal )\n\t\t\t\tlhs.m_signal->addConnection( lhs );\n\t\t\tif ( rhs.m_signal )\n\t\t\t\trhs.m_signal->addConnection( rhs );\n\t\t}\n\n\tprivate:\n\t\tuint32_t m_connection;\n\t\tSignalT * m_signal;\n\t};\n\t/**\n\t*\\brief\n\t*\tSignal implementation.\n\t*/\n\ttemplate< typename Function >\n\tclass Signal\n\t{\n\t\tfriend class SignalConnection< Signal< Function > >;\n\t\tusing my_connection = SignalConnection< Signal< Function > >;\n\t\tusing my_connection_ptr = my_connection *;\n\t\tusing lock_type = std::unique_lock< std::recursive_mutex >;\n\n\tprivate:\n\t\tSignal( Signal const & )noexcept = delete;\n\t\tSignal & operator=( Signal const & )noexcept = delete;\n\t\tSignal( Signal && )noexcept = delete;\n\t\tSignal & operator=( Signal && )noexcept = delete;\n\n\tpublic:\n\t\tSignal()noexcept = default;\n\t\t/**\n\t\t*\\brief\n\t\t*\tDestructor.\n\t\t*\\remarks\n\t\t*\tDisconnects all remaining connections.\n\t\t*/\n\t\t~Signal()noexcept\n\t\t{\n\t\t\t// SignalConnection::disconnect appelle Signal::remConnection, qui\n\t\t\t// supprime la connection de m_connections, invalidant ainsi\n\t\t\t// l'itérateur, donc on ne peut pas utiliser un for_each, ni\n\t\t\t// un range for loop.\n\t\t\tlock_type lock( m_mutex );\n\t\t\tauto it = m_connections.begin();\n\n\t\t\twhile ( it != m_connections.end() )\n\t\t\t{\n\t\t\t\t( *it )->disconnect();\n\t\t\t\tit = m_connections.begin();\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tConnects a new function, called when the signal is emitted.\n\t\t*\\param[in] function\n\t\t*\tThe function.\n\t\t*\\return\n\t\t*\tThe connection.\n\t\t*/\n\t\tmy_connection connect( Function function )\n\t\t{\n\t\t\tuint32_t index = uint32_t( m_slots.size() ) + 1u;\n\t\t\tm_slots.emplace( index, function );\n\t\t\treturn my_connection{ index, *this };\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tEmits the signal, calling all connected functions.\n\t\t*/\n\t\tvoid operator()()const\n\t\t{\n\t\t\tauto it = m_slots.begin();\n\t\t\tsize_t size = m_slots.size();\n\t\t\tsize_t index = 0u;\n\n\t\t\twhile ( it != m_slots.end() )\n\t\t\t{\n\t\t\t\tit->second();\n\t\t\t\tadjustSlots( size, index, it );\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tEmits the signal, calling all connected functions.\n\t\t*\\param[in] params\n\t\t*\tThe functions parameters.\n\t\t*/\n\t\ttemplate< typename ... Params >\n\t\tvoid operator()( Params && ... params )const\n\t\t{\n\t\t\tauto it = m_slots.begin();\n\t\t\tsize_t size = m_slots.size();\n\t\t\tsize_t index = 0u;\n\n\t\t\twhile ( it != m_slots.end() )\n\t\t\t{\n\t\t\t\tit->second( std::forward< Params >( params )... );\n\t\t\t\tadjustSlots( size, index, it );\n\t\t\t}\n\t\t}\n\n\tprivate:\n\t\t/**\n\t\t*\\brief\n\t\t*\tDisconnects a function.\n\t\t*\\param[in] index\n\t\t*\tThe function index.\n\t\t*/\n\t\tvoid disconnect( uint32_t index )noexcept\n\t\t{\n\t\t\tauto it = m_slots.find( index );\n\n\t\t\tif ( it != m_slots.end() )\n\t\t\t{\n\t\t\t\tm_slots.erase( it );\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tAdds a connection to the list.\n\t\t*\\param[in] connection\n\t\t*\tThe connection to add.\n\t\t*/\n\t\tvoid addConnection( my_connection & connection )\n\t\t{\n\t\t\tlock_type lock( m_mutex );\n\t\t\tm_connections.insert( &connection );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tRemoves a connection from the list.\n\t\t*\\param[in] connection\n\t\t*\tThe connection to remove.\n\t\t*/\n\t\tvoid remConnection( my_connection & connection )noexcept\n\t\t{\n\t\t\tlock_type lock( m_mutex );\n\t\t\tassert( m_connections.find( &connection ) != m_connections.end() );\n\t\t\tm_connections.erase( &connection );\n\t\t}\n\t\t/**\n\t\t*\\brief\n\t\t*\tAdjusts returned slot iterator.\n\t\t*\\param[in,out] size\n\t\t*\tThe expected size, receives the real size.\n\t\t*\\param[in,out] index\n\t\t*\tThe current iteration index.\n\t\t*/\n\t\ttemplate< typename IterT >\n\t\tvoid adjustSlots( size_t & size\n\t\t\t, size_t & index\n\t\t\t, IterT & it )const noexcept\n\t\t{\n\t\t\tif ( size != m_slots.size() )\n\t\t\t{\n\t\t\t\t// Slots changed by the slot itself.\n\t\t\t\tsize = m_slots.size();\n\t\t\t\tit = m_slots.begin();\n\t\t\t\tstd::advance( it, index );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t++index;\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\tprivate:\n\t\tstd::map< uint32_t, Function > m_slots;\n\t\tstd::set< my_connection_ptr > m_connections;\n\t\tstd::recursive_mutex m_mutex;\n\t};\n}\n"
  },
  {
    "path": "include/RenderGraph/Version.hpp.in",
    "content": "/*\nSee LICENSE file in root folder\n*/\n#ifndef ___CRG_Version___\n#define ___CRG_Version___\n\n#define CRG_VersionMajor ${VERSION_MAJOR}\n#define CRG_VersionMinor ${VERSION_MINOR}\n#define CRG_VersionBuild ${VERSION_BUILD}\n\n#endif\n"
  },
  {
    "path": "include/RenderGraph/WriteDescriptorSet.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\nnamespace crg\n{\n\tstruct WriteDescriptorSet\n\t{\n\t\tWriteDescriptorSet( uint32_t dstBinding\n\t\t\t, uint32_t dstArrayElement\n\t\t\t, uint32_t descriptorCount\n\t\t\t, VkDescriptorType descriptorType )\n\t\t\t: vk{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, VkDescriptorSet{}, dstBinding, dstArrayElement, descriptorCount, descriptorType, nullptr, nullptr, nullptr }\n\t\t\t, needsUpdate{ true }\n\t\t{\n\t\t}\n\n\t\tWriteDescriptorSet( uint32_t dstBinding\n\t\t\t, uint32_t dstArrayElement\n\t\t\t, VkDescriptorType descriptorType\n\t\t\t, VkDescriptorImageInfo imageInfos )\n\t\t\t: imageInfo{ 1u, imageInfos }\n\t\t\t, vk{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, VkDescriptorSet{}, dstBinding, dstArrayElement, uint32_t( this->imageInfo.size() ), descriptorType, nullptr, nullptr, nullptr }\n\t\t\t, needsUpdate{ true }\n\t\t{\n\t\t}\n\n\t\tWriteDescriptorSet( uint32_t dstBinding\n\t\t\t, uint32_t dstArrayElement\n\t\t\t, VkDescriptorType descriptorType\n\t\t\t, VkDescriptorImageInfoArray imageInfos )\n\t\t\t: imageInfo{ std::move( imageInfos ) }\n\t\t\t, vk{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, VkDescriptorSet{}, dstBinding, dstArrayElement, uint32_t( this->imageInfo.size() ), descriptorType, nullptr, nullptr, nullptr }\n\t\t\t, needsUpdate{ true }\n\t\t{\n\t\t}\n\n\t\tWriteDescriptorSet( VkDescriptorSet set\n\t\t\t, uint32_t dstBinding\n\t\t\t, uint32_t dstArrayElement\n\t\t\t, uint32_t descriptorCount\n\t\t\t, VkDescriptorType descriptorType\n\t\t\t, VkDescriptorImageInfo const * imageInfo\n\t\t\t, VkDescriptorBufferInfo const * bufferInfo\n\t\t\t, VkBufferView const * texelBufferView )\n\t\t\t: vk{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, set, dstBinding, dstArrayElement, descriptorCount, descriptorType, imageInfo, bufferInfo, texelBufferView }\n\t\t\t, needsUpdate{ false }\n\t\t{\n\t\t}\n\n\t\tvoid update( VkDescriptorSet descriptorSet )const noexcept\n\t\t{\n\t\t\tif ( needsUpdate )\n\t\t\t{\n\t\t\t\tvk.dstSet = descriptorSet;\n\t\t\t\tvk.pImageInfo = imageInfo.data();\n\t\t\t\tvk.pBufferInfo = bufferInfo.data();\n\t\t\t\tvk.pTexelBufferView = texelBufferView.data();\n\t\t\t}\n\t\t}\n\n\t\texplicit operator VkWriteDescriptorSet const & ()const noexcept\n\t\t{\n\t\t\treturn vk;\n\t\t}\n\n\t\tVkWriteDescriptorSet const * operator->()const noexcept\n\t\t{\n\t\t\treturn &vk;\n\t\t}\n\n\t\tVkWriteDescriptorSet * operator->()noexcept\n\t\t{\n\t\t\treturn &vk;\n\t\t}\n\n\t\tVkDescriptorImageInfoArray imageInfo;\n\t\tVkDescriptorBufferInfoArray bufferInfo;\n\t\tVkDescriptorBufferInfoArray bufferViewInfo;\n\t\tVkBufferViewArray texelBufferView;\n\n\tprivate:\n\t\tmutable VkWriteDescriptorSet vk;\n\t\tbool needsUpdate;\n\t};\n}\n"
  },
  {
    "path": "source/CMakeLists.txt",
    "content": "cmake_minimum_required( VERSION 3.10 )\ncmake_policy( VERSION 3.10 )\n\n#--------------------------------------------------------------------------------------------------\n#\tInitial configurations\n#--------------------------------------------------------------------------------------------------\n# Set project name, used in folders and in workspace creation\nset( MAIN_PROJECT_NAME \"RenderGraph\" )\n\n# Set project version numbers\nset( VERSION_MAJOR 2 )\nset( VERSION_MINOR 1 )\nset( VERSION_BUILD 0 )\nset( VERSION_YEAR 2025 )\n\nset( _PROJECT_VERSION \"${VERSION_MAJOR}.${VERSION_MINOR}\" )\nset( _PROJECT_SOVERSION \"${VERSION_BUILD}\" )\n\n# Used to look for external modules\nif ( NOT CMAKE_MODULE_PATH )\n\tset( CMAKE_MODULE_PATH\n\t\t${CMAKE_SOURCE_DIR}/CMake\n\t\t${CMAKE_SOURCE_DIR}/CMake/Modules\n\t\t${CMAKE_SOURCE_DIR}/CMake/Toolchains\n\t)\n\tset( CMAKE_TEMPLATES_DIR ${CMAKE_SOURCE_DIR}/CMake/Templates )\nendif ()\n\nset( CMAKE_POSITION_INDEPENDENT_CODE ON )\nset( CMAKE_CONFIGURATION_TYPES \"Debug;Release;RelWithDebInfo\" CACHE STRING \"The configuration types\" FORCE )\n\n# Experimental Precompiled headers support for GCC\ninclude( PCHSupport )\n\n# Declare the project\nproject( ${MAIN_PROJECT_NAME} )\n\ninclude( Setup )\ninclude( Project )\ninclude( CompilerVersion )\ninclude( UnitTest )\ninclude( CompilationFlags )\ninclude( AStyleUtils )\ninclude( ExternalDependencies )\ninclude( Coverage )\n\n# Organize projects into folders\nset_property( GLOBAL PROPERTY USE_FOLDERS ON )\n\n#--------------------------------------------------------------------------------------------------\n#\tAdding include dirs to include search path\n#--------------------------------------------------------------------------------------------------\nset( CRG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )\nset( CRG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )\n\nset( CRG_EDITORCONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/.editorconfig )\n\nif ( NOT DEFINED CRG_BUILD_STATIC )\n\toption( CRG_BUILD_STATIC \"Build as a static library\" ON )\nendif ()\nif ( NOT DEFINED CRG_BUILD_TESTS )\n\toption( CRG_BUILD_TESTS \"Build RenderGraph test applications\" OFF )\nendif ()\nif ( NOT DEFINED CRG_UNITY_BUILD )\n\toption( CRG_UNITY_BUILD \"Build RenderGraph using Unity (Jumbo) build method\" OFF )\nendif ()\n\nset( PROJECTS_UNITY_BUILD ${CRG_UNITY_BUILD} )\n\nif ( MSVC OR NOT \"${CMAKE_BUILD_TYPE}\" STREQUAL \"\" )\n\tconfigure_file(\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Version.hpp.in\n\t\t${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\tNEWLINE_STYLE LF\n\t)\n\t# RenderGraph library\n\tproject( RenderGraph )\n\tset( ${PROJECT_NAME}_HDR_FILES\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Attachment.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/AttachmentTransition.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/BufferViewData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/DotExport.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Exception.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraph.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphBase.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphEnums.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphFunctions.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphPrerequisites.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FrameGraphStructs.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePassGroup.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/FramePassTimer.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphContext.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphNode.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/GraphVisitor.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Hash.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Id.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ImageViewData.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/LayerLayoutStatesHandler.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Log.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/PixelFormat.inl\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RecordContext.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/ResourceHandler.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnableGraph.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/Signal.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/WriteDescriptorSet.hpp\n\t\t${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.hpp\n\t)\n\tset( ${PROJECT_NAME}_SRC_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/Attachment.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/AttachmentTransition.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/DotExport.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraph.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraphPrerequisites.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassGroup.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FramePassTimer.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphBuilder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphContext.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/GraphNode.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/LayerLayoutStatesHandler.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/Log.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RecordContext.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/ResourceHandler.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnableGraph.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePass.cpp\n\t)\n\tset( ${PROJECT_NAME}_NVS_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/FrameGraph.natvis\n\t)\n\tsource_group( \"Header Files\" FILES ${${PROJECT_NAME}_HDR_FILES} )\n\tsource_group( \"Source Files\" FILES ${${PROJECT_NAME}_SRC_FILES} )\n\tsource_group( \"Visualisation Files\" FILES ${${PROJECT_NAME}_NVS_FILES} )\n\tset( ${PROJECT_NAME}_FOLDER_HDR_FILES\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/BufferCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/BufferToImageCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ComputePass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/GenerateMipmaps.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageBlit.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/ImageToBufferCopy.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/PipelineConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/PipelineHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderPass.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderPassHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMesh.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMeshConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderMeshHolder.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuad.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuadConfig.hpp\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}/RunnablePasses/RenderQuadHolder.hpp\n\t)\n\tset( ${PROJECT_NAME}_FOLDER_SRC_FILES\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/BufferCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/BufferToImageCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ComputePass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/GenerateMipmaps.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageBlit.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/ImageToBufferCopy.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/PipelineHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderPass.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderPassHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderMesh.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderMeshHolder.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderQuad.cpp\n\t\t${CRG_SOURCE_DIR}/source/${PROJECT_NAME}/RunnablePasses/RenderQuadHolder.cpp\n\t)\n\tset( ${PROJECT_NAME}_SRC_FILES\n\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t${${PROJECT_NAME}_FOLDER_SRC_FILES}\n\t)\n\tset( ${PROJECT_NAME}_HDR_FILES\n\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t${${PROJECT_NAME}_FOLDER_HDR_FILES}\n\t)\n\tsource_group( \"Header Files\\\\RunnablePasses\" FILES ${${PROJECT_NAME}_FOLDER_HDR_FILES} )\n\tsource_group( \"Source Files\\\\RunnablePasses\" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} )\n\tif ( ${PROJECTS_UNITY_BUILD} )\n\t\tfile( GLOB ${PROJECT_NAME}_FOLDER_SRC_FILES\n\t\t\t${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/Unity/*.cxx\n\t\t)\n\t\tsource_group( \"Source Files\\\\Unity\" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} )\n\tendif ()\n\tif ( CRG_BUILD_STATIC )\n\t\tadd_library( ${PROJECT_NAME} STATIC\n\t\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t\t${${PROJECT_NAME}_NVS_FILES}\n\t\t)\n\t\ttarget_compile_definitions( ${PROJECT_NAME}\n\t\t\tPUBLIC\n\t\t\t\tCRG_BUILD_STATIC\n\t\t)\n\telse ()\n\t\tadd_library( ${PROJECT_NAME} SHARED\n\t\t\t${${PROJECT_NAME}_HDR_FILES}\n\t\t\t${${PROJECT_NAME}_SRC_FILES}\n\t\t\t${${PROJECT_NAME}_NVS_FILES}\n\t\t)\n\t\tset_target_properties( ${PROJECT_NAME}\n\t\t\tPROPERTIES\n\t\t\t\tVERSION ${_PROJECT_VERSION}\n\t\t\t\tSOVERSION ${_PROJECT_SOVERSION}\n\t\t)\n\t\tif ( WIN32 )\n\t\t\ttarget_link_libraries( ${PROJECT_NAME}\n\t\t\t\tPUBLIC\n\t\t\t\t\tDbghelp\n\t\t\t)\n\t\telse ()\n\t\t\ttarget_link_libraries( ${PROJECT_NAME}\n\t\t\t\tPRIVATE\n\t\t\t\t\tdl\n\t\t\t)\n\t\tendif ()\n\tendif ()\n\tadd_library( crg::${PROJECT_NAME}\n\t\tALIAS\n\t\t\t${PROJECT_NAME}\n\t)\n\ttarget_add_coverage_flags( ${PROJECT_NAME} )\n\ttarget_sources( ${PROJECT_NAME} \n\t\tPRIVATE\n\t\t\t${CRG_EDITORCONFIG_FILE}\n\t)\n\ttarget_add_compilation_flags( ${PROJECT_NAME} )\n\ttarget_compile_options( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\t$<$<CXX_COMPILER_ID:MSVC>:/Zm300>\n\t\t\t$<$<CXX_COMPILER_ID:AppleClang>:-Wno-poison-system-directories>\n\t\t\t$<$<CXX_COMPILER_ID:Clang>:-Wno-poison-system-directories>\n\t)\n\ttarget_compile_definitions( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\tCRG_VERSION_MAJOR=${VERSION_MAJOR}\n\t\t\tCRG_VERSION_MINOR=${VERSION_MINOR}\n\t\t\tCRG_VERSION_BUILD=${VERSION_BUILD}\n\t)\n\ttarget_include_directories( ${PROJECT_NAME}\n\t\tPUBLIC\n\t\t\t$<BUILD_INTERFACE:${CRG_SOURCE_DIR}/include>\n\t\t\t$<BUILD_INTERFACE:${CRG_BINARY_DIR}>\n\t\t\t$<BUILD_INTERFACE:${Vulkan_INCLUDE_DIR}>\n\t\t\t$<INSTALL_INTERFACE:include>\n\t)\n\tfind_package( VulkanHeaders CONFIG )\n\ttarget_link_libraries( ${PROJECT_NAME}\n\t\tPRIVATE\n\t\t\tVulkan::Headers\n\t)\n\tmessage( STATUS \"PROJECTS_UNITY_BUILD [${PROJECTS_UNITY_BUILD}]\" )\n\tset_target_properties( ${PROJECT_NAME}\n\t\tPROPERTIES\n\t\t\tCXX_STANDARD 20\n\t\t\tFOLDER \"${CRG_BASE_DIR}/Core\"\n\t\t\tDEBUG_POSTFIX \"d\"\n\t\t\tUNITY_BUILD \"${PROJECTS_UNITY_BUILD}\"\n\t)\n\tinstall(\n\t\tTARGETS ${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tEXPORT ${PROJECT_NAME}\n\t\tRUNTIME DESTINATION bin\n\t\tARCHIVE DESTINATION lib\n\t\tLIBRARY DESTINATION lib\n\t)\n\tinstall(\n\t\tFILES ${CRG_BINARY_DIR}/include/${PROJECT_NAME}/Version.hpp\n\t\tDESTINATION include/${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tCONFIGURATIONS Release\n\t)\n\ttarget_install_headers( ${PROJECT_NAME}\n\t\t${CRG_SOURCE_DIR}/include/${PROJECT_NAME}\n\t)\n\tinstall( EXPORT ${PROJECT_NAME}\n\t\tCOMPONENT ${PROJECT_NAME}\n\t\tFILE ${PROJECT_NAME}Config.cmake\n\t\tNAMESPACE crg::\n\t\tDESTINATION share/${PROJECT_NAME}\n\t)\n\tinclude(CMakePackageConfigHelpers)\n\twrite_basic_package_version_file( ${PROJECT_NAME}ConfigVersion.cmake\n\t\tVERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}\n\t\tCOMPATIBILITY AnyNewerVersion\n\t)\n\n\tif ( CRG_BUILD_TESTS )\n\t\tadd_subdirectory( test )\n\tendif ()\nelse()\n\tmessage( SEND_ERROR \"Please select a build type (Debug or Release)\" )\nendif()\n"
  },
  {
    "path": "source/RenderGraph/Attachment.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/Attachment.hpp\"\n#include \"RenderGraph/BufferData.hpp\"\n#include \"RenderGraph/BufferViewData.hpp\"\n#include \"RenderGraph/Exception.hpp\"\n#include \"RenderGraph/ImageData.hpp\"\n#include \"RenderGraph/ImageViewData.hpp\"\n#include \"RenderGraph/WriteDescriptorSet.hpp\"\n\n#include <cassert>\n#include <cstring>\n\nnamespace crg\n{\n\t//*********************************************************************************************\n\n\tBufferAttachment::BufferAttachment( BufferViewIdArray views )\n\t\t: buffers{ std::move( views ) }\n\t\t, flags{ FlagKind( buffers.front().data->info.format == PixelFormat::eUNDEFINED\n\t\t\t? Flag::None\n\t\t\t: Flag::View ) }\n\t{\n\t}\n\n\tBufferAttachment::BufferAttachment( FlagKind pflags\n\t\t, BufferViewIdArray views\n\t\t, AccessState access )\n\t\t: buffers{ std::move( views ) }\n\t\t, flags{ FlagKind( pflags\n\t\t\t| FlagKind( buffers.front().data->info.format == PixelFormat::eUNDEFINED ? Flag::None : Flag::View ) ) }\n\t\t, wantedAccess{ std::move( access ) }\n\t{\n\t}\n\n\tBufferViewId BufferAttachment::buffer( uint32_t index )const\n\t{\n\t\treturn buffers.size() == 1u\n\t\t\t? buffers.front()\n\t\t\t: buffers[index];\n\t}\n\n\tAccessFlags BufferAttachment::getAccessMask( bool isInput\n\t\t, bool isOutput )const\n\t{\n\t\tAccessFlags result{ 0u };\n\n\t\tif ( isTransition() )\n\t\t{\n\t\t\tresult = wantedAccess.access;\n\t\t}\n\t\telse if ( isStorage() )\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t{\n\t\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t\t}\n\n\t\t\tif ( isOutput )\n\t\t\t{\n\t\t\t\tresult |= AccessFlags::eShaderWrite;\n\t\t\t}\n\t\t}\n\t\telse if ( isTransfer() )\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t{\n\t\t\t\tresult |= AccessFlags::eTransferRead;\n\t\t\t}\n\n\t\t\tif ( isOutput )\n\t\t\t{\n\t\t\t\tresult |= AccessFlags::eTransferWrite;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tPipelineStageFlags BufferAttachment::getPipelineStageFlags( bool isCompute )const\n\t{\n\t\tPipelineStageFlags result{ 0u };\n\n\t\tif ( isTransition() )\n\t\t{\n\t\t\tresult = wantedAccess.pipelineStage;\n\t\t}\n\t\telse if ( isTransfer() )\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eTransfer;\n\t\t}\n\t\telse if ( isCompute )\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eComputeShader;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eFragmentShader;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tuint32_t BufferAttachment::getBufferCount()const\n\t{\n\t\treturn uint32_t( buffers.size() );\n\t}\n\n\t//*********************************************************************************************\n\n\tImageAttachment::ImageAttachment( ImageViewIdArray views )\n\t\t: views{std::move( views )  }\n\t{\n\t}\n\n\tImageAttachment::ImageAttachment( FlagKind flags\n\t\t, ImageViewIdArray views\n\t\t, AttachmentLoadOp loadOp\n\t\t, AttachmentStoreOp storeOp\n\t\t, AttachmentLoadOp stencilLoadOp\n\t\t, AttachmentStoreOp stencilStoreOp\n\t\t, ClearValue clearValue\n\t\t, PipelineColorBlendAttachmentState blendState\n\t\t, ImageLayout wantedLayout )\n\t\t: views{ std::move( views ) }\n\t\t, loadOp{ loadOp }\n\t\t, storeOp{ storeOp }\n\t\t, stencilLoadOp{ stencilLoadOp }\n\t\t, stencilStoreOp{ stencilStoreOp }\n\t\t, clearValue{ std::move( clearValue ) }\n\t\t, blendState{ std::move( blendState ) }\n\t\t, wantedLayout{ wantedLayout }\n\t\t, flags{ flags }\n\t{\n\t\tassert( ( checkFlag( getAspectFlags( view() ), ImageAspectFlags::eColor ) && isColourFormat( getFormat( view() ) ) )\n\t\t\t|| ( checkFlag( getAspectFlags( view() ), ImageAspectFlags::eDepthStencil ) && isDepthStencilFormat( getFormat( view() ) ) )\n\t\t\t|| ( checkFlag( getAspectFlags( view() ), ImageAspectFlags::eDepth ) && isDepthFormat( getFormat( view() ) ) )\n\t\t\t|| ( checkFlag( getAspectFlags( view() ), ImageAspectFlags::eStencil ) && isStencilFormat( getFormat( view() ) ) ) );\n\t\tassert( ( !isSampledView() && !isTransitionView() && !isTransferView() )\n\t\t\t|| ( ( this->loadOp == AttachmentLoadOp::eDontCare )\n\t\t\t\t&& ( this->storeOp == AttachmentStoreOp::eDontCare )\n\t\t\t\t&& ( this->stencilLoadOp == AttachmentLoadOp::eDontCare )\n\t\t\t\t&& ( this->stencilStoreOp == AttachmentStoreOp::eDontCare ) ) );\n\t}\n\n\tImageViewId ImageAttachment::view( uint32_t index )const\n\t{\n\t\treturn views.size() == 1u\n\t\t\t? views.front()\n\t\t\t: views[index];\n\t}\n\n\tImageLayout ImageAttachment::getImageLayout( bool separateDepthStencilLayouts\n\t\t, bool isInput\n\t\t, bool isOutput )const\n\t{\n\t\tauto result = ImageLayout::eReadOnly;\n\n\t\tif ( isSampledView() )\n\t\t{\n\t\t\tresult = ImageLayout::eShaderReadOnly;\n\t\t}\n\t\telse if ( isTransitionView() )\n\t\t{\n\t\t\tresult = wantedLayout;\n\t\t}\n\t\telse if ( isStorageView() )\n\t\t{\n\t\t\tresult = ImageLayout::eGeneral;\n\t\t}\n\t\telse if ( isTransferView() )\n\t\t{\n\t\t\tif ( isOutput )\n\t\t\t\tresult = ImageLayout::eTransferDst;\n\t\t\telse if ( isInput )\n\t\t\t\tresult = ImageLayout::eTransferSrc;\n\t\t}\n\t\telse if ( isColourTarget() )\n\t\t{\n\t\t\tresult = ImageLayout::eColorAttachment;\n\t\t}\n#if VK_KHR_separate_depth_stencil_layouts\n\t\telse if ( separateDepthStencilLayouts )\n\t\t{\n\t\t\tif ( isDepthStencilTarget() )\n\t\t\t{\n\t\t\t\tif ( isOutput )\n\t\t\t\t\tresult = ImageLayout::eDepthStencilAttachment;\n\t\t\t\telse if ( isInput )\n\t\t\t\t\tresult = ImageLayout::eDepthStencilReadOnly;\n\t\t\t}\n\t\t\telse if ( isStencilTarget() )\n\t\t\t{\n\t\t\t\tif ( isOutput && isStencilOutputTarget() )\n\t\t\t\t\tresult = ImageLayout::eStencilAttachment;\n\t\t\t\telse if ( isInput && isStencilInputTarget() )\n\t\t\t\t\tresult = ImageLayout::eStencilReadOnly;\n\t\t\t}\n\t\t\telse if ( isDepthTarget() )\n\t\t\t{\n\t\t\t\tif ( isOutput )\n\t\t\t\t\tresult = ImageLayout::eDepthAttachment;\n\t\t\t\telse if ( isInput )\n\t\t\t\t\tresult = ImageLayout::eDepthReadOnly;\n\t\t\t}\n\t\t}\n\t\telse\n#endif\n\t\t{\n\t\t\tif ( isOutput\n\t\t\t\t&& ( isDepthTarget() || isStencilOutputTarget() ) )\n\t\t\t{\n\t\t\t\tresult = ImageLayout::eDepthStencilAttachment;\n\t\t\t}\n\t\t\telse if ( isInput\n\t\t\t\t&& ( isDepthTarget() || isStencilInputTarget() ) )\n\t\t\t{\n\t\t\t\tresult = ImageLayout::eDepthStencilReadOnly;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tAccessFlags ImageAttachment::getAccessMask( bool isInput\n\t\t, bool isOutput )const\n\t{\n\t\tAccessFlags result{ 0u };\n\n\t\tif ( isSampledView() )\n\t\t{\n\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t}\n\t\telse if ( isTransitionView() )\n\t\t{\n\t\t\tresult |= crg::getAccessMask( wantedLayout );\n\t\t}\n\t\telse if ( isStorageView() )\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t\tif ( isOutput )\n\t\t\t\tresult |= AccessFlags::eShaderWrite;\n\t\t}\n\t\telse if ( isTransferView() )\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t\tresult |= AccessFlags::eTransferRead;\n\t\t\tif ( isOutput )\n\t\t\t\tresult |= AccessFlags::eTransferWrite;\n\t\t}\n\t\telse if ( isDepthTarget() || isStencilTarget() )\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t\tresult |= AccessFlags::eDepthStencilAttachmentRead;\n\t\t\tif ( isOutput )\n\t\t\t\tresult |= AccessFlags::eDepthStencilAttachmentWrite;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( isInput )\n\t\t\t\tresult |= AccessFlags::eColorAttachmentRead;\n\t\t\tif ( isOutput )\n\t\t\t\tresult |= AccessFlags::eColorAttachmentWrite;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tPipelineStageFlags ImageAttachment::getPipelineStageFlags( bool isCompute )const\n\t{\n\t\tPipelineStageFlags result{ 0u };\n\n\t\tif ( isSampledView() )\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eFragmentShader;\n\t\t}\n\t\telse if ( isTransitionView() )\n\t\t{\n\t\t\tresult |= getStageMask( wantedLayout );\n\t\t}\n\t\telse if ( isStorageView() )\n\t\t{\n\t\t\tif ( isCompute )\n\t\t\t\tresult |= PipelineStageFlags::eComputeShader;\n\t\t\telse\n\t\t\t\tresult |= PipelineStageFlags::eFragmentShader;\n\t\t}\n\t\telse if ( isTransferView() )\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eTransfer;\n\t\t}\n\t\telse if ( isDepthTarget() || isStencilTarget() )\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eLateFragmentTests;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult |= PipelineStageFlags::eColorAttachmentOutput;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t//*********************************************************************************************\n\n\tAttachment::Attachment( Attachment const & rhs )\n\t\t: pass{ rhs.pass }\n\t\t, name{ rhs.name }\n\t\t, imageAttach{ rhs.imageAttach }\n\t\t, bufferAttach{ rhs.bufferAttach }\n\t\t, flags{ rhs.flags }\n\t{\n\t}\n\n\tAttachment & Attachment::operator=( Attachment const & rhs )\n\t{\n\t\tpass = rhs.pass;\n\t\tname = rhs.name;\n\t\timageAttach = rhs.imageAttach;\n\t\tbufferAttach = rhs.bufferAttach;\n\t\tflags = rhs.flags;\n\n\t\treturn *this;\n\t}\n\n\tAttachment::Attachment( ImageViewId view\n\t\t, Attachment const & origin )\n\t\t: pass{ origin.pass }\n\t\t, name{ origin.name + view.data->name }\n\t\t, imageAttach{ origin.imageAttach }\n\t\t, flags{ origin.flags }\n\t{\n\t\timageAttach.views = { view };\n\t}\n\n\tAttachment::Attachment( BufferViewId view\n\t\t, Attachment const & origin )\n\t\t: pass{ origin.pass }\n\t\t, name{ origin.name + view.data->name }\n\t\t, bufferAttach{ origin.bufferAttach }\n\t\t, flags{ origin.flags }\n\t{\n\t\tbufferAttach.buffers = { view };\n\t}\n\n\tAttachment::Attachment( ImageViewIdArray views )\n\t\t: imageAttach{ std::move( views ) }\n\t\t, flags{ FlagKind( Attachment::Flag::Image ) }\n\t{\n\t}\n\n\tAttachment::Attachment( BufferViewIdArray views )\n\t\t: bufferAttach{ std::move( views ) }\n\t\t, flags{ FlagKind( Attachment::Flag::Buffer ) }\n\t{\n\t}\n\n\tAttachment::Attachment( FlagKind pflags\n\t\t, FramePass const & framePass\n\t\t, std::string name\n\t\t, ImageAttachment::FlagKind imageFlags\n\t\t, ImageViewIdArray views\n\t\t, AttachmentLoadOp loadOp\n\t\t, AttachmentStoreOp storeOp\n\t\t, AttachmentLoadOp stencilLoadOp\n\t\t, AttachmentStoreOp stencilStoreOp\n\t\t, ClearValue clearValue\n\t\t, PipelineColorBlendAttachmentState blendState\n\t\t, ImageLayout wantedLayout\n\t\t, Token )\n\t\t: pass{ &framePass }\n\t\t, name{ std::move( name ) }\n\t\t, imageAttach{ imageFlags\n\t\t\t, std::move( views )\n\t\t\t, loadOp\n\t\t\t, storeOp\n\t\t\t, stencilLoadOp\n\t\t\t, stencilStoreOp\n\t\t\t, std::move( clearValue )\n\t\t\t, std::move( blendState )\n\t\t\t, wantedLayout }\n\t\t, flags{ FlagKind( pflags\n\t\t\t| FlagKind( Flag::Image )\n\t\t\t| ( loadOp == AttachmentLoadOp::eLoad\n\t\t\t\t? FlagKind( Flag::Input )\n\t\t\t\t: FlagKind( Flag::None ) )\n\t\t\t| ( storeOp == AttachmentStoreOp::eStore\n\t\t\t\t? FlagKind( Flag::Output )\n\t\t\t\t: FlagKind( Flag::None ) )\n\t\t\t| ( stencilLoadOp == AttachmentLoadOp::eLoad\n\t\t\t\t? FlagKind( Flag::Input )\n\t\t\t\t: FlagKind( Flag::None ) )\n\t\t\t| ( stencilStoreOp == AttachmentStoreOp::eStore\n\t\t\t\t? FlagKind( Flag::Output )\n\t\t\t\t: FlagKind( Flag::None ) ) ) }\n\t{\n\t}\n\n\tAttachment::Attachment( FlagKind pflags\n\t\t, FramePass const & framePass\n\t\t, std::string name\n\t\t, BufferAttachment::FlagKind bufferFlags\n\t\t, BufferViewIdArray views\n\t\t, AccessState wantedAccess\n\t\t, Token )\n\t\t: pass{ &framePass }\n\t\t, name{ std::move( name ) }\n\t\t, bufferAttach{ bufferFlags, std::move( views ), std::move( wantedAccess ) }\n\t\t, flags{ FlagKind( pflags\n\t\t\t| FlagKind( Flag::Buffer ) ) }\n\t{\n\t}\n\n\tAttachment::Attachment( FlagKind pflags\n\t\t, std::string name\n\t\t, FramePass const * framePass\n\t\t, ImageAttachment attach\n\t\t, Token )\n\t\t: pass{ framePass }\n\t\t, name{ std::move( name ) }\n\t\t, imageAttach{ std::move( attach ) }\n\t\t, flags{ pflags }\n\t{\n\t}\n\n\tAttachment::Attachment( FlagKind pflags\n\t\t, std::string name\n\t\t, FramePass const * framePass\n\t\t, BufferAttachment attach\n\t\t, Token )\n\t\t: pass{ framePass }\n\t\t, name{ std::move( name ) }\n\t\t, bufferAttach{ std::move( attach ) }\n\t\t, flags{ pflags }\n\t{\n\t}\n\n\tuint32_t Attachment::getViewCount()const\n\t{\n\t\treturn isImage()\n\t\t\t? imageAttach.getViewCount()\n\t\t\t: uint32_t{};\n\t}\n\n\tuint32_t Attachment::getBufferCount()const\n\t{\n\t\treturn isBuffer()\n\t\t\t? bufferAttach.getBufferCount()\n\t\t\t: uint32_t{};\n\t}\n\n\tImageViewId Attachment::view( uint32_t index )const\n\t{\n\t\treturn isImage()\n\t\t\t? imageAttach.view( index )\n\t\t\t: ImageViewId{};\n\t}\n\n\tBufferViewId Attachment::buffer( uint32_t index )const\n\t{\n\t\treturn isBuffer()\n\t\t\t? bufferAttach.buffer( index )\n\t\t\t: BufferViewId{};\n\t}\n\n\tImageLayout Attachment::getImageLayout( bool separateDepthStencilLayouts )const\n\t{\n\t\tassert( isImage() );\n\t\treturn imageAttach.getImageLayout( separateDepthStencilLayouts\n\t\t\t, isInput()\n\t\t\t, isOutput() );\n\t}\n\n\tAccessFlags Attachment::getAccessMask()const\n\t{\n\t\tif ( isImage() )\n\t\t{\n\t\t\treturn imageAttach.getAccessMask( isInput()\n\t\t\t\t, isOutput() );\n\t\t}\n\n\t\treturn bufferAttach.getAccessMask( isInput()\n\t\t\t, isOutput() );\n\t}\n\n\tPipelineStageFlags Attachment::getPipelineStageFlags( bool isCompute )const\n\t{\n\t\tif ( isImage() )\n\t\t{\n\t\t\treturn imageAttach.getPipelineStageFlags( isCompute );\n\t\t}\n\n\t\treturn bufferAttach.getPipelineStageFlags( isCompute );\n\t}\n\n\tAttachment const * Attachment::getSource( uint32_t index )const\n\t{\n\t\tif ( index > 0 && index >= source.size() )\n\t\t\tCRG_Exception( \"Invalid index\" );\n\n\t\tif ( source.empty() )\n\t\t\treturn this;\n\n\t\treturn source[index].attach.get();\n\t}\n\n\tvoid Attachment::initSources()\n\t{\n\t\tfor ( uint32_t index = 0u; index < source.size(); ++index )\n\t\t{\n\t\t\tSource & attachSource = source[index];\n\t\t\tif ( isImage() )\n\t\t\t{\n\t\t\t\tattachSource.attach = std::make_unique< Attachment >( flags\n\t\t\t\t\t, name + std::to_string( index )\n\t\t\t\t\t, attachSource.pass\n\t\t\t\t\t, *attachSource.imageAttach\n\t\t\t\t\t, Token{} );\n\t\t\t\tattachSource.imageAttach = &attachSource.attach->imageAttach;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tattachSource.attach = std::make_unique< Attachment >( flags\n\t\t\t\t\t, name + std::to_string( index )\n\t\t\t\t\t, attachSource.pass\n\t\t\t\t\t, *attachSource.bufferAttach\n\t\t\t\t\t, Token{} );\n\t\t\t\tattachSource.bufferAttach = &attachSource.attach->bufferAttach;\n\t\t\t}\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/AttachmentTransition.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/AttachmentTransition.hpp\"\n\n#include \"RenderGraph/FramePass.hpp\"\n#include \"RenderGraph/LayerLayoutStatesHandler.hpp\"\n\n#include <algorithm>\n\nnamespace crg\n{\n\tnamespace attTran\n\t{\n\t\ttemplate< typename TransitionT >\n\t\tstd::vector< TransitionT > mergeIdenticalTransitionsT( std::vector< TransitionT > transitions )\n\t\t{\n\t\t\tstd::vector< TransitionT > result;\n\n\t\t\tfor ( auto & transition : transitions )\n\t\t\t{\n\t\t\t\tif ( auto it = std::find( result.begin(), result.end(), transition );\n\t\t\t\t\tit == result.end() )\n\t\t\t\t{\n\t\t\t\t\tresult.push_back( transition );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tAttachmentTransitions mergeIdenticalTransitions( AttachmentTransitions transitions )\n\t{\n\t\tAttachmentTransitions result{};\n\t\tresult.imageTransitions = attTran::mergeIdenticalTransitionsT( std::move( transitions.imageTransitions ) );\n\t\tresult.bufferTransitions = attTran::mergeIdenticalTransitionsT( std::move( transitions.bufferTransitions ) );\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/BuilderCommon.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#pragma once\n\n#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n\n#include <functional>\n\nnamespace crg::builder\n{\n\tusing FramePassSet = std::set< FramePass const * >;\n\n\ttemplate< typename TypeT >\n\tvoid filter( std::vector< TypeT > const & inputs\n\t\t, std::function< bool( TypeT const & ) > filterFunc\n\t\t, std::function< void( TypeT const & ) > trueFunc\n\t\t, std::function< void( TypeT const & ) > falseFunc = nullptr )\n\t{\n\t\tfor ( auto & input : inputs )\n\t\t{\n\t\t\tif ( filterFunc( input ) )\n\t\t\t{\n\t\t\t\ttrueFunc( input );\n\t\t\t}\n\t\t\telse if ( falseFunc )\n\t\t\t{\n\t\t\t\tfalseFunc( input );\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate< typename TypeT >\n\tvoid filter( std::vector< TypeT > & inputs\n\t\t, std::function< bool( TypeT & ) > filterFunc\n\t\t, std::function< void( TypeT & ) > trueFunc\n\t\t, std::function< void( TypeT & ) > falseFunc = nullptr )\n\t{\n\t\tfor ( auto & input : inputs )\n\t\t{\n\t\t\tif ( filterFunc( input ) )\n\t\t\t{\n\t\t\t\ttrueFunc( input );\n\t\t\t}\n\t\t\telse if ( falseFunc )\n\t\t\t{\n\t\t\t\tfalseFunc( input );\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/DotExport.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/DotExport.hpp\"\n#include \"RenderGraph/FrameGraph.hpp\"\n#include \"RenderGraph/FramePass.hpp\"\n#include \"RenderGraph/GraphVisitor.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <numeric>\n#include <array>\n#include <span>\n#include <string>\n#include <type_traits>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <atomic>\n#include <fstream>\n#include <sstream>\n#pragma warning( pop )\n\nnamespace crg::dot\n{\n\tnamespace dotexp\n\t{\n\t\ttemplate < typename char_type, char_type fill_char = ' ', typename traits = std::char_traits< char_type > >\n\t\tstruct BasicIndentBuffer\n\t\t\t: public std::basic_streambuf< char_type, traits >\n\t\t{\n\t\tpublic:\n\t\t\tusing int_type = typename traits::int_type;\n\t\t\tusing pos_type = typename traits::pos_type;\n\t\t\tusing off_type = typename traits::off_type;\n\n\t\tprivate:\n\t\t\tBasicIndentBuffer( const BasicIndentBuffer< char_type, fill_char, traits > & ) = delete;\n\t\t\tBasicIndentBuffer< char_type, fill_char, traits > & operator =( const BasicIndentBuffer< char_type, fill_char, traits > & ) = delete;\n\n\t\tpublic:\n\t\t\texplicit BasicIndentBuffer( std::basic_streambuf< char_type, traits > * sbuf )\n\t\t\t\t: m_sbuf{ sbuf }\n\t\t\t\t, m_set{ true }\n\t\t\t{\n\t\t\t}\n\n\t\t\tint indent() const\n\t\t\t{\n\t\t\t\treturn m_count;\n\t\t\t}\n\n\t\t\tvoid indent( long i )\n\t\t\t{\n\t\t\t\tm_count += i;\n\t\t\t\tm_count = std::max( 0L, m_count );\n\t\t\t}\n\n\t\t\tstd::streambuf * sbuf() const\n\t\t\t{\n\t\t\t\treturn m_sbuf;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tint_type overflow( int_type c = traits::eof() )override\n\t\t\t{\n\t\t\t\tif ( traits::eq_int_type( c, traits::eof() ) )\n\t\t\t\t{\n\t\t\t\t\treturn m_sbuf->sputc( static_cast< char_type >( c ) );\n\t\t\t\t}\n\n\t\t\t\tif ( m_set )\n\t\t\t\t{\n\t\t\t\t\tstd::fill_n( std::ostreambuf_iterator< char_type >( m_sbuf ), m_count, fill_char );\n\t\t\t\t\tm_set = false;\n\t\t\t\t}\n\n\t\t\t\tif ( traits::eq_int_type( m_sbuf->sputc( static_cast< char_type >( c ) ), traits::eof() ) )\n\t\t\t\t{\n\t\t\t\t\treturn traits::eof();\n\t\t\t\t}\n\n\t\t\t\tif ( traits::eq_int_type( c, traits::to_char_type( '\\n' ) ) )\n\t\t\t\t{\n\t\t\t\t\tm_set = true;\n\t\t\t\t}\n\n\t\t\t\treturn traits::not_eof( c );\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstd::basic_streambuf< char_type, traits > * m_sbuf;\n\t\t\tlong m_count{ 0 };\n\t\t\tbool m_set{ false };\n\t\t};\n\n\t\ttemplate< typename char_type, typename traits = std::char_traits< char_type > >\n\t\tclass BasicIndentBufferManager\n\t\t{\n\t\tprivate:\n\t\t\tusing bos = std::ios_base;\n\t\t\tusing bsb = std::basic_streambuf< char_type, traits >;\n\t\t\tusing table_type = std::map< bos *, bsb * >;\n\t\t\tusing value_type = typename table_type::value_type;\n\t\t\tusing iterator = typename table_type::iterator;\n\t\t\tusing const_iterator = typename table_type::const_iterator;\n\t\t\tusing lock_type = std::unique_lock< std::mutex >;\n\n\t\t\tBasicIndentBufferManager()\n\t\t\t{\n\t\t\t\t++sm_instances;\n\t\t\t}\n\n\t\t\tBasicIndentBufferManager( BasicIndentBufferManager< char_type, traits > & obj ) = delete;\n\n\t\tpublic:\n\t\t\t~BasicIndentBufferManager()noexcept\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t--sm_instances;\n\t\t\t\t\tlock_type lock{ m_mutex };\n\n\t\t\t\t\tfor ( iterator it = m_list.begin(); it != m_list.end(); ++it )\n\t\t\t\t\t{\n\t\t\t\t\t\tdelete it->second;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( ... )\n\t\t\t\t{\n\t\t\t\t\t// What to do here ?\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool insert( bos & o_s, bsb * b_s )\n\t\t\t{\n\t\t\t\tlock_type lock{ m_mutex };\n\t\t\t\treturn m_list.emplace( &o_s, b_s ).second;\n\t\t\t}\n\n\t\t\tsize_t size()\n\t\t\t{\n\t\t\t\tlock_type lock{ m_mutex };\n\t\t\t\treturn m_list.size();\n\t\t\t}\n\n\t\t\tbsb * getBuffer( std::ios_base & io_s )\n\t\t\t{\n\t\t\t\tlock_type lock{ m_mutex };\n\t\t\t\tconst_iterator cb_iter( m_list.find( &io_s ) );\n\t\t\t\tbsb * result{};\n\n\t\t\t\tif ( cb_iter != m_list.end() )\n\t\t\t\t{\n\t\t\t\t\tresult = cb_iter->second;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tbool erase( std::ios_base & io_s )\n\t\t\t{\n\t\t\t\tdelete getBuffer( io_s );\n\t\t\t\tlock_type lock{ m_mutex };\n\t\t\t\treturn ( m_list.erase( &io_s ) == 1u );\n\t\t\t}\n\n\t\t\tstatic size_t instances()\n\t\t\t{\n\t\t\t\treturn size_t( sm_instances );\n\t\t\t}\n\n\t\t\tstatic BasicIndentBufferManager< char_type, traits > * instance()\n\t\t\t{\n\t\t\t\tstatic BasicIndentBufferManager< char_type, traits > ibm;\n\t\t\t\treturn &ibm;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstatic std::atomic_int sm_instances;\n\t\t\ttable_type m_list;\n\t\t\tstd::mutex m_mutex;\n\t\t};\n\n\t\ttemplate< typename char_type, typename traits >\n\t\tstd::atomic_int BasicIndentBufferManager< char_type, traits >::sm_instances = 0;\n\n\t\tinline void addIndent( std::ios_base & ios, long val );\n\n\t\tinline long & indentValue( std::ios_base & ios )\n\t\t{\n\t\t\tstatic int indentIndex = std::ios_base::xalloc();\n\t\t\treturn ios.iword( indentIndex );\n\t\t}\n\n\t\tinline long getIndent( std::ios_base & ios )\n\t\t{\n\t\t\treturn indentValue( ios );\n\t\t}\n\n\t\tinline void addIndent( std::ios_base & ios, long val )\n\t\t{\n\t\t\tindentValue( ios ) += val;\n\t\t}\n\n\t\ttemplate< typename CharType, typename BufferType = BasicIndentBuffer< CharType >, typename BufferManagerType = BasicIndentBufferManager< CharType > >\n\t\tinline BufferType * installIndentBuffer( std::basic_ostream< CharType > & stream )\n\t\t{\n\t\t\tBufferType * sbuf( new BufferType( stream.rdbuf() ) );\n\t\t\tBufferManagerType::instance()->insert( stream, sbuf );\n\t\t\tstream.rdbuf( sbuf );\n\t\t\treturn sbuf;\n\t\t}\n\n\t\ttemplate< typename CharType >\n\t\tinline void callback( std::ios_base::event ev, std::ios_base & ios, int )\n\t\t{\n\t\t\tif ( BasicIndentBufferManager< CharType >::instances()\n\t\t\t\t&& ev == std::ios_base::erase_event )\n\t\t\t{\n\t\t\t\tBasicIndentBufferManager< CharType >::instance()->erase( ios );\n\t\t\t}\n\t\t}\n\n\t\tstruct Indent\n\t\t{\n\t\t\texplicit Indent( long i )\n\t\t\t\t: indent( i )\n\t\t\t{\n\t\t\t}\n\n\t\t\tlong indent;\n\n\t\tprivate:\n\t\t\ttemplate< typename CharType >\n\t\t\tfriend std::basic_ostream< CharType > & operator<<( std::basic_ostream< CharType > & stream, Indent const & ind )\n\t\t\t{\n\t\t\t\tauto sbuf = dynamic_cast< BasicIndentBuffer< CharType > * >( stream.rdbuf() );\n\n\t\t\t\tif ( !sbuf )\n\t\t\t\t{\n\t\t\t\t\tsbuf = installIndentBuffer( stream );\n\t\t\t\t\tstream.register_callback( callback< CharType >, 0 );\n\t\t\t\t}\n\n\t\t\t\taddIndent( stream, ind.indent );\n\t\t\t\tsbuf->indent( ind.indent );\n\t\t\t\treturn stream;\n\t\t\t}\n\t\t};\n\n\t\tstatic std::string_view constexpr imgColour{ \"#8b008b\" };\n\t\tstatic std::string_view constexpr bufColour{ \"#458b00\" };\n\t\tstatic std::string_view constexpr extColour{ \"#ff7f00\" };\n\t\tstatic std::string_view constexpr passColour{ \"#00007f\" };\n\n\t\tstruct FramePassGroupStreams\n\t\t{\n\t\t\tusing FramePassGroupStreamsPtr = std::unique_ptr< FramePassGroupStreams >;\n\n\t\t\texplicit FramePassGroupStreams( Config const & config\n\t\t\t\t, FramePassGroupStreams * parent = nullptr\n\t\t\t\t, FramePassGroup const * group = nullptr )\n\t\t\t\t: m_config{ config }\n\t\t\t\t, m_parent{ parent }\n\t\t\t\t, m_group{ group }\n\t\t\t{\n\t\t\t}\n\n\t\t\tstd::pair< FramePassGroupStreams *, bool > emplace( FramePassGroup const * group )\n\t\t\t{\n\t\t\t\tauto streams = find( group );\n\t\t\t\tif ( streams )\n\t\t\t\t\treturn { streams, false };\n\n\t\t\t\tassert( group != nullptr );\n\n\t\t\t\tif ( group->getParent() == m_group )\n\t\t\t\t{\n\t\t\t\t\tm_children.emplace_back( std::make_unique< FramePassGroupStreams >( m_config, this, group ) );\n\t\t\t\t\tstreams = m_children.back().get();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstreams = emplace( group->getParent() ).first;\n\t\t\t\t\tstreams = streams->emplace( group ).first;\n\t\t\t\t}\n\n\t\t\t\treturn { streams, true };\n\t\t\t}\n\n\t\t\tFramePassGroupStreams * find( FramePassGroup const * group )\n\t\t\t{\n\t\t\t\tif ( m_group == group )\n\t\t\t\t\treturn this;\n\n\t\t\t\tFramePassGroupStreams * result{};\n\t\t\t\tauto it = std::find_if( m_children.begin(), m_children.end()\n\t\t\t\t\t, [group, &result]( FramePassGroupStreamsPtr const & lookup )\n\t\t\t\t\t{\n\t\t\t\t\t\tauto ret = lookup->find( group );\n\t\t\t\t\t\tif ( ret )\n\t\t\t\t\t\t\tresult = ret;\n\t\t\t\t\t\treturn ret != nullptr;\n\t\t\t\t\t} );\n\n\t\t\t\treturn it == m_children.end()\n\t\t\t\t\t? nullptr\n\t\t\t\t\t: result;\n\t\t\t}\n\n\t\t\tvoid doWriteSplitted( DisplayResult & streams )const\n\t\t\t{\n\t\t\t\tif ( m_group )\n\t\t\t\t{\n\t\t\t\t\tauto & stream = streams.try_emplace( m_group->getName() ).first->second;\n\t\t\t\t\tstream << \"digraph \\\"\" << m_group->getName() << \"\\\" {\\n\";\n\t\t\t\t\tstream << m_stream.str();\n\t\t\t\t\tstream << \"}\\n\";\n\t\t\t\t}\n\n\t\t\t\tfor ( auto & group : m_children )\n\t\t\t\t\tgroup->write( streams );\n\t\t\t}\n\n\t\t\tvoid doWriteUnsplittedWithGroups( DisplayResult & streams\n\t\t\t\t, std::stringstream const & global )const\n\t\t\t{\n\t\t\t\tauto & stream = streams.try_emplace( m_group ? m_group->getName() : std::string{} ).first->second;\n\n\t\t\t\tif ( m_group )\n\t\t\t\t{\n\t\t\t\t\tstream << \"subgraph cluster_\" << m_group->getId() << \" {\\n\";\n\t\t\t\t\tstream << \"  label=\\\"\" << m_group->getName() << \"\\\";\\n\";\n\n\t\t\t\t\tif ( m_config.withColours )\n\t\t\t\t\t{\n\t\t\t\t\t\tstatic std::vector< std::string_view > colours\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t{ \"#FFFFFF\" },\n\t\t\t\t\t\t\t{ \"#EEEEEE\" },\n\t\t\t\t\t\t\t{ \"#DDDDDD\" },\n\t\t\t\t\t\t\t{ \"#CCCCCC\" },\n\t\t\t\t\t\t\t{ \"#BBBBBB\" },\n\t\t\t\t\t\t\t{ \"#AAAAAA\" },\n\t\t\t\t\t\t\t{ \"#999999\" },\n\t\t\t\t\t\t\t{ \"#888888\" },\n\t\t\t\t\t\t};\n\t\t\t\t\t\tstream << \"  style=filled;\\n\";\n\t\t\t\t\t\tstream << \"  fillcolor=\\\"\" << colours[std::min( size_t( getLevel() ), colours.size() - 1u )] << \"\\\";\\n\";\n\t\t\t\t\t\tstream << \"  color=black;\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstream << \"digraph {\\n\";\n\t\t\t\t}\n\n\t\t\t\tstream << Indent{ 2 };\n\n\t\t\t\tfor ( auto & group : m_children )\n\t\t\t\t{\n\t\t\t\t\tgroup->write( streams );\n\t\t\t\t\tstream << streams.find( group->getName() )->second.str();\n\t\t\t\t}\n\n\t\t\t\tauto & stream2 = streams.try_emplace( m_group ? m_group->getName() : std::string{} ).first->second;\n\t\t\t\tstream2 << Indent{ -2 };\n\t\t\t\tstream2 << m_stream.str();\n\t\t\t\tif ( !m_group )\n\t\t\t\t\tstream2 << global.str();\n\t\t\t\tstream2 << \"}\\n\";\n\t\t\t}\n\n\t\t\tvoid doWriteUnsplitted( DisplayResult & streams\n\t\t\t\t, std::stringstream const & global )const\n\t\t\t{\n\t\t\t\tauto & stream = streams.try_emplace( m_group ? m_group->getName() : std::string{} ).first->second;\n\n\t\t\t\tif ( !m_group )\n\t\t\t\t\tstream << \"digraph {\\n\";\n\n\t\t\t\tfor ( auto & group : m_children )\n\t\t\t\t{\n\t\t\t\t\tgroup->write( streams );\n\t\t\t\t\tstream << streams.find( group->getName() )->second.str();\n\t\t\t\t}\n\n\t\t\t\tauto & stream2 = streams.try_emplace( m_group ? m_group->getName() : std::string{} ).first->second;\n\t\t\t\tstream2 << m_stream.str();\n\n\t\t\t\tif ( !m_group )\n\t\t\t\t{\n\t\t\t\t\tstream2 << global.str();\n\t\t\t\t\tstream2 << \"}\\n\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid write( DisplayResult & streams\n\t\t\t\t, std::stringstream const & global = std::stringstream{} )const\n\t\t\t{\n\t\t\t\tif ( m_config.splitGroups )\n\t\t\t\t\tdoWriteSplitted( streams );\n\t\t\t\telse if ( m_config.withGroups )\n\t\t\t\t\tdoWriteUnsplittedWithGroups( streams, global );\n\t\t\t\telse\n\t\t\t\t\tdoWriteUnsplitted( streams, global );\n\t\t\t}\n\n\t\t\tstd::string const & getName()const\n\t\t\t{\n\t\t\t\tstatic std::string const dummy;\n\t\t\t\treturn m_group ? m_group->getName() : dummy;\n\t\t\t}\n\n\t\t\tstd::set< std::string, std::less<> > & getNodes()\n\t\t\t{\n\t\t\t\treturn m_nodes;\n\t\t\t}\n\n\t\t\tFramePassGroupStreams * getParent()const\n\t\t\t{\n\t\t\t\treturn m_parent;\n\t\t\t}\n\n\t\t\tuint32_t getLevel()const\n\t\t\t{\n\t\t\t\tif ( m_parent )\n\t\t\t\t\treturn ( m_parent->m_parent\n\t\t\t\t\t\t? 1u + m_parent->getLevel()\n\t\t\t\t\t\t: m_parent->getLevel() );\n\t\t\t\treturn 0u;\n\t\t\t}\n\n\t\t\tstd::stringstream & getStream()const\n\t\t\t{\n\t\t\t\treturn m_stream;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tConfig const & m_config;\n\t\t\tmutable std::stringstream m_stream;\n\t\t\tFramePassGroupStreams * m_parent;\n\t\t\tstd::vector< FramePassGroupStreamsPtr > m_children;\n\t\t\tFramePassGroup const * m_group;\n\t\t\tstd::set< std::string, std::less<> > m_nodes;\n\t\t};\n\n\t\tstatic void displayNode( std::ostream & stream\n\t\t\t, std::string const & name\n\t\t\t, std::string const & shape\n\t\t\t, std::string_view colour\n\t\t\t, std::set< std::string, std::less<> > & nodes\n\t\t\t, Config const & config )\n\t\t{\n\t\t\tif ( nodes.insert( name ).second )\n\t\t\t{\n\t\t\t\tstream << Indent{ 2 };\n\t\t\t\tstream << \"\\\"\" << name << \"\\\" [ shape=\" << shape;\n\n\t\t\t\tif ( config.withColours )\n\t\t\t\t{\n\t\t\t\t\tstream << \" style=filled\";\n\t\t\t\t\tstream << \" fillcolor=white\";\n\t\t\t\t\tstream << \" color=\\\"\" << colour << \"\\\"\";\n\t\t\t\t}\n\n\t\t\t\tstream << \" ];\\n\";\n\t\t\t\tstream << Indent{ -2 };\n\t\t\t}\n\t\t}\n\n\t\tstatic FramePassGroupStreams & displayGroupNode( FramePassGroup const * group\n\t\t\t, FramePassGroupStreams & groups\n\t\t\t, Config const & )\n\t\t{\n\t\t\treturn *groups.emplace( group ).first;\n\t\t}\n\n\t\tstatic FramePassGroupStreams & displayPassNode( uint32_t id\n\t\t\t, std::string const & name\n\t\t\t, FramePassGroup const * group\n\t\t\t, std::string_view colour\n\t\t\t, FramePassGroupStreams & groups\n\t\t\t, Config const & config )\n\t\t{\n\t\t\tauto & groupStream = displayGroupNode( group, groups, config );\n\t\t\tauto & stream = groupStream.getStream();\n\n\t\t\tif ( groupStream.getNodes().insert( name ).second )\n\t\t\t{\n\t\t\t\tstream << Indent{ 2 };\n\t\t\t\tstream << \"\\\"\" << name << \"\\\" [ shape=ellipse\";\n\n\t\t\t\tif ( config.withIds )\n\t\t\t\t{\n\t\t\t\t\tstream << \" id=\\\"\" << id << \"\\\"\";\n\t\t\t\t}\n\n\t\t\t\tif ( config.withColours )\n\t\t\t\t{\n\t\t\t\t\tstream << \" style=filled\";\n\t\t\t\t\tstream << \" fillcolor=white\";\n\t\t\t\t\tstream << \" color=\\\"\" << colour << \"\\\"\";\n\t\t\t\t}\n\n\t\t\t\tstream << \" ];\\n\";\n\t\t\t\tstream << Indent{ -2 };\n\t\t\t}\n\n\t\t\treturn groupStream;\n\t\t}\n\n\t\tstatic void displayEdge( std::ostream & stream\n\t\t\t, std::string const & from\n\t\t\t, std::string const & to\n\t\t\t, std::string const & label\n\t\t\t, std::string_view colour\n\t\t\t, Config const & config )\n\t\t{\n\t\t\tstream << Indent{ 2 };\n\t\t\tstream << \"\\\"\" << from << \"\\\" -> \\\"\" << to << \"\\\" [ label=\\\"\" << label << \"\\\"\";\n\n\t\t\tif ( config.withColours )\n\t\t\t{\n\t\t\t\tstream << \" color = \\\"\" << colour << \"\\\" fontcolor=\\\"\" << colour << \"\\\"\";\n\t\t\t}\n\n\t\t\tstream << \" ];\\n\";\n\t\t\tstream << Indent{ -2 };\n\t\t}\n\n\t\tstatic void displayAttachPass( Attachment const & attach\n\t\t\t, FramePassGroupStreams & groups\n\t\t\t, Config const & config )\n\t\t{\n\t\t\tuint32_t nodeId = 0;\n\t\t\tstd::string node = \"ExternalSource\";\n\t\t\tFramePassGroup const * group = nullptr;\n\t\t\tstd::string_view colour = extColour;\n\n\t\t\tif ( attach.pass )\n\t\t\t{\n\t\t\t\tnodeId = attach.pass->getId();\n\t\t\t\tnode = attach.pass->getGroupName();\n\t\t\t\tgroup = &attach.pass->getGroup();\n\t\t\t\tcolour = passColour;\n\t\t\t}\n\n\t\t\tdisplayPassNode( nodeId, node, group, colour, groups, config );\n\t\t}\n\n\t\tstatic std::string const & getAttachName( crg::BufferViewId const & data )\n\t\t{\n\t\t\treturn data.data->name;\n\t\t}\n\n\t\tstatic std::string const & getAttachName( crg::ImageViewId const & data )\n\t\t{\n\t\t\treturn data.data->name;\n\t\t}\n\n\t\tstatic bool isIn( FramePassGroupStreams const * inner\n\t\t\t, FramePassGroupStreams const * outer )\n\t\t{\n\t\t\treturn outer == inner\n\t\t\t\t|| ( outer && isIn( inner, outer->getParent() ) );\n\t\t}\n\n\t\tstatic FramePassGroupStreams * getCommonGroup( FramePassGroupStreams * lhs\n\t\t\t, FramePassGroupStreams const * rhs )\n\t\t{\n\t\t\tauto current = lhs;\n\n\t\t\twhile ( current && !isIn( current, rhs ) )\n\t\t\t{\n\t\t\t\tcurrent = current->getParent();\n\t\t\t}\n\n\t\t\treturn current;\n\t\t}\n\n\t\ttemplate< typename TransitionT >\n\t\tstatic void displayTransitionEdge( std::ostream & stream\n\t\t\t, std::string_view colour\n\t\t\t, TransitionT const & transition\n\t\t\t, FramePassGroupStreams & groups\n\t\t\t, Config const & config )\n\t\t{\n\t\t\tauto srcName = transition.outputAttach.name;\n\t\t\tauto dstName = transition.inputAttach.name;\n\t\t\tstd::string srcNode = \"ExternalSource\";\n\t\t\tstd::string dstNode = \"ExternalDestination\";\n\t\t\tauto srcStream = &groups;\n\t\t\tauto dstStream = &groups;\n\t\t\tauto curStreams = &groups;\n\n\t\t\tif ( transition.outputAttach.pass )\n\t\t\t{\n\t\t\t\tsrcNode = transition.outputAttach.pass->getGroupName();\n\t\t\t\tsrcStream = groups.find( &transition.outputAttach.pass->getGroup() );\n\t\t\t}\n\n\t\t\tif ( transition.inputAttach.pass )\n\t\t\t{\n\t\t\t\tdstNode = transition.inputAttach.pass->getGroupName();\n\t\t\t\tdstStream = groups.find( &transition.inputAttach.pass->getGroup() );\n\t\t\t}\n\n\t\t\tstd::string name{ \"Transition to\\\\n\" + dstName };\n\t\t\tauto curstream = &stream;\n\n\t\t\tif ( srcStream != &groups\n\t\t\t\t&& dstStream != &groups )\n\t\t\t{\n\t\t\t\tif ( srcStream == dstStream )\n\t\t\t\t{\n\t\t\t\t\tcurStreams = srcStream;\n\t\t\t\t\tcurstream = &srcStream->getStream();\n\t\t\t\t}\n\t\t\t\telse if ( auto groupStreams = getCommonGroup( srcStream, dstStream ) )\n\t\t\t\t{\n\t\t\t\t\tcurStreams = groupStreams;\n\t\t\t\t\tcurstream = &groupStreams->getStream();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdisplayNode( *curstream, name, \"box\", colour, curStreams->getNodes(), config );\n\t\t\tdisplayEdge( *curstream, srcNode, name, getAttachName( transition.data ), colour, config );\n\t\t\tdisplayEdge( *curstream, name, dstNode, getAttachName( transition.data ), colour, config );\n\t\t}\n\n\t\tclass DotTransitionsVisitor\n\t\t\t: public GraphVisitor\n\t\t{\n\t\tpublic:\n\t\t\tstatic void submit( DisplayResult & streams\n\t\t\t\t, ConstGraphAdjacentNode node\n\t\t\t\t, Config const & config )\n\t\t\t{\n\t\t\t\tstd::set< ConstGraphAdjacentNode > visited;\n\t\t\t\tstd::stringstream trstream;\n\t\t\t\tFramePassGroupStreams groups{ config };\n\t\t\t\tsubmit( streams, node, config, groups, trstream, visited );\n\t\t\t\tgroups.write( streams, trstream );\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstatic void submit( DisplayResult & streams\n\t\t\t\t, ConstGraphAdjacentNode node\n\t\t\t\t, Config const & config\n\t\t\t\t, FramePassGroupStreams & groups\n\t\t\t\t, std::stringstream & trstream\n\t\t\t\t, std::set< ConstGraphAdjacentNode > & visited )\n\t\t\t{\n\t\t\t\tDotTransitionsVisitor vis{ streams, groups, trstream, config, visited };\n\t\t\t\tnode->accept( &vis );\n\t\t\t}\n\n\t\t\tDotTransitionsVisitor( DisplayResult & streams\n\t\t\t\t, FramePassGroupStreams & groups\n\t\t\t\t, std::stringstream & trstream\n\t\t\t\t, Config const & config\n\t\t\t\t, std::set< ConstGraphAdjacentNode > & visited )\n\t\t\t\t: m_streams{ streams }\n\t\t\t\t, m_groups{ groups }\n\t\t\t\t, m_trstream{ trstream }\n\t\t\t\t, m_config{ config }\n\t\t\t\t, m_visited{ visited }\n\t\t\t{\n\t\t\t}\n\n\t\t\tvoid submit( ConstGraphAdjacentNode node )\n\t\t\t{\n\t\t\t\tsubmit( m_streams\n\t\t\t\t\t, node\n\t\t\t\t\t, m_config\n\t\t\t\t\t, m_groups\n\t\t\t\t\t, m_trstream\n\t\t\t\t\t, m_visited );\n\t\t\t}\n\n\t\t\tvoid visitRootNode( RootNode const * node )override\n\t\t\t{\n\t\t\t\tfor ( auto & pred : node->getPredecessors() )\n\t\t\t\t{\n\t\t\t\t\tsubmit( m_streams\n\t\t\t\t\t\t, pred\n\t\t\t\t\t\t, m_config\n\t\t\t\t\t\t, m_groups\n\t\t\t\t\t\t, m_trstream\n\t\t\t\t\t\t, m_visited );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid visitFramePassNode( FramePassNode const * node )override\n\t\t\t{\n\t\t\t\tfor ( auto & transition : node->getImageTransitions() )\n\t\t\t\t{\n\t\t\t\t\tdisplayAttachPass( transition.outputAttach, m_groups, m_config );\n\t\t\t\t\tdisplayAttachPass( transition.inputAttach, m_groups, m_config );\n\t\t\t\t}\n\n\t\t\t\tfor ( auto & transition : node->getBufferTransitions() )\n\t\t\t\t{\n\t\t\t\t\tdisplayAttachPass( transition.outputAttach, m_groups, m_config );\n\t\t\t\t\tdisplayAttachPass( transition.inputAttach, m_groups, m_config );\n\t\t\t\t}\n\n\t\t\t\tfor ( auto & transition : node->getImageTransitions() )\n\t\t\t\t{\n\t\t\t\t\tdisplayTransitionEdge( m_trstream, imgColour, transition, m_groups, m_config );\n\t\t\t\t}\n\n\t\t\t\tfor ( auto & transition : node->getBufferTransitions() )\n\t\t\t\t{\n\t\t\t\t\tdisplayTransitionEdge( m_trstream, bufColour, transition, m_groups, m_config );\n\t\t\t\t}\n\n\t\t\t\tm_visited.insert( node );\n\n\t\t\t\tfor ( auto & pred : node->getPredecessors() )\n\t\t\t\t{\n\t\t\t\t\tif ( m_visited.end() == m_visited.find( pred ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tsubmit( pred );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tprivate:\n\t\t\tDisplayResult & m_streams;\n\t\t\tFramePassGroupStreams & m_groups;\n\t\t\tstd::stringstream & m_trstream;\n\t\t\tConfig const & m_config;\n\t\t\tstd::set< GraphNode const * > & m_visited;\n\t\t};\n\n\t\tstatic std::string applyRemove( std::string const & text, Config const & config )\n\t\t{\n\t\t\tif ( config.toRemove.empty() )\n\t\t\t\treturn text;\n\n\t\t\tauto result = text;\n\t\t\tsize_t startPos = 0u;\n\n\t\t\twhile ( ( startPos = result.find( config.toRemove, startPos ) ) != std::string::npos )\n\t\t\t\tresult.replace( startPos, config.toRemove.length(), \"\" );\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tDisplayResult displayTransitions( RunnableGraph const & value\n\t\t, Config const & config )\n\t{\n\t\tDisplayResult result;\n\t\tdotexp::DotTransitionsVisitor::submit( result, value.getNodeGraph(), config );\n\t\treturn result;\n\t}\n\n\tvoid displayTransitions( std::ostream & stream\n\t\t, RunnableGraph const & value\n\t\t, Config const & config )\n\t{\n\t\tauto result = displayTransitions( value, config );\n\n\t\tif ( config.splitGroups )\n\t\t{\n\t\t\tfor ( auto const & [name, strm] : result )\n\t\t\t{\n\t\t\t\tif ( !name.empty() )\n\t\t\t\t{\n\t\t\t\t\tstream << dotexp::applyRemove( strm.str(), config );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto it = result.find( std::string{} );\n\t\t\tstream << dotexp::applyRemove( it->second.str(), config );\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/FrameGraph.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/FrameGraph.hpp\"\n\n#include \"RenderGraph/Exception.hpp\"\n#include \"RenderGraph/FramePass.hpp\"\n#include \"RenderGraph/FramePassGroup.hpp\"\n#include \"RenderGraph/Hash.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/ResourceHandler.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n#include \"GraphBuilder.hpp\"\n\n#include <algorithm>\n\nnamespace crg\n{\n\tnamespace fgph\n\t{\n\t\tstatic void mergeViewData( ImageViewId const & view\n\t\t\t, bool mergeMipLevels\n\t\t\t, bool mergeArrayLayers\n\t\t\t, ImageViewData & data )\n\t\t{\n\t\t\tif ( data.image.id == 0 )\n\t\t\t{\n\t\t\t\tdata.image = view.data->image;\n\t\t\t\tdata.name = data.image.data->name;\n\t\t\t\tdata.info.flags = view.data->info.flags;\n\t\t\t\tdata.info.format = view.data->info.format;\n\t\t\t\tdata.info.viewType = view.data->info.viewType;\n\t\t\t\tdata.info.subresourceRange = getSubresourceRange( view );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert( data.image == view.data->image );\n\n\t\t\t\tif ( mergeMipLevels )\n\t\t\t\t{\n\t\t\t\t\tauto maxLevel = std::max( data.info.subresourceRange.levelCount + data.info.subresourceRange.baseMipLevel\n\t\t\t\t\t\t, getSubresourceRange( view ).levelCount + getSubresourceRange( view ).baseMipLevel );\n\t\t\t\t\tdata.info.subresourceRange.baseMipLevel = std::min( getSubresourceRange( view ).baseMipLevel\n\t\t\t\t\t\t, data.info.subresourceRange.baseMipLevel );\n\t\t\t\t\tdata.info.subresourceRange.levelCount = maxLevel - data.info.subresourceRange.baseMipLevel;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdata.info.subresourceRange.baseMipLevel = std::min( getSubresourceRange( view ).baseMipLevel\n\t\t\t\t\t\t, data.info.subresourceRange.baseMipLevel );\n\t\t\t\t\tdata.info.subresourceRange.levelCount = 1u;\n\t\t\t\t}\n\n\t\t\t\tif ( mergeArrayLayers )\n\t\t\t\t{\n\t\t\t\t\tauto maxLayer = std::max( data.info.subresourceRange.layerCount + data.info.subresourceRange.baseArrayLayer\n\t\t\t\t\t\t, getSubresourceRange( view ).layerCount + getSubresourceRange( view ).baseArrayLayer );\n\t\t\t\t\tdata.info.subresourceRange.baseArrayLayer = std::min( getSubresourceRange( view ).baseArrayLayer\n\t\t\t\t\t\t, data.info.subresourceRange.baseArrayLayer );\n\t\t\t\t\tdata.info.subresourceRange.layerCount = maxLayer - data.info.subresourceRange.baseArrayLayer;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdata.info.subresourceRange.baseArrayLayer = std::min( getSubresourceRange( view ).baseArrayLayer\n\t\t\t\t\t\t, data.info.subresourceRange.baseArrayLayer );\n\t\t\t\t\tdata.info.subresourceRange.layerCount = 1u;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdata.source.push_back( view );\n\t\t}\n\n\t\tstatic void mergeViewData( BufferViewId const & view\n\t\t\t, BufferViewData & data )\n\t\t{\n\t\t\tif ( data.buffer.id == 0 )\n\t\t\t{\n\t\t\t\tdata.buffer = view.data->buffer;\n\t\t\t\tdata.name = data.buffer.data->name;\n\t\t\t\tdata.info.format = view.data->info.format;\n\t\t\t\tdata.info.subresourceRange = getSubresourceRange( view );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert( data.buffer == view.data->buffer );\n\t\t\t\tauto maxUpperBound = std::max( data.info.subresourceRange.offset + data.info.subresourceRange.size\n\t\t\t\t\t, getSubresourceRange( view ).offset + getSubresourceRange( view ).size );\n\t\t\t\tauto minLowerBound = std::min( data.info.subresourceRange.offset\n\t\t\t\t\t, getSubresourceRange( view ).offset );\n\t\t\t\tdata.info.subresourceRange.offset = minLowerBound;\n\t\t\t\tdata.info.subresourceRange.size = maxUpperBound - minLowerBound;\n\t\t\t}\n\n\t\t\tdata.source.push_back( view );\n\t\t}\n\n\t\tstatic size_t makeHash( AttachmentArray const & attachments\n\t\t\t, bool mergeMipLevels\n\t\t\t, bool mergeArrayLayers )\n\t\t{\n\t\t\tauto result = std::hash< bool >{}( mergeMipLevels );\n\t\t\tresult = hashCombine( result, mergeArrayLayers );\n\t\t\tfor ( auto attach : attachments )\n\t\t\t\tresult = hashCombine( result, attach );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic AttachmentPtr mergeAttachments( FrameGraph & graph\n\t\t\t, AttachmentArray const & attachments\n\t\t\t, uint32_t passCount\n\t\t\t, bool mergeMipLevels\n\t\t\t, bool mergeArrayLayers )\n\t\t{\n\t\t\tAttachmentPtr result;\n\n\t\t\tfor ( uint32_t passIndex = 0u; passIndex < passCount; ++passIndex )\n\t\t\t{\n\t\t\t\tImageViewIdArray views;\n\t\t\t\tfor ( auto attach : attachments )\n\t\t\t\t{\n\t\t\t\t\tviews.push_back( attach->view( passIndex ) );\n\t\t\t\t\tif ( !result )\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = std::make_unique< Attachment >( views.back(), *attach );\n\t\t\t\t\t\tresult->imageAttach.views.clear();\n\t\t\t\t\t\tresult->pass = nullptr;\n\t\t\t\t\t}\n\n\t\t\t\t\tresult->source.emplace_back( attach, attach->pass, attach->imageAttach );\n\t\t\t\t}\n\n\t\t\t\tresult->imageAttach.views.push_back( graph.mergeViews( views, mergeMipLevels, mergeArrayLayers ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic AttachmentPtr mergeAttachments( FrameGraph & graph\n\t\t\t, AttachmentArray const & attachments\n\t\t\t, uint32_t passCount )\n\t\t{\n\t\t\tAttachmentPtr result;\n\n\t\t\tfor ( uint32_t passIndex = 0u; passIndex < passCount; ++passIndex )\n\t\t\t{\n\t\t\t\tBufferViewIdArray views;\n\t\t\t\tfor ( auto attach : attachments )\n\t\t\t\t{\n\t\t\t\t\tviews.push_back( attach->buffer( passIndex ) );\n\t\t\t\t\tif ( !result )\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = std::make_unique< Attachment >( views.back(), *attach );\n\t\t\t\t\t\tresult->bufferAttach.buffers.clear();\n\t\t\t\t\t\tresult->pass = nullptr;\n\t\t\t\t\t}\n\n\t\t\t\t\tresult->source.emplace_back( attach, attach->pass, attach->bufferAttach );\n\t\t\t\t}\n\n\t\t\t\tresult->bufferAttach.buffers.push_back( graph.mergeViews( views ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tFrameGraph::FrameGraph( ResourceHandler & handler\n\t\t, std::string name )\n\t\t: m_handler{ handler }\n\t\t, m_name{ std::move( name ) }\n\t\t, m_defaultGroup{ std::make_unique< FramePassGroup >( *this, 0u, m_name, FramePassGroup::Token{} ) }\n\t\t, m_finalState{ handler }\n\t{\n\t}\n\n\tFramePass & FrameGraph::createPass( std::string const & name\n\t\t, RunnablePassCreator runnableCreator )\n\t{\n\t\treturn m_defaultGroup->createPass( name, std::move( runnableCreator ) );\n\t}\n\n\tFramePassGroup & FrameGraph::createPassGroup( std::string const & groupName )\n\t{\n\t\treturn m_defaultGroup->createPassGroup( groupName );\n\t}\n\n\tBufferId FrameGraph::createBuffer( BufferData const & img )\n\t{\n\t\tauto result = m_handler.createBufferId( img );\n\t\tm_buffers.insert( result );\n\t\treturn result;\n\t}\n\n\tBufferViewId FrameGraph::createView( BufferViewData const & view )\n\t{\n\t\tauto result = m_handler.createViewId( view );\n\t\tm_bufferViews.insert( result );\n\t\treturn result;\n\t}\n\n\tImageId FrameGraph::createImage( ImageData const & img )\n\t{\n\t\tauto result = m_handler.createImageId( img );\n\t\tm_images.insert( result );\n\t\treturn result;\n\t}\n\n\tImageViewId FrameGraph::createView( ImageViewData const & view )\n\t{\n\t\tauto result = m_handler.createViewId( view );\n\t\tm_imageViews.insert( result );\n\t\treturn result;\n\t}\n\n\tImageViewId FrameGraph::mergeViews( ImageViewIdArray const & views\n\t\t, bool mergeMipLevels\n\t\t, bool mergeArrayLayers )\n\t{\n\t\tImageViewData data;\n\t\tfor ( auto & view : views )\n\t\t\tfgph::mergeViewData( view, mergeMipLevels, mergeArrayLayers, data );\n\n\t\tif ( data.info.subresourceRange.layerCount > 1u )\n\t\t{\n\t\t\tswitch ( data.info.viewType )\n\t\t\t{\n\t\t\tcase ImageViewType::e1D:\n\t\t\t\tdata.info.viewType = ImageViewType::e1DArray;\n\t\t\t\tbreak;\n\t\t\tcase ImageViewType::e2D:\n\t\t\t\tif ( checkFlag( data.image.data->info.flags, ImageCreateFlags::eCubeCompatible )\n\t\t\t\t\t&& ( data.info.subresourceRange.layerCount % 6u ) == 0u\n\t\t\t\t\t&& data.info.subresourceRange.baseArrayLayer == 0u )\n\t\t\t\t\tdata.info.viewType = ( data.info.subresourceRange.layerCount > 6u )\n\t\t\t\t\t\t? ImageViewType::eCubeArray\n\t\t\t\t\t\t: ImageViewType::eCube;\n\t\t\t\telse\n\t\t\t\t\tdata.info.viewType = ImageViewType::e2DArray;\n\t\t\t\tbreak;\n\t\t\tcase ImageViewType::eCube:\n\t\t\t\tif ( data.info.subresourceRange.layerCount > 6u )\n\t\t\t\t\tdata.info.viewType = ImageViewType::eCubeArray;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn createView( data );\n\t}\n\n\tBufferViewId FrameGraph::mergeViews( BufferViewIdArray const & views )\n\t{\n\t\tBufferViewData data;\n\t\tfor ( auto & view : views )\n\t\t\tfgph::mergeViewData( view, data );\n\t\treturn createView( data );\n\t}\n\n\tAttachment const * FrameGraph::mergeAttachments( AttachmentArray const & attachments\n\t\t, bool mergeMipLevels\n\t\t, bool mergeArrayLayers )\n\t{\n\t\tif ( attachments.empty() )\n\t\t{\n\t\t\tLogger::logWarning( \"No attachments to merge\" );\n\t\t\treturn nullptr;\n\t\t}\n\t\tif ( attachments.size() == 1 )\n\t\t{\n\t\t\tLogger::logDebug( \"Single attachment, nothing to merge\" );\n\t\t\treturn attachments.front();\n\t\t}\n\n\t\tauto allImages = std::all_of( attachments.begin(), attachments.end()\n\t\t\t, []( Attachment const * attach )\n\t\t\t{\n\t\t\t\treturn attach->isImage();\n\t\t\t} );\n\t\tif ( auto allBuffers = std::all_of( attachments.begin(), attachments.end()\n\t\t\t, []( Attachment const * attach )\n\t\t\t{\n\t\t\t\treturn attach->isBuffer();\n\t\t\t} );\n\t\t\t!allImages && !allBuffers )\n\t\t{\n\t\t\tLogger::logWarning( \"Can only merge attachments of the same type\" );\n\t\t\tCRG_Exception( \"Can only merge attachments of the same type\" );\n\t\t}\n\n\t\tauto passCount = allImages\n\t\t\t? attachments.front()->getViewCount()\n\t\t\t: attachments.front()->getBufferCount();\n\n\t\tif ( passCount == 0 )\n\t\t{\n\t\t\tLogger::logWarning( \"Can't merge empty attachments\" );\n\t\t\tCRG_Exception( \"Can't merge empty attachments\" );\n\t\t}\n\n\t\tif ( allImages )\n\t\t{\n\t\t\tif ( !std::all_of( attachments.begin(), attachments.end()\n\t\t\t\t, [passCount]( Attachment const * attach )\n\t\t\t\t{\n\t\t\t\t\treturn attach->getViewCount() == passCount;\n\t\t\t\t} ) )\n\t\t\t{\n\t\t\t\tLogger::logWarning( \"Can only merge attachments with the same pass count\" );\n\t\t\t\tCRG_Exception( \"Can only merge attachments with the same pass count\" );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( !std::all_of( attachments.begin(), attachments.end()\n\t\t\t\t, [passCount]( Attachment const * attach )\n\t\t\t\t{\n\t\t\t\t\treturn attach->getBufferCount() == passCount;\n\t\t\t\t} ) )\n\t\t\t{\n\t\t\t\tLogger::logWarning( \"Can only merge attachments with the same pass count\" );\n\t\t\t\tCRG_Exception( \"Can only merge attachments with the same pass count\" );\n\t\t\t}\n\t\t}\n\n\t\tsize_t hash = allImages\n\t\t\t? fgph::makeHash( attachments, mergeMipLevels, mergeArrayLayers )\n\t\t\t: fgph::makeHash( attachments, false, false );\n\t\tauto [it, inserted] = m_mergedAttachments.try_emplace( hash, nullptr );\n\n\t\tif ( inserted )\n\t\t{\n\t\t\tif ( allImages )\n\t\t\t{\n\t\t\t\tit->second = fgph::mergeAttachments( *this, attachments, passCount, mergeMipLevels, mergeArrayLayers );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tit->second = fgph::mergeAttachments( *this, attachments, passCount );\n\t\t\t}\n\n\t\t\tit->second->initSources();\n\t\t}\n\n\t\treturn it->second.get();\n\t}\n\n\tRunnableGraphPtr FrameGraph::compile( GraphContext & context )\n\t{\n\t\tFramePassArray passes;\n\t\tm_defaultGroup->listPasses( passes );\n\n\t\tif ( passes.empty() )\n\t\t{\n\t\t\tLogger::logWarning( \"No FramePass registered.\" );\n\t\t\tCRG_Exception( \"No FramePass registered.\" );\n\t\t}\n\n\t\tauto endPoints = builder::findEndPoints( passes );\n\t\tRootNode root{ *this };\n\t\tGraphNodePtrArray nodes;\n\t\tbuilder::buildGraph( endPoints, root, nodes, context.separateDepthStencilLayouts );\n\t\treturn std::make_unique< RunnableGraph >( *this\n\t\t\t, std::move( nodes )\n\t\t\t, std::move( root )\n\t\t\t, context );\n\t}\n\n\tLayoutState FrameGraph::getFinalLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range )const\n\t{\n\t\treturn m_finalState.getLayoutState( image, viewType, range );\n\t}\n\n\tLayoutState FrameGraph::getFinalLayoutState( ImageViewId view\n\t\t, uint32_t passIndex )const\n\t{\n\t\tif ( view.data->source.empty() )\n\t\t{\n\t\t\treturn getFinalLayoutState( view.data->image\n\t\t\t\t, view.data->info.viewType\n\t\t\t\t, getSubresourceRange( view ) );\n\t\t}\n\n\t\treturn getFinalLayoutState( view.data->source[passIndex], 0u );\n\t}\n\n\tAccessState const & FrameGraph::getFinalAccessState( BufferId buffer\n\t\t, BufferSubresourceRange const & range )const\n\t{\n\t\treturn m_finalState.getAccessState( buffer, range );\n\t}\n\n\tAccessState const & FrameGraph::getFinalAccessState( BufferViewId view\n\t\t, uint32_t passIndex )const\n\t{\n\t\tif ( view.data->source.empty() )\n\t\t{\n\t\t\treturn getFinalAccessState( view.data->buffer\n\t\t\t\t, getSubresourceRange( view ) );\n\t\t}\n\n\t\treturn getFinalAccessState( view.data->source[passIndex], 0u );\n\t}\n\n\tvoid FrameGraph::addInput( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\tm_inputs.setLayoutState( image\n\t\t\t, viewType\n\t\t\t, range\n\t\t\t, outputLayout );\n\t}\n\n\tvoid FrameGraph::addInput( ImageViewId view\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\taddInput( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view )\n\t\t\t, outputLayout );\n\t}\n\n\tLayoutState FrameGraph::getInputLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range )const\n\t{\n\t\treturn m_inputs.getLayoutState( image\n\t\t\t, viewType\n\t\t\t, range );\n\t}\n\n\tLayoutState FrameGraph::getInputLayoutState( ImageViewId view )const\n\t{\n\t\treturn getInputLayoutState( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view ) );\n\t}\n\n\tvoid FrameGraph::addOutput( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\tm_outputs.setLayoutState( image\n\t\t\t, viewType\n\t\t\t, range\n\t\t\t, outputLayout );\n\t}\n\n\tvoid FrameGraph::addOutput( ImageViewId view\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\taddOutput( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view )\n\t\t\t, outputLayout );\n\t}\n\n\tLayoutState FrameGraph::getOutputLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range )const\n\t{\n\t\treturn m_outputs.getLayoutState( image\n\t\t\t, viewType\n\t\t\t, range );\n\t}\n\n\tLayoutState FrameGraph::getOutputLayoutState( ImageViewId view )const\n\t{\n\t\treturn getOutputLayoutState( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view ) );\n\t}\n\n\tLayerLayoutStatesMap const & FrameGraph::getOutputLayoutStates()const\n\t{\n\t\treturn m_outputs.images;\n\t}\n\n\tvoid FrameGraph::registerFinalState( RecordContext const & context )\n\t{\n\t\tm_finalState = context;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/FrameGraph.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n\t<Type Name=\"crg::BufferData\">\n\t\t<DisplayString>{name,sb} fmt={info.size}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"flags\">info.flags</Item>\n\t\t\t<Item Name=\"size\">info.size</Item>\n\t\t\t<Item Name=\"usage\">info.usage</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::BufferViewData\">\n\t\t<DisplayString>{name,sb} fmt={info.format} offset={info.subresourceRange.offset} size={info.subresourceRange.size}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"buffer\">buffer</Item>\n\t\t\t<Item Name=\"format\">info.format</Item>\n\t\t\t<Item Name=\"offset\">info.subresourceRange.offset</Item>\n\t\t\t<Item Name=\"size\">info.subresourceRange.size</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::ImageData\">\n\t\t<DisplayString>{name,sb} fmt={info.format} mips={info.mipLevels}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"flags\">info.flags</Item>\n\t\t\t<Item Name=\"imageType\">info.imageType</Item>\n\t\t\t<Item Name=\"format\">info.format</Item>\n\t\t\t<Item Name=\"extent\">info.extent</Item>\n\t\t\t<Item Name=\"mipLevels\">info.mipLevels</Item>\n\t\t\t<Item Name=\"arrayLayers\">info.arrayLayers</Item>\n\t\t\t<Item Name=\"samples\">info.samples</Item>\n\t\t\t<Item Name=\"tiling\">info.tiling</Item>\n\t\t\t<Item Name=\"usage\">info.usage</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::ImageViewData\">\n\t\t<DisplayString>{name,sb} fmt={info.format} mipLevel={info.subresourceRange.baseMipLevel} mipCount={info.subresourceRange.levelCount}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"image\">image</Item>\n\t\t\t<Item Name=\"flags\">info.flags</Item>\n\t\t\t<Item Name=\"viewType\">info.viewType</Item>\n\t\t\t<Item Name=\"format\">info.format</Item>\n\t\t\t<Item Name=\"baseArrayLayer\">info.subresourceRange.baseArrayLayer</Item>\n\t\t\t<Item Name=\"layerCount\">info.subresourceRange.layerCount</Item>\n\t\t\t<Item Name=\"baseMipLevel\">info.subresourceRange.baseMipLevel</Item>\n\t\t\t<Item Name=\"levelCount\">info.subresourceRange.levelCount</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::Id&lt;*&gt;\">\n\t\t<DisplayString>{id} {data->name,sb}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"id\">id</Item>\n\t\t\t<Item Name=\"data\">*data</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::BufferAttachment\">\n\t\t<DisplayString Condition=\"flags == 0\">{buffers[0]}</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::BufferAttachment::Flag::Uniform) != 0\">Uniform {buffers[0]}</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::BufferAttachment::Flag::Storage) != 0\">Storage {buffers[0]}</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::BufferAttachment::Flag::Transfer) != 0\">Transfer {buffers[0]}</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::BufferAttachment::Flag::Transition) != 0\">Transition {buffers[0]}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"buffers\">buffers</Item>\n\t\t\t<Item Name=\"wantedAccess\">wantedAccess</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::ImageAttachment\">\n\t\t<DisplayString Condition=\"flags == 0\">{views[0]}</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::ImageAttachment::Flag::Sampled) != 0\">Sampled {views[0]}\"</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::ImageAttachment::Flag::Storage) != 0\">Storage {views[0]}\"</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::ImageAttachment::Flag::Transfer) != 0\">Transfer {views[0]}\"</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::ImageAttachment::Flag::Transition) != 0\">Transition {views[0]}\"</DisplayString>\n\t\t<DisplayString Condition=\"(flags &amp; crg::ImageAttachment::Flag::Sampled) == 0 &amp;&amp; (flags &amp; crg::ImageAttachment::Flag::Storage) == 0 &amp;&amp; (flags &amp; crg::ImageAttachment::Flag::Transfer) == 0 &amp;&amp; (flags &amp; crg::ImageAttachment::Flag::Transition) == 0\">Target {views[0]}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"views\">views</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"loadOp\">loadOp</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"storeOp\">storeOp</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"stencilLoadOp\">stencilLoadOp</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"stencilStoreOp\">stencilStoreOp</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"blendState\">blendState</Item>\n\t\t\t<Item Condition=\"!(flags &amp; crg::ImageAttachment::Flag::Sampled) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Storage) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transfer) &amp;&amp; !(flags &amp; crg::ImageAttachment::Flag::Transition)\" Name=\"clearValue\">clearValue</Item>\n\t\t\t<Item Name=\"wantedLayout\">wantedLayout</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::Attachment\">\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags == crg::Attachment::Flag::Image)\">Image {imageAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags == crg::Attachment::Flag::Buffer)\">Buffer {bufferAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags == crg::Attachment::Flag::Image)\">Image {imageAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags == crg::Attachment::Flag::Buffer)\">Buffer {bufferAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) == 0\">Image In {imageAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Image Out {imageAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Image InOut {imageAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) == 0\">Buffer In {bufferAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Buffer Out {bufferAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Buffer InOut {bufferAttach} ({*pass})\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) == 0\">Image In {imageAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Image Out {imageAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Image) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Image InOut {imageAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) == 0\">Buffer In {bufferAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Buffer Out {bufferAttach}\"</DisplayString>\n\t\t<DisplayString Condition=\"pass == 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Buffer) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Input) != 0 &amp;&amp; (flags &amp; crg::Attachment::Flag::Output) != 0\">Buffer InOut {bufferAttach}\"</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Condition=\"(flags &amp; crg::Attachment::Flag::Image)\" Name=\"image\">imageAttach</Item>\n\t\t\t<Item Condition=\"(flags &amp; crg::Attachment::Flag::Buffer)\" Name=\"buffer\">bufferAttach</Item>\n\t\t\t<Item Condition=\"pass != 0\" Name=\"pass\">*pass</Item>\n\t\t\t<Item Condition=\"pass == 0\" Name=\"source\">source</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::FramePass\">\n\t\t<DisplayString>{m_group}/{m_id} {m_name,sb}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"group\">m_group</Item>\n\t\t\t<Item Name=\"id\">m_id</Item>\n\t\t\t<Item Name=\"name\">m_name</Item>\n\t\t\t<Item Name=\"uniforms\">m_uniforms</Item>\n\t\t\t<Item Name=\"sampled\">m_sampled</Item>\n\t\t\t<Item Name=\"inputs\">m_inputs</Item>\n\t\t\t<Item Name=\"inouts\">m_inouts</Item>\n\t\t\t<Item Name=\"outputs\">m_outputs</Item>\n\t\t\t<Item Name=\"targets\">m_targets</Item>\n\t\t\t<Item Name=\"ownAttaches\">m_ownAttaches</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::FramePassGroup\">\n\t\t<DisplayString Condition=\"m_parent == 0\">{m_name,sb}</DisplayString>\n\t\t<DisplayString Condition=\"m_parent != 0\">{*m_parent}/{m_name,sb}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"id\">m_id</Item>\n\t\t\t<Item Name=\"name\">m_name</Item>\n\t\t\t<Item Name=\"passes\">m_passes</Item>\n\t\t\t<Item Name=\"groups\">m_groups</Item>\n\t\t\t<Item Name=\"parent\">m_parent</Item>\n\t\t\t<Item Name=\"graph\">m_graph</Item>\n\t\t\t<Item Name=\"inputs\">m_inputs</Item>\n\t\t\t<Item Name=\"outputs\">m_outputs</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::GraphNode\">\n\t\t<DisplayString>{kind} {name}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"kind\">kind</Item>\n\t\t\t<Item Name=\"pred\">prev</Item>\n\t\t\t<Item Name=\"attachsToPrev\">attachsToPrev</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::FramePassNode\">\n\t\t<DisplayString>{kind} {*pass}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"pass\">*pass</Item>\n\t\t\t<Item Name=\"pred\">prev</Item>\n\t\t\t<Item Name=\"attachsToPrev\">attachsToPrev</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::RootNode\">\n\t\t<DisplayString>{kind} {name}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"name\">name</Item>\n\t\t\t<Item Name=\"pred\">prev</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::details::PassAttach\">\n\t\t<DisplayString>{*attach}, passes={passes}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"attach\">attach</Item>\n\t\t\t<Item Name=\"passes\">passes</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::FramePassDependencies\">\n\t\t<DisplayString>src={*srcPass}, dst={*dstPass}, in={dstInputs}, out={srcOutputs}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"srcPass\">*srcPass</Item>\n\t\t\t<Item Name=\"dstPass\">*dstPass</Item>\n\t\t\t<Item Name=\"srcOutputs\">srcOutputs</Item>\n\t\t\t<Item Name=\"dstInputs\">dstInputs</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::DataTransitionT&lt;crg::Id&lt;crg::ImageViewData&gt;&gt;\">\n\t\t<DisplayString>{data.data->name} : {outputAttach.name} -> {inputAttach.name}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"data\">data</Item>\n\t\t\t<Item Name=\"src\">outputAttach</Item>\n\t\t\t<Item Name=\"dst\">inputAttach</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::DataTransitionT&lt;crg::Buffer&gt;\">\n\t\t<DisplayString>{data.name} : {outputAttach.name} -> {inputAttach.name}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"buffer\">data</Item>\n\t\t\t<Item Name=\"src\">outputAttach</Item>\n\t\t\t<Item Name=\"dst\">inputAttach</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::RunnablePass\">\n\t\t<DisplayString>{m_pass}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"pass\">m_pass</Item>\n\t\t\t<Item Name=\"context\">m_context</Item>\n\t\t\t<Item Name=\"graph\">m_graph</Item>\n\t\t\t<Item Name=\"callbacks\">m_callbacks</Item>\n\t\t\t<Item Name=\"ruConfig\">m_ruConfig</Item>\n\t\t\t<Item Name=\"timer\">m_timer</Item>\n\t\t\t<Item Name=\"passContexts\">m_passContexts</Item>\n\t\t</Expand>\n\t</Type>\n\n\t<Type Name=\"crg::RecordContext::ImplicitTransition\">\n\t\t<DisplayString>{view} {*pass}</DisplayString>\n\t\t<Expand>\n\t\t\t<Item Name=\"pass\">pass</Item>\n\t\t\t<Item Name=\"view\">view</Item>\n\t\t\t<Item Name=\"action\">action</Item>\n\t\t</Expand>\n\t</Type>\n\n</AutoVisualizer>\n"
  },
  {
    "path": "source/RenderGraph/FrameGraphPrerequisites.cpp",
    "content": "#include \"RenderGraph/FrameGraphPrerequisites.hpp\"\n#include \"RenderGraph/BufferData.hpp\"\n#include \"RenderGraph/BufferViewData.hpp\"\n#include \"RenderGraph/ImageData.hpp\"\n#include \"RenderGraph/ImageViewData.hpp\"\n\n#include <cassert>\n\nnamespace crg\n{\n\tnamespace fgph\n\t{\n\t\tstatic bool match( ImageSubresourceRange const & lhsRange\n\t\t\t, ImageSubresourceRange const & rhsRange )noexcept\n\t\t{\n\t\t\treturn ( ( lhsRange.aspectMask & rhsRange.aspectMask ) != ImageAspectFlags::eNone )\n\t\t\t\t&& lhsRange.baseArrayLayer == rhsRange.baseArrayLayer\n\t\t\t\t&& lhsRange.layerCount == rhsRange.layerCount\n\t\t\t\t&& lhsRange.baseMipLevel == rhsRange.baseMipLevel\n\t\t\t\t&& lhsRange.levelCount == rhsRange.levelCount;\n\t\t}\n\n\t\tstatic bool match( ImageId const & image\n\t\t\t, ImageViewType lhsType\n\t\t\t, ImageViewType rhsType\n\t\t\t, ImageSubresourceRange const & lhsRange\n\t\t\t, ImageSubresourceRange const & rhsRange )noexcept\n\t\t{\n\t\t\treturn match( getVirtualRange( image, lhsType, lhsRange )\n\t\t\t\t, getVirtualRange( image, rhsType, rhsRange ) );\n\t\t}\n\n\t\tstatic bool match( ImageId const & image\n\t\t\t, ImageViewCreateInfo const & lhsInfo\n\t\t\t, ImageViewCreateInfo const & rhsInfo )noexcept\n\t\t{\n\t\t\treturn lhsInfo.flags == rhsInfo.flags\n\t\t\t\t&& lhsInfo.format == rhsInfo.format\n\t\t\t\t&& match( image\n\t\t\t\t\t, lhsInfo.viewType, rhsInfo.viewType\n\t\t\t\t\t, lhsInfo.subresourceRange, rhsInfo.subresourceRange );\n\t\t}\n\n\t\tstatic bool match( ImageViewData const & lhs, ImageViewData const & rhs )noexcept\n\t\t{\n\t\t\treturn lhs.image.id == rhs.image.id\n\t\t\t\t&& match( lhs.image, lhs.info, rhs.info );\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tstd::string_view getName( PixelFormat format )\n\t{\n\t\tswitch ( format )\n\t\t{\n\t\tcase PixelFormat::eR4G4_UNORM:\n\t\t\treturn \"rg8\";\n\t\tcase PixelFormat::eR4G4B4A4_UNORM:\n\t\t\treturn \"rgba16\";\n\t\tcase PixelFormat::eB4G4R4A4_UNORM:\n\t\t\treturn \"rgba16s\";\n\t\tcase PixelFormat::eR5G6B5_UNORM:\n\t\t\treturn \"rgb565\";\n\t\tcase PixelFormat::eB5G6R5_UNORM:\n\t\t\treturn \"bgr565\";\n\t\tcase PixelFormat::eR5G5B5A1_UNORM:\n\t\t\treturn \"rgba5551\";\n\t\tcase PixelFormat::eB5G5R5A1_UNORM:\n\t\t\treturn \"bgra5551\";\n\t\tcase PixelFormat::eA1R5G5B5_UNORM:\n\t\t\treturn \"argb1555\";\n\t\tcase PixelFormat::eR8_UNORM:\n\t\t\treturn \"r8\";\n\t\tcase PixelFormat::eR8_SNORM:\n\t\t\treturn \"r8s\";\n\t\tcase PixelFormat::eR8_USCALED:\n\t\t\treturn \"r8us\";\n\t\tcase PixelFormat::eR8_SSCALED:\n\t\t\treturn \"r8ss\";\n\t\tcase PixelFormat::eR8_UINT:\n\t\t\treturn \"r8ui\";\n\t\tcase PixelFormat::eR8_SINT:\n\t\t\treturn \"r8si\";\n\t\tcase PixelFormat::eR8_SRGB:\n\t\t\treturn \"r8srgb\";\n\t\tcase PixelFormat::eR8G8_UNORM:\n\t\t\treturn \"rg16\";\n\t\tcase PixelFormat::eR8G8_SNORM:\n\t\t\treturn \"rg16s\";\n\t\tcase PixelFormat::eR8G8_USCALED:\n\t\t\treturn \"rg16us\";\n\t\tcase PixelFormat::eR8G8_SSCALED:\n\t\t\treturn \"rg16ss\";\n\t\tcase PixelFormat::eR8G8_UINT:\n\t\t\treturn \"rg16ui\";\n\t\tcase PixelFormat::eR8G8_SINT:\n\t\t\treturn \"rg16si\";\n\t\tcase PixelFormat::eR8G8_SRGB:\n\t\t\treturn \"rg16srgb\";\n\t\tcase PixelFormat::eR8G8B8_UNORM:\n\t\t\treturn \"rgb24\";\n\t\tcase PixelFormat::eR8G8B8_SNORM:\n\t\t\treturn \"rgb24s\";\n\t\tcase PixelFormat::eR8G8B8_USCALED:\n\t\t\treturn \"rgb24us\";\n\t\tcase PixelFormat::eR8G8B8_SSCALED:\n\t\t\treturn \"rgb24ss\";\n\t\tcase PixelFormat::eR8G8B8_UINT:\n\t\t\treturn \"rgb24ui\";\n\t\tcase PixelFormat::eR8G8B8_SINT:\n\t\t\treturn \"rgb24si\";\n\t\tcase PixelFormat::eR8G8B8_SRGB:\n\t\t\treturn \"rgb24srgb\";\n\t\tcase PixelFormat::eB8G8R8_UNORM:\n\t\t\treturn \"bgr24\";\n\t\tcase PixelFormat::eB8G8R8_SNORM:\n\t\t\treturn \"bgr24s\";\n\t\tcase PixelFormat::eB8G8R8_USCALED:\n\t\t\treturn \"bgr24us\";\n\t\tcase PixelFormat::eB8G8R8_SSCALED:\n\t\t\treturn \"bgr24ss\";\n\t\tcase PixelFormat::eB8G8R8_UINT:\n\t\t\treturn \"bgr24ui\";\n\t\tcase PixelFormat::eB8G8R8_SINT:\n\t\t\treturn \"bgr24si\";\n\t\tcase PixelFormat::eB8G8R8_SRGB:\n\t\t\treturn \"bgr24srgb\";\n\t\tcase PixelFormat::eR8G8B8A8_UNORM:\n\t\t\treturn \"rgba32\";\n\t\tcase PixelFormat::eR8G8B8A8_SNORM:\n\t\t\treturn \"rgba32s\";\n\t\tcase PixelFormat::eR8G8B8A8_USCALED:\n\t\t\treturn \"rgba32us\";\n\t\tcase PixelFormat::eR8G8B8A8_SSCALED:\n\t\t\treturn \"rgba32ss\";\n\t\tcase PixelFormat::eR8G8B8A8_UINT:\n\t\t\treturn \"rgba32ui\";\n\t\tcase PixelFormat::eR8G8B8A8_SINT:\n\t\t\treturn \"rgba32si\";\n\t\tcase PixelFormat::eR8G8B8A8_SRGB:\n\t\t\treturn \"rgba32srgb\";\n\t\tcase PixelFormat::eB8G8R8A8_UNORM:\n\t\t\treturn \"bgra32\";\n\t\tcase PixelFormat::eB8G8R8A8_SNORM:\n\t\t\treturn \"bgra32s\";\n\t\tcase PixelFormat::eB8G8R8A8_USCALED:\n\t\t\treturn \"bgra32us\";\n\t\tcase PixelFormat::eB8G8R8A8_SSCALED:\n\t\t\treturn \"bgra32ss\";\n\t\tcase PixelFormat::eB8G8R8A8_UINT:\n\t\t\treturn \"bgra32ui\";\n\t\tcase PixelFormat::eB8G8R8A8_SINT:\n\t\t\treturn \"bgra32si\";\n\t\tcase PixelFormat::eB8G8R8A8_SRGB:\n\t\t\treturn \"bgra32srgb\";\n\t\tcase PixelFormat::eA8B8G8R8_UNORM:\n\t\t\treturn \"abgr32\";\n\t\tcase PixelFormat::eA8B8G8R8_SNORM:\n\t\t\treturn \"abgr32s\";\n\t\tcase PixelFormat::eA8B8G8R8_USCALED:\n\t\t\treturn \"abgr32us\";\n\t\tcase PixelFormat::eA8B8G8R8_SSCALED:\n\t\t\treturn \"abgr32ss\";\n\t\tcase PixelFormat::eA8B8G8R8_UINT:\n\t\t\treturn \"abgr32ui\";\n\t\tcase PixelFormat::eA8B8G8R8_SINT:\n\t\t\treturn \"abgr32si\";\n\t\tcase PixelFormat::eA8B8G8R8_SRGB:\n\t\t\treturn \"abgr32srgb\";\n\t\tcase PixelFormat::eA2R10G10B10_UNORM:\n\t\t\treturn \"argb2101010\";\n\t\tcase PixelFormat::eA2R10G10B10_SNORM:\n\t\t\treturn \"argb2101010s\";\n\t\tcase PixelFormat::eA2R10G10B10_USCALED:\n\t\t\treturn \"argb2101010us\";\n\t\tcase PixelFormat::eA2R10G10B10_SSCALED:\n\t\t\treturn \"argb2101010ss\";\n\t\tcase PixelFormat::eA2R10G10B10_UINT:\n\t\t\treturn \"argb2101010ui\";\n\t\tcase PixelFormat::eA2R10G10B10_SINT:\n\t\t\treturn \"argb2101010si\";\n\t\tcase PixelFormat::eA2B10G10R10_UNORM:\n\t\t\treturn \"abgr2101010\";\n\t\tcase PixelFormat::eA2B10G10R10_SNORM:\n\t\t\treturn \"abgr2101010s\";\n\t\tcase PixelFormat::eA2B10G10R10_USCALED:\n\t\t\treturn \"abgr2101010us\";\n\t\tcase PixelFormat::eA2B10G10R10_SSCALED:\n\t\t\treturn \"abgr2101010ss\";\n\t\tcase PixelFormat::eA2B10G10R10_UINT:\n\t\t\treturn \"abgr2101010ui\";\n\t\tcase PixelFormat::eA2B10G10R10_SINT:\n\t\t\treturn \"abgr2101010si\";\n\t\tcase PixelFormat::eR16_UNORM:\n\t\t\treturn \"r16\";\n\t\tcase PixelFormat::eR16_SNORM:\n\t\t\treturn \"rg16s\";\n\t\tcase PixelFormat::eR16_USCALED:\n\t\t\treturn \"rg16us\";\n\t\tcase PixelFormat::eR16_SSCALED:\n\t\t\treturn \"rg16ss\";\n\t\tcase PixelFormat::eR16_UINT:\n\t\t\treturn \"rg16ui\";\n\t\tcase PixelFormat::eR16_SINT:\n\t\t\treturn \"rg16si\";\n\t\tcase PixelFormat::eR16_SFLOAT:\n\t\t\treturn \"rg16f\";\n\t\tcase PixelFormat::eR16G16_UNORM:\n\t\t\treturn \"rg32\";\n\t\tcase PixelFormat::eR16G16_SNORM:\n\t\t\treturn \"rg32s\";\n\t\tcase PixelFormat::eR16G16_USCALED:\n\t\t\treturn \"rg32us\";\n\t\tcase PixelFormat::eR16G16_SSCALED:\n\t\t\treturn \"rg32ss\";\n\t\tcase PixelFormat::eR16G16_UINT:\n\t\t\treturn \"rg32ui\";\n\t\tcase PixelFormat::eR16G16_SINT:\n\t\t\treturn \"rg32si\";\n\t\tcase PixelFormat::eR16G16_SFLOAT:\n\t\t\treturn \"rg32f\";\n\t\tcase PixelFormat::eR16G16B16_UNORM:\n\t\t\treturn \"rgb48\";\n\t\tcase PixelFormat::eR16G16B16_SNORM:\n\t\t\treturn \"rgb48s\";\n\t\tcase PixelFormat::eR16G16B16_USCALED:\n\t\t\treturn \"rgb48us\";\n\t\tcase PixelFormat::eR16G16B16_SSCALED:\n\t\t\treturn \"rgb48ss\";\n\t\tcase PixelFormat::eR16G16B16_UINT:\n\t\t\treturn \"rgb48ui\";\n\t\tcase PixelFormat::eR16G16B16_SINT:\n\t\t\treturn \"rgb48si\";\n\t\tcase PixelFormat::eR16G16B16_SFLOAT:\n\t\t\treturn \"rgb48f\";\n\t\tcase PixelFormat::eR16G16B16A16_UNORM:\n\t\t\treturn \"rgba64\";\n\t\tcase PixelFormat::eR16G16B16A16_SNORM:\n\t\t\treturn \"rgba64s\";\n\t\tcase PixelFormat::eR16G16B16A16_USCALED:\n\t\t\treturn \"rgba64us\";\n\t\tcase PixelFormat::eR16G16B16A16_SSCALED:\n\t\t\treturn \"rgba64ss\";\n\t\tcase PixelFormat::eR16G16B16A16_UINT:\n\t\t\treturn \"rgba64ui\";\n\t\tcase PixelFormat::eR16G16B16A16_SINT:\n\t\t\treturn \"rgba64si\";\n\t\tcase PixelFormat::eR16G16B16A16_SFLOAT:\n\t\t\treturn \"rgba64f\";\n\t\tcase PixelFormat::eR32_UINT:\n\t\t\treturn \"r32ui\";\n\t\tcase PixelFormat::eR32_SINT:\n\t\t\treturn \"r32si\";\n\t\tcase PixelFormat::eR32_SFLOAT:\n\t\t\treturn \"r32f\";\n\t\tcase PixelFormat::eR32G32_UINT:\n\t\t\treturn \"rg64ui\";\n\t\tcase PixelFormat::eR32G32_SINT:\n\t\t\treturn \"rg64si\";\n\t\tcase PixelFormat::eR32G32_SFLOAT:\n\t\t\treturn \"rg64f\";\n\t\tcase PixelFormat::eR32G32B32_UINT:\n\t\t\treturn \"rgb96ui\";\n\t\tcase PixelFormat::eR32G32B32_SINT:\n\t\t\treturn \"rgb96si\";\n\t\tcase PixelFormat::eR32G32B32_SFLOAT:\n\t\t\treturn \"rgb96f\";\n\t\tcase PixelFormat::eR32G32B32A32_UINT:\n\t\t\treturn \"rgba128ui\";\n\t\tcase PixelFormat::eR32G32B32A32_SINT:\n\t\t\treturn \"rgba128si\";\n\t\tcase PixelFormat::eR32G32B32A32_SFLOAT:\n\t\t\treturn \"rgba128f\";\n\t\tcase PixelFormat::eR64_UINT:\n\t\t\treturn \"r64ui\";\n\t\tcase PixelFormat::eR64_SINT:\n\t\t\treturn \"r64si\";\n\t\tcase PixelFormat::eR64_SFLOAT:\n\t\t\treturn \"r64f\";\n\t\tcase PixelFormat::eR64G64_UINT:\n\t\t\treturn \"rg128ui\";\n\t\tcase PixelFormat::eR64G64_SINT:\n\t\t\treturn \"rg128si\";\n\t\tcase PixelFormat::eR64G64_SFLOAT:\n\t\t\treturn \"rg128f\";\n\t\tcase PixelFormat::eR64G64B64_UINT:\n\t\t\treturn \"rgb192ui\";\n\t\tcase PixelFormat::eR64G64B64_SINT:\n\t\t\treturn \"rgb192si\";\n\t\tcase PixelFormat::eR64G64B64_SFLOAT:\n\t\t\treturn \"rgb192f\";\n\t\tcase PixelFormat::eR64G64B64A64_UINT:\n\t\t\treturn \"rgba256ui\";\n\t\tcase PixelFormat::eR64G64B64A64_SINT:\n\t\t\treturn \"rgba256si\";\n\t\tcase PixelFormat::eR64G64B64A64_SFLOAT:\n\t\t\treturn \"rgba256f\";\n\t\tcase PixelFormat::eB10G11R11_UFLOAT:\n\t\t\treturn \"bgr32f\";\n\t\tcase PixelFormat::eE5B9G9R9_UFLOAT:\n\t\t\treturn \"ebgr32f\";\n\t\tcase PixelFormat::eD16_UNORM:\n\t\t\treturn \"depth16\";\n\t\tcase PixelFormat::eX8_D24_UNORM:\n\t\t\treturn \"depth24\";\n\t\tcase PixelFormat::eD32_SFLOAT:\n\t\t\treturn \"depth32f\";\n\t\tcase PixelFormat::eS8_UINT:\n\t\t\treturn \"stencil8\";\n\t\tcase PixelFormat::eD16_UNORM_S8_UINT:\n\t\t\treturn \"depth16s8\";\n\t\tcase PixelFormat::eD24_UNORM_S8_UINT:\n\t\t\treturn \"depth24s8\";\n\t\tcase PixelFormat::eD32_SFLOAT_S8_UINT:\n\t\t\treturn \"depth32fs8\";\n\t\tcase PixelFormat::eBC1_RGB_UNORM_BLOCK:\n\t\t\treturn \"bc1_rgb\";\n\t\tcase PixelFormat::eBC1_RGB_SRGB_BLOCK:\n\t\t\treturn \"bc1_srgb\";\n\t\tcase PixelFormat::eBC1_RGBA_UNORM_BLOCK:\n\t\t\treturn \"bc1_rgba\";\n\t\tcase PixelFormat::eBC1_RGBA_SRGB_BLOCK:\n\t\t\treturn \"bc1_rgba_srgb\";\n\t\tcase PixelFormat::eBC2_UNORM_BLOCK:\n\t\t\treturn \"bc2_rgba\";\n\t\tcase PixelFormat::eBC2_SRGB_BLOCK:\n\t\t\treturn \"bc2_rgba_srgb\";\n\t\tcase PixelFormat::eBC3_UNORM_BLOCK:\n\t\t\treturn \"bc3_rgba\";\n\t\tcase PixelFormat::eBC3_SRGB_BLOCK:\n\t\t\treturn \"bc3_rgba_srgb\";\n\t\tcase PixelFormat::eBC4_UNORM_BLOCK:\n\t\t\treturn \"bc4_r\";\n\t\tcase PixelFormat::eBC4_SNORM_BLOCK:\n\t\t\treturn \"bc4_r_s\";\n\t\tcase PixelFormat::eBC5_UNORM_BLOCK:\n\t\t\treturn \"bc5_rg\";\n\t\tcase PixelFormat::eBC5_SNORM_BLOCK:\n\t\t\treturn \"bc5_rg_s\";\n\t\tcase PixelFormat::eBC6H_UFLOAT_BLOCK:\n\t\t\treturn \"bc6h\";\n\t\tcase PixelFormat::eBC6H_SFLOAT_BLOCK:\n\t\t\treturn \"bc6h_s\";\n\t\tcase PixelFormat::eBC7_UNORM_BLOCK:\n\t\t\treturn \"bc7\";\n\t\tcase PixelFormat::eBC7_SRGB_BLOCK:\n\t\t\treturn \"bc7_srgb\";\n\t\tcase PixelFormat::eETC2_R8G8B8_UNORM_BLOCK:\n\t\t\treturn \"etc2_rgb\";\n\t\tcase PixelFormat::eETC2_R8G8B8_SRGB_BLOCK:\n\t\t\treturn \"etc2_rgb_srgb\";\n\t\tcase PixelFormat::eETC2_R8G8B8A1_UNORM_BLOCK:\n\t\t\treturn \"etc2_rgba1\";\n\t\tcase PixelFormat::eETC2_R8G8B8A1_SRGB_BLOCK:\n\t\t\treturn \"etc2_rgba1_srgb\";\n\t\tcase PixelFormat::eETC2_R8G8B8A8_UNORM_BLOCK:\n\t\t\treturn \"etc2_rgba\";\n\t\tcase PixelFormat::eETC2_R8G8B8A8_SRGB_BLOCK:\n\t\t\treturn \"etc2_rgba_srgb\";\n\t\tcase PixelFormat::eEAC_R11_UNORM_BLOCK:\n\t\t\treturn \"eac_r\";\n\t\tcase PixelFormat::eEAC_R11_SNORM_BLOCK:\n\t\t\treturn \"eac_r_s\";\n\t\tcase PixelFormat::eEAC_R11G11_UNORM_BLOCK:\n\t\t\treturn \"eac_rg\";\n\t\tcase PixelFormat::eEAC_R11G11_SNORM_BLOCK:\n\t\t\treturn \"eac_rg_s\";\n\t\tcase PixelFormat::eASTC_4x4_UNORM_BLOCK:\n\t\t\treturn \"astc_4x4\";\n\t\tcase PixelFormat::eASTC_4x4_SRGB_BLOCK:\n\t\t\treturn \"astc_4x4_srgb\";\n\t\tcase PixelFormat::eASTC_5x4_UNORM_BLOCK:\n\t\t\treturn \"astc_5x4\";\n\t\tcase PixelFormat::eASTC_5x4_SRGB_BLOCK:\n\t\t\treturn \"astc_5x4_srgb\";\n\t\tcase PixelFormat::eASTC_5x5_UNORM_BLOCK:\n\t\t\treturn \"astc_5x5\";\n\t\tcase PixelFormat::eASTC_5x5_SRGB_BLOCK:\n\t\t\treturn \"astc_5x5_srgb\";\n\t\tcase PixelFormat::eASTC_6x5_UNORM_BLOCK:\n\t\t\treturn \"astc_6x5\";\n\t\tcase PixelFormat::eASTC_6x5_SRGB_BLOCK:\n\t\t\treturn \"astc_6x5_srgb\";\n\t\tcase PixelFormat::eASTC_6x6_UNORM_BLOCK:\n\t\t\treturn \"astc_6x6\";\n\t\tcase PixelFormat::eASTC_6x6_SRGB_BLOCK:\n\t\t\treturn \"astc_6x6_srgb\";\n\t\tcase PixelFormat::eASTC_8x5_UNORM_BLOCK:\n\t\t\treturn \"astc_8x5\";\n\t\tcase PixelFormat::eASTC_8x5_SRGB_BLOCK:\n\t\t\treturn \"astc_8x5_srgb\";\n\t\tcase PixelFormat::eASTC_8x6_UNORM_BLOCK:\n\t\t\treturn \"astc_8x6\";\n\t\tcase PixelFormat::eASTC_8x6_SRGB_BLOCK:\n\t\t\treturn \"astc_8x6_srgb\";\n\t\tcase PixelFormat::eASTC_8x8_UNORM_BLOCK:\n\t\t\treturn \"astc_8x8\";\n\t\tcase PixelFormat::eASTC_8x8_SRGB_BLOCK:\n\t\t\treturn \"astc_8x8_srgb\";\n\t\tcase PixelFormat::eASTC_10x5_UNORM_BLOCK:\n\t\t\treturn \"astc_10x5\";\n\t\tcase PixelFormat::eASTC_10x5_SRGB_BLOCK:\n\t\t\treturn \"astc_10x5_srgb\";\n\t\tcase PixelFormat::eASTC_10x6_UNORM_BLOCK:\n\t\t\treturn \"astc_10x6\";\n\t\tcase PixelFormat::eASTC_10x6_SRGB_BLOCK:\n\t\t\treturn \"astc_10x6_srgb\";\n\t\tcase PixelFormat::eASTC_10x8_UNORM_BLOCK:\n\t\t\treturn \"astc_10x8\";\n\t\tcase PixelFormat::eASTC_10x8_SRGB_BLOCK:\n\t\t\treturn \"astc_10x8_srgb\";\n\t\tcase PixelFormat::eASTC_10x10_UNORM_BLOCK:\n\t\t\treturn \"astc_10x10\";\n\t\tcase PixelFormat::eASTC_10x10_SRGB_BLOCK:\n\t\t\treturn \"astc_10x10_srgb\";\n\t\tcase PixelFormat::eASTC_12x10_UNORM_BLOCK:\n\t\t\treturn \"astc_12x10\";\n\t\tcase PixelFormat::eASTC_12x10_SRGB_BLOCK:\n\t\t\treturn \"astc_12x10_srgb\";\n\t\tcase PixelFormat::eASTC_12x12_UNORM_BLOCK:\n\t\t\treturn \"astc_12x12\";\n\t\tcase PixelFormat::eASTC_12x12_SRGB_BLOCK:\n\t\t\treturn \"astc_12x12_srgb\";\n\t\tdefault:\n\t\t\treturn \"undefined\";\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tstd::string_view getName( FilterMode v )\n\t{\n\t\tif ( v == FilterMode::eLinear )\n\t\t\treturn \"linear\";\n\t\treturn \"nearest\";\n\t}\n\n\t//*********************************************************************************************\n\n\tstd::string_view getName( MipmapMode v )\n\t{\n\t\tif ( v == MipmapMode::eLinear )\n\t\t\treturn \"linear\";\n\t\treturn \"nearest\";\n\t}\n\n\t//*********************************************************************************************\n\n\tstd::string_view getName( WrapMode v )\n\t{\n\t\tswitch ( v )\n\t\t{\n\t\tcase WrapMode::eMirroredRepeat:\n\t\t\treturn \"mirrored_repeat\";\n\t\tcase WrapMode::eClampToEdge:\n\t\t\treturn \"clamp_to_edge\";\n\t\tcase WrapMode::eClampToBorder:\n\t\t\treturn \"clamp_to_border\";\n\t\tcase WrapMode::eMirrorClampToEdge:\n\t\t\treturn \"mirrored_clamp_to_edge\";\n\t\tdefault:\n\t\t\treturn \"repeat\";\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tImageCreateFlags getImageCreateFlags( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.flags;\n\t}\n\n\tImageCreateFlags getImageCreateFlags( ImageViewId const & image )noexcept\n\t{\n\t\treturn getImageCreateFlags( image.data->image );\n\t}\n\n\tExtent3D const & getExtent( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.extent;\n\t}\n\n\tExtent3D const & getExtent( ImageViewId const & image )noexcept\n\t{\n\t\treturn getExtent( image.data->image );\n\t}\n\n\tDeviceSize getSize( BufferId const & buffer )noexcept\n\t{\n\t\treturn buffer.data->info.size;\n\t}\n\n\tDeviceSize getSize( BufferViewId const & buffer )noexcept\n\t{\n\t\treturn buffer.data->info.subresourceRange.size;\n\t}\n\n\tExtent3D getMipExtent( ImageViewId const & image )noexcept\n\t{\n\t\tauto result = getExtent( image.data->image );\n\t\tresult.width >>= getSubresourceRange( image ).baseMipLevel;\n\t\tresult.height >>= getSubresourceRange( image ).baseMipLevel;\n\t\tresult.depth >>= getSubresourceRange( image ).baseMipLevel;\n\t\treturn result;\n\t}\n\n\tPixelFormat getFormat( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.format;\n\t}\n\n\tPixelFormat getFormat( ImageViewId const & image )noexcept\n\t{\n\t\treturn image.data->info.format;\n\t}\n\n\tImageType getImageType( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.imageType;\n\t}\n\n\tImageType getImageType( ImageViewId const & image )noexcept\n\t{\n\t\treturn getImageType( image.data->image );\n\t}\n\n\tImageViewType getImageViewType( ImageViewId const & image )noexcept\n\t{\n\t\treturn image.data->info.viewType;\n\t}\n\n\tuint32_t getMipLevels( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.mipLevels;\n\t}\n\n\tuint32_t getMipLevels( ImageViewId const & image )noexcept\n\t{\n\t\treturn getSubresourceRange( image ).levelCount;\n\t}\n\n\tuint32_t getArrayLayers( ImageId const & image )noexcept\n\t{\n\t\treturn image.data->info.arrayLayers;\n\t}\n\n\tuint32_t getArrayLayers( ImageViewId const & image )noexcept\n\t{\n\t\treturn getSubresourceRange( image ).layerCount;\n\t}\n\n\tImageAspectFlags getAspectFlags( ImageViewId const & image )noexcept\n\t{\n\t\treturn getSubresourceRange( image ).aspectMask;\n\t}\n\n\tImageSubresourceRange const & getSubresourceRange( ImageViewId const & image )noexcept\n\t{\n\t\treturn image.data->info.subresourceRange;\n\t}\n\n\tBufferSubresourceRange const & getSubresourceRange( BufferViewId const & buffer )noexcept\n\t{\n\t\treturn buffer.data->info.subresourceRange;\n\t}\n\n\tAccessFlags getAccessMask( ImageLayout layout )noexcept\n\t{\n\t\tAccessFlags result{ 0u };\n\n\t\tswitch ( layout )\n\t\t{\n\t\tcase ImageLayout::ePresentSrc:\n\t\tcase ImageLayout::eSharedPresent:\n\t\t\tresult |= AccessFlags::eMemoryRead;\n\t\t\tbreak;\n\t\tcase ImageLayout::eColorAttachment:\n\t\t\tresult |= AccessFlags::eColorAttachmentWrite;\n\t\t\tbreak;\n\t\tcase ImageLayout::eDepthStencilAttachment:\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentWrite;\n\t\t\tbreak;\n\t\tcase ImageLayout::eDepthStencilReadOnly:\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentRead;\n\t\t\tbreak;\n\t\tcase ImageLayout::eShaderReadOnly:\n\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t\tbreak;\n\t\tcase ImageLayout::eTransferSrc:\n\t\t\tresult |= AccessFlags::eTransferRead;\n\t\t\tbreak;\n\t\tcase ImageLayout::eTransferDst:\n\t\t\tresult |= AccessFlags::eTransferWrite;\n\t\t\tbreak;\n\t\tcase ImageLayout::eDepthReadOnlyStencilAttachment:\n\t\tcase ImageLayout::eDepthAttachmentStencilReadOnly:\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentRead;\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentWrite;\n\t\t\tbreak;\n#ifdef VK_NV_shading_rate_image\n\t\tcase ImageLayout::eFragmentShadingRateAttachment:\n\t\t\tresult |= AccessFlags::eFragmentShadingRateAttachmentRead;\n\t\t\tbreak;\n#endif\n#ifdef VK_EXT_fragment_density_map\n\t\tcase ImageLayout::eFragmentDensityMap:\n\t\t\tresult |= AccessFlags::eFragmentDensityMapRead;\n\t\t\tbreak;\n#endif\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tPipelineState getPipelineState( PipelineStageFlags flags )noexcept\n\t{\n\t\tAccessFlags result{ 0u };\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eBottomOfPipe ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eMemoryRead;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eColorAttachmentOutput ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eColorAttachmentWrite | AccessFlags::eColorAttachmentRead;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eLateFragmentTests ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentWrite;\n\t\t\tresult |= AccessFlags::eDepthStencilAttachmentRead;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eFragmentShader ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eTransfer ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eTransferRead;\n\t\t\tresult |= AccessFlags::eTransferWrite;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eFragmentShadingRateAttachment ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eFragmentShadingRateAttachmentRead;\n\t\t}\n\n\t\tif ( checkFlag( flags, PipelineStageFlags::eComputeShader ) )\n\t\t{\n\t\t\tresult |= AccessFlags::eShaderRead;\n\t\t}\n\n\t\treturn { result, flags };\n\t}\n\n\tLayoutState makeLayoutState( ImageLayout layout )noexcept\n\t{\n\t\treturn { layout\n\t\t\t, getAccessMask( layout )\n\t\t\t, getStageMask( layout ) };\n\t}\n\n\tPipelineStageFlags getStageMask( ImageLayout layout )noexcept\n\t{\n\t\tPipelineStageFlags result{ 0u };\n\n\t\tswitch ( layout )\n\t\t{\n\t\tcase ImageLayout::eUndefined:\n\t\t\tresult |= PipelineStageFlags::eHost;\n\t\t\tbreak;\n\t\tcase ImageLayout::eGeneral:\n\t\t\tresult |= PipelineStageFlags::eBottomOfPipe;\n\t\t\tbreak;\n\t\tcase ImageLayout::ePresentSrc:\n\t\tcase ImageLayout::eSharedPresent:\n\t\t\tresult |= PipelineStageFlags::eBottomOfPipe;\n\t\t\tbreak;\n\t\tcase ImageLayout::eDepthStencilReadOnly:\n\t\tcase ImageLayout::eDepthReadOnlyStencilAttachment:\n\t\tcase ImageLayout::eDepthAttachmentStencilReadOnly:\n\t\tcase ImageLayout::eDepthStencilAttachment:\n\t\t\tresult |= PipelineStageFlags::eLateFragmentTests;\n\t\t\tbreak;\n\t\tcase ImageLayout::eColorAttachment:\n\t\t\tresult |= PipelineStageFlags::eColorAttachmentOutput;\n\t\t\tbreak;\n#ifdef VK_EXT_fragment_density_map\n\t\tcase ImageLayout::eFragmentDensityMap:\n#endif\n\t\tcase ImageLayout::eShaderReadOnly:\n\t\t\tresult |= PipelineStageFlags::eFragmentShader;\n\t\t\tbreak;\n\t\tcase ImageLayout::eTransferSrc:\n\t\tcase ImageLayout::eTransferDst:\n\t\t\tresult |= PipelineStageFlags::eTransfer;\n\t\t\tbreak;\n#ifdef VK_NV_shading_rate_image\n\t\tcase ImageLayout::eFragmentShadingRateAttachment:\n\t\t\tresult |= PipelineStageFlags::eFragmentShadingRateAttachment;\n\t\t\tbreak;\n#endif\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tImageAspectFlags getAspectMask( PixelFormat format )noexcept\n\t{\n\t\tif ( isDepthStencilFormat( format ) )\n\t\t\treturn ImageAspectFlags::eDepth | ImageAspectFlags::eStencil;\n\t\tif ( isDepthFormat( format ) )\n\t\t\treturn ImageAspectFlags::eDepth;\n\t\tif ( isStencilFormat( format ) )\n\t\t\treturn ImageAspectFlags::eStencil;\n\t\treturn ImageAspectFlags::eColor;\n\t}\n\n\tLayoutState const & addSubresourceRangeLayout( LayerLayoutStates & ranges\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & newLayout )\n\t{\n\t\tfor ( uint32_t layerIdx = 0u; layerIdx < range.layerCount; ++layerIdx )\n\t\t{\n\t\t\tauto & layers = ranges.try_emplace( range.baseArrayLayer + layerIdx ).first->second;\n\n\t\t\tfor ( uint32_t levelIdx = 0u; levelIdx < range.levelCount; ++levelIdx )\n\t\t\t{\n\t\t\t\tlayers.insert_or_assign( range.baseMipLevel + levelIdx, newLayout );\n\t\t\t}\n\t\t}\n\n\t\treturn newLayout;\n\t}\n\n\tstatic void gatherSubresourceRangeLayoutMips( ImageSubresourceRange const & range\n\t\t, MipLayoutStates const & layers\n\t\t, std::map< ImageLayout, LayoutState > & states )\n\t{\n\t\tfor ( uint32_t levelIdx = 0u; levelIdx < range.levelCount; ++levelIdx )\n\t\t{\n\t\t\tif ( auto it = layers.find( range.baseMipLevel + levelIdx );\n\t\t\t\tit != layers.end() )\n\t\t\t{\n\t\t\t\tauto state = it->second;\n\t\t\t\tauto [rit, res] = states.emplace( state.layout, state );\n\n\t\t\t\tif ( !res )\n\t\t\t\t{\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wnull-dereference\"\n\t\t\t\t\trit->second.state.access |= state.state.access;\n#pragma GCC diagnostic pop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLayoutState getSubresourceRangeLayout( LayerLayoutStates const & ranges\n\t\t, ImageSubresourceRange const & range )\n\t{\n\t\tstd::map< ImageLayout, LayoutState > states;\n\n\t\tfor ( uint32_t layerIdx = 0u; layerIdx < range.layerCount; ++layerIdx )\n\t\t{\n\t\t\tif ( auto layerIt = ranges.find( range.baseArrayLayer + layerIdx );\n\t\t\t\tlayerIt != ranges.end() )\n\t\t\t{\n\t\t\t\tauto & layers = layerIt->second;\n\t\t\t\tgatherSubresourceRangeLayoutMips( range, layers, states );\n\t\t\t}\n\t\t}\n\n\t\tif ( states.empty() )\n\t\t{\n\t\t\treturn { ImageLayout::eUndefined\n\t\t\t\t, getAccessMask( ImageLayout::eUndefined )\n\t\t\t\t, getStageMask( ImageLayout::eUndefined ) };\n\t\t}\n\n\t\treturn states.begin()->second;\n\t}\n\n\tImageSubresourceRange getVirtualRange( ImageId const & image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range )noexcept\n\t{\n\t\tImageSubresourceRange result = range;\n\n\t\tif ( viewType == ImageViewType::e3D\n\t\t\t&& ( range.levelCount == 1u\n\t\t\t\t|| range.levelCount == image.data->info.mipLevels ) )\n\t\t{\n\t\t\tresult.baseArrayLayer = 0u;\n\t\t\tresult.layerCount = getExtent( image ).depth >> range.baseMipLevel;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool match( ImageViewId const & lhs, ImageViewId const & rhs )noexcept\n\t{\n\t\treturn fgph::match( *lhs.data, *rhs.data );\n\t}\n\n\tbool match( BufferViewId const & lhs, BufferViewId const & rhs )noexcept\n\t{\n\t\treturn lhs == rhs;\n\t}\n\n\tImageViewId const & resolveView( ImageViewId const & view\n\t\t, uint32_t passIndex )\n\t{\n\t\treturn view.data->source.empty()\n\t\t\t? view\n\t\t\t: view.data->source[passIndex];\n\t}\n\n\tBufferViewId const & resolveView( BufferViewId const & view\n\t\t, uint32_t passIndex )\n\t{\n\t\treturn view.data->source.empty()\n\t\t\t? view\n\t\t\t: view.data->source[passIndex];\n\t}\n\n\tClearColorValue getClearColorValue( ClearValue const & v )\n\t{\n\t\tif ( v.isColor() )\n\t\t\treturn v.color();\n\t\tstatic ClearColorValue dummy{};\n\t\treturn dummy;\n\t}\n\n\tClearDepthStencilValue getClearDepthStencilValue( ClearValue const & v )\n\t{\n\t\tif ( v.isDepthStencil() )\n\t\t\treturn v.depthStencil();\n\t\tstatic ClearDepthStencilValue dummy{};\n\t\treturn dummy;\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/FramePass.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/FramePass.hpp\"\n\n#include \"RenderGraph/FrameGraph.hpp\"\n#include \"RenderGraph/RunnablePass.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tinline uint32_t constexpr ImplicitOffset = 1024U;\n\tinline uint32_t constexpr TransferOffset = 4096U;\n\n\tnamespace fpass\n\t{\n\t\tstatic std::string adjustName( FramePass const & pass\n\t\t\t, std::string const & dataName )\n\t\t{\n\t\t\tauto result = pass.getGroupName() + \"/\" + dataName;\n\t\t\tuint32_t index = 0u;\n\n\t\t\twhile ( result[index] == '/' )\n\t\t\t{\n\t\t\t\t++index;\n\t\t\t}\n\n\t\t\treturn result.substr( index );\n\t\t}\n\t}\n\n\tFramePass::FramePass( FramePassGroup const & group\n\t\t, FrameGraph & graph\n\t\t, uint32_t id\n\t\t, std::string const & name\n\t\t, RunnablePassCreator runnableCreator )\n\t\t: m_group{ group }\n\t\t, m_graph{ graph }\n\t\t, m_id{ id }\n\t\t, m_runnableCreator{ std::move( runnableCreator ) }\n\t\t, m_name{ name }\n\t{\n\t}\n\n\tAttachment const * FramePass::getParentAttachment( Attachment const & attach )const\n\t{\n\t\tauto it = m_ownAttaches.find( &attach );\n\t\treturn it != m_ownAttaches.end()\n\t\t\t? it->second.parent\n\t\t\t: nullptr;\n\t}\n\n\tvoid FramePass::addInputUniformBuffer( BufferViewIdArray buffers\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, buffers.front().data->name ) + \"/UB\";\n\t\tauto attach = addOwnAttach( std::move( buffers )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Uniform )\n\t\t\t, AccessState{}\n\t\t\t, nullptr );\n\t\tm_uniforms.try_emplace( binding, attach );\n\t}\n\n\tvoid FramePass::addInputSampledImage( ImageViewIdArray views\n\t\t, uint32_t binding\n\t\t, SamplerDesc samplerDesc )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/Spl\";\n\t\tauto attach = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Sampled )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eShaderReadOnly\n\t\t\t, nullptr );\n\t\tm_sampled.try_emplace( binding, attach, std::move( samplerDesc ) );\n\t}\n\n\tvoid FramePass::addInputUniform( Attachment const & attachment\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/UB\";\n\t\tauto attach = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Uniform )\n\t\t\t, AccessState{}\n\t\t\t, &attachment );\n\t\tm_uniforms.try_emplace( binding, attach );\n\t}\n\n\tvoid FramePass::addInputSampled( Attachment const & attachment\n\t\t, uint32_t binding\n\t\t, SamplerDesc samplerDesc )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view( 0 ).data->name ) + \"/Spl\";\n\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Sampled )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eShaderReadOnly\n\t\t\t, &attachment );\n\t\tm_sampled.try_emplace( binding, attach, std::move( samplerDesc ) );\n\t}\n\n\tvoid FramePass::addInputStorageBuffer( BufferViewIdArray buffers\n\t\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, buffers.front().data->name ) + \"/SB\";\n\t\tauto attach = addOwnAttach( std::move( buffers )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Storage )\n\t\t\t, AccessState{}\n\t\t, nullptr );\n\t\tm_inputs.try_emplace( binding, attach );\n\t}\n\n\tvoid FramePass::addInputStorageImage( ImageViewIdArray views\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/IStr\";\n\t\tauto attach = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Storage )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eGeneral\n\t\t\t, nullptr );\n\t\tm_inputs.try_emplace( binding, attach );\n\t}\n\n\tvoid FramePass::addInputStorage( Attachment const & attachment\n\t\t, uint32_t binding )\n\t{\n\t\tif ( attachment.isImage() )\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IStr\";\n\t\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Storage )\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, ClearValue{}\n\t\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t\t, ImageLayout::eGeneral\n\t\t\t\t, &attachment );\n\t\t\tm_inputs.try_emplace( binding, attach );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/IStr\";\n\t\t\tauto attach = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Storage )\n\t\t\t\t, AccessState{}\n\t\t\t, &attachment );\n\t\t\tm_inputs.try_emplace( binding, attach );\n\t\t}\n\t}\n\n\tAttachment const * FramePass::addInOutStorage( Attachment const & attachment\n\t\t, uint32_t binding )\n\t{\n\t\tAttachment const * result{};\n\n\t\tif ( attachment.isImage() )\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IOStr\";\n\t\t\tresult = addOwnAttach( attachment.imageAttach.views\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Storage )\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, ClearValue{}\n\t\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t\t, ImageLayout::eGeneral\n\t\t\t\t, &attachment );\n\t\t\tm_inouts.try_emplace( binding, result );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/IOStr\";\n\t\t\tresult = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Storage )\n\t\t\t\t, AccessState{}\n\t\t\t, &attachment );\n\t\t\tm_inouts.try_emplace( binding, result );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputStorageBuffer( BufferViewIdArray buffers\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, buffers.front().data->name ) + \"/OSB\";\n\t\tauto result = addOwnAttach( std::move( buffers )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Storage )\n\t\t\t, AccessState{}\n\t\t, nullptr );\n\t\tm_outputs.try_emplace( binding, result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addClearableOutputStorageBuffer( BufferViewIdArray buffers\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, buffers.front().data->name ) + \"/OSB\";\n\t\tauto result = addOwnAttach( std::move( buffers )\n\t\t\t, std::move( attachName )\n\t\t\t, ( Attachment::FlagKind( Attachment::Flag::Output ) | Attachment::FlagKind( Attachment::Flag::Clearable ) )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Storage )\n\t\t\t, AccessState{}\n\t\t, nullptr );\n\t\tm_outputs.try_emplace( binding, result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputStorageImage( ImageViewIdArray views\n\t\t, uint32_t binding )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/OStr\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Storage )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eGeneral\n\t\t\t, nullptr );\n\t\tm_outputs.try_emplace( binding, result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addClearableOutputStorageImage( ImageViewIdArray views\n\t\t, uint32_t binding\n\t\t, ClearValue clearValue )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/COStr\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, ( Attachment::FlagKind( Attachment::Flag::Output ) | Attachment::FlagKind( Attachment::Flag::Clearable ) )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Storage )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, std::move( clearValue )\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eGeneral\n\t\t\t, nullptr );\n\t\tm_outputs.try_emplace( binding, result );\n\t\treturn result;\n\t}\n\n\tvoid FramePass::addInputTransferBuffer( BufferViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ITrf\";\n\t\tauto attach = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer )\n\t\t\t, AccessState{}\n\t\t\t, nullptr );\n\t\tm_inputs.try_emplace( TransferOffset + uint32_t( m_inputs.size() ), attach );\n\t}\n\n\tvoid FramePass::addInputTransferImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ITrf\";\n\t\tauto attach = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eTransferSrc\n\t\t\t, nullptr );\n\t\tm_inputs.try_emplace( TransferOffset + uint32_t( m_inputs.size() ), attach );\n\t}\n\n\tvoid FramePass::addInputTransfer( Attachment const & attachment )\n\t{\n\t\tif ( attachment.isImage() )\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/ITrf\";\n\t\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer )\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, ClearValue{}\n\t\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t\t, ImageLayout::eTransferSrc\n\t\t\t\t, & attachment );\n\t\t\tm_inputs.try_emplace( TransferOffset + uint32_t( m_inputs.size() ), attach );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/ITrf\";\n\t\t\tauto attach = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer )\n\t\t\t\t, AccessState{}\n\t\t\t\t, &attachment );\n\t\t\tm_inputs.try_emplace( TransferOffset + uint32_t( m_inputs.size() ), attach );\n\t\t}\n\t}\n\n\tAttachment const * FramePass::addInOutTransfer( Attachment const & attachment\n\t\t\t, Attachment::Flag flag )\n\t{\n\t\tAttachment const * result{};\n\n\t\tif ( attachment.isImage() )\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IOTrf\";\n\t\t\tresult = addOwnAttach( attachment.imageAttach.views\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) )\n\t\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer )\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t\t, ClearValue{}\n\t\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t\t, ImageLayout::eTransferSrc\n\t\t\t\t, &attachment );\n\t\t\tm_inouts.try_emplace( TransferOffset + uint32_t( m_inouts.size() ), result );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/IOTrf\";\n\t\t\tresult = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t\t, std::move( attachName )\n\t\t\t\t, Attachment::FlagKind( Attachment::FlagKind( Attachment::Flag::InOut ) | Attachment::FlagKind( flag ) )\n\t\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer )\n\t\t\t\t, AccessState{}\n\t\t\t, &attachment );\n\t\t\tm_inouts.try_emplace( TransferOffset + uint32_t( m_inouts.size() ), result );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputTransferBuffer( BufferViewIdArray buffers )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, buffers.front().data->name ) + \"/OTB\";\n\t\tauto result = addOwnAttach( std::move( buffers )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::Flag::Transfer )\n\t\t\t, AccessState{}\n\t\t, nullptr );\n\t\tm_outputs.try_emplace( TransferOffset + uint32_t( m_outputs.size() ), result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputTransferImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/OT\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Transfer )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eTransferDst\n\t\t\t, nullptr );\n\t\tm_outputs.try_emplace( TransferOffset + uint32_t( m_outputs.size() ), result );\n\t\treturn result;\n\t}\n\n\tvoid FramePass::addInputColourTargetImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/IRcl\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::None )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearColorValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eColorAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace_back( result );\n\t}\n\n\tvoid FramePass::addInputDepthTargetImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/IRdp\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Depth )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace_back( result );\n\t}\n\n\tvoid FramePass::addInputStencilTargetImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/IRst\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace_back( result );\n\t}\n\n\tvoid FramePass::addInputDepthStencilTargetImage( ImageViewIdArray views )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/IRds\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace_back( result );\n\t}\n\n\tvoid FramePass::addInputColourTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IRcl\";\n\t\tauto result = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::None )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearColorValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eColorAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( result );\n\t}\n\n\tvoid FramePass::addInputDepthTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IRdp\";\n\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Depth )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( attach );\n\t}\n\n\tvoid FramePass::addInputStencilTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IRst\";\n\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( attach );\n\t}\n\n\tvoid FramePass::addInputDepthStencilTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IRds\";\n\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( attach );\n\t}\n\n\tAttachment const * FramePass::addInOutColourTarget( Attachment const & attachment\n\t\t, PipelineColorBlendAttachmentState blendState )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IORcl\";\n\t\tauto result = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::None )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearColorValue{} }\n\t\t\t, std::move( blendState )\n\t\t\t, ImageLayout::eColorAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addInOutDepthTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IORdp\";\n\t\tauto result = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Depth )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addInOutStencilTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IORst\";\n\t\tauto result = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addInOutDepthStencilTarget( Attachment const & attachment )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/IORds\";\n\t\tauto result = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::InOut )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::StencilInOut ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil )\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eLoad, AttachmentStoreOp::eStore\n\t\t\t, ClearValue{ ClearDepthStencilValue{} }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, &attachment );\n\t\tm_targets.emplace_back( result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputColourTarget( ImageViewIdArray views\n\t\t, ClearColorValue clearValue )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ORcl\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::None )\n\t\t\t, AttachmentLoadOp::eClear, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ std::move( clearValue ) }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eColorAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace_back( result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputDepthTarget( ImageViewIdArray views\n\t\t, ClearDepthStencilValue clearValue )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ORdp\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::Flag::Depth )\n\t\t\t, AttachmentLoadOp::eClear, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{ std::move( clearValue ) }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace( m_targets.begin(), result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputStencilTarget( ImageViewIdArray views\n\t\t, ClearDepthStencilValue clearValue )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ORst\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::Stencil ) )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eClear, AttachmentStoreOp::eStore\n\t\t\t, ClearValue{ std::move( clearValue ) }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eStencilAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace( m_targets.begin(), result );\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOutputDepthStencilTarget( ImageViewIdArray views\n\t\t, ClearDepthStencilValue clearValue )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, views.front().data->name ) + \"/ORds\";\n\t\tauto result = addOwnAttach( std::move( views )\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Output )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::StencilOutput ) | ImageAttachment::FlagKind( ImageAttachment::Flag::DepthStencil ) )\n\t\t\t, AttachmentLoadOp::eClear, AttachmentStoreOp::eStore\n\t\t\t, AttachmentLoadOp::eClear, AttachmentStoreOp::eStore\n\t\t\t, ClearValue{ std::move( clearValue ) }\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, ImageLayout::eDepthStencilAttachment\n\t\t\t, nullptr );\n\t\tm_targets.emplace( m_targets.begin(), result );\n\t\treturn result;\n\t}\n\n\tvoid FramePass::addImplicit( Attachment const & attachment\n\t\t, AccessState wantedAccess )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.buffer().data->name ) + \"/Impl\";\n\t\tauto attach = addOwnAttach( attachment.bufferAttach.buffers\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, BufferAttachment::FlagKind( BufferAttachment::FlagKind( BufferAttachment::Flag::Transition ) | attachment.bufferAttach.getFormatFlags() )\n\t\t\t, std::move( wantedAccess )\n\t\t\t, &attachment );\n\t\tm_inputs.try_emplace( ImplicitOffset + uint32_t( m_inputs.size() ), attach );\n\t}\n\n\tvoid FramePass::addImplicit( Attachment const & attachment\n\t\t, ImageLayout wantedLayout )\n\t{\n\t\tauto attachName = fpass::adjustName( *this, attachment.view().data->name ) + \"/Impl\";\n\t\tauto attach = addOwnAttach( attachment.imageAttach.views\n\t\t\t, std::move( attachName )\n\t\t\t, Attachment::FlagKind( Attachment::Flag::Input )\n\t\t\t, ImageAttachment::FlagKind( ImageAttachment::FlagKind( ImageAttachment::Flag::Transition ) | attachment.imageAttach.getFormatFlags() )\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, AttachmentLoadOp::eDontCare, AttachmentStoreOp::eDontCare\n\t\t\t, ClearValue{}\n\t\t\t, PipelineColorBlendAttachmentState{}\n\t\t\t, wantedLayout\n\t\t\t, &attachment );\n\t\tm_inputs.try_emplace( ImplicitOffset + uint32_t( m_inputs.size() ), attach );\n\t}\n\n\tRunnablePassPtr FramePass::createRunnable( GraphContext & context\n\t\t, RunnableGraph & pgraph )const\n\t{\n\t\treturn m_runnableCreator( *this, context, pgraph );\n\t}\n\n\tstd::string FramePass::getFullName()const\n\t{\n\t\treturn m_group.getFullName() + \"/\" + getName();\n\t}\n\n\tstd::string FramePass::getGroupName()const\n\t{\n\t\treturn m_group.getName() + \"/\" + getName();\n\t}\n\n\tAttachment const * FramePass::addOwnAttach( ImageViewIdArray views, std::string attachName\n\t\t, Attachment::FlagKind flags, ImageAttachment::FlagKind imageFlags\n\t\t, AttachmentLoadOp loadOp, AttachmentStoreOp storeOp\n\t\t, AttachmentLoadOp stencilLoadOp, AttachmentStoreOp stencilStoreOp\n\t\t, ClearValue clearValue, PipelineColorBlendAttachmentState blendState\n\t\t, ImageLayout wantedLayout\n\t\t, Attachment const * parent )\n\t{\n\t\tif ( views.front().data->source.empty() )\n\t\t\treturn addOwnAttach( new Attachment{ flags\n\t\t\t\t\t, *this, std::move( attachName )\n\t\t\t\t\t, imageFlags\n\t\t\t\t\t, std::move( views )\n\t\t\t\t\t, loadOp, storeOp\n\t\t\t\t\t, stencilLoadOp, stencilStoreOp\n\t\t\t\t\t, std::move( clearValue )\n\t\t\t\t\t, std::move( blendState )\n\t\t\t\t\t, wantedLayout\n\t\t\t\t\t, Attachment::Token{} }\n\t\t\t\t, parent );\n\n\t\t// Dispatch merged views sources in source attachs views\n\t\tstd::vector< ImageViewIdArray > sourceAttachsViews;\n\t\tsourceAttachsViews.resize( views.front().data->source.size() );\n\t\tfor ( auto view : views )\n\t\t{\n\t\t\tfor ( uint32_t i = 0u; i < view.data->source.size(); ++i )\n\t\t\t\tsourceAttachsViews[i].push_back( view.data->source[i] );\n\t\t}\n\n\t\t// Use these views to create attachs\n\t\tuint32_t index{};\n\t\tstd::vector< AttachmentPtr > sources;\n\t\tfor ( auto & sourceViews : sourceAttachsViews )\n\t\t{\n\t\t\tsources.push_back( std::make_unique< Attachment >( flags\n\t\t\t\t, *this, attachName + std::to_string( index )\n\t\t\t\t, imageFlags\n\t\t\t\t, std::move( sourceViews )\n\t\t\t\t, loadOp, storeOp\n\t\t\t\t, stencilLoadOp, stencilStoreOp\n\t\t\t\t, clearValue, blendState\n\t\t\t\t, wantedLayout\n\t\t\t\t, Attachment::Token{} ) );\n\t\t\t++index;\n\t\t}\n\n\t\t// Create the resulting attach\n\t\tauto result = addOwnAttach( new Attachment{ flags\n\t\t\t\t, *this, std::move( attachName )\n\t\t\t\t, imageFlags\n\t\t\t\t, std::move( views )\n\t\t\t\t, loadOp, storeOp\n\t\t\t\t, stencilLoadOp, stencilStoreOp\n\t\t\t\t, std::move( clearValue )\n\t\t\t\t, std::move( blendState )\n\t\t\t\t, wantedLayout\n\t\t\t\t, Attachment::Token{} }\n\t\t\t, parent );\n\t\tresult->pass = nullptr;\n\n\t\t// And set its sources\n\t\tif ( !parent || parent->source.empty() )\n\t\t{\n\t\t\tfor ( auto & sourceAttach : sources )\n\t\t\t\tresult->source.emplace_back( std::move( sourceAttach ) );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If parent has sources, link the new attachment sources to the parent ones\n\t\t\tassert( parent->source.size() == sources.size() );\n\t\t\tfor ( uint32_t i = 0; i < sources.size(); ++i )\n\t\t\t{\n\t\t\t\tauto source = addOwnAttach( sources[i].release()\n\t\t\t\t\t, ( parent->source[i].parent\n\t\t\t\t\t\t? parent->source[i].parent\n\t\t\t\t\t\t: parent->source[i].attach.get() ) );\n\t\t\t\tresult->source.emplace_back( parent->source[i].attach.get(), source->pass, source->imageAttach );\n\t\t\t}\n\n\t\t\tresult->initSources();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tAttachment const * FramePass::addOwnAttach( BufferViewIdArray views, std::string attachName\n\t\t, Attachment::FlagKind flags, BufferAttachment::FlagKind bufferFlags\n\t\t, AccessState access\n\t\t, Attachment const * parent )\n\t{\n\t\tif ( views.front().data->source.empty() )\n\t\t\treturn addOwnAttach( new Attachment{ flags\n\t\t\t\t\t, *this, std::move( attachName )\n\t\t\t\t\t, bufferFlags\n\t\t\t\t\t, std::move( views )\n\t\t\t\t\t, std::move( access )\n\t\t\t\t\t, Attachment::Token{} }\n\t\t\t\t, parent );\n\n\t\t// Dispatch merged views sources in source attachs views\n\t\tstd::vector< BufferViewIdArray > sourceAttachsViews;\n\t\tsourceAttachsViews.resize( views.front().data->source.size() );\n\t\tfor ( auto view : views )\n\t\t{\n\t\t\tfor ( uint32_t i = 0u; i < view.data->source.size(); ++i )\n\t\t\t\tsourceAttachsViews[i].push_back( view.data->source[i] );\n\t\t}\n\n\t\t// Use these views to create attachs\n\t\tuint32_t index{};\n\t\tstd::vector< AttachmentPtr > sources;\n\t\tfor ( auto & sourceViews : sourceAttachsViews )\n\t\t{\n\t\t\tsources.push_back( std::make_unique< Attachment >( flags\n\t\t\t\t, *this, attachName + std::to_string( index )\n\t\t\t\t, bufferFlags\n\t\t\t\t, std::move( sourceViews )\n\t\t\t\t, access\n\t\t\t\t, Attachment::Token{} ) );\n\t\t\t++index;\n\t\t}\n\n\t\t// Create the resulting attach\n\t\tauto result = addOwnAttach( new Attachment{ flags\n\t\t\t\t, *this, std::move( attachName )\n\t\t\t\t, bufferFlags\n\t\t\t\t, std::move( views )\n\t\t\t\t, std::move( access )\n\t\t\t\t, Attachment::Token{} }\n\t\t\t, parent );\n\t\tresult->pass = nullptr;\n\n\t\t// And set its sources\n\t\tif ( !parent || parent->source.empty() )\n\t\t{\n\t\t\tfor ( auto & sourceAttach : sources )\n\t\t\t\tresult->source.emplace_back( std::move( sourceAttach ) );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If parent has sources, link the new attachment sources to the parent ones\n\t\t\tassert( parent->source.size() == sources.size() );\n\t\t\tfor ( uint32_t i = 0; i < sources.size(); ++i )\n\t\t\t{\n\t\t\t\tauto source = addOwnAttach( sources[i].release()\n\t\t\t\t\t, ( parent->source[i].parent\n\t\t\t\t\t\t? parent->source[i].parent\n\t\t\t\t\t\t: parent->source[i].attach.get() ) );\n\t\t\t\tresult->source.emplace_back( parent->source[i].attach.get(), source->pass, source->bufferAttach );\n\t\t\t}\n\n\t\t\tresult->initSources();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tAttachment * FramePass::addOwnAttach( Attachment * mine\n\t\t, Attachment const * parent )\n\t{\n\t\tauto & own = m_ownAttaches.try_emplace( mine ).first->second;\n\t\town.mine.reset( mine );\n\t\town.parent = parent;\n\t\treturn mine;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/FramePassGroup.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/FramePassGroup.hpp\"\n\n#include \"RenderGraph/Exception.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/FrameGraph.hpp\"\n\n#include <numeric>\n#include <array>\n\nnamespace crg\n{\n\tnamespace group\n\t{\n\t\tstatic FramePassGroup const * getOutermost( FramePassGroup const * group )\n\t\t{\n\t\t\twhile ( group && group->getParent() )\n\t\t\t\tgroup = group->getParent();\n\t\t\treturn group;\n\t\t}\n\n\t\tstatic uint32_t countPasses( FramePassGroup const * group )\n\t\t{\n\t\t\treturn std::accumulate( group->getGroups().begin()\n\t\t\t\t, group->getGroups().end()\n\t\t\t\t, uint32_t( group->getPasses().size() )\n\t\t\t\t, []( uint32_t val, FramePassGroupPtr const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn val + countPasses( lookup.get() );\n\t\t\t\t} );\n\t\t}\n\n\t\tstatic uint32_t countGroups( FramePassGroup const * group )\n\t\t{\n\t\t\treturn std::accumulate( group->getGroups().begin()\n\t\t\t\t, group->getGroups().end()\n\t\t\t\t, uint32_t( group->getGroups().size() )\n\t\t\t\t, []( uint32_t val, FramePassGroupPtr const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn val + countGroups( lookup.get() );\n\t\t\t\t} );\n\t\t}\n\t}\n\n\tFramePassGroup::FramePassGroup( FrameGraph & graph\n\t\t, uint32_t pid\n\t\t, std::string const & name\n\t\t, Token )\n\t\t: m_id{ pid }\n\t\t, m_name{ name }\n\t\t, m_graph{ graph }\n\t{\n\t}\n\n\tFramePassGroup::FramePassGroup( FramePassGroup & pparent\n\t\t, uint32_t pid\n\t\t, std::string const & name\n\t\t, Token )\n\t\t: m_id{ pid }\n\t\t, m_parent{ &pparent }\n\t\t, m_name{ name }\n\t\t, m_graph{ m_parent->m_graph }\n\t{\n\t}\n\n\tFramePass & FramePassGroup::createPass( std::string const & passName\n\t\t, RunnablePassCreator runnableCreator )\n\t{\n\t\tif ( hasPass( passName ) )\n\t\t{\n\t\t\tLogger::logWarning( \"Duplicate FramePass name detected.\" );\n\t\t\tCRG_Exception( \"Duplicate FramePass name detected.\" );\n\t\t}\n\n\t\tauto count = group::countPasses( group::getOutermost( this ) );\n\t\tm_passes.emplace_back( new FramePass{ *this\n\t\t\t, m_graph\n\t\t\t, count + 1u\n\t\t\t, passName\n\t\t\t, std::move( runnableCreator ) } );\n\t\treturn *m_passes.back();\n\t}\n\n\tFramePassGroup & FramePassGroup::createPassGroup( std::string const & groupName )\n\t{\n\t\tauto it = std::find_if( m_groups.begin()\n\t\t\t, m_groups.end()\n\t\t\t, [&groupName]( FramePassGroupPtr const & lookup )\n\t\t\t{\n\t\t\t\treturn lookup->getName() == groupName;\n\t\t\t} );\n\n\t\tif ( it == m_groups.end() )\n\t\t{\n\t\t\tauto count = group::countGroups( group::getOutermost( this ) );\n\t\t\tm_groups.emplace_back( std::make_unique< FramePassGroup >( *this, count + 1u, groupName, Token{} ) );\n\t\t\tit = std::next( m_groups.begin(), ptrdiff_t( m_groups.size() - 1u ) );\n\t\t}\n\n\t\treturn **it;\n\t}\n\n\tbool FramePassGroup::hasPass( std::string const & passName )const\n\t{\n\t\treturn m_passes.end() != std::find_if( m_passes.begin()\n\t\t\t, m_passes.end()\n\t\t\t, [&passName]( FramePassPtr const & lookup )\n\t\t\t{\n\t\t\t\treturn lookup->getName() == passName;\n\t\t\t} );\n\t}\n\n\tvoid FramePassGroup::listPasses( FramePassArray & result )const\n\t{\n\t\tfor ( auto & pass : m_passes )\n\t\t{\n\t\t\tresult.push_back( pass.get() );\n\t\t}\n\n\t\tfor ( auto & group : m_groups )\n\t\t{\n\t\t\tgroup->listPasses( result );\n\t\t}\n\t}\n\n\tvoid FramePassGroup::addGroupInput( ImageViewId view )\n\t{\n\t\tm_inputs.emplace( view.id );\n\t}\n\n\tvoid FramePassGroup::addGroupOutput( ImageViewId view )\n\t{\n\t\tm_outputs.emplace( view.id );\n\t}\n\n\tLayoutState FramePassGroup::getFinalLayoutState( ImageViewId view\n\t\t, uint32_t passIndex )const\n\t{\n\t\treturn m_graph.getFinalLayoutState( view, passIndex );\n\t}\n\n\tBufferId FramePassGroup::createBuffer( BufferData const & img )const\n\t{\n\t\treturn m_graph.createBuffer( img );\n\t}\n\n\tBufferViewId FramePassGroup::createView( BufferViewData const & view )const\n\t{\n\t\treturn m_graph.createView( view );\n\t}\n\n\tImageId FramePassGroup::createImage( ImageData const & img )const\n\t{\n\t\treturn m_graph.createImage( img );\n\t}\n\n\tImageViewId FramePassGroup::createView( ImageViewData const & view )const\n\t{\n\t\treturn m_graph.createView( view );\n\t}\n\n\tvoid FramePassGroup::addInput( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\tm_graph.addInput( image\n\t\t\t, viewType\n\t\t\t, range\n\t\t\t, outputLayout );\n\t}\n\n\tvoid FramePassGroup::addInput( ImageViewId view\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\taddInput( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, view.data->info.subresourceRange\n\t\t\t, outputLayout );\n\t}\n\n\tvoid FramePassGroup::addOutput( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & range\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\tm_graph.addOutput( image\n\t\t\t, viewType\n\t\t\t, range\n\t\t\t, outputLayout );\n\t}\n\n\tvoid FramePassGroup::addOutput( ImageViewId view\n\t\t, LayoutState const & outputLayout )\n\t{\n\t\taddOutput( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, view.data->info.subresourceRange\n\t\t\t, outputLayout );\n\t}\n\n\tstd::string FramePassGroup::getFullName()const\n\t{\n\t\treturn ( &m_graph.getDefaultGroup() == this )\n\t\t\t? m_graph.getName()\n\t\t\t: m_parent->getFullName() + \"/\" + getName();\n\t}\n\n\tImageViewId FramePassGroup::mergeViews( ImageViewIdArray const & views\n\t\t, bool mergeMipLevels\n\t\t, bool mergeArrayLayers )\n\t{\n\t\treturn m_graph.mergeViews( views\n\t\t\t, mergeMipLevels\n\t\t\t, mergeArrayLayers );\n\t}\n\n\tBufferViewId FramePassGroup::mergeViews( BufferViewIdArray const & views )\n\t{\n\t\treturn m_graph.mergeViews( views );\n\t}\n\n\tAttachment const * FramePassGroup::mergeAttachments( AttachmentArray const & attachments\n\t\t, bool mergeMipLevels\n\t\t, bool mergeArrayLayers )\n\t{\n\t\treturn m_graph.mergeAttachments( attachments\n\t\t\t, mergeMipLevels\n\t\t\t, mergeArrayLayers );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/FramePassTimer.cpp",
    "content": "#include \"RenderGraph/FramePassTimer.hpp\"\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/Log.hpp\"\n\n#include <cassert>\n\nnamespace crg\n{\n\tusing namespace std::literals::chrono_literals;\n\n\t//*********************************************************************************************\n\n\tFramePassTimerBlock::FramePassTimerBlock( FramePassTimer & timer )\n\t\t: m_timer{ &timer }\n\t{\n\t}\n\n\tFramePassTimerBlock::FramePassTimerBlock( FramePassTimerBlock && block )noexcept\n\t\t: m_timer{ block.m_timer }\n\t{\n\t\tblock.m_timer = {};\n\t}\n\n\tFramePassTimerBlock::~FramePassTimerBlock()noexcept\n\t{\n\t\tif ( m_timer )\n\t\t{\n\t\t\tm_timer->stop();\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tFramePassTimer::FramePassTimer( GraphContext & context\n\t\t, std::string const & name\n\t\t, TimerScope scope\n\t\t, VkQueryPool timerQueries\n\t\t, uint32_t & baseQueryOffset )\n\t\t: m_context{ context }\n\t\t, m_scope{ scope }\n\t\t, m_name{ name }\n\t\t, m_colour{ context.getNextRainbowColour() }\n\t\t, m_timerQueries{ timerQueries }\n\t\t, m_queries{ { { baseQueryOffset, false, false }, { baseQueryOffset + 2u, false, false } } }\n\t{\n\t\tbaseQueryOffset += 4u;\n\t}\n\n\tFramePassTimer::FramePassTimer( GraphContext & context\n\t\t, std::string const & name\n\t\t, TimerScope scope )\n\t\t: m_context{ context }\n\t\t, m_scope{ scope }\n\t\t, m_name{ name }\n\t\t, m_colour{ context.getNextRainbowColour() }\n\t\t, m_timerQueries{ createQueryPool( context, name, 4u ) }\n\t\t, m_ownPool{ true }\n\t\t, m_queries{ { { 0u, false, false }, { 2u, false, false } } }\n\t{\n\t}\n\n\tFramePassTimer::~FramePassTimer()noexcept\n\t{\n\t\ttry\n\t\t{\n\t\t\tonDestroy( *this );\n\n\t\t\tif ( m_ownPool && m_timerQueries )\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( m_context, m_timerQueries );\n\t\t\t\tm_context.vkDestroyQueryPool( m_context.device\n\t\t\t\t\t, m_timerQueries\n\t\t\t\t\t, m_context.allocator );\n\t\t\t}\n\t\t}\n\t\tcatch ( ... )\n\t\t{\n\t\t\t// Nothing to do here\n\t\t}\n\t}\n\n\tFramePassTimerBlock FramePassTimer::start()\n\t{\n\t\tm_cpuSaveTime = Clock::now();\n\t\treturn FramePassTimerBlock{ *this };\n\t}\n\n\tvoid FramePassTimer::notifyPassRender( [[maybe_unused]] uint32_t passIndex )noexcept\n\t{\n\t\tauto & query = m_queries.front();\n\t\tquery.started = true;\n\t}\n\n\tvoid FramePassTimer::stop()noexcept\n\t{\n\t\tauto current = Clock::now();\n\t\tm_cpuTime += ( current - m_cpuSaveTime );\n\t}\n\n\tvoid FramePassTimer::reset()noexcept\n\t{\n\t\tm_cpuTime = 0ns;\n\t\tm_gpuTime = 0ns;\n\t}\n\n\tvoid FramePassTimer::beginPass( VkCommandBuffer commandBuffer\n\t\t, std::string const & groupName\n\t\t, uint32_t passId )noexcept\n\t{\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wrestrict\"\n\t\tm_context.vkCmdBeginDebugBlock( commandBuffer\n\t\t\t, { \"[\" + std::to_string( passId ) + \"] \" + groupName\n\t\t\t, m_colour } );\n#pragma GCC diagnostic pop\n\t\tstd::swap( m_queries.front(), m_queries.back() );\n\t\tauto const & query = m_queries.front();\n\t\tm_context.vkCmdResetQueryPool( commandBuffer\n\t\t\t, m_timerQueries\n\t\t\t, query.offset\n\t\t\t, 2u );\n\t\tm_context.vkCmdWriteTimestamp( commandBuffer\n\t\t\t, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT\n\t\t\t, m_timerQueries\n\t\t\t, query.offset + 0u );\n\t}\n\n\tvoid FramePassTimer::endPass( VkCommandBuffer commandBuffer )noexcept\n\t{\n\t\tauto & query = m_queries.front();\n\t\tm_context.vkCmdWriteTimestamp( commandBuffer\n\t\t\t, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT\n\t\t\t, m_timerQueries\n\t\t\t, query.offset + 1u );\n\t\tquery.written = true;\n\t\tm_context.vkCmdEndDebugBlock( commandBuffer );\n\t}\n\n\tvoid FramePassTimer::retrieveGpuTime()noexcept\n\t{\n\t\tstatic float const period = m_context.properties.limits.timestampPeriod;\n\n\t\tauto before = Clock::now();\n\t\tm_gpuTime = 0ns;\n\n\t\tif ( auto & query = m_queries.front(); query.started && query.written )\n\t\t{\n\t\t\tstd::array< uint64_t, 2u > values{ 0u, 0u };\n\t\t\tm_context.vkGetQueryPoolResults( m_context.device\n\t\t\t\t, m_timerQueries\n\t\t\t\t, query.offset\n\t\t\t\t, 2u\n\t\t\t\t, sizeof( uint64_t ) * values.size()\n\t\t\t\t, values.data()\n\t\t\t\t, sizeof( uint64_t )\n\t\t\t\t, VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT );\n\n\t\t\tauto gpuTime = Nanoseconds{ uint64_t( float( values[1] - values[0] ) / period ) };\n\t\t\tm_gpuTime += gpuTime;\n\n\t\t\tquery.started = false;\n\t\t\tquery.written = false;\n\t\t}\n\n\t\tauto after = Clock::now();\n\t\tm_cpuTime += ( after - before );\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/GraphBuilder.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"GraphBuilder.hpp\"\n\n#include \"RenderGraph/FramePass.hpp\"\n#include \"RenderGraph/GraphNode.hpp\"\n#include \"RenderGraph/Log.hpp\"\n\n#include <algorithm>\n\nnamespace crg::builder\n{\n\t//*********************************************************************************************\n\n\tnamespace endpoints\n\t{\n\t\tstatic void addAttach( Attachment const & attach\n\t\t\t, AttachmentArray & result )\n\t\t{\n\t\t\tif ( attach.source.empty() )\n\t\t\t\tresult.push_back( &attach );\n\t\t\tfor ( auto & source : attach.source )\n\t\t\t\tresult.push_back( source.attach.get() );\n\t\t}\n\n\t\tstatic void listAllAttachs( FramePassArray const & passes\n\t\t\t, AttachmentArray & result )\n\t\t{\n\t\t\tfor ( auto pass : passes )\n\t\t\t{\n\t\t\t\tfor ( auto & [binding, attach] : pass->getInouts() )\n\t\t\t\t\taddAttach( *attach, result );\n\t\t\t\tfor ( auto & [binding, attach] : pass->getOutputs() )\n\t\t\t\t\taddAttach( *attach, result );\n\t\t\t\tfor ( auto & attach : pass->getTargets() )\n\t\t\t\t\tif ( attach->isOutput() )\n\t\t\t\t\t\taddAttach( *attach, result );\n\t\t\t}\n\t\t}\n\n\t\tstatic void listBuffersRec( Attachment const & attach\n\t\t\t, FramePass const * pass\n\t\t\t, BufferViewIdArray & result )\n\t\t{\n\t\t\tif ( attach.source.empty() && ( !pass || attach.pass == pass ) )\n\t\t\t\tfor ( auto & view : attach.bufferAttach.buffers )\n\t\t\t\t\tresult.push_back( view );\n\n\t\t\tfor ( auto const & source : attach.source )\n\t\t\t\tlistBuffersRec( *source.attach, pass, result );\n\t\t}\n\n\t\tstatic BufferViewIdArray listBuffers( Attachment const & attach\n\t\t\t, FramePass const * pass )\n\t\t{\n\t\t\tBufferViewIdArray result;\n\t\t\tlistBuffersRec( attach, pass, result );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void listImagesRec( Attachment const & attach\n\t\t\t, FramePass const * pass\n\t\t\t, ImageViewIdArray & result )\n\t\t{\n\t\t\tif ( attach.source.empty() && ( !pass || attach.pass == pass ) )\n\t\t\t\tfor ( auto & view : attach.imageAttach.views )\n\t\t\t\t\tresult.push_back( view );\n\n\t\t\tfor ( auto const & source : attach.source )\n\t\t\t\tlistImagesRec( *source.attach, pass, result );\n\t\t}\n\n\t\tstatic ImageViewIdArray listImages( Attachment const & attach\n\t\t\t, FramePass const * pass )\n\t\t{\n\t\t\tImageViewIdArray result;\n\t\t\tlistImagesRec( attach, pass, result );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic bool isBufferAttachParent( Attachment const & parent, Attachment const & attach )\n\t\t{\n\t\t\tauto parentBuffers = listBuffers( parent, attach.pass );\n\t\t\tauto attachBuffers = listBuffers( attach, nullptr );\n\t\t\treturn std::any_of( attachBuffers.begin(), attachBuffers.end()\n\t\t\t\t, [&parentBuffers]( BufferViewId const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn parentBuffers.end() != std::find( parentBuffers.begin(), parentBuffers.end(), lookup );\n\t\t\t\t} );\n\t\t}\n\n\t\tstatic bool isImageAttachParent( Attachment const & parent, Attachment const & attach )\n\t\t{\n\t\t\tauto parentBuffers = listImages( parent, attach.pass );\n\t\t\tauto attachBuffers = listImages( attach, nullptr );\n\t\t\treturn std::any_of( attachBuffers.begin(), attachBuffers.end()\n\t\t\t\t, [&parentBuffers]( ImageViewId const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn parentBuffers.end() != std::find( parentBuffers.begin(), parentBuffers.end(), lookup );\n\t\t\t\t} );\n\t\t}\n\n\t\tstatic bool isAttachParent( Attachment const * parent, Attachment const * attach )\n\t\t{\n\t\t\tif ( bool result = ( parent == attach );\n\t\t\t\tresult || !parent )\n\t\t\t\treturn result;\n\n\t\t\tif ( attach->isBuffer() != parent->isBuffer() )\n\t\t\t\treturn false;\n\n\t\t\tif ( attach->isBuffer() )\n\t\t\t\treturn isBufferAttachParent( *parent, *attach );\n\n\t\t\treturn isImageAttachParent( *parent, *attach );\n\t\t}\n\n\t\tstatic bool isParentAttachForPass( Attachment const * attach, FramePass const * pass )\n\t\t{\n\t\t\treturn pass->end() != std::find_if( pass->begin(), pass->end()\n\t\t\t\t, [&attach]( auto const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn isAttachParent( lookup.second.parent, attach );\n\t\t\t\t} );\n\t\t}\n\n\t\tstatic void listNonParentAttachs( FramePassArray const & passes\n\t\t\t, AttachmentArray const & allAttachs\n\t\t\t, AttachmentArray & result )\n\t\t{\n\t\t\tfor ( auto attach : allAttachs )\n\t\t\t{\n\t\t\t\tif ( std::none_of( passes.begin(), passes.end()\n\t\t\t\t\t, [&attach]( FramePass const * pass )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn attach->pass != pass\n\t\t\t\t\t\t\t&& isParentAttachForPass( attach, pass );\n\t\t\t\t\t} ) )\n\t\t\t\t{\n\t\t\t\t\taddAttach( *attach, result );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstatic bool hasOutput( FramePass const & pass )\n\t\t{\n\t\t\tauto result = ( !pass.getOutputs().empty() || !pass.getInouts().empty() );\n\n\t\t\tif ( !result )\n\t\t\t{\n\t\t\t\tfor ( auto & attach : pass.getTargets() )\n\t\t\t\t\tresult = result || attach->isOutput();\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void addPassInputs( FramePass const & pass\n\t\t\t, AttachmentArray & result )\n\t\t{\n\t\t\tfor ( auto & [_, attach] : pass.getInputs() )\n\t\t\t\taddAttach( *attach, result );\n\t\t\tfor ( auto & [_, attach] : pass.getUniforms() )\n\t\t\t\taddAttach( *attach, result );\n\t\t\tfor ( auto & [_, attach] : pass.getSampled() )\n\t\t\t\tresult.push_back( attach.attach );\n\t\t\tfor ( auto & attach : pass.getTargets() )\n\t\t\t\tif ( attach->isInput() )\n\t\t\t\t\taddAttach( *attach, result );\n\t\t}\n\n\t\tstatic void addSinkPassInputs( FramePassArray const & passes\n\t\t\t, AttachmentArray & result )\n\t\t{\n\t\t\tfor ( auto & pass : passes )\n\t\t\t\tif ( !hasOutput( *pass ) )\n\t\t\t\t{\n\t\t\t\t\taddPassInputs( *pass, result );\n\t\t\t\t}\n\t\t}\n\n\t\tstatic AttachmentArray listPassOutputs( FramePass const & pass )\n\t\t{\n\t\t\tAttachmentArray result;\n\t\t\tfor ( auto & [_, attach] : pass.getOutputs() )\n\t\t\t\taddAttach( *attach, result );\n\t\t\tfor ( auto & [_, attach] : pass.getInouts() )\n\t\t\t\taddAttach( *attach, result );\n\t\t\tfor ( auto & attach : pass.getTargets() )\n\t\t\t\tif ( attach->isOutput() )\n\t\t\t\t\taddAttach( *attach, result );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic bool areAllPassAttachsListed( FramePass const & pass\n\t\t\t, AttachmentArray const & result )\n\t\t{\n\t\t\tauto passOutputs = listPassOutputs( pass );\n\t\t\treturn std::all_of( passOutputs.begin(), passOutputs.end()\n\t\t\t\t, [&result]( Attachment const * lookup )\n\t\t\t\t{\n\n\t\t\t\t\treturn result.end() != std::find( result.begin(), result.end(), lookup );\n\t\t\t\t} );\n\t\t}\n\n\t\tstatic void removeMismatchs( AttachmentArray & result )\n\t\t{\n\t\t\tauto it = result.begin();\n\n\t\t\twhile ( it != result.end() )\n\t\t\t{\n\t\t\t\tif ( !areAllPassAttachsListed( *( *it )->pass, result ) )\n\t\t\t\t\tit = result.erase( it );\n\t\t\t\telse\n\t\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tnamespace graph\n\t{\n\t\tstruct AttachmentStates\n\t\t{\n\t\t\tbool separateDepthStencilLayouts;\n\t\t\tstd::vector< ImageLayout > imageStates{};\n\t\t\tstd::vector< AccessFlags > bufferStates{};\n\t\t};\n\n\t\tstatic FramePassArray listAttachmentPasses( Attachment const & attach )\n\t\t{\n\t\t\tif ( attach.pass )\n\t\t\t\treturn { attach.pass };\n\n\t\t\tFramePassArray result;\n\t\t\tfor ( auto const & source : attach.source )\n\t\t\t\tresult.push_back( source.pass );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic AttachmentArray splitImage( Attachment const & attach )\n\t\t{\n\t\t\tassert( attach.view().data->source.empty() );\n\t\t\treturn { &attach };\n\t\t}\n\n\t\tstatic AttachmentArray splitBuffer( Attachment const & attach )\n\t\t{\n\t\t\tassert( attach.buffer().data->source.empty() );\n\t\t\treturn { &attach };\n\t\t}\n\n\t\tstatic AttachmentArray splitAttach( Attachment const & attach )\n\t\t{\n\t\t\tif ( !attach.source.empty() )\n\t\t\t{\n\t\t\t\tAttachmentArray result;\n\t\t\t\tfor ( auto & source : attach.source )\n\t\t\t\t{\n\t\t\t\t\tAttachmentArray splitSource = splitAttach( *source.attach );\n\t\t\t\t\tresult.insert( result.end(), splitSource.begin(), splitSource.end() );\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif ( attach.isImage() )\n\t\t\t\treturn splitImage( attach );\n\t\t\treturn splitBuffer( attach );\n\t\t}\n\n\t\ttemplate< typename UIntT >\n\t\tstatic bool isInRange( UIntT value\n\t\t\t, UIntT offset, UIntT count )\n\t\t{\n\t\t\treturn value >= offset && value < offset + count;\n\t\t}\n\n\t\ttemplate< typename UIntT >\n\t\tstatic bool areIntersecting( UIntT lhsOffset, UIntT lhsCount\n\t\t\t, UIntT rhsOffset, UIntT rhsCount )\n\t\t{\n\t\t\treturn isInRange( lhsOffset, rhsOffset, rhsCount )\n\t\t\t\t|| isInRange( rhsOffset, lhsOffset, lhsCount );\n\t\t}\n\n\t\tstatic bool areIntersecting( ImageSubresourceRange const & lhs\n\t\t\t, ImageSubresourceRange const & rhs )\n\t\t{\n\t\t\treturn areIntersecting( lhs.baseMipLevel, lhs.levelCount, rhs.baseMipLevel, rhs.levelCount )\n\t\t\t\t&& areIntersecting( lhs.baseArrayLayer, lhs.layerCount, rhs.baseArrayLayer, lhs.layerCount );\n\t\t}\n\n\t\tstatic bool areIntersecting( BufferSubresourceRange const & lhs\n\t\t\t, BufferSubresourceRange const & rhs )\n\t\t{\n\t\t\treturn areIntersecting( lhs.offset, lhs.size\n\t\t\t\t, rhs.offset, rhs.size );\n\t\t}\n\n\t\tstatic bool areOverlapping( ImageViewData const & lhs\n\t\t\t, ImageViewData const & rhs )\n\t\t{\n\t\t\treturn lhs.image == rhs.image\n\t\t\t\t&& areIntersecting( getVirtualRange( lhs.image, lhs.info.viewType, lhs.info.subresourceRange )\n\t\t\t\t\t, getVirtualRange( rhs.image, rhs.info.viewType, rhs.info.subresourceRange ) );\n\t\t}\n\n\t\tstatic bool areOverlapping( BufferViewData const & lhs\n\t\t\t, BufferViewData const & rhs )\n\t\t{\n\t\t\treturn lhs.buffer == rhs.buffer\n\t\t\t\t&& areIntersecting( lhs.info.subresourceRange\n\t\t\t\t\t, rhs.info.subresourceRange );\n\t\t}\n\n\t\tstatic bool areOverlapping( Attachment const & lhs\n\t\t\t, Attachment const & rhs )\n\t\t{\n\t\t\tif ( lhs.isImage() )\n\t\t\t\treturn areOverlapping( *lhs.view().data, *rhs.view().data );\n\t\t\treturn areOverlapping( *lhs.buffer().data, *rhs.buffer().data );\n\t\t}\n\n\t\tvoid traverseAttachmentPasses( GraphNode & parent\n\t\t\t, Attachment const * currentAttach\n\t\t\t, Attachment const * parentAttach\n\t\t\t, AttachmentTransitions & transitions\n\t\t\t, GraphNodePtrArray & nodes );\n\n\t\tstatic void traversePassAttach( FramePassNode & node, std::map< uint32_t, Attachment const * > const & attachments\n\t\t\t, AttachmentTransitions & transitions\n\t\t\t, GraphNodePtrArray & nodes )\n\t\t{\n\t\t\tfor ( auto [binding, attach] : attachments )\n\t\t\t\ttraverseAttachmentPasses( node\n\t\t\t\t\t, node.getFramePass().getParentAttachment( *attach ), attach\n\t\t\t\t\t, transitions, nodes );\n\t\t}\n\n\t\tstatic void traversePassAttach( FramePassNode & node, std::map< uint32_t, FramePass::SampledAttachment > const & attachments\n\t\t\t, AttachmentTransitions & transitions\n\t\t\t, GraphNodePtrArray & nodes )\n\t\t{\n\t\t\tfor ( auto const & [binding, attach] : attachments )\n\t\t\t\ttraverseAttachmentPasses( node\n\t\t\t\t\t, node.getFramePass().getParentAttachment( *attach.attach ), attach.attach\n\t\t\t\t\t, transitions, nodes );\n\t\t}\n\n\t\tstatic void traversePassAttach( FramePassNode & node, AttachmentArray const & targets, Attachment::Flag flag\n\t\t\t, AttachmentTransitions & transitions\n\t\t\t, GraphNodePtrArray & nodes )\n\t\t{\n\t\t\tfor ( auto attach : targets )\n\t\t\t{\n\t\t\t\tif ( attach->hasFlag( flag ) )\n\t\t\t\t\ttraverseAttachmentPasses( node\n\t\t\t\t\t\t, node.getFramePass().getParentAttachment( *attach ), attach\n\t\t\t\t\t\t, transitions, nodes );\n\t\t\t}\n\t\t}\n\n\t\tstatic void insertTransition( bool isImage\n\t\t\t, Attachment const * output\n\t\t\t, Attachment const * input\n\t\t\t, AttachmentTransitions & transitions )\n\t\t{\n\t\t\tif ( isImage )\n\t\t\t{\n\t\t\t\tif ( output && input )\n\t\t\t\t\ttransitions.imageTransitions.emplace_back( output->view(), *output, *input );\n\t\t\t\telse if ( output )\n\t\t\t\t\ttransitions.imageTransitions.emplace_back( output->view(), *output, Attachment::createDefault( output->view() ) );\n\t\t\t\telse if ( input )\n\t\t\t\t\ttransitions.imageTransitions.emplace_back( input->view(), Attachment::createDefault( input->view() ), *input );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ( output && input )\n\t\t\t\t\ttransitions.bufferTransitions.emplace_back( output->buffer(), *output, *input );\n\t\t\t\telse if ( output )\n\t\t\t\t\ttransitions.bufferTransitions.emplace_back( output->buffer(), *output, Attachment::createDefault( output->buffer() ) );\n\t\t\t\telse if ( input )\n\t\t\t\t\ttransitions.bufferTransitions.emplace_back( input->buffer(), Attachment::createDefault( input->buffer() ), *input );\n\t\t\t}\n\t\t}\n\n\t\tvoid traverseAttachmentPasses( GraphNode & parent\n\t\t\t, Attachment const * outputAttach\n\t\t\t, Attachment const * inputAttach\n\t\t\t, AttachmentTransitions & parentTransitions\n\t\t\t, GraphNodePtrArray & nodes )\n\t\t{\n\t\t\tif ( outputAttach )\n\t\t\t{\n\t\t\t\tfor ( auto pass : listAttachmentPasses( *outputAttach ) )\n\t\t\t\t{\n\t\t\t\t\tauto it = std::find_if( nodes.begin(), nodes.end()\n\t\t\t\t\t\t, [&pass]( GraphNodePtr const & lookup )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn lookup->getName() == pass->getGroupName();\n\t\t\t\t\t\t} );\n\t\t\t\t\tif ( nodes.end() == it )\n\t\t\t\t\t{\n\t\t\t\t\t\tauto & node = static_cast< FramePassNode & >( *nodes.emplace_back( std::make_unique< FramePassNode >( *pass ) ) );\n\t\t\t\t\t\tAttachmentTransitions transitions;\n\t\t\t\t\t\ttraversePassAttach( node, pass->getTargets(), Attachment::Flag::InOut, transitions, nodes );\n\t\t\t\t\t\ttraversePassAttach( node, pass->getInouts(), transitions, nodes );\n\t\t\t\t\t\ttraversePassAttach( node, pass->getUniforms(), transitions, nodes );\n\t\t\t\t\t\ttraversePassAttach( node, pass->getSampled(), transitions, nodes );\n\t\t\t\t\t\ttraversePassAttach( node, pass->getInputs(), transitions, nodes );\n\t\t\t\t\t\ttraversePassAttach( node, pass->getTargets(), Attachment::Flag::Input, transitions, nodes );\n\t\t\t\t\t\tnode.setTransitions( mergeIdenticalTransitions( std::move( transitions ) ) );\n\t\t\t\t\t\tparent.attachNode( node );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tparent.attachNode( **it );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( outputAttach && inputAttach )\n\t\t\t{\n\t\t\t\tauto outputs = splitAttach( *outputAttach );\n\t\t\t\tauto inputs = splitAttach( *inputAttach );\n\t\t\t\tfor ( auto output : outputs )\n\t\t\t\t{\n\t\t\t\t\tfor ( auto input : inputs )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( areOverlapping( *output, *input ) )\n\t\t\t\t\t\t\tinsertTransition( output->isImage(), output, input, parentTransitions );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( outputAttach )\n\t\t\t{\n\t\t\t\t// Attach to external\n\t\t\t\tauto outputs = splitAttach( *outputAttach );\n\t\t\t\tfor ( auto output : outputs )\n\t\t\t\t\tinsertTransition( output->isImage(), output, nullptr, parentTransitions );\n\t\t\t}\n\t\t\telse if ( inputAttach )\n\t\t\t{\n\t\t\t\t// External resource\n\t\t\t\tauto inputs = splitAttach( *inputAttach );\n\t\t\t\tfor ( auto input : inputs )\n\t\t\t\t\tinsertTransition( input->isImage(), nullptr, input, parentTransitions );\n\t\t\t}\n\t\t}\n\n\t\tstatic bool hasInPredecessors( GraphNode & parent, GraphNode & child )\n\t\t{\n\t\t\treturn parent.getPredecessors().end() != std::find( parent.getPredecessors().begin()\n\t\t\t\t, parent.getPredecessors().end()\n\t\t\t\t, &child );\n\t\t}\n\n\t\tstatic void removeShortcuts( GraphNode & node )\n\t\t{\n\t\t\tGraphAdjacentNodeArray & predecessors = node.getPredecessors();\n\t\t\tauto it = predecessors.begin();\n\n\t\t\twhile ( it != predecessors.end() )\n\t\t\t{\n\t\t\t\tauto curr = *it;\n\t\t\t\tbool found = false;\n\t\t\t\tauto oit = predecessors.begin();\n\t\t\t\twhile ( oit != predecessors.end() && !found )\n\t\t\t\t{\n\t\t\t\t\tif ( oit != it )\n\t\t\t\t\t\tfound = hasInPredecessors( **oit, *curr );\n\t\t\t\t\t++oit;\n\t\t\t\t}\n\n\t\t\t\tremoveShortcuts( *curr );\n\t\t\t\tif ( found )\n\t\t\t\t\tit = predecessors.erase( it );\n\t\t\t\telse\n\t\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tstatic void sortNodes( GraphNode & node\n\t\t\t, GraphNodePtrArray & sourceGraph\n\t\t\t, GraphNodePtrArray & targetGraph )\n\t\t{\n\t\t\tfor ( auto & pred : node.getPredecessors() )\n\t\t\t\tsortNodes( *pred, sourceGraph, targetGraph );\n\n\t\t\tauto it = std::find_if( sourceGraph.begin(), sourceGraph.end()\n\t\t\t\t, [&node]( GraphNodePtr const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn &node == lookup.get();\n\t\t\t\t} );\n\t\t\tif ( sourceGraph.end() != it )\n\t\t\t{\n\t\t\t\ttargetGraph.emplace_back( std::move( *it ) );\n\t\t\t\tsourceGraph.erase( it );\n\t\t\t}\n\t\t}\n\n\t\tstatic void sortNodes( RootNode & root\n\t\t\t, GraphNodePtrArray & graph )\n\t\t{\n\t\t\tauto sourceGraph = std::move( graph );\n\t\t\tgraph.clear();\n\t\t\tfor ( auto & pred : root.getPredecessors() )\n\t\t\t\tsortNodes( *pred, sourceGraph, graph );\n\t\t}\n\n\t\tstatic void updateState( Attachment const & inputAttach\n\t\t\t, std::vector< ImageLayout > & states\n\t\t\t, bool separateDepthStencilLayouts )\n\t\t{\n\t\t\tauto id = inputAttach.view().id;\n\t\t\twhile ( states.size() <= id )\n\t\t\t\tstates.resize( std::max< size_t >( 1u, states.size() * 2u ) );\n\t\t\tstates[id] = inputAttach.getImageLayout( separateDepthStencilLayouts );\n\t\t}\n\n\t\tstatic void updateState( Attachment const & inputAttach\n\t\t\t, std::vector< AccessFlags > & states )\n\t\t{\n\t\t\tauto id = inputAttach.buffer().id;\n\t\t\twhile ( states.size() <= id )\n\t\t\t\tstates.resize( std::max< size_t >( 1u, states.size() * 2u ) );\n\t\t\tstates[id] = inputAttach.getAccessMask();\n\t\t}\n\n\t\tstatic void insertNeededTransition( Attachment const & output\n\t\t\t, Attachment const & input\n\t\t\t, AttachmentTransitions & transitions\n\t\t\t, graph::AttachmentStates & states )\n\t\t{\n\t\t\tif ( output.isImage() )\n\t\t\t{\n\t\t\t\ttransitions.imageTransitions.emplace_back( output.view(), output, input );\n\t\t\t\tupdateState( input, states.imageStates, states.separateDepthStencilLayouts );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttransitions.bufferTransitions.emplace_back( output.buffer(), output, input );\n\t\t\t\tupdateState( input, states.bufferStates );\n\t\t\t}\n\t\t}\n\n\t\tstatic bool isInNeededState( Attachment const & inputAttach\n\t\t\t, std::vector< ImageLayout > const & states\n\t\t\t, bool separateDepthStencilLayouts )\n\t\t{\n\t\t\tauto id = inputAttach.view().id;\n\t\t\tif ( states.size() <= id )\n\t\t\t\treturn false;\n\n\t\t\tauto & state = states[id];\n\t\t\treturn state == inputAttach.getImageLayout( separateDepthStencilLayouts );\n\t\t}\n\n\t\tstatic bool isInNeededState( Attachment const & inputAttach\n\t\t\t, std::vector< AccessFlags > const & states )\n\t\t{\n\t\t\tauto id = inputAttach.buffer().id;\n\t\t\tif ( states.size() <= id )\n\t\t\t\treturn false;\n\n\t\t\tauto & state = states[id];\n\t\t\treturn state == inputAttach.getAccessMask();\n\t\t}\n\n\t\tstatic bool isInNeededState( Attachment const & inputAttach\n\t\t\t, AttachmentStates const & states )\n\t\t{\n\t\t\tif ( inputAttach.isImage() )\n\t\t\t\treturn isInNeededState( inputAttach, states.imageStates, states.separateDepthStencilLayouts );\n\t\t\treturn isInNeededState( inputAttach, states.bufferStates );\n\t\t}\n\n\t\tstatic void buildTransitions( GraphNodePtrArray const & graph\n\t\t\t, graph::AttachmentStates & states )\n\t\t{\n\t\t\tfor ( auto & node : graph )\n\t\t\t{\n\t\t\t\tif ( node->getKind() == GraphNode::Kind::FramePass )\n\t\t\t\t{\n\t\t\t\t\tAttachmentTransitions transitions;\n\t\t\t\t\tfor ( auto & transition : node->getImageTransitions() )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( !isInNeededState( transition.inputAttach, states ) )\n\t\t\t\t\t\t\tinsertNeededTransition( transition.outputAttach, transition.inputAttach, transitions, states );\n\t\t\t\t\t}\n\t\t\t\t\tfor ( auto & transition : node->getBufferTransitions() )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( !isInNeededState( transition.inputAttach, states ) )\n\t\t\t\t\t\t\tinsertNeededTransition( transition.outputAttach, transition.inputAttach, transitions, states );\n\t\t\t\t\t}\n\t\t\t\t\tnode->setTransitions( std::move( transitions ) );\n\t\t\t\t}\n\t\t\t}\n\t\t\tAttachmentTransitions transitions;\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tAttachmentArray findEndPoints( FramePassArray const & passes )\n\t{\n\t\t// List all attaches\n\t\tAttachmentArray allAttachs;\n\t\tendpoints::listAllAttachs( passes, allAttachs );\n\n\t\t// Filter out the attaches that are used as parent to pass attaches\n\t\tAttachmentArray result;\n\t\tendpoints::listNonParentAttachs( passes, allAttachs, result );\n\n\t\t// Also look for passes without outputs, and add their inputs\n\t\tendpoints::addSinkPassInputs( passes, result );\n\n\t\t// Remove attachs for which the pass has other output attachs which are not in the list\n\t\tendpoints::removeMismatchs( result );\n\n\t\treturn result;\n\t}\n\n\t//*********************************************************************************************\n\n\tvoid buildGraph( AttachmentArray const & endPoints\n\t\t, RootNode & root\n\t\t, GraphNodePtrArray & graph\n\t\t, bool separateDepthStencilLayouts )\n\t{\n\t\t// First generate the graph with all transitions and links.\n\t\tAttachmentTransitions transitions;\n\t\tfor ( auto endPoint : endPoints )\n\t\t\tgraph::traverseAttachmentPasses( root, endPoint, nullptr, transitions, graph );\n\n\t\t// Then remove the shortcuts (if pass C depends on A and B, if B depends on A, then remove link between A and C)\n\t\tgraph::removeShortcuts( root );\n\n\t\t// Now sort the graph nodes regarding their position in the final graph.\n\t\tgraph::sortNodes( root, graph );\n\n\t\t// Eventually parse the sorted nodes to generate a curated transitions list per node.\n\t\tgraph::AttachmentStates states{ separateDepthStencilLayouts };\n\t\tgraph::buildTransitions( graph, states );\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/GraphBuilder.hpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"BuilderCommon.hpp\"\n\nnamespace crg::builder\n{\n\tAttachmentArray findEndPoints( FramePassArray const & passes );\n\tvoid buildGraph( AttachmentArray const & endPoints\n\t\t, RootNode & root\n\t\t, GraphNodePtrArray & graph\n\t\t, bool separateDepthStencilLayouts );\n}\n"
  },
  {
    "path": "source/RenderGraph/GraphContext.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/Exception.hpp\"\n#include \"RenderGraph/Log.hpp\"\n\n#include <cassert>\n#include <cmath>\n#include <stdexcept>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <iomanip>\n#include <sstream>\n#pragma warning( pop )\n\nnamespace crg\n{\n\tusing lock_type = std::unique_lock< std::mutex >;\n\n\tGraphContext::GraphContext( VkDevice device\n\t\t, VkPipelineCache cache\n\t\t, VkAllocationCallbacks const * allocator\n\t\t, VkPhysicalDeviceMemoryProperties memoryProperties\n\t\t, VkPhysicalDeviceProperties properties\n\t\t, bool separateDepthStencilLayouts\n\t\t, PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr )\n\t\t: device{ device }\n\t\t, cache{ cache }\n\t\t, allocator{ allocator }\n\t\t, memoryProperties{ std::move( memoryProperties ) }\n\t\t, properties{ std::move( properties ) }\n\t\t, separateDepthStencilLayouts{ separateDepthStencilLayouts }\n\t{\n#pragma warning( push )\n#pragma warning( disable: 4191 )\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcast-function-type-strict\"\n#define DECL_vkFunction( name )\\\n\t\tif ( vkGetDeviceProcAddr && device )\\\n\t\t\tvk##name = reinterpret_cast< PFN_vk##name >( vkGetDeviceProcAddr( device, \"vk\"#name ) )\n\n\t\tDECL_vkFunction( CreateGraphicsPipelines );\n\t\tDECL_vkFunction( CreateComputePipelines );\n\t\tDECL_vkFunction( DestroyPipeline );\n\t\tDECL_vkFunction( CreatePipelineLayout );\n\t\tDECL_vkFunction( DestroyPipelineLayout );\n\t\tDECL_vkFunction( CreateDescriptorSetLayout );\n\t\tDECL_vkFunction( DestroyDescriptorSetLayout );\n\t\tDECL_vkFunction( CreateDescriptorPool );\n\t\tDECL_vkFunction( DestroyDescriptorPool );\n\t\tDECL_vkFunction( AllocateDescriptorSets );\n\t\tDECL_vkFunction( FreeDescriptorSets );\n\t\tDECL_vkFunction( CreateBuffer );\n\t\tDECL_vkFunction( DestroyBuffer );\n\t\tDECL_vkFunction( CreateBufferView );\n\t\tDECL_vkFunction( DestroyBufferView );\n\t\tDECL_vkFunction( GetBufferMemoryRequirements );\n\t\tDECL_vkFunction( GetImageMemoryRequirements );\n\t\tDECL_vkFunction( AllocateMemory );\n\t\tDECL_vkFunction( FreeMemory );\n\t\tDECL_vkFunction( BindBufferMemory );\n\t\tDECL_vkFunction( BindImageMemory );\n\t\tDECL_vkFunction( MapMemory );\n\t\tDECL_vkFunction( UnmapMemory );\n\t\tDECL_vkFunction( FlushMappedMemoryRanges );\n\t\tDECL_vkFunction( InvalidateMappedMemoryRanges );\n\t\tDECL_vkFunction( CreateRenderPass );\n\t\tDECL_vkFunction( DestroyRenderPass );\n\t\tDECL_vkFunction( CreateFramebuffer );\n\t\tDECL_vkFunction( DestroyFramebuffer );\n\t\tDECL_vkFunction( CreateImage );\n\t\tDECL_vkFunction( DestroyImage );\n\t\tDECL_vkFunction( CreateImageView );\n\t\tDECL_vkFunction( DestroyImageView );\n\t\tDECL_vkFunction( CreateSampler );\n\t\tDECL_vkFunction( DestroySampler );\n\t\tDECL_vkFunction( CreateCommandPool );\n\t\tDECL_vkFunction( DestroyCommandPool );\n\t\tDECL_vkFunction( AllocateCommandBuffers );\n\t\tDECL_vkFunction( FreeCommandBuffers );\n\t\tDECL_vkFunction( CreateSemaphore );\n\t\tDECL_vkFunction( DestroySemaphore );\n\t\tDECL_vkFunction( UpdateDescriptorSets );\n\t\tDECL_vkFunction( BeginCommandBuffer );\n\t\tDECL_vkFunction( EndCommandBuffer );\n\t\tDECL_vkFunction( QueueSubmit );\n\t\tDECL_vkFunction( CreateQueryPool );\n\t\tDECL_vkFunction( DestroyQueryPool );\n\t\tDECL_vkFunction( GetQueryPoolResults );\n\t\tDECL_vkFunction( ResetCommandBuffer );\n\t\tDECL_vkFunction( CreateEvent );\n\t\tDECL_vkFunction( DestroyEvent );\n\t\tDECL_vkFunction( ResetEvent );\n\t\tDECL_vkFunction( SetEvent );\n\t\tDECL_vkFunction( GetEventStatus );\n\t\tDECL_vkFunction( CreateFence );\n\t\tDECL_vkFunction( DestroyFence );\n\t\tDECL_vkFunction( GetFenceStatus );\n\t\tDECL_vkFunction( WaitForFences );\n\t\tDECL_vkFunction( ResetFences );\n\n\t\tDECL_vkFunction( CmdBindPipeline );\n\t\tDECL_vkFunction( CmdBindDescriptorSets );\n\t\tDECL_vkFunction( CmdBindVertexBuffers );\n\t\tDECL_vkFunction( CmdBindIndexBuffer );\n\t\tDECL_vkFunction( CmdClearColorImage );\n\t\tDECL_vkFunction( CmdClearDepthStencilImage );\n\t\tDECL_vkFunction( CmdDispatch );\n\t\tDECL_vkFunction( CmdDispatchIndirect );\n\t\tDECL_vkFunction( CmdDraw );\n\t\tDECL_vkFunction( CmdDrawIndexed );\n\t\tDECL_vkFunction( CmdDrawIndexedIndirect );\n\t\tDECL_vkFunction( CmdDrawIndirect );\n\t\tDECL_vkFunction( CmdBeginRenderPass );\n\t\tDECL_vkFunction( CmdEndRenderPass );\n\t\tDECL_vkFunction( CmdPushConstants );\n\t\tDECL_vkFunction( CmdResetQueryPool );\n\t\tDECL_vkFunction( CmdWriteTimestamp );\n\t\tDECL_vkFunction( CmdPipelineBarrier );\n\t\tDECL_vkFunction( CmdBlitImage );\n\t\tDECL_vkFunction( CmdCopyBuffer );\n\t\tDECL_vkFunction( CmdCopyBufferToImage );\n\t\tDECL_vkFunction( CmdCopyImage );\n\t\tDECL_vkFunction( CmdCopyImageToBuffer );\n\t\tDECL_vkFunction( CmdExecuteCommands );\n\t\tDECL_vkFunction( CmdResetEvent );\n\t\tDECL_vkFunction( CmdSetEvent );\n\t\tDECL_vkFunction( CmdWaitEvents );\n\t\tDECL_vkFunction( CmdFillBuffer );\n\n#if VK_EXT_debug_utils\n\t\tDECL_vkFunction( SetDebugUtilsObjectNameEXT );\n\t\tDECL_vkFunction( CmdBeginDebugUtilsLabelEXT );\n\t\tDECL_vkFunction( CmdEndDebugUtilsLabelEXT );\n#endif\n#if VK_EXT_debug_marker\n\t\tDECL_vkFunction( DebugMarkerSetObjectNameEXT );\n\t\tDECL_vkFunction( CmdDebugMarkerBeginEXT );\n\t\tDECL_vkFunction( CmdDebugMarkerEndEXT );\n#endif\n\n#undef DECL_vkFunction\n#pragma clang diagnostic pop\n#pragma warning( pop )\n\t}\n\n\tGraphContext::~GraphContext()noexcept\n\t{\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n\t\tfor ( auto const & [_, alloc] : m_allocated )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [\" << alloc.type << \"](\" << alloc.name << \"), allocation stack:\\n\" << alloc.callstack;\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n#endif\n\t}\n\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n\n\tvoid GraphContext::vkCmdBeginDebugBlock( VkCommandBuffer commandBuffer\n\t\t, DebugBlockInfo const & labelInfo )const\n\t{\n#if VK_EXT_debug_utils\n\t\tdoBeginDebugUtilsLabel( commandBuffer\n\t\t\t, { VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT\n\t\t\t\t, nullptr\n\t\t\t\t, labelInfo.markerName.c_str()\n\t\t\t\t, { labelInfo.colour[0]\n\t\t\t\t\t, labelInfo.colour[1]\n\t\t\t\t\t, labelInfo.colour[2]\n\t\t\t\t\t, labelInfo.colour[3] } } );\n#endif\n#if VK_EXT_debug_marker\n\t\tdoDebugMarkerBegin( commandBuffer\n\t\t\t, { VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT\n\t\t\t\t, nullptr\n\t\t\t\t, labelInfo.markerName.c_str()\n\t\t\t\t, { labelInfo.colour[0]\n\t\t\t\t\t, labelInfo.colour[1]\n\t\t\t\t\t, labelInfo.colour[2]\n\t\t\t\t\t, labelInfo.colour[3] } } );\n#endif\n\t}\n\n\tvoid GraphContext::vkCmdEndDebugBlock( VkCommandBuffer commandBuffer )const\n\t{\n#if VK_EXT_debug_utils\n\t\tdoEndDebugUtilsLabel( commandBuffer );\n#endif\n#if VK_EXT_debug_marker\n\t\tdoDebugMarkerEnd( commandBuffer );\n#endif\n\t}\n\n#endif\n\n\tstd::array< float, 4u > GraphContext::getNextRainbowColour()const\n\t{\n\t\tstatic float currentColourHue{ 0.0f };\n\t\tcurrentColourHue += 0.0125f;\n\n\t\tif ( currentColourHue > 1.0f )\n\t\t{\n\t\t\tcurrentColourHue = 0.0f;\n\t\t}\n\n\t\tfloat brightness = 1.0f;\n\t\tfloat saturation = 1.0f;\n\t\tfloat h = currentColourHue == 1.0f ? 0 : currentColourHue * 6.0f;\n\t\tfloat f = h - std::floor( h );\n\t\tfloat p = brightness * ( 1.0f - saturation );\n\t\tfloat q = brightness * ( 1.0f - saturation * f );\n\t\tfloat t = brightness * ( 1.0f - ( saturation * ( 1.0f - f ) ) );\n\n\t\tif ( h < 1 )\n\t\t{\n\t\t\treturn { brightness, t, p, 1.0f };\n\t\t}\n\n\t\tif ( h < 2 )\n\t\t{\n\t\t\treturn { q, brightness, p, 1.0f };\n\t\t}\n\n\t\tif ( h < 3 )\n\t\t{\n\t\t\treturn { p, brightness, t, 1.0f };\n\t\t}\n\n\t\tif ( h < 4 )\n\t\t{\n\t\t\treturn { p, q, brightness, 1.0f };\n\t\t}\n\n\t\tif ( h < 5 )\n\t\t{\n\t\t\treturn { t, p, brightness, 1.0f };\n\t\t}\n\n\t\treturn { brightness, p, q, 1.0f };\n\t}\n\n\tuint32_t GraphContext::deduceMemoryType( uint32_t typeBits\n\t\t, VkMemoryPropertyFlags requirements )const\n\t{\n\t\tfor ( uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i )\n\t\t{\n\t\t\tif ( ( typeBits & 1 ) == 1\n\t\t\t\t&& ( memoryProperties.memoryTypes[i].propertyFlags & requirements ) == requirements )\n\t\t\t{\n\t\t\t\treturn i;\n\t\t\t}\n\n\t\t\ttypeBits >>= 1;\n\t\t}\n\n\t\tLogger::logError( \"Could not deduce memory type\" );\n\t\tCRG_Exception( \"Could not deduce memory type\" );\n\t}\n\n#if VK_EXT_debug_utils\n\n\tvoid GraphContext::doBeginDebugUtilsLabel( VkCommandBuffer commandBuffer\n\t\t, VkDebugUtilsLabelEXT const & labelInfo )const\n\t{\n\t\tif ( vkCmdBeginDebugUtilsLabelEXT )\n\t\t{\n\t\t\tvkCmdBeginDebugUtilsLabelEXT( commandBuffer, &labelInfo );\n\t\t}\n\t}\n\n\tvoid GraphContext::doEndDebugUtilsLabel( VkCommandBuffer commandBuffer )const\n\t{\n\t\tif ( vkCmdEndDebugUtilsLabelEXT )\n\t\t{\n\t\t\tvkCmdEndDebugUtilsLabelEXT( commandBuffer );\n\t\t}\n\t}\n\n#endif\n#if VK_EXT_debug_marker\n\n\tvoid GraphContext::doDebugMarkerBegin( VkCommandBuffer commandBuffer\n\t\t, VkDebugMarkerMarkerInfoEXT const & labelInfo )const\n\t{\n\t\tif ( vkCmdDebugMarkerBeginEXT )\n\t\t{\n\t\t\tvkCmdDebugMarkerBeginEXT( commandBuffer, &labelInfo );\n\t\t}\n\t}\n\n\tvoid GraphContext::doDebugMarkerEnd( VkCommandBuffer commandBuffer )const\n\t{\n\t\tif ( vkCmdDebugMarkerEndEXT )\n\t\t{\n\t\t\tvkCmdDebugMarkerEndEXT( commandBuffer );\n\t\t}\n\t}\n\n#endif\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n\n\tvoid GraphContext::doRegisterObject( uint64_t object\n\t\t, uint32_t objectType\n\t\t, std::string const & objectName\n\t\t, std::string const & typeName )\n\t{\n\t\tdoRegisterObjectName( object\n\t\t\t, objectType\n\t\t\t, objectName );\n\t\tstd::stringstream stream;\n\t\tstream.imbue( std::locale{ \"C\" } );\n\t\tstream << \"Created \" << typeName\n\t\t\t<< \" [0x\" << std::hex << std::setw( 8u ) << std::setfill( '0' ) << object << \"]\"\n\t\t\t<< \" - \" << objectName;\n\t\tLogger::logTrace( stream.str() );\n\t\tstd::stringstream callStack;\n\n\t\tif ( m_callstackCallback )\n\t\t{\n\t\t\tcallStack << m_callstackCallback();\n\t\t}\n\n\t\tlock_type lock{ m_mutex };\n\t\tm_allocated.insert_or_assign( object\n\t\t\t, ObjectAllocation{\n\t\t\t\ttypeName,\n\t\t\t\tobjectName,\n\t\t\t\tcallStack.str() } );\n\t}\n\n\tvoid GraphContext::doRegisterObjectName( uint64_t object\n\t\t, uint32_t objectType\n\t\t, std::string const & objectName )\n\t{\n#\tif VK_EXT_debug_utils\n\t\tif ( vkSetDebugUtilsObjectNameEXT )\n\t\t{\n\t\t\tVkDebugUtilsObjectNameInfoEXT nameInfo{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT\n\t\t\t\t, nullptr\n\t\t\t\t, VkObjectType( objectType )\n\t\t\t\t, object\n\t\t\t\t, objectName.c_str() };\n\t\t\tvkSetDebugUtilsObjectNameEXT( device, &nameInfo );\n\t\t}\n#\tendif\n#\tif VK_EXT_debug_marker\n\t\tif ( vkDebugMarkerSetObjectNameEXT )\n\t\t{\n\t\t\tVkDebugMarkerObjectNameInfoEXT nameInfo{ VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT\n\t\t\t\t, nullptr\n\t\t\t\t, VkDebugReportObjectTypeEXT( objectType )\n\t\t\t\t, object\n\t\t\t\t, objectName.c_str() };\n\t\t\tvkDebugMarkerSetObjectNameEXT( device, &nameInfo );\n\t\t}\n#\tendif\n\t}\n\n\tvoid GraphContext::doUnregisterObject( uint64_t object )\n\t{\n\t\tif ( object )\n\t\t{\n\t\t\tlock_type lock{ m_mutex };\n\n\t\t\tif ( auto it = m_allocated.find( size_t( object ) );\n\t\t\t\tit != m_allocated.end() )\n\t\t\t{\n\t\t\t\tstd::stringstream stream;\n\t\t\t\tstream.imbue( std::locale{ \"C\" } );\n\t\t\t\tstream << \"Destroyed \" << it->second.type\n\t\t\t\t\t<< \" [0x\" << std::hex << std::setw( 8u ) << std::setfill( '0' ) << object << \"]\"\n\t\t\t\t\t<< \" - \" << it->second.name;\n\t\t\t\tLogger::logTrace( stream.str() );\n\t\t\t\tm_allocated.erase( it );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::stringstream stream;\n\t\t\t\tstream.imbue( std::locale{ \"C\" } );\n\t\t\t\tstream << \"Destroyed Unknown\"\n\t\t\t\t\t<< \" [0x\" << std::hex << std::setw( 8u ) << std::setfill( '0' ) << object << \"]\"\n\t\t\t\t\t<< \" - Unregistered\";\n\t\t\t\tLogger::logTrace( stream.str() );\n\t\t\t}\n\t\t}\n\t}\n\n#endif\n\n\tvoid checkVkResult( VkResult result, char const * const stepName )\n\t{\n\t\tif ( result != VK_SUCCESS )\n\t\t{\n\t\t\tLogger::logError( stepName );\n\t\t\tCRG_Exception( stepName );\n\t\t}\n\t}\n\n\tvoid checkVkResult( VkResult result, std::string const & stepName )\n\t{\n\t\tcheckVkResult( result, stepName.c_str() );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/GraphNode.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/GraphNode.hpp\"\n\n#include \"RenderGraph/GraphVisitor.hpp\"\n#include \"RenderGraph/FrameGraph.hpp\"\n#include \"RenderGraph/FramePass.hpp\"\n\nnamespace crg\n{\n\t//*********************************************************************************************\n\n\tGraphNode::~GraphNode()noexcept = default;\n\n\tGraphNode::GraphNode( GraphNode && rhs )noexcept\n\t\t: kind{ rhs.kind }\n\t\t, id{ rhs.id }\n\t\t, name{ std::move( rhs.name ) }\n\t\t, group{ rhs.group }\n\t\t, prev{ std::move( rhs.prev ) }\n\t{\n\t\trhs.kind = Kind::Undefined;\n\t\trhs.id = 0u;\n\t}\n\n\tGraphNode::GraphNode( Kind pkind\n\t\t, uint32_t pid\n\t\t, std::string pname\n\t\t, FramePassGroup const & passGroup )\n\t\t: kind{ pkind }\n\t\t, id{ pid }\n\t\t, name{ std::move( pname ) }\n\t\t, group{ &passGroup }\n\t{\n\t}\n\n\tvoid GraphNode::attachNode( GraphNode & child )\n\t{\n\t\tif ( prev.end() == std::find( prev.begin(), prev.end(), &child ) )\n\t\t\tprev.push_back( &child );\n\t}\n\n\t//*********************************************************************************************\n\n\tFramePassNode::~FramePassNode()noexcept = default;\n\n\tFramePassNode::FramePassNode( FramePass const & framePass )\n\t\t: GraphNode{ MyKind, framePass.getId(), framePass.getGroupName(), framePass.getGroup() }\n\t\t, pass{ &framePass }\n\t{\n\t}\n\n\tvoid FramePassNode::accept( GraphVisitor * vis )const\n\t{\n\t\tvis->visitFramePassNode( this );\n\t}\n\n\t//*********************************************************************************************\n\n\tRootNode::~RootNode()noexcept = default;\n\n\tRootNode::RootNode( FrameGraph const & frameGraph )\n\t\t: GraphNode{ MyKind, 0u, frameGraph.getName(), frameGraph.getDefaultGroup() }\n\t\t, graph{ &frameGraph }\n\t{\n\t}\n\n\tvoid RootNode::accept( GraphVisitor * vis )const\n\t{\n\t\tvis->visitRootNode( this );\n\t}\n\n\t//*********************************************************************************************\n\n\tFramePass const * getFramePass( GraphNode const & node )\n\t{\n\t\tif ( !isFramePassNode( node ) )\n\t\t{\n\t\t\treturn nullptr;\n\t\t}\n\n\t\treturn &nodeCast< FramePassNode >( node ).getFramePass();\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/LayerLayoutStatesHandler.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/LayerLayoutStatesHandler.hpp\"\n\n#include \"RenderGraph/ImageData.hpp\"\n#include \"RenderGraph/ImageViewData.hpp\"\n\n#include <cassert>\n\nnamespace crg\n{\n\tLayerLayoutStatesHandler::LayerLayoutStatesHandler( LayerLayoutStatesMap const & rhs )\n\t\t: images{ rhs }\n\t{\n\t}\n\n\tvoid LayerLayoutStatesHandler::addStates( LayerLayoutStatesHandler const & data )\n\t{\n\t\tfor ( auto & state : data.images )\n\t\t{\n\t\t\timages.insert( state );\n\t\t}\n\t}\n\n\tvoid LayerLayoutStatesHandler::setLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, LayoutState const & layoutState )\n\t{\n\t\tauto range = getVirtualRange( image\n\t\t\t, viewType\n\t\t\t, subresourceRange );\n\t\tauto [it, _] = images.try_emplace( image.id );\n\t\taddSubresourceRangeLayout( it->second\n\t\t\t, range\n\t\t\t, layoutState );\n\t}\n\n\tvoid LayerLayoutStatesHandler::setLayoutState( crg::ImageViewId view\n\t\t, LayoutState const & layoutState )\n\t{\n\t\tassert( view.data->source.empty()\n\t\t\t&& \"Merged image views must be resolved before setting their layout state\" );\n\t\tsetLayoutState( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, view.data->info.subresourceRange\n\t\t\t, layoutState );\n\t}\n\n\tLayoutState LayerLayoutStatesHandler::getLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange )const\n\t{\n\t\tif ( auto imageIt = images.find( image.id ); imageIt != images.end() )\n\t\t{\n\t\t\tauto range = getVirtualRange( image\n\t\t\t\t, viewType\n\t\t\t\t, subresourceRange );\n\t\t\treturn getSubresourceRangeLayout( imageIt->second\n\t\t\t\t, range );\n\t\t}\n\n\t\treturn { ImageLayout::eUndefined, { AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe } };\n\t}\n\n\tLayoutState LayerLayoutStatesHandler::getLayoutState( ImageViewId view )const\n\t{\n\t\tassert( view.data->source.empty()\n\t\t\t&& \"Merged image views must be resolved before finding their layout state\" );\n\t\treturn getLayoutState( view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, view.data->info.subresourceRange );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/Log.cpp",
    "content": "#include \"RenderGraph/Log.hpp\"\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <iostream>\n#include <sstream>\n#include <mutex>\n#pragma warning( pop )\n\nnamespace crg\n{\n\tnamespace log\n\t{\n\t\tusing lock_type = std::unique_lock< std::mutex >;\n\n\t\tstatic void doLog( std::string_view message\n\t\t\t, bool newLine\n\t\t\t, FILE * stream )noexcept\n\t\t{\n\t\t\tfprintf( stream, \"%s\", message.data() );\n\n\t\t\tif ( newLine )\n\t\t\t{\n\t\t\t\tfprintf( stream, \"\\n\" );\n\t\t\t}\n\t\t}\n\t}\n\n\tLogger::Logger()\n\t\t: m_trace{ []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); } }\n\t\t, m_debug{ []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); } }\n\t\t, m_info{ []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); } }\n\t\t, m_warning{ []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); } }\n\t\t, m_error{ []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stderr ); } }\n\t{\n\t}\n\n\tvoid Logger::logTrace( std::string_view message, bool newLine )noexcept\n\t{\n\t\tdoGetInstance().m_trace( message, newLine );\n\t}\n\n\tvoid Logger::logDebug( std::string_view message, bool newLine )noexcept\n\t{\n\t\tdoGetInstance().m_debug( message, newLine );\n\t}\n\n\tvoid Logger::logInfo( std::string_view message, bool newLine )noexcept\n\t{\n\t\tdoGetInstance().m_info( message, newLine );\n\t}\n\n\tvoid Logger::logWarning( std::string_view message, bool newLine )noexcept\n\t{\n\t\tdoGetInstance().m_warning( message, newLine );\n\t}\n\n\tvoid Logger::logError( std::string_view message, bool newLine )noexcept\n\t{\n\t\tdoGetInstance().m_error( message, newLine );\n\t}\n\n\tvoid Logger::setTraceCallback( LogCallback callback )\n\t{\n\t\tif ( callback )\n\t\t\tdoGetInstance().m_trace = std::move( callback );\n\t\telse\n\t\t\tdoGetInstance().m_trace = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); };\n\t}\n\n\tvoid Logger::setDebugCallback( LogCallback callback )\n\t{\n\t\tif ( callback )\n\t\t\tdoGetInstance().m_debug = std::move( callback );\n\t\telse\n\t\t\tdoGetInstance().m_debug = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); };\n\t}\n\n\tvoid Logger::setInfoCallback( LogCallback callback )\n\t{\n\t\tif ( callback )\n\t\t\tdoGetInstance().m_info = std::move( callback );\n\t\telse\n\t\t\tdoGetInstance().m_info = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); };\n\t}\n\n\tvoid Logger::setWarningCallback( LogCallback callback )\n\t{\n\t\tif ( callback )\n\t\t\tdoGetInstance().m_warning = std::move( callback );\n\t\telse\n\t\t\tdoGetInstance().m_warning = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stdout ); };\n\t}\n\n\tvoid Logger::setErrorCallback( LogCallback callback )\n\t{\n\t\tif ( callback )\n\t\t\tdoGetInstance().m_error = std::move( callback );\n\t\telse\n\t\t\tdoGetInstance().m_error = []( std::string_view msg, bool newLine )noexcept { log::doLog( msg, newLine, stderr ); };\n\t}\n\n\tLogger & Logger::doGetInstance()noexcept\n\t{\n\t\tstatic Logger instance;\n\t\tstatic std::mutex mutex;\n\n\t\tlog::lock_type lock{ mutex };\n\t\treturn instance;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RecordContext.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RecordContext.hpp\"\n\n#include \"RenderGraph/Exception.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/ResourceHandler.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n#include <string>\n#include <type_traits>\n#include <unordered_set>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <fstream>\n#pragma warning( pop )\n\nnamespace crg\n{\n\t//************************************************************************************************\n\n\tnamespace recctx\n\t{\n\t\tstatic ImageSubresourceRange adaptRange( GraphContext const & context\n\t\t\t, ImageType type\n\t\t\t, PixelFormat format\n\t\t\t, ImageSubresourceRange const & subresourceRange )\n\t\t{\n\t\t\tImageSubresourceRange result = subresourceRange;\n\n\t\t\tif ( type == ImageType::e3D )\n\t\t\t{\n\t\t\t\tresult.baseArrayLayer = 0;\n\t\t\t\tresult.layerCount = 1;\n\t\t\t}\n\n\t\t\tif ( !context.separateDepthStencilLayouts\n\t\t\t\t&& isDepthStencilFormat( format )\n\t\t\t\t&& ( checkFlag( result.aspectMask, ImageAspectFlags::eDepth )\n\t\t\t\t\t|| checkFlag( result.aspectMask, ImageAspectFlags::eStencil ) ) )\n\t\t\t\tresult.aspectMask = ImageAspectFlags::eDepthStencil;\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t//************************************************************************************************\n\n\tRecordContext::RecordContext( ContextResourcesCache & resources )\n\t\t: m_handler{ &resources.getHandler() }\n\t\t, m_resources{ &resources }\n\t\t, m_prevPipelineState{ AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe }\n\t\t, m_currPipelineState{ AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe }\n\t\t, m_nextPipelineState{ AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe }\n\t{\n\t}\n\n\tRecordContext::RecordContext( ResourceHandler & handler )\n\t\t: m_handler{ &handler }\n\t\t, m_resources{ nullptr }\n\t{\n\t}\n\n\tvoid RecordContext::addStates( RecordContext const & data )\n\t{\n\t\tm_images.addStates( data.m_images );\n\n\t\tfor ( auto & state : data.m_buffers )\n\t\t{\n\t\t\tm_buffers.insert( state );\n\t\t}\n\n\t\tif ( m_prevPipelineState.access < data.m_currPipelineState.access )\n\t\t{\n\t\t\tm_prevPipelineState = data.m_currPipelineState;\n\t\t}\n\t}\n\n\tvoid RecordContext::setNextPipelineState( PipelineState const & state\n\t\t, LayerLayoutStatesMap const & imageLayouts )\n\t{\n\t\tm_prevPipelineState = m_currPipelineState;\n\t\tm_currPipelineState = m_nextPipelineState;\n\t\tm_nextPipelineState = state;\n\t\tm_nextImages = LayerLayoutStatesHandler{ imageLayouts };\n\t}\n\n\tvoid RecordContext::setLayoutState( ImageViewId view\n\t\t, LayoutState const & layoutState )\n\t{\n\t\tm_images.setLayoutState( view, layoutState );\n\t}\n\n\tLayoutState RecordContext::getLayoutState( ImageViewId view )const\n\t{\n\t\treturn m_images.getLayoutState( view );\n\t}\n\n\tvoid RecordContext::setLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, LayoutState const & layoutState )\n\t{\n\t\tm_images.setLayoutState( image\n\t\t\t, viewType\n\t\t\t, subresourceRange\n\t\t\t, layoutState );\n\t}\n\n\tLayoutState RecordContext::getLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange )const\n\t{\n\t\treturn m_images.getLayoutState( image\n\t\t\t, viewType\n\t\t\t, subresourceRange );\n\t}\n\n\tLayoutState RecordContext::getNextLayoutState( ImageViewId view )const\n\t{\n\t\treturn m_nextImages.getLayoutState( view );\n\t}\n\n\tLayoutState RecordContext::getNextLayoutState( ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange )const\n\t{\n\t\treturn m_nextImages.getLayoutState( image\n\t\t\t, viewType\n\t\t\t, subresourceRange );\n\t}\n\n\tvoid RecordContext::registerImplicitTransition( RunnablePass const & pass\n\t\t, ImageViewId view\n\t\t, RecordContext::ImplicitAction action )\n\t{\n\t\tregisterImplicitTransition( { &pass, view, std::move( action ) } );\n\t}\n\n\tvoid RecordContext::registerImplicitTransition( RunnablePass const & pass\n\t\t, BufferViewId view\n\t\t, RecordContext::ImplicitAction action )\n\t{\n\t\tregisterImplicitTransition( { &pass, view, std::move( action ) } );\n\t}\n\n\tvoid RecordContext::registerImplicitTransition( ImplicitImageTransition transition )\n\t{\n\t\tm_implicitImageTransitions.emplace_back( std::move( transition ) );\n\t}\n\n\tvoid RecordContext::registerImplicitTransition( ImplicitBufferTransition transition )\n\t{\n\t\tm_implicitBufferTransitions.emplace_back( std::move( transition ) );\n\t}\n\n\tvoid RecordContext::runImplicitTransition( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, ImageViewId view )\n\t{\n\t\tauto it = std::find_if( m_implicitImageTransitions.begin()\n\t\t\t, m_implicitImageTransitions.end()\n\t\t\t, [&view]( ImplicitImageTransition const & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.view == view;\n\t\t\t} );\n\n\t\tif ( it != m_implicitImageTransitions.end() )\n\t\t{\n\t\t\tauto pass = it->pass;\n\t\t\tauto action = it->action;\n\t\t\tm_implicitImageTransitions.erase( it );\n\n\t\t\tif ( !pass->isEnabled() )\n\t\t\t{\n\t\t\t\taction( *this, commandBuffer, index );\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid RecordContext::runImplicitTransition( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, BufferViewId view )\n\t{\n\t\tauto it = std::find_if( m_implicitBufferTransitions.begin()\n\t\t\t, m_implicitBufferTransitions.end()\n\t\t\t, [&view]( ImplicitBufferTransition const & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.view == view;\n\t\t\t} );\n\n\t\tif ( it != m_implicitBufferTransitions.end() )\n\t\t{\n\t\t\tauto pass = it->pass;\n\t\t\tauto action = it->action;\n\t\t\tm_implicitBufferTransitions.erase( it );\n\n\t\t\tif ( !pass->isEnabled() )\n\t\t\t{\n\t\t\t\taction( *this, commandBuffer, index );\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid RecordContext::setAccessState( BufferViewId buffer\n\t\t, AccessState const & accessState )\n\t{\n\t\treturn setAccessState( buffer.data->buffer, getSubresourceRange( buffer ), accessState );\n\t}\n\n\tAccessState RecordContext::getAccessState( BufferViewId buffer )const\n\t{\n\t\treturn getAccessState( buffer.data->buffer, getSubresourceRange( buffer ) );\n\t}\n\n\tvoid RecordContext::setAccessState( BufferId buffer\n\t\t, [[maybe_unused]] BufferSubresourceRange const & subresourceRange\n\t\t, AccessState const & accessState )\n\t{\n\t\tm_buffers.insert_or_assign( buffer.id, accessState );\n\t}\n\n\tAccessState const & RecordContext::getAccessState( BufferId buffer\n\t\t, [[maybe_unused]] BufferSubresourceRange const & subresourceRange )const\n\t{\n\t\tif ( auto bufferIt = m_buffers.find( buffer.id ); bufferIt != m_buffers.end() )\n\t\t{\n\t\t\treturn bufferIt->second;\n\t\t}\n\n\t\tstatic AccessState const dummy{ AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe };\n\t\treturn dummy;\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageViewId const & view\n\t\t, ImageLayout initialLayout\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view )\n\t\t\t, initialLayout\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageId const & image\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, ImageLayout initialLayout\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, image\n\t\t\t, ImageViewType( image.data->info.imageType )\n\t\t\t, subresourceRange\n\t\t\t, initialLayout\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageId const & image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, ImageLayout initialLayout\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tauto range = recctx::adaptRange( m_resources->getContext()\n\t\t\t\t, image.data->info.imageType\n\t\t\t\t, image.data->info.format\n\t\t\t\t, subresourceRange );\n\t\tauto from = getLayoutState( image\n\t\t\t, viewType\n\t\t\t, range );\n\n\t\tif ( from.layout == ImageLayout::eUndefined )\n\t\t{\n\t\t\tfrom = makeLayoutState( initialLayout );\n\t\t}\n\n\t\tif ( force\n\t\t\t|| ( ( from.layout != wantedState.layout\n\t\t\t\t|| from.state.pipelineStage != wantedState.state.pipelineStage )\n\t\t\t\t&& wantedState.layout != ImageLayout::eUndefined ) )\n\t\t{\n\t\t\tauto & resources = getResources();\n\t\t\tVkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\n\t\t\t\t, nullptr\n\t\t\t\t, getAccessFlags( from.state.access )\n\t\t\t\t, getAccessFlags( wantedState.state.access )\n\t\t\t\t, convert( from.layout )\n\t\t\t\t, convert( wantedState.layout )\n\t\t\t\t, VK_QUEUE_FAMILY_IGNORED\n\t\t\t\t, VK_QUEUE_FAMILY_IGNORED\n\t\t\t\t, resources.createImage( image )\n\t\t\t\t, convert( range ) };\n\t\t\tresources->vkCmdPipelineBarrier( commandBuffer\n\t\t\t\t, getPipelineStageFlags( from.state.pipelineStage )\n\t\t\t\t, getPipelineStageFlags( wantedState.state.pipelineStage )\n\t\t\t\t, VK_DEPENDENCY_BY_REGION_BIT\n\t\t\t\t, 0u\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, nullptr\n\t\t\t\t, 1u\n\t\t\t\t, &barrier );\n\t\t\tsetLayoutState( image\n\t\t\t\t, viewType\n\t\t\t\t, range\n\t\t\t\t, wantedState );\n\t\t}\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageViewId const & view\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view )\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageId const & image\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, image\n\t\t\t, ImageViewType( image.data->info.imageType )\n\t\t\t, subresourceRange\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, ImageId const & image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange const & subresourceRange\n\t\t, LayoutState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, image\n\t\t\t, viewType\n\t\t\t, subresourceRange\n\t\t\t, ImageLayout::eUndefined\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, BufferViewId view\n\t\t, AccessState const & initialState\n\t\t, AccessState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, view.data->buffer\n\t\t\t, getSubresourceRange( view )\n\t\t\t, initialState\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, BufferId buffer\n\t\t, BufferSubresourceRange const & subresourceRange\n\t\t, AccessState const & initialState\n\t\t, AccessState const & wantedState\n\t\t, bool force )\n\t{\n\t\tauto from = getAccessState( buffer\n\t\t\t, subresourceRange );\n\n\t\tif ( checkFlag( from.pipelineStage, PipelineStageFlags::eBottomOfPipe ) )\n\t\t{\n\t\t\tfrom = initialState;\n\t\t}\n\n\t\tif ( force\n\t\t\t|| ( from.access != wantedState.access\n\t\t\t\t|| from.pipelineStage != wantedState.pipelineStage ) )\n\t\t{\n\t\t\tauto & resources = getResources();\n\t\t\tVkBufferMemoryBarrier barrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER\n\t\t\t\t, nullptr\n\t\t\t\t, getAccessFlags( from.access )\n\t\t\t\t, getAccessFlags( wantedState.access )\n\t\t\t\t, VK_QUEUE_FAMILY_IGNORED\n\t\t\t\t, VK_QUEUE_FAMILY_IGNORED\n\t\t\t\t, resources.createBuffer( buffer )\n\t\t\t\t, subresourceRange.offset\n\t\t\t\t, subresourceRange.size };\n\t\t\tresources->vkCmdPipelineBarrier( commandBuffer\n\t\t\t\t, getPipelineStageFlags( from.pipelineStage )\n\t\t\t\t, getPipelineStageFlags( wantedState.pipelineStage )\n\t\t\t\t, VK_DEPENDENCY_BY_REGION_BIT\n\t\t\t\t, 0u\n\t\t\t\t, nullptr\n\t\t\t\t, 1u\n\t\t\t\t, &barrier\n\t\t\t\t, 0u\n\t\t\t\t, nullptr );\n\t\t\tsetAccessState( buffer\n\t\t\t\t, subresourceRange\n\t\t\t\t, wantedState );\n\t\t}\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, BufferId buffer\n\t\t, BufferSubresourceRange const & subresourceRange\n\t\t, AccessState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, buffer\n\t\t\t, subresourceRange\n\t\t\t, { AccessFlags::eNone, PipelineStageFlags::eBottomOfPipe }\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tvoid RecordContext::memoryBarrier( VkCommandBuffer commandBuffer\n\t\t, BufferViewId view\n\t\t, AccessState const & wantedState\n\t\t, bool force )\n\t{\n\t\tmemoryBarrier( commandBuffer\n\t\t\t, view.data->buffer\n\t\t\t, getSubresourceRange( view )\n\t\t\t, wantedState\n\t\t\t, force );\n\t}\n\n\tGraphContext & RecordContext::getContext()const\n\t{\n\t\treturn getResources().getContext();\n\t}\n\n\tContextResourcesCache & RecordContext::getResources()const\n\t{\n\t\tif ( !m_resources )\n\t\t{\n\t\t\tLogger::logError( \"No resources available.\" );\n\t\t\tCRG_Exception( \"No resources available.\" );\n\t\t}\n\n\t\treturn *m_resources;\n\t}\n\n\tvoid RecordContext::copyImage( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, ImageViewId srcView\n\t\t, ImageViewId dstView\n\t\t, Extent2D const & extent\n\t\t, ImageLayout finalLayout )\n\t{\n\t\trunImplicitTransition( commandBuffer, index, srcView );\n\t\tauto & srcSubresource = getSubresourceRange( srcView );\n\t\tauto & dstSubresource = getSubresourceRange( dstView );\n\t\tVkImageCopy region{ getSubresourceLayer( srcSubresource ), VkOffset3D{ 0u, 0u, 0u }\n\t\t\t, getSubresourceLayer( dstSubresource ), VkOffset3D{ 0u, 0u, 0u }\n\t\t, { extent.width, extent.height, 1u } };\n\t\tmemoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) );\n\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) );\n\t\tauto & resources = getResources();\n\t\tresources->vkCmdCopyImage( commandBuffer\n\t\t\t, resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t, resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t, 1u, &region );\n\n\t\tif ( finalLayout != ImageLayout::eUndefined )\n\t\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) );\n\t}\n\n\tvoid RecordContext::blitImage( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, ImageViewId srcView\n\t\t, ImageViewId dstView\n\t\t, Rect2D const & srcRect\n\t\t, Rect2D const & dstRect\n\t\t, FilterMode filter\n\t\t, ImageLayout finalLayout )\n\t{\n\t\trunImplicitTransition( commandBuffer, index, srcView );\n\t\tauto & srcSubresource = getSubresourceRange( srcView );\n\t\tauto & dstSubresource = getSubresourceRange( dstView );\n\t\tmemoryBarrier( commandBuffer, srcView, makeLayoutState( ImageLayout::eTransferSrc ) );\n\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) );\n\t\tauto & resources = getResources();\n\t\tVkImageBlit region{ getSubresourceLayer( srcSubresource ), { VkOffset3D{ srcRect.offset.x, srcRect.offset.y, 0u }, VkOffset3D{ int32_t( srcRect.extent.width ), int32_t( srcRect.extent.height ), 1 } }\n\t\t\t, getSubresourceLayer( dstSubresource ), { VkOffset3D{ dstRect.offset.x, dstRect.offset.y, 0u }, VkOffset3D{ int32_t( dstRect.extent.width ), int32_t( dstRect.extent.height ), 1 } } };\n\t\tresources->vkCmdBlitImage( commandBuffer\n\t\t\t, resources.createImage( srcView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t, resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t, 1u, &region, convert( filter ) );\n\n\t\tif ( finalLayout != ImageLayout::eUndefined )\n\t\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) );\n\t}\n\n\tvoid RecordContext::clearAttachment( VkCommandBuffer commandBuffer\n\t\t, ImageViewId dstView\n\t\t, ClearColorValue const & clearValue\n\t\t, ImageLayout finalLayout )\n\t{\n\t\tauto & resources = getResources();\n\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) );\n\t\tauto subresourceRange = convert( getSubresourceRange( dstView ) );\n\t\tassert( isColourFormat( getFormat( dstView ) ) );\n\t\tauto vkClearValue = convert( clearValue );\n\t\tresources->vkCmdClearColorImage( commandBuffer\n\t\t\t, resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t, &vkClearValue, 1u, &subresourceRange );\n\n\t\tif ( finalLayout != ImageLayout::eUndefined )\n\t\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) );\n\t}\n\n\tvoid RecordContext::clearAttachment( VkCommandBuffer commandBuffer\n\t\t, ImageViewId dstView\n\t\t, ClearDepthStencilValue const & clearValue\n\t\t, ImageLayout finalLayout )\n\t{\n\t\tauto & resources = getResources();\n\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( ImageLayout::eTransferDst ) );\n\t\tauto subresourceRange = convert( getSubresourceRange( dstView ) );\n\t\tassert( isDepthOrStencilFormat( getFormat( dstView ) ) );\n\t\tauto vkClearValue = convert( clearValue );\n\t\tresources->vkCmdClearDepthStencilImage( commandBuffer\n\t\t\t, resources.createImage( dstView.data->image ), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t, &vkClearValue, 1u, &subresourceRange );\n\n\t\tif ( finalLayout != ImageLayout::eUndefined )\n\t\t\tmemoryBarrier( commandBuffer, dstView, makeLayoutState( finalLayout ) );\n\t}\n\n\tvoid RecordContext::copyBuffer( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, BufferViewId srcView\n\t\t, BufferViewId dstView\n\t\t, DeviceSize srcOffset, DeviceSize dstOffset\n\t\t, DeviceSize size\n\t\t, AccessState const & finalState )\n\t{\n\t\trunImplicitTransition( commandBuffer, index, srcView );\n\t\tmemoryBarrier( commandBuffer, srcView, { AccessFlags::eTransferRead, PipelineStageFlags::eTransfer } );\n\t\tmemoryBarrier( commandBuffer, dstView, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } );\n\t\tauto & resources = getResources();\n\t\tVkBufferCopy region{ srcOffset, dstOffset, size };\n\t\tresources->vkCmdCopyBuffer( commandBuffer\n\t\t\t, resources.createBuffer( srcView.data->buffer )\n\t\t\t, resources.createBuffer( dstView.data->buffer )\n\t\t\t, 1u, &region );\n\n\t\tif ( finalState != AccessState{} )\n\t\t\tmemoryBarrier( commandBuffer, dstView, finalState );\n\t}\n\n\tvoid RecordContext::clearBuffer( VkCommandBuffer commandBuffer\n\t\t, BufferViewId dstView\n\t\t, uint32_t clearValue\n\t\t, AccessState const & finalState )\n\t{\n\t\tauto & resources = getResources();\n\t\tmemoryBarrier( commandBuffer, dstView, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } );\n\t\tauto subresourceRange = getSubresourceRange( dstView );\n\t\tresources->vkCmdFillBuffer( commandBuffer\n\t\t\t, resources.createBuffer( dstView.data->buffer )\n\t\t\t, subresourceRange.offset, subresourceRange.size\n\t\t\t, clearValue );\n\n\t\tif ( finalState != AccessState{} )\n\t\t\tmemoryBarrier( commandBuffer, dstView, finalState );\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::copyImage( ImageViewId srcView\n\t\t, ImageViewId dstView\n\t\t, Extent2D const & extent\n\t\t, ImageLayout finalLayout )\n\t{\n\t\treturn [srcView, dstView, extent, finalLayout]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )\n\t\t{\n\t\t\trecContext.copyImage( commandBuffer, index, srcView, dstView, extent, finalLayout );\n\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::blitImage( ImageViewId srcView\n\t\t, ImageViewId dstView\n\t\t, Rect2D const & srcRect\n\t\t, Rect2D const & dstRect\n\t\t, FilterMode filter\n\t\t, ImageLayout finalLayout )\n\t{\n\t\treturn [srcView, dstView, srcRect, dstRect, filter, finalLayout]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )\n\t\t{\n\t\t\trecContext.blitImage( commandBuffer, index, srcView, dstView, srcRect, dstRect, filter, finalLayout );\n\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::clearAttachment( Attachment const & attach\n\t\t, ImageLayout finalLayout )\n\t{\n\t\treturn [&attach, finalLayout]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )\n\t\t{\n\t\t\tauto dstView = attach.view( index );\n\t\t\tif ( isColourFormat( getFormat( dstView ) ) )\n\t\t\t\trecContext.clearAttachment( commandBuffer, dstView, getClearColorValue( attach.getClearValue() ), finalLayout );\n\t\t\telse\n\t\t\t\trecContext.clearAttachment( commandBuffer, dstView, getClearDepthStencilValue( attach.getClearValue() ), finalLayout );\n\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::clearAttachment( ImageViewId dstView\n\t\t, ClearColorValue const & clearValue\n\t\t, ImageLayout finalLayout )\n\t{\n\t\treturn [clearValue, dstView, finalLayout]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, [[maybe_unused]] uint32_t index )\n\t\t\t{\n\t\t\t\trecContext.clearAttachment( commandBuffer, dstView, clearValue, finalLayout );\n\t\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::clearAttachment( ImageViewId dstView\n\t\t, ClearDepthStencilValue const & clearValue\n\t\t, ImageLayout finalLayout )\n\t{\n\t\treturn [clearValue, dstView, finalLayout]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, [[maybe_unused]] uint32_t index )\n\t\t\t{\n\t\t\t\trecContext.clearAttachment( commandBuffer, dstView, clearValue, finalLayout );\n\t\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::clearBuffer( BufferViewId dstView\n\t\t, AccessState const & finalState )\n\t{\n\t\treturn clearBuffer( dstView, 0u, finalState );\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::clearBuffer( BufferViewId dstView\n\t\t, uint32_t clearValue\n\t\t, AccessState const & finalState )\n\t{\n\t\treturn [clearValue, dstView, finalState]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, [[maybe_unused]] uint32_t index )\n\t\t\t{\n\t\t\t\trecContext.clearBuffer( commandBuffer, dstView, clearValue, finalState );\n\t\t\t};\n\t}\n\n\tRecordContext::ImplicitAction RecordContext::copyBuffer( BufferViewId srcView\n\t\t, BufferViewId dstView\n\t\t, DeviceSize srcOffset, DeviceSize dstOffset\n\t\t, DeviceSize size\n\t\t, AccessState const & finalState )\n\t{\n\t\treturn [srcOffset, dstOffset, size, srcView, dstView, finalState]( RecordContext & recContext\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )\n\t\t\t{\n\t\t\t\trecContext.copyBuffer( commandBuffer, index, srcView, dstView, srcOffset, dstOffset, size, finalState );\n\t\t\t};\n\t}\n\n\t//************************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/ResourceHandler.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/ResourceHandler.hpp\"\n\n#include \"RenderGraph/Attachment.hpp\"\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/BufferData.hpp\"\n#include \"RenderGraph/BufferViewData.hpp\"\n#include \"RenderGraph/Hash.hpp\"\n#include \"RenderGraph/ImageData.hpp\"\n#include \"RenderGraph/ImageViewData.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <cassert>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <sstream>\n#pragma warning( pop )\n\nnamespace crg\n{\n\tusing lock_type = std::unique_lock< std::mutex >;\n\n\t//*********************************************************************************************\n\n\tnamespace reshdl\n\t{\n\t\tstruct Quad\n\t\t{\n\t\t\tusing Data = std::array< float, 2u >;\n\t\t\tstruct Vertex\n\t\t\t{\n\t\t\t\tData position;\n\t\t\t\tData texture;\n\t\t\t};\n\t\t};\n\n\t\tstatic VkBufferCreateInfo convert( BufferData const & data )\n\t\t{\n\t\t\treturn convert( data.info );\n\t\t}\n\n\t\tstatic VkBufferViewCreateInfo convert( BufferViewData const & data\n\t\t\t, VkBuffer buffer )\n\t\t{\n\t\t\tauto result = convert( data.info );\n\t\t\tresult.buffer = buffer;\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic VkImageCreateInfo convert( ImageData const & data )\n\t\t{\n\t\t\treturn convert( data.info );\n\t\t}\n\n\t\tstatic VkImageViewCreateInfo convert( ImageViewData const & data\n\t\t\t, VkImage image )\n\t\t{\n\t\t\tauto result = convert( data.info );\n\t\t\tresult.image = image;\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic size_t makeHash( SamplerDesc const & samplerDesc )\n\t\t{\n\t\t\tauto result = std::hash< FilterMode >{}( samplerDesc.magFilter );\n\t\t\tresult = hashCombine( result, samplerDesc.minFilter );\n\t\t\tresult = hashCombine( result, samplerDesc.mipmapMode );\n\t\t\tresult = hashCombine( result, samplerDesc.addressModeU );\n\t\t\tresult = hashCombine( result, samplerDesc.addressModeV );\n\t\t\tresult = hashCombine( result, samplerDesc.addressModeW );\n\t\t\tresult = hashCombine( result, samplerDesc.mipLodBias );\n\t\t\tresult = hashCombine( result, samplerDesc.minLod );\n\t\t\tresult = hashCombine( result, samplerDesc.maxLod );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic size_t makeHash( bool texCoords\n\t\t\t, Texcoord const & config )\n\t\t{\n\t\t\tsize_t result{ ( ( texCoords ? 0x01u : 0x00u ) << 0u )\n\t\t\t\t| ( ( config.invertU ? 0x01u : 0x00u ) << 1u )\n\t\t\t\t| ( ( config.invertV ? 0x01u : 0x00u ) << 2u ) };\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tResourceHandler::~ResourceHandler()noexcept\n\t{\n\t\tfor ( auto const & [data, _] : m_bufferViews )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [VkBufferView](\" << data.data->name << \")\";\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n\n\t\tfor ( auto const & [data, _] : m_buffers )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [VkBuffer](\" << data.data->name << \")\";\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n\n\t\tfor ( auto const & [data, _] : m_imageViews )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [VkImageView](\" << data.data->name << \")\";\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n\n\t\tfor ( auto const & [data, _] : m_images )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [VkImage](\" << data.data->name << \")\";\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n\n\t\tfor ( auto const & [_, data] : m_samplers )\n\t\t{\n\t\t\tstd::stringstream stream;\n\t\t\tstream << \"Leaked [VkSampler](\" << data.name << \")\";\n\t\t\tLogger::logError( stream.str() );\n\t\t}\n\t}\n\n\tBufferId ResourceHandler::createBufferId( BufferData const & img )\n\t{\n\t\tlock_type lock( m_buffersMutex );\n\t\tauto data = std::make_unique< BufferData >( img );\n\t\tBufferId result{ uint32_t( m_bufferIds.size() + 1u ), data.get() };\n\t\tm_bufferIds.try_emplace( result, std::move( data ) );\n\t\treturn result;\n\t}\n\n\tBufferViewId ResourceHandler::createViewId( BufferViewData const & view )\n\t{\n\t\tlock_type lock( m_bufferViewsMutex );\n\t\tauto it = std::find_if( m_bufferViewIds.begin()\n\t\t\t, m_bufferViewIds.end()\n\t\t\t, [&view]( BufferViewIdDataOwnerCont::value_type const & lookup )\n\t\t\t{\n\t\t\t\treturn *lookup.second == view;\n\t\t\t} );\n\t\tBufferViewId result{};\n\n\t\tif ( it == m_bufferViewIds.end() )\n\t\t{\n\t\t\tauto data = std::make_unique< BufferViewData >( view );\n\t\t\tresult = BufferViewId{ uint32_t( m_bufferViewIds.size() + 1u ), data.get() };\n\t\t\tm_bufferViewIds.try_emplace( result, std::move( data ) );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult = it->first;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tResourceHandler::CreatedT< VkBuffer > ResourceHandler::createBuffer( GraphContext & context\n\t\t, BufferId bufferId )\n\t{\n\t\tResourceHandler::CreatedT< VkBuffer > result{};\n\n\t\tif ( context.vkCreateBuffer )\n\t\t{\n\t\t\tlock_type lock( m_buffersMutex );\n\t\t\tauto [it, ins] = m_buffers.try_emplace( bufferId, std::pair< VkBuffer, VkDeviceMemory >{} );\n\n\t\t\tif ( ins && context.device )\n\t\t\t{\n\t\t\t\t// Create buffer\n\t\t\t\tauto createInfo = reshdl::convert( *bufferId.data );\n\t\t\t\tauto res = context.vkCreateBuffer( context.device\n\t\t\t\t\t, &createInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second.first );\n\t\t\t\tresult.resource = it->second.first;\n\t\t\t\tcheckVkResult( res, \"Buffer creation\" );\n\t\t\t\tcrgRegisterObjectName( context, bufferId.data->name, result.resource );\n\n\t\t\t\t// Create Buffer memory\n\t\t\t\tVkMemoryRequirements requirements{};\n\t\t\t\tcontext.vkGetBufferMemoryRequirements( context.device\n\t\t\t\t\t, result.resource\n\t\t\t\t\t, &requirements );\n\t\t\t\tuint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits\n\t\t\t\t\t, getMemoryPropertyFlags( bufferId.data->info.memory ) );\n\t\t\t\tVkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO\n\t\t\t\t\t, nullptr\n\t\t\t\t\t, requirements.size\n\t\t\t\t\t, deduced };\n\t\t\t\tres = context.vkAllocateMemory( context.device\n\t\t\t\t\t, &allocateInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second.second );\n\t\t\t\tresult.memory = it->second.second;\n\t\t\t\tcheckVkResult( res, \"Buffer memory allocation\" );\n\t\t\t\tcrgRegisterObjectName( context, bufferId.data->name, result.memory );\n\n\t\t\t\t// Bind buffer and memory\n\t\t\t\tres = context.vkBindBufferMemory( context.device\n\t\t\t\t\t, result.resource\n\t\t\t\t\t, result.memory\n\t\t\t\t\t, 0u );\n\t\t\t\tcheckVkResult( res, \"Buffer memory binding\" );\n\t\t\t\tresult.created = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.resource = it->second.first;\n\t\t\t\tresult.memory = it->second.second;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tResourceHandler::CreatedViewT< VkBufferView > ResourceHandler::createBufferView( GraphContext & context\n\t\t, BufferViewId view )\n\t{\n\t\tResourceHandler::CreatedViewT< VkBufferView > result{};\n\n\t\tif ( context.vkCreateBufferView )\n\t\t{\n\t\t\tlock_type lock( m_bufferViewsMutex );\n\t\t\tauto [it, ins] = m_bufferViews.try_emplace( view, VkBufferView{} );\n\n\t\t\tif ( ins )\n\t\t\t{\n\t\t\t\tauto buffer = createBuffer( context, view.data->buffer ).resource;\n\t\t\t\tauto createInfo = reshdl::convert( *view.data, buffer );\n\t\t\t\tauto res = context.vkCreateBufferView( context.device\n\t\t\t\t\t, &createInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second );\n\t\t\t\tcheckVkResult( res, \"BufferView creation\" );\n\t\t\t\tcrgRegisterObjectName( context, view.data->name, it->second );\n\t\t\t\tresult.view = it->second;\n\t\t\t\tresult.created = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.view = it->second;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tImageId ResourceHandler::createImageId( ImageData const & img )\n\t{\n\t\tlock_type lock( m_imagesMutex );\n\t\tauto data = std::make_unique< ImageData >( img );\n\t\tImageId result{ uint32_t( m_imageIds.size() + 1u ), data.get() };\n\t\tm_imageIds.try_emplace( result, std::move( data ) );\n\t\treturn result;\n\t}\n\n\tImageViewId ResourceHandler::createViewId( ImageViewData const & view )\n\t{\n\t\tlock_type lock( m_imageViewsMutex );\n\t\tauto it = std::find_if( m_imageViewIds.begin()\n\t\t\t, m_imageViewIds.end()\n\t\t\t, [&view]( ImageViewIdDataOwnerCont::value_type const & lookup )\n\t\t\t{\n\t\t\t\treturn *lookup.second == view;\n\t\t\t} );\n\t\tImageViewId result{};\n\n\t\tif ( it == m_imageViewIds.end() )\n\t\t{\n\t\t\tauto data = std::make_unique< ImageViewData >( view );\n\t\t\tresult = ImageViewId{ uint32_t( m_imageViewIds.size() + 1u ), data.get() };\n\t\t\tm_imageViewIds.try_emplace( result, std::move( data ) );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult = it->first;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tResourceHandler::CreatedT< VkImage > ResourceHandler::createImage( GraphContext & context\n\t\t, ImageId imageId )\n\t{\n\t\tResourceHandler::CreatedT< VkImage > result{};\n\n\t\tif ( context.vkCreateImage )\n\t\t{\n\t\t\tlock_type lock( m_imagesMutex );\n\t\t\tauto [it, ins] = m_images.try_emplace( imageId, std::pair< VkImage, VkDeviceMemory >{} );\n\n\t\t\tif ( ins && context.device )\n\t\t\t{\n\t\t\t\t// Create image\n\t\t\t\tauto createInfo = reshdl::convert( *imageId.data );\n\t\t\t\tauto res = context.vkCreateImage( context.device\n\t\t\t\t\t, &createInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second.first );\n\t\t\t\tresult.resource = it->second.first;\n\t\t\t\tcheckVkResult( res, \"Image creation\" );\n\t\t\t\tcrgRegisterObjectName( context, imageId.data->name, result.resource );\n\n\t\t\t\t// Create Image memory\n\t\t\t\tVkMemoryRequirements requirements{};\n\t\t\t\tcontext.vkGetImageMemoryRequirements( context.device\n\t\t\t\t\t, result.resource\n\t\t\t\t\t, &requirements );\n\t\t\t\tuint32_t deduced = context.deduceMemoryType( requirements.memoryTypeBits\n\t\t\t\t\t, getMemoryPropertyFlags( imageId.data->info.memory ) );\n\t\t\t\tVkMemoryAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO\n\t\t\t\t\t, nullptr\n\t\t\t\t\t, requirements.size\n\t\t\t\t\t, deduced };\n\t\t\t\tres = context.vkAllocateMemory( context.device\n\t\t\t\t\t, &allocateInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second.second );\n\t\t\t\tresult.memory = it->second.second;\n\t\t\t\tcheckVkResult( res, \"Image memory allocation\" );\n\t\t\t\tcrgRegisterObjectName( context, imageId.data->name, result.memory );\n\n\t\t\t\t// Bind image and memory\n\t\t\t\tres = context.vkBindImageMemory( context.device\n\t\t\t\t\t, result.resource\n\t\t\t\t\t, result.memory\n\t\t\t\t\t, 0u );\n\t\t\t\tcheckVkResult( res, \"Image memory binding\" );\n\t\t\t\tresult.created = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.resource = it->second.first;\n\t\t\t\tresult.memory = it->second.second;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tResourceHandler::CreatedViewT< VkImageView > ResourceHandler::createImageView( GraphContext & context\n\t\t, ImageViewId view )\n\t{\n\t\tResourceHandler::CreatedViewT< VkImageView > result{};\n\n\t\tif ( context.vkCreateImageView )\n\t\t{\n\t\t\tlock_type lock( m_bufferViewsMutex );\n\t\t\tauto [it, ins] = m_imageViews.try_emplace( view, VkImageView{} );\n\n\t\t\tif ( ins )\n\t\t\t{\n\t\t\t\tauto image = createImage( context, view.data->image ).resource;\n\t\t\t\tauto createInfo = reshdl::convert( *view.data, image );\n\t\t\t\tauto res = context.vkCreateImageView( context.device\n\t\t\t\t\t, &createInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &it->second );\n\t\t\t\tcheckVkResult( res, \"ImageView creation\" );\n\t\t\t\tcrgRegisterObjectName( context, view.data->name, it->second );\n\t\t\t\tresult.view = it->second;\n\t\t\t\tresult.created = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.view = it->second;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tVkSampler ResourceHandler::createSampler( GraphContext & context\n\t\t, std::string const & suffix\n\t\t, SamplerDesc const & samplerDesc )\n\t{\n\t\tVkSampler result{};\n\n\t\tif ( context.vkCreateSampler )\n\t\t{\n\t\t\tlock_type lock( m_samplersMutex );\n\t\t\tVkSamplerCreateInfo createInfo{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, convert( samplerDesc.magFilter )\n\t\t\t\t, convert( samplerDesc.minFilter )\n\t\t\t\t, convert( samplerDesc.mipmapMode )\n\t\t\t\t, convert( samplerDesc.addressModeU )\n\t\t\t\t, convert( samplerDesc.addressModeV )\n\t\t\t\t, convert( samplerDesc.addressModeW )\n\t\t\t\t, samplerDesc.mipLodBias // mipLodBias\n\t\t\t\t, VK_FALSE // anisotropyEnable\n\t\t\t\t, 0.0f // maxAnisotropy\n\t\t\t\t, VK_FALSE // compareEnable\n\t\t\t\t, VK_COMPARE_OP_ALWAYS // compareOp\n\t\t\t\t, samplerDesc.minLod\n\t\t\t\t, samplerDesc.maxLod\n\t\t\t\t, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK\n\t\t\t\t, VK_FALSE };\n\t\t\tauto res = context.vkCreateSampler( context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, context.allocator\n\t\t\t\t, &result );\n\t\t\tauto & sampler = m_samplers.try_emplace( result, Sampler{ result, {} } ).first->second;\n\t\t\tcheckVkResult( res, \"Sampler creation\" );\n\t\t\tsampler.name = \"Sampler_\" + suffix;\n\t\t\tcrgRegisterObject( context, sampler.name, result );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tVertexBuffer const * ResourceHandler::createQuadTriVertexBuffer( GraphContext & context\n\t\t, std::string const & suffix\n\t\t, bool texCoords\n\t\t, Texcoord const & config )\n\t{\n\t\tVertexBuffer * vertexBuffer{};\n\t\tlock_type lock( m_vertexBuffersMutex );\n\n\t\tif ( context.vkCreateBuffer )\n\t\t{\n\t\t\tauto bufferId = createBufferId( BufferData{ \"QuadVertexMemory_\" + suffix\n\t\t\t\t, BufferCreateFlags::eNone\n\t\t\t\t, 3u * sizeof( reshdl::Quad::Vertex )\n\t\t\t\t, BufferUsageFlags::eVertexBuffer\n\t\t\t\t, MemoryPropertyFlags::eHostVisible } );\n\t\t\tauto result = std::make_unique< VertexBuffer >( createViewId( BufferViewData{ \"QuadVertexMemory_\" + suffix\n\t\t\t\t, bufferId\n\t\t\t\t, { 0u, bufferId.data->info.size } } ) );\n\t\t\tvertexBuffer = result.get();\n\n\t\t\tif ( context.device )\n\t\t\t{\n\t\t\t\tauto created = createBuffer( context, vertexBuffer->buffer.data->buffer );\n\t\t\t\treshdl::Quad::Vertex * buffer{};\n\t\t\t\tauto res = context.vkMapMemory( context.device\n\t\t\t\t\t, created.memory\n\t\t\t\t\t, 0u\n\t\t\t\t\t, VK_WHOLE_SIZE\n\t\t\t\t\t, 0u\n\t\t\t\t\t, reinterpret_cast< void ** >( &buffer ) );\n\t\t\t\tcheckVkResult( res, \"Buffer memory mapping\" );\n\n\t\t\t\tif ( buffer )\n\t\t\t\t{\n\t\t\t\t\tauto rangeU = 1.0;\n\t\t\t\t\tauto minU = 0.0;\n\t\t\t\t\tauto maxU = minU + 2.0 * rangeU;\n\t\t\t\t\tauto rangeV = 1.0;\n\t\t\t\t\tauto minV = -rangeV;\n\t\t\t\t\tauto maxV = minV + 2.0 * rangeV;\n\t\t\t\t\tauto realMinU = float( config.invertU ? maxU : minU );\n\t\t\t\t\tauto realMaxU = float( config.invertU ? minU : maxU );\n\t\t\t\t\tauto realMinV = float( config.invertV ? maxV : minV );\n\t\t\t\t\tauto realMaxV = float( config.invertV ? minV : maxV );\n\t\t\t\t\tstd::array<reshdl::Quad::Vertex, 3u > vertexData\n\t\t\t\t\t\t{ reshdl::Quad::Vertex{ reshdl::Quad::Data{ -1.0f, -3.0f }, reshdl::Quad::Data{ realMinU, realMinV } }\n\t\t\t\t\t\t, reshdl::Quad::Vertex{ reshdl::Quad::Data{ -1.0f, +1.0f }, reshdl::Quad::Data{ realMinU, realMaxV } }\n\t\t\t\t\t\t, reshdl::Quad::Vertex{ reshdl::Quad::Data{ +3.0f, +1.0f }, reshdl::Quad::Data{ realMaxU, realMaxV } } };\n\t\t\t\t\tstd::copy( vertexData.begin(), vertexData.end(), buffer );\n\n\t\t\t\t\tVkMappedMemoryRange memoryRange{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE\n\t\t\t\t\t\t, nullptr\n\t\t\t\t\t\t, created.memory\n\t\t\t\t\t\t, 0u\n\t\t\t\t\t\t, VK_WHOLE_SIZE };\n\t\t\t\t\tcontext.vkFlushMappedMemoryRanges( context.device, 1u, &memoryRange );\n\t\t\t\t\tcontext.vkUnmapMemory( context.device, created.memory );\n\t\t\t\t}\n\n\t\t\t\tvertexBuffer->vertexAttribs.push_back( { 0u, 0u, VK_FORMAT_R32G32_SFLOAT, offsetof( reshdl::Quad::Vertex, position ) } );\n\n\t\t\t\tif ( texCoords )\n\t\t\t\t{\n\t\t\t\t\tvertexBuffer->vertexAttribs.push_back( { 1u, 0u, VK_FORMAT_R32G32_SFLOAT, offsetof( reshdl::Quad::Vertex, texture ) } );\n\t\t\t\t}\n\n\t\t\t\tvertexBuffer->vertexBindings.push_back( { 0u, sizeof( reshdl::Quad::Vertex ), VK_VERTEX_INPUT_RATE_VERTEX } );\n\t\t\t\tvertexBuffer->inputState = VkPipelineVertexInputStateCreateInfo{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\n\t\t\t\t\t, nullptr\n\t\t\t\t\t, 0u\n\t\t\t\t\t, uint32_t( vertexBuffer->vertexBindings.size() )\n\t\t\t\t\t, vertexBuffer->vertexBindings.data()\n\t\t\t\t\t, uint32_t( vertexBuffer->vertexAttribs.size() )\n\t\t\t\t\t, vertexBuffer->vertexAttribs.data() };\n\t\t\t}\n\n\t\t\tm_vertexBuffers.emplace( std::move( result ) );\n\t\t}\n\n\t\treturn vertexBuffer;\n\t}\n\n\tvoid ResourceHandler::destroyBuffer( GraphContext & context\n\t\t, BufferId bufferId )\n\t{\n\t\tlock_type lock( m_buffersMutex );\n\t\tauto it = m_buffers.find( bufferId );\n\n\t\tif ( it != m_buffers.end() )\n\t\t{\n\t\t\tif ( context.vkDestroyBuffer && it->second.first )\n\t\t\t{\n\t\t\t\tcontext.vkDestroyBuffer( context.device, it->second.first, context.allocator );\n\t\t\t}\n\n\t\t\tif ( context.vkFreeMemory && it->second.second )\n\t\t\t{\n\t\t\t\tcontext.vkFreeMemory( context.device, it->second.second, context.allocator );\n\t\t\t}\n\n\t\t\tm_buffers.erase( it );\n\t\t}\n\t}\n\n\tvoid ResourceHandler::destroyBufferView( GraphContext & context\n\t\t, BufferViewId viewId )\n\t{\n\t\tlock_type lock( m_bufferViewsMutex );\n\t\tauto it = m_bufferViews.find( viewId );\n\n\t\tif ( it != m_bufferViews.end() )\n\t\t{\n\t\t\tif ( context.vkDestroyBufferView && it->second )\n\t\t\t{\n\t\t\t\tcontext.vkDestroyBufferView( context.device, it->second, context.allocator );\n\t\t\t}\n\n\t\t\tm_bufferViews.erase( it );\n\t\t}\n\t}\n\n\tvoid ResourceHandler::destroyImage( GraphContext & context\n\t\t, ImageId imageId )\n\t{\n\t\tlock_type lock( m_imagesMutex );\n\t\tauto it = m_images.find( imageId );\n\n\t\tif ( it != m_images.end() )\n\t\t{\n\t\t\tif ( context.vkDestroyImage && it->second.first )\n\t\t\t{\n\t\t\t\tcontext.vkDestroyImage( context.device, it->second.first, context.allocator );\n\t\t\t}\n\n\t\t\tif ( context.vkFreeMemory && it->second.second )\n\t\t\t{\n\t\t\t\tcontext.vkFreeMemory( context.device, it->second.second, context.allocator );\n\t\t\t}\n\n\t\t\tm_images.erase( it );\n\t\t}\n\t}\n\n\tvoid ResourceHandler::destroyImageView( GraphContext & context\n\t\t, ImageViewId viewId )\n\t{\n\t\tlock_type lock( m_bufferViewsMutex );\n\t\tauto it = m_imageViews.find( viewId );\n\n\t\tif ( it != m_imageViews.end() )\n\t\t{\n\t\t\tif ( context.vkDestroyImageView && it->second )\n\t\t\t{\n\t\t\t\tcontext.vkDestroyImageView( context.device, it->second, context.allocator );\n\t\t\t}\n\n\t\t\tm_imageViews.erase( it );\n\t\t}\n\t}\n\n\tvoid ResourceHandler::destroySampler( GraphContext & context\n\t\t, VkSampler sampler )\n\t{\n\t\tlock_type lock( m_samplersMutex );\n\t\tauto it = m_samplers.find( sampler );\n\n\t\tif ( it != m_samplers.end() )\n\t\t{\n\t\t\tif ( context.vkDestroySampler && it->first )\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( context, it->first );\n\t\t\t\tcontext.vkDestroySampler( context.device\n\t\t\t\t\t, it->first\n\t\t\t\t\t, context.allocator );\n\t\t\t}\n\n\t\t\tm_samplers.erase( it );\n\t\t}\n\t}\n\n\tvoid ResourceHandler::destroyVertexBuffer( GraphContext & context\n\t\t, VertexBuffer const * buffer )\n\t{\n\t\tlock_type lock( m_vertexBuffersMutex );\n\t\tauto it = std::find_if( m_vertexBuffers.begin()\n\t\t\t, m_vertexBuffers.end()\n\t\t\t, [buffer]( VertexBufferPtr const & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.get() == buffer;\n\t\t\t} );\n\n\t\tif ( it != m_vertexBuffers.end() )\n\t\t{\n\t\t\tauto const & vertexBuffer = **it;\n\t\t\tdestroyBuffer( context, vertexBuffer.buffer.data->buffer );\n\t\t\tm_vertexBuffers.erase( it );\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tContextResourcesCache::ContextResourcesCache( ResourceHandler & handler\n\t\t, GraphContext & context )\n\t\t: m_handler{ handler }\n\t\t, m_context{ context }\n\t{\n\t}\n\n\tContextResourcesCache::~ContextResourcesCache()noexcept\n\t{\n\t\tfor ( auto const & [bufferView, _] : m_bufferViews )\n\t\t{\n\t\t\tm_handler.destroyBufferView( m_context, bufferView );\n\t\t}\n\n\t\tfor ( auto const & [buffer, _] : m_buffers )\n\t\t{\n\t\t\tm_handler.destroyBuffer( m_context, buffer );\n\t\t}\n\n\t\tfor ( auto const & [imageView, _] : m_imageViews )\n\t\t{\n\t\t\tm_handler.destroyImageView( m_context, imageView );\n\t\t}\n\n\t\tfor ( auto const & [image, _] : m_images )\n\t\t{\n\t\t\tm_handler.destroyImage( m_context, image );\n\t\t}\n\n\t\tfor ( auto const & [_, sampler] : m_samplers )\n\t\t{\n\t\t\tm_handler.destroySampler( m_context, sampler );\n\t\t}\n\n\t\tfor ( auto const & [_, buffer] : m_vertexBuffers )\n\t\t{\n\t\t\tm_handler.destroyVertexBuffer( m_context, buffer );\n\t\t}\n\t}\n\n\tVkBuffer ContextResourcesCache::createBuffer( BufferId const & buffer )\n\t{\n\t\tVkDeviceMemory memory{};\n\t\treturn createBuffer( buffer, memory );\n\t}\n\n\tVkBuffer ContextResourcesCache::createBuffer( BufferId const & buffer, VkDeviceMemory & memory )\n\t{\n\t\tauto [created, result, mem] = m_handler.createBuffer( m_context, buffer );\n\n\t\tif ( created )\n\t\t{\n\t\t\tm_buffers[buffer] = result;\n\t\t}\n\n\t\tmemory = mem;\n\t\treturn result;\n\t}\n\n\tVkBufferView ContextResourcesCache::createBufferView( BufferViewId const & view )\n\t{\n\t\tauto [created, result] = m_handler.createBufferView( m_context, view );\n\n\t\tif ( created )\n\t\t{\n\t\t\tm_bufferViews[view] = result;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool ContextResourcesCache::destroyBuffer( BufferId const & bufferId )\n\t{\n\t\tauto it = m_buffers.find( bufferId );\n\t\tauto result = it != m_buffers.end();\n\n\t\tif ( result )\n\t\t{\n\t\t\tm_handler.destroyBuffer( m_context, bufferId );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool ContextResourcesCache::destroyBufferView( BufferViewId const & viewId )\n\t{\n\t\tauto it = m_bufferViews.find( viewId );\n\t\tauto result = it != m_bufferViews.end();\n\n\t\tif ( result )\n\t\t{\n\t\t\tm_handler.destroyBufferView( m_context, viewId );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tVkImage ContextResourcesCache::createImage( ImageId const & image )\n\t{\n\t\tVkDeviceMemory memory{};\n\t\treturn createImage( image, memory );\n\t}\n\n\tVkImage ContextResourcesCache::createImage( ImageId const & image, VkDeviceMemory & memory )\n\t{\n\t\tauto [created, result, mem] = m_handler.createImage( m_context, image );\n\n\t\tif ( created )\n\t\t{\n\t\t\tm_images[image] = result;\n\t\t}\n\n\t\tmemory = mem;\n\t\treturn result;\n\t}\n\n\tVkImageView ContextResourcesCache::createImageView( ImageViewId const & view )\n\t{\n\t\tauto [created, result] = m_handler.createImageView( m_context, view );\n\n\t\tif ( created )\n\t\t{\n\t\t\tm_imageViews[view] = result;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool ContextResourcesCache::destroyImage( ImageId const & imageId )\n\t{\n\t\tauto it = m_images.find( imageId );\n\t\tauto result = it != m_images.end();\n\n\t\tif ( result )\n\t\t{\n\t\t\tm_handler.destroyImage( m_context, imageId );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool ContextResourcesCache::destroyImageView( ImageViewId const & viewId )\n\t{\n\t\tauto it = m_imageViews.find( viewId );\n\t\tauto result = it != m_imageViews.end();\n\n\t\tif ( result )\n\t\t{\n\t\t\tm_handler.destroyImageView( m_context, viewId );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tVkSampler ContextResourcesCache::createSampler( SamplerDesc const & samplerDesc )\n\t{\n\t\tauto hash = reshdl::makeHash( samplerDesc );\n\t\tauto [it, res] = m_samplers.try_emplace( hash, VkSampler{} );\n\n\t\tif ( res )\n\t\t{\n\t\t\tit->second = m_handler.createSampler( m_context\n\t\t\t\t, std::to_string( hash )\n\t\t\t\t, samplerDesc );\n\t\t}\n\n\t\treturn it->second;\n\t}\n\n\tVertexBuffer const & ContextResourcesCache::createQuadTriVertexBuffer( bool texCoords\n\t\t, Texcoord const & config )\n\t{\n\t\tauto hash = reshdl::makeHash( texCoords, config );\n\t\tauto [it, res] = m_vertexBuffers.emplace( hash, nullptr );\n\n\t\tif ( res )\n\t\t{\n\t\t\tit->second = m_handler.createQuadTriVertexBuffer( m_context\n\t\t\t\t, std::to_string( hash )\n\t\t\t\t, texCoords\n\t\t\t\t, config );\n\t\t}\n\n\t\treturn *it->second;\n\t}\n\n\t//*********************************************************************************************\n\n\tResourcesCache::ResourcesCache( ResourceHandler & handler )\n\t\t: m_handler{ handler }\n\t{\n\t}\n\n\tVkBuffer ResourcesCache::createBuffer( GraphContext & context\n\t\t, BufferId const & bufferId\n\t\t, VkDeviceMemory & memory )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createBuffer( bufferId, memory );\n\t}\n\n\tVkBuffer ResourcesCache::createBuffer( GraphContext & context\n\t\t, BufferId const & bufferId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createBuffer( bufferId );\n\t}\n\n\tVkBufferView ResourcesCache::createBufferView( GraphContext & context\n\t\t, BufferViewId const & viewId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createBufferView( viewId );\n\t}\n\n\tbool ResourcesCache::destroyBuffer( BufferId const & bufferId )\n\t{\n\t\tauto it = std::find_if( m_caches.begin()\n\t\t\t, m_caches.end()\n\t\t\t, [&bufferId]( ContextCacheMap::value_type & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.second.destroyBuffer( bufferId );\n\t\t\t} );\n\t\treturn it != m_caches.end();\n\t}\n\n\tbool ResourcesCache::destroyBufferView( BufferViewId const & viewId )\n\t{\n\t\tauto it = std::find_if( m_caches.begin()\n\t\t\t, m_caches.end()\n\t\t\t, [&viewId]( ContextCacheMap::value_type & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.second.destroyBufferView( viewId );\n\t\t\t} );\n\t\treturn it != m_caches.end();\n\t}\n\n\tbool ResourcesCache::destroyBuffer( GraphContext & context\n\t\t, BufferId const & bufferId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.destroyBuffer( bufferId );\n\t}\n\n\tbool ResourcesCache::destroyBufferView( GraphContext & context\n\t\t, BufferViewId const & viewId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.destroyBufferView( viewId );\n\t}\n\n\tVkImage ResourcesCache::createImage( GraphContext & context\n\t\t, ImageId const & imageId\n\t\t, VkDeviceMemory & memory )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createImage( imageId, memory );\n\t}\n\n\tVkImage ResourcesCache::createImage( GraphContext & context\n\t\t, ImageId const & imageId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createImage( imageId );\n\t}\n\n\tVkImageView ResourcesCache::createImageView( GraphContext & context\n\t\t, ImageViewId const & viewId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createImageView( viewId );\n\t}\n\n\tbool ResourcesCache::destroyImage( ImageId const & imageId )\n\t{\n\t\tauto it = std::find_if( m_caches.begin()\n\t\t\t, m_caches.end()\n\t\t\t, [&imageId]( ContextCacheMap::value_type & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.second.destroyImage( imageId );\n\t\t\t} );\n\t\treturn it != m_caches.end();\n\t}\n\n\tbool ResourcesCache::destroyImageView( ImageViewId const & viewId )\n\t{\n\t\tauto it = std::find_if( m_caches.begin()\n\t\t\t, m_caches.end()\n\t\t\t, [&viewId]( ContextCacheMap::value_type & lookup )\n\t\t\t{\n\t\t\t\treturn lookup.second.destroyImageView( viewId );\n\t\t\t} );\n\t\treturn it != m_caches.end();\n\t}\n\n\tbool ResourcesCache::destroyImage( GraphContext & context\n\t\t, ImageId const & imageId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.destroyImage( imageId );\n\t}\n\n\tbool ResourcesCache::destroyImageView( GraphContext & context\n\t\t, ImageViewId const & viewId )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.destroyImageView( viewId );\n\t}\n\n\tVkSampler ResourcesCache::createSampler( GraphContext & context\n\t\t, SamplerDesc const & samplerDesc )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createSampler( samplerDesc );\n\t}\n\n\tVertexBuffer const & ResourcesCache::createQuadTriVertexBuffer( GraphContext & context\n\t\t, bool texCoords\n\t\t, Texcoord const & config )\n\t{\n\t\tauto & cache = getContextCache( context );\n\t\treturn cache.createQuadTriVertexBuffer( texCoords, config );\n\t}\n\n\tContextResourcesCache & ResourcesCache::getContextCache( GraphContext & context )\n\t{\n\t\tauto it = m_caches.find( &context );\n\n\t\tif ( it == m_caches.end() )\n\t\t{\n\t\t\tit = m_caches.try_emplace( &context, m_handler, context ).first;\n\t\t}\n\n\t\treturn it->second;\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnableGraph.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnableGraph.hpp\"\n#include \"RenderGraph/GraphVisitor.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/ResourceHandler.hpp\"\n\n#include <array>\n#include <cassert>\n#include <string>\n#include <type_traits>\n#include <unordered_set>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <fstream>\n#pragma warning( pop )\n\n#pragma GCC diagnostic ignored \"-Wnull-dereference\"\n\nnamespace crg\n{\n\t//************************************************************************************************\n\n\tnamespace rungrf\n\t{\n\t\tstatic VkCommandPool createCommandPool( GraphContext & context\n\t\t\t, std::string const & name )\n\t\t{\n\t\t\tVkCommandPool result{};\n\n\t\t\tif ( context.vkCreateCommandPool )\n\t\t\t{\n\t\t\t\tVkCommandPoolCreateInfo createInfo{ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO\n\t\t\t\t\t, nullptr\n\t\t\t\t\t, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT\n\t\t\t\t\t, 0 };\n\t\t\t\tauto res = context.vkCreateCommandPool( context.device\n\t\t\t\t\t, &createInfo\n\t\t\t\t\t, context.allocator\n\t\t\t\t\t, &result );\n\t\t\t\tcheckVkResult( res, name + \" - CommandPool creation\" );\n\t\t\t\tcrgRegisterObject( context, name, result );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void mergeMipRanges( LayerLayoutStates const & nextLayout\n\t\t\t, uint32_t currentLayout\n\t\t\t, MipLayoutStates const & curStates\n\t\t\t, LayerLayoutStates & result )\n\t\t{\n\t\t\tif ( auto nextLayerIt = nextLayout.find( currentLayout );\n\t\t\t\tnextLayerIt != nextLayout.end() )\n\t\t\t{\n\t\t\t\tauto resLayerIt = result.try_emplace( currentLayout ).first;\n\n\t\t\t\tfor ( auto & [curLevel, _] : curStates )\n\t\t\t\t{\n\t\t\t\t\tif ( auto nextLevelIt = nextLayerIt->second.find( curLevel );\n\t\t\t\t\t\tnextLevelIt != nextLayerIt->second.end() )\n\t\t\t\t\t\tresLayerIt->second.emplace( *nextLevelIt );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstatic LayerLayoutStates mergeRanges( LayerLayoutStatesMap const & nextLayouts\n\t\t\t, LayerLayoutStatesMap::value_type const & currentLayout )\n\t\t{\n\t\t\tLayerLayoutStates result;\n\n\t\t\tif ( auto nextIt = nextLayouts.find( currentLayout.first );\n\t\t\t\tnextIt != nextLayouts.end() )\n\t\t\t{\n\t\t\t\tauto & nxtLayout = nextIt->second;\n\n\t\t\t\tfor ( auto & [curLayout, curStates] : currentLayout.second )\n\t\t\t\t\tmergeMipRanges( nxtLayout, curLayout, curStates, result );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic LayerLayoutStatesMap gatherNextImageLayouts( LayerLayoutStatesMap currentLayouts\n\t\t\t, std::vector< RunnablePassPtr >::iterator nextPassIt\n\t\t\t, std::vector< RunnablePassPtr >::iterator endIt )\n\t\t{\n\t\t\tLayerLayoutStatesMap result;\n\n\t\t\twhile ( !currentLayouts.empty()\n\t\t\t\t&& endIt != nextPassIt )\n\t\t\t{\n\t\t\t\tif ( auto const & nextPass = **nextPassIt;\n\t\t\t\t\tnextPass.isEnabled() )\n\t\t\t\t{\n\t\t\t\t\tauto & nextLayouts = nextPass.getImageLayouts();\n\t\t\t\t\tLayerLayoutStates layoutStates;\n\t\t\t\t\tauto currIt = std::find_if( currentLayouts.begin()\n\t\t\t\t\t\t, currentLayouts.end()\n\t\t\t\t\t\t, [&nextLayouts, &layoutStates]( LayerLayoutStatesMap::value_type const & lookup )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlayoutStates = mergeRanges( nextLayouts, lookup );\n\t\t\t\t\t\t\treturn !layoutStates.empty();\n\t\t\t\t\t\t} );\n\n\t\t\t\t\tif ( currIt != currentLayouts.end() )\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.try_emplace( currIt->first, layoutStates );\n\t\t\t\t\t\tcurrentLayouts.erase( currIt );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t++nextPassIt;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic PipelineState getNextState( PipelineState currentState\n\t\t\t, std::vector< RunnablePassPtr >::iterator nextPassIt\n\t\t\t, std::vector< RunnablePassPtr >::iterator endIt )\n\t\t{\n\t\t\twhile ( endIt != nextPassIt\n\t\t\t\t&& !( *nextPassIt )->isEnabled() )\n\t\t\t{\t\n\t\t\t\t++nextPassIt;\n\t\t\t}\n\n\t\t\treturn ( endIt != nextPassIt && ( *nextPassIt )->isEnabled() )\n\t\t\t\t? ( *nextPassIt )->getPipelineState()\n\t\t\t\t: currentState;\n\t\t}\n\n\t\tstatic VkDescriptorType getDescriptorType( BufferAttachment const & attach )\n\t\t{\n\t\t\tif ( attach.isUniformView() )\n\t\t\t\treturn VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;\n\t\t\tif ( attach.isStorageView() )\n\t\t\t\treturn VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;\n\t\t\tif ( attach.isUniform() )\n\t\t\t\treturn VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n\t\t\treturn VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\t}\n\n\t\tstatic VkDescriptorType getDescriptorType( ImageAttachment const & attach )\n\t\t{\n\t\t\tif ( attach.isStorageView() )\n\t\t\t\treturn VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;\n\t\t\treturn VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\t\t}\n\n\t\tstatic WriteDescriptorSet getWrite( ImageAttachment const & attach\n\t\t\t, SamplerDesc const & samplerDesc\n\t\t\t, uint32_t binding\n\t\t\t, uint32_t count\n\t\t\t, uint32_t index\n\t\t\t, RunnableGraph & graph )\n\t\t{\n\t\t\tWriteDescriptorSet result{ binding\n\t\t\t\t, 0u\n\t\t\t\t, count\n\t\t\t\t, getDescriptorType( attach ) };\n\t\t\tVkSampler sampler = attach.isSampledView()\n\t\t\t\t? graph.createSampler( samplerDesc )\n\t\t\t\t: VkSampler{};\n\t\t\tVkImageLayout layout = attach.isSampledView()\n\t\t\t\t? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\n\t\t\t\t: VK_IMAGE_LAYOUT_GENERAL;\n\t\t\tVkDescriptorImageInfo info{ sampler\n\t\t\t\t, graph.createImageView( attach.view( index ) )\n\t\t\t\t, layout };\n\t\t\tresult.imageInfo.push_back( info );\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic WriteDescriptorSet getWrite( BufferAttachment const & attach\n\t\t\t, uint32_t binding\n\t\t\t, uint32_t count\n\t\t\t, uint32_t index\n\t\t\t, RunnableGraph & graph )\n\t\t{\n\t\t\tWriteDescriptorSet result{ binding\n\t\t\t\t, 0u\n\t\t\t\t, count\n\t\t\t\t, getDescriptorType( attach ) };\n\t\t\tauto bufferViewId = attach.buffer( index );\n\t\t\tVkDescriptorBufferInfo info{ graph.createBuffer( bufferViewId.data->buffer )\n\t\t\t\t, getSubresourceRange( bufferViewId ).offset\n\t\t\t\t, getSubresourceRange( bufferViewId ).size };\n\n\t\t\tif ( attach.isView() )\n\t\t\t{\n\t\t\t\tresult.bufferViewInfo.push_back( info );\n\t\t\t\tresult.texelBufferView.push_back( graph.createBufferView( bufferViewId ) );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.bufferInfo.push_back( info );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t//************************************************************************************************\n\n\tVkQueryPool createQueryPool( GraphContext & context\n\t\t, std::string const & name\n\t\t, uint32_t passesCount )\n\t{\n\t\tVkQueryPool result{};\n\n\t\tif ( context.vkCreateQueryPool )\n\t\t{\n\t\t\tVkQueryPoolCreateInfo createInfo{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, VK_QUERY_TYPE_TIMESTAMP\n\t\t\t\t, passesCount\n\t\t\t\t, 0u };\n\t\t\tauto res = context.vkCreateQueryPool( context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, context.allocator\n\t\t\t\t, &result );\n\t\t\tcheckVkResult( res, name + \" - VkQueryPool creation\" );\n\t\t\tcrgRegisterObject( context, name, result );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t//************************************************************************************************\n\n\tRunnableGraph::RunnableGraph( FrameGraph & graph\n\t\t, GraphNodePtrArray nodes\n\t\t, RootNode rootNode\n\t\t, GraphContext & context )\n\t\t: m_graph{ graph }\n\t\t, m_context{ context }\n\t\t, m_resources{ m_graph.getHandler(), m_context }\n\t\t, m_nodes{ std::move( nodes ) }\n\t\t, m_rootNode{ std::move( rootNode ) }\n\t\t, m_timerQueries{ m_context\n\t\t\t, createQueryPool( m_context, m_graph.getName() + \"TimerQueries\", uint32_t( ( m_nodes.size() + 1u ) * 2u * 2u ) )\n\t\t\t, []( GraphContext & ctx, VkQueryPool & object )noexcept\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( ctx, object );\n\t\t\t\tctx.vkDestroyQueryPool( ctx.device, object, ctx.allocator );\n\t\t\t\tobject = {};\n\t\t\t} }\n\t\t, m_commandPool{ m_context\n\t\t\t, rungrf::createCommandPool( m_context, m_graph.getName() )\n\t\t\t, []( GraphContext & ctx, VkCommandPool & object )noexcept\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( ctx, object );\n\t\t\t\tctx.vkDestroyCommandPool( ctx.device, object, ctx.allocator );\n\t\t\t\tobject = {};\n\t\t\t} }\n\t\t, m_fence{ m_context\n\t\t\t, graph.getName() + \"/Graph\"\n\t\t\t, { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT } }\n\t\t, m_timer{ context, graph.getName() + \"/Graph\", TimerScope::eGraph, getTimerQueryPool(), getTimerQueryOffset() }\n\t{\n\t\tauto name = m_graph.getName() + \"/Graph\";\n\n\t\tif ( m_context.vkCreateSemaphore )\n\t\t{\n\t\t\tVkSemaphoreCreateInfo createInfo{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u };\n\t\t\tauto res = context.vkCreateSemaphore( m_context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &m_semaphore );\n\t\t\tcheckVkResult( res, name + \" - Semaphore creation\" );\n\t\t\tcrgRegisterObject( m_context, name, m_semaphore );\n\t\t}\n\n\t\tif ( m_context.vkAllocateCommandBuffers )\n\t\t{\n\t\t\tVkCommandBufferAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, getCommandPool()\n\t\t\t\t, VK_COMMAND_BUFFER_LEVEL_PRIMARY\n\t\t\t\t, 1u };\n\t\t\tauto res = m_context.vkAllocateCommandBuffers( m_context.device\n\t\t\t\t, &allocateInfo\n\t\t\t\t, &m_commandBuffer );\n\t\t\tcheckVkResult( res, name + \" - CommandBuffer allocation\" );\n\t\t\tcrgRegisterObject( m_context, name, m_commandBuffer );\n\n\t\t\tVkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\n\t\t\t\t, nullptr };\n\t\t\tm_context.vkBeginCommandBuffer( m_commandBuffer, &beginInfo );\n\t\t\tm_context.vkEndCommandBuffer( m_commandBuffer );\n\t\t}\n\n\t\tLogger::logDebug( m_graph.getName() + \" - Initialising resources\" );\n\n\t\tfor ( auto & img : m_graph.m_images )\n\t\t{\n\t\t\tm_resources.createImage( img );\n\t\t}\n\n\t\tfor ( auto & view : m_graph.m_imageViews )\n\t\t{\n\t\t\tm_resources.createImageView( view );\n\t\t}\n\n\t\tLogger::logDebug( m_graph.getName() + \" - Creating runnable passes\" );\n\n\t\tfor ( auto const & node : m_nodes )\n\t\t{\n\t\t\tif ( node->getKind() == GraphNode::Kind::FramePass )\n\t\t\t{\n\t\t\t\tauto const & renderPassNode = nodeCast< FramePassNode >( *node );\n\t\t\t\tm_passes.push_back( renderPassNode.getFramePass().createRunnable( m_context\n\t\t\t\t\t, *this ) );\n\t\t\t}\n\t\t}\n\n\t\tLogger::logDebug( m_graph.getName() + \" - Initialising passes\" );\n\n\t\tfor ( auto const & pass : m_passes )\n\t\t{\n\t\t\tif ( pass->isEnabled() )\n\t\t\t{\n\t\t\t\tpass->initialise( pass->getIndex() );\n\t\t\t}\n\t\t}\n\t}\n\n\tRunnableGraph::~RunnableGraph()noexcept\n\t{\n\t\tif ( m_context.vkDestroySemaphore && m_semaphore )\n\t\t{\n\t\t\tcrgUnregisterObject( m_context, m_semaphore );\n\t\t\tm_context.vkDestroySemaphore( m_context.device\n\t\t\t\t, m_semaphore\n\t\t\t\t, m_context.allocator );\n\t\t}\n\n\t\tif ( m_context.vkFreeCommandBuffers && m_commandBuffer )\n\t\t{\n\t\t\tcrgUnregisterObject( m_context, m_commandBuffer );\n\t\t\tm_context.vkFreeCommandBuffers( m_context.device\n\t\t\t\t, getCommandPool()\n\t\t\t\t, 1u\n\t\t\t\t, &m_commandBuffer );\n\t\t}\n\t}\n\n\tvoid RunnableGraph::record()\n\t{\n\t\tauto block( m_timer.start() );\n\t\tm_states.clear();\n\t\tRecordContext recordContext{ m_resources };\n\n\t\tfor ( auto & dependency : m_graph.getDependencies() )\n\t\t{\n\t\t\trecordContext.addStates( dependency->getFinalStates() );\n\t\t\tm_states.try_emplace( dependency\n\t\t\t\t, dependency->getFinalStates().getIndexState() );\n\t\t}\n\n\t\tauto itGraph = m_states.try_emplace( &m_graph ).first;\n\t\titGraph->second.resize( m_passes.size() );\n\n\t\tif ( !m_passes.empty() )\n\t\t{\n\t\t\tauto it = itGraph->second.begin();\n\t\t\tauto currPass = m_passes.begin();\n\t\t\trecordContext.setNextPipelineState( ( *currPass )->getPipelineState()\n\t\t\t\t, ( *currPass )->getImageLayouts() );\n\t\t\tauto nextPass = std::next( currPass );\n\t\t\tm_fence.wait( 0xFFFFFFFFFFFFFFFFULL );\n\t\t\tm_context.vkResetCommandBuffer( m_commandBuffer, 0u );\n\t\t\tVkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\n\t\t\t\t, nullptr };\n\t\t\tm_context.vkBeginCommandBuffer( m_commandBuffer, &beginInfo );\n\t\t\tm_timer.beginPass( m_commandBuffer, getName(), 0u );\n\n\t\t\twhile ( currPass != m_passes.end() )\n\t\t\t{\n\t\t\t\tauto const & pass = *currPass;\n\t\t\t\t++currPass;\n\n\t\t\t\tif ( nextPass != m_passes.end() )\n\t\t\t\t{\n\t\t\t\t\trecordContext.setNextPipelineState( rungrf::getNextState( pass->getPipelineState(), nextPass, m_passes.end() )\n\t\t\t\t\t\t, rungrf::gatherNextImageLayouts( pass->getImageLayouts(), nextPass, m_passes.end() ) );\n\t\t\t\t\t++nextPass;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\trecordContext.setNextPipelineState( pass->getPipelineState()\n\t\t\t\t\t\t, m_graph.getOutputLayoutStates() );\n\t\t\t\t}\n\n\t\t\t\t*it = pass->recordCurrentInto( recordContext, m_commandBuffer );\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_timer.endPass( m_commandBuffer );\n\t\t\tm_context.vkEndCommandBuffer( m_commandBuffer );\n\t\t}\n\n\t\tm_graph.registerFinalState( recordContext );\n\t}\n\n\tSemaphoreWaitArray RunnableGraph::run( VkQueue queue )\n\t{\n\t\treturn run( SemaphoreWaitArray{}\n\t\t\t, queue );\n\t}\n\n\tSemaphoreWaitArray RunnableGraph::run( SemaphoreWait toWait\n\t\t, VkQueue queue )\n\t{\n\t\treturn run( ( toWait.semaphore\n\t\t\t\t? SemaphoreWaitArray{ 1u, toWait }\n\t\t\t\t: SemaphoreWaitArray{} )\n\t\t\t, queue );\n\t}\n\n\tSemaphoreWaitArray RunnableGraph::run( SemaphoreWaitArray const & toWait\n\t\t, VkQueue queue )\n\t{\n\t\trecord();\n\t\tstd::vector< VkSemaphore > semaphores;\n\t\tstd::vector< VkPipelineStageFlags > dstStageMasks;\n\t\tconvert( toWait, semaphores, dstStageMasks );\n\t\tm_timer.notifyPassRender();\n\n\t\tfor ( auto const & pass : m_passes )\n\t\t{\n\t\t\tpass->notifyPassRender();\n\t\t}\n\n\t\tVkSubmitInfo submitInfo{ VK_STRUCTURE_TYPE_SUBMIT_INFO\n\t\t\t, nullptr\n\t\t\t, uint32_t( semaphores.size() )\n\t\t\t, semaphores.data()\n\t\t\t, dstStageMasks.data()\n\t\t\t, 1u\n\t\t\t, &m_commandBuffer\n\t\t\t, 1u\n\t\t\t, &m_semaphore };\n\t\tm_fence.reset();\n\t\tm_context.delQueue.clear( m_context );\n\t\tm_context.vkQueueSubmit( queue\n\t\t\t, 1u\n\t\t\t, &submitInfo\n\t\t\t, m_fence.getInternal() );\n\t\treturn { SemaphoreWait{ m_semaphore\n\t\t\t, m_graph.getFinalStates().getCurrPipelineState().pipelineStage } };\n\t}\n\n\tVkBuffer RunnableGraph::createBuffer( BufferId const & buffer )\n\t{\n\t\treturn m_resources.createBuffer( buffer );\n\t}\n\n\tVkBufferView RunnableGraph::createBufferView( BufferViewId const & view )\n\t{\n\t\treturn m_resources.createBufferView( view );\n\t}\n\n\tVkImage RunnableGraph::createImage( ImageId const & image )\n\t{\n\t\treturn m_resources.createImage( image );\n\t}\n\n\tVkImageView RunnableGraph::createImageView( ImageViewId const & view )\n\t{\n\t\treturn m_resources.createImageView( view );\n\t}\n\n\tVkSampler RunnableGraph::createSampler( SamplerDesc const & samplerDesc )\n\t{\n\t\treturn m_resources.createSampler( samplerDesc );\n\t}\n\n\tVertexBuffer const & RunnableGraph::createQuadTriVertexBuffer( bool texCoords\n\t\t, Texcoord const & config )\n\t{\n\t\treturn m_resources.createQuadTriVertexBuffer( texCoords\n\t\t\t, config );\n\t}\n\n\tLayoutState RunnableGraph::getCurrentLayoutState( RecordContext & context\n\t\t, ImageId image\n\t\t, ImageViewType viewType\n\t\t, ImageSubresourceRange range )const\n\t{\n\t\tauto result = context.getLayoutState( image, viewType, range );\n\n\t\tif ( result.layout == ImageLayout::eUndefined )\n\t\t{\n\t\t\t// Lookup in graph's external inputs.\n\t\t\tresult = m_graph.getInputLayoutState( image, viewType, range );\n\n\t\t\tif ( result.layout != ImageLayout::eUndefined )\n\t\t\t{\n\t\t\t\tcontext.setLayoutState( image, viewType, range, result );\n\t\t\t}\n\t\t}\n\n\t\tif ( result.layout == ImageLayout::eUndefined )\n\t\t{\n\t\t\t// Lookup in graph's previous final state.\n\t\t\tresult = m_graph.getFinalLayoutState( image, viewType, range );\n\n\t\t\tif ( result.layout != ImageLayout::eUndefined )\n\t\t\t{\n\t\t\t\tcontext.setLayoutState( image, viewType, range, result );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tLayoutState RunnableGraph::getCurrentLayoutState( RecordContext & context\n\t\t, ImageViewId view )const\n\t{\n\t\treturn getCurrentLayoutState( context\n\t\t\t, view.data->image\n\t\t\t, view.data->info.viewType\n\t\t\t, getSubresourceRange( view ) );\n\t}\n\n\tLayoutState RunnableGraph::getNextLayoutState( RecordContext const & context\n\t\t, crg::RunnablePass const & runnable\n\t\t, ImageViewId view )const\n\t{\n\t\tauto result = context.getNextLayoutState( view );\n\n\t\tif ( result.layout == ImageLayout::eUndefined )\n\t\t{\n\t\t\t// Next layout undefined means that there is no pass after this one in the graph.\n\t\t\tresult = getOutputLayoutState( view );\n\t\t}\n\n\t\tif ( result.layout == ImageLayout::eUndefined )\n\t\t{\n\t\t\t// Prevent from outputing a ImageLayout::eUndefined anyway.\n\t\t\tresult = runnable.getLayoutState( view );\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tLayoutState RunnableGraph::getOutputLayoutState( ImageViewId view )const\n\t{\n\t\treturn m_graph.getOutputLayoutState( view );\n\t}\n\n\tVkDescriptorType RunnableGraph::getDescriptorType( Attachment const & attach )const\n\t{\n\t\tif ( attach.isImage() )\n\t\t\treturn rungrf::getDescriptorType( attach.imageAttach );\n\t\treturn rungrf::getDescriptorType( attach.bufferAttach );\n\t}\n\n\tWriteDescriptorSet RunnableGraph::getDescriptorWrite( Attachment const & attach, uint32_t binding, uint32_t index )\n\t{\n\t\tif ( attach.isImage() )\n\t\t\treturn rungrf::getWrite( attach.imageAttach, SamplerDesc{}, binding, 1u, index, *this );\n\t\treturn rungrf::getWrite( attach.bufferAttach, binding, 1u, index, *this );\n\t}\n\n\tWriteDescriptorSet RunnableGraph::getDescriptorWrite( Attachment const & attach, SamplerDesc const & samplerDesc, uint32_t binding, uint32_t index )\n\t{\n\t\tassert( attach.isImage() );\n\t\treturn rungrf::getWrite( attach.imageAttach, samplerDesc, binding, 1u, index, *this );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePass.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePass.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <cassert>\n\n#pragma warning( push )\n#pragma warning( disable: 5262 )\n#include <thread>\n#pragma warning( pop )\n\nnamespace crg\n{\n\tnamespace details\n\t{\n\t\tstatic constexpr DeviceSize getAlignedSize( DeviceSize size, DeviceSize align )\n\t\t{\n\t\t\tauto rem = size % align;\n\t\t\treturn ( rem\n\t\t\t\t? size + ( align - rem )\n\t\t\t\t: size );\n\t\t}\n\n\t\tstatic void registerImage( Attachment const & attach\n\t\t\t, bool isComputePass, bool separateDepthStencilLayouts\n\t\t\t, LayerLayoutStatesHandler & imageLayouts )\n\t\t{\n\t\t\tfor ( uint32_t i = 0u; i < attach.getViewCount(); ++i )\n\t\t\t{\n\t\t\t\tauto view = attach.view( i );\n\n\t\t\t\tif ( view.data->source.empty() )\n\t\t\t\t{\n\t\t\t\t\timageLayouts.setLayoutState( view\n\t\t\t\t\t\t, { attach.getImageLayout( separateDepthStencilLayouts )\n\t\t\t\t\t\t\t, attach.getAccessMask()\n\t\t\t\t\t\t\t, attach.getPipelineStageFlags( isComputePass ) } );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor ( auto & source : view.data->source )\n\t\t\t\t\t{\n\t\t\t\t\t\timageLayouts.setLayoutState( source\n\t\t\t\t\t\t\t, { attach.getImageLayout( separateDepthStencilLayouts )\n\t\t\t\t\t\t\t\t, attach.getAccessMask()\n\t\t\t\t\t\t\t\t, attach.getPipelineStageFlags( isComputePass ) } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstatic void registerBuffer( Attachment const & attach\n\t\t\t, bool isComputePass\n\t\t\t, AccessStateMap & bufferAccesses )\n\t\t{\n\t\t\tfor ( uint32_t i = 0u; i < attach.getBufferCount(); ++i )\n\t\t\t{\n\t\t\t\tbufferAccesses.insert_or_assign( attach.buffer( i ).data->buffer.id\n\t\t\t\t\t, AccessState{ attach.getAccessMask()\n\t\t\t\t\t\t, attach.getPipelineStageFlags( isComputePass ) } );\n\t\t\t}\n\t\t}\n\n\t\tstatic void registerResources( FramePass const & pass\n\t\t\t, RunnablePass::Callbacks const & callbacks\n\t\t\t, GraphContext const & graphContext\n\t\t\t, LayerLayoutStatesHandler & imageLayouts\n\t\t\t, AccessStateMap & bufferAccesses )\n\t\t{\n\t\t\tbool isComputePass = callbacks.isComputePass();\n\t\t\tfor ( auto & [binding, attach] : pass.getUniforms() )\n\t\t\t\tregisterBuffer( *attach, isComputePass, bufferAccesses );\n\t\t\tfor ( auto & [binding, attach] : pass.getSampled() )\n\t\t\t\tregisterImage( *attach.attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts );\n\t\t\tfor ( auto & [binding, attach] : pass.getInputs() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tregisterImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts );\n\t\t\t\telse\n\t\t\t\t\tregisterBuffer( *attach, isComputePass, bufferAccesses );\n\t\t\tfor ( auto & [binding, attach] : pass.getInouts() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tregisterImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts );\n\t\t\t\telse\n\t\t\t\t\tregisterBuffer( *attach, isComputePass, bufferAccesses );\n\t\t\tfor ( auto & [binding, attach] : pass.getOutputs() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tregisterImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts );\n\t\t\t\telse\n\t\t\t\t\tregisterBuffer( *attach, isComputePass, bufferAccesses );\n\t\t\tfor ( auto attach : pass.getTargets() )\n\t\t\t\tregisterImage( *attach, isComputePass, graphContext.separateDepthStencilLayouts, imageLayouts );\n\t\t}\n\n\t\tstatic void prepareImage( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, Attachment const & attach\n\t\t\t, bool separateDepthStencilLayouts\n\t\t\t, RunnableGraph & graph\n\t\t\t, RecordContext & recordContext )\n\t\t{\n\t\t\tauto view = attach.view( index );\n\t\t\trecordContext.runImplicitTransition( commandBuffer\n\t\t\t\t, index\n\t\t\t\t, view );\n\n\t\t\tif ( !attach.isNoTransition()\n\t\t\t\t&& ( attach.isSampledImageView() || attach.isStorageImageView() || attach.isTransferImageView() || attach.isTransitionImageView() ) )\n\t\t\t{\n\t\t\t\tauto needed = makeLayoutState( attach.getImageLayout( separateDepthStencilLayouts ) );\n\t\t\t\tauto currentLayout = ( !attach.isInput()\n\t\t\t\t\t? crg::makeLayoutState( ImageLayout::eUndefined )\n\t\t\t\t\t: graph.getCurrentLayoutState( recordContext, view ) );\n\t\t\t\tcheckUndefinedInput( \"Record\", attach, view, currentLayout.layout );\n\n\t\t\t\tif ( attach.isClearableImage() )\n\t\t\t\t{\n\t\t\t\t\trecordContext.memoryBarrier( commandBuffer\n\t\t\t\t\t\t, view\n\t\t\t\t\t\t, currentLayout.layout\n\t\t\t\t\t\t, makeLayoutState( ImageLayout::eTransferDst ) );\n\t\t\t\t\tauto subresourceRange = convert( getSubresourceRange( view ) );\n\n\t\t\t\t\tif ( isColourFormat( getFormat( view ) ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tVkClearColorValue colour{};\n\t\t\t\t\t\trecordContext->vkCmdClearColorImage( commandBuffer\n\t\t\t\t\t\t\t, graph.createImage( view.data->image )\n\t\t\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t\t\t\t, &colour\n\t\t\t\t\t\t\t, 1u, &subresourceRange );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tVkClearDepthStencilValue depthStencil{};\n\t\t\t\t\t\trecordContext->vkCmdClearDepthStencilImage( commandBuffer\n\t\t\t\t\t\t\t, graph.createImage( view.data->image )\n\t\t\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t\t\t\t, &depthStencil\n\t\t\t\t\t\t\t, 1u, &subresourceRange );\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentLayout.layout = ImageLayout::eTransferDst;\n\t\t\t\t\tcurrentLayout.state.access = AccessFlags::eTransferWrite;\n\t\t\t\t\tcurrentLayout.state.pipelineStage = PipelineStageFlags::eTransfer;\n\t\t\t\t}\n\n\t\t\t\trecordContext.memoryBarrier( commandBuffer\n\t\t\t\t\t, view\n\t\t\t\t\t, currentLayout.layout\n\t\t\t\t\t, needed );\n\t\t\t}\n\t\t}\n\n\t\tstatic void prepareBuffer( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, Attachment const & attach\n\t\t\t, bool isComputePass\n\t\t\t, RunnableGraph & graph\n\t\t\t, RecordContext & recordContext )\n\t\t{\n\t\t\tauto view = attach.buffer( index );\n\t\t\trecordContext.runImplicitTransition( commandBuffer\n\t\t\t\t, index\n\t\t\t\t, view );\n\n\t\t\tif ( !attach.isNoTransition()\n\t\t\t\t&& ( attach.isStorageBuffer() || attach.isTransferBuffer() || attach.isTransitionBuffer() ) )\n\t\t\t{\n\t\t\t\tauto buffer = view.data->buffer;\n\t\t\t\tauto & range = getSubresourceRange( view );\n\t\t\t\tauto currentState = recordContext.getAccessState( view );\n\n\t\t\t\tif ( attach.isClearableBuffer() )\n\t\t\t\t{\n\t\t\t\t\trecordContext.memoryBarrier( commandBuffer\n\t\t\t\t\t\t, buffer\n\t\t\t\t\t\t, range\n\t\t\t\t\t\t, currentState\n\t\t\t\t\t\t, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } );\n\t\t\t\t\trecordContext->vkCmdFillBuffer( commandBuffer\n\t\t\t\t\t\t, graph.createBuffer( buffer )\n\t\t\t\t\t\t, range.offset == 0u ? 0u : details::getAlignedSize( range.offset, 4u )\n\t\t\t\t\t\t, range.size == VK_WHOLE_SIZE ? VK_WHOLE_SIZE : details::getAlignedSize( range.size, 4u )\n\t\t\t\t\t\t, 0u );\n\t\t\t\t\tcurrentState.access = AccessFlags::eTransferWrite;\n\t\t\t\t\tcurrentState.pipelineStage = PipelineStageFlags::eTransfer;\n\t\t\t\t}\n\n\t\t\t\trecordContext.memoryBarrier( commandBuffer\n\t\t\t\t\t, buffer\n\t\t\t\t\t, range\n\t\t\t\t\t, currentState\n\t\t\t\t\t, { attach.getAccessMask(), attach.getPipelineStageFlags( isComputePass ) } );\n\t\t\t}\n\t\t}\n\n\t\tstatic void prepareResources( VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index\n\t\t\t, RecordContext & recordContext\n\t\t\t, RunnableGraph & graph\n\t\t\t, FramePass const & pass\n\t\t\t, RunnablePass::Callbacks const & callbacks\n\t\t\t, GraphContext const & graphContext )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : pass.getSampled() )\n\t\t\t\tprepareImage( commandBuffer, index, *attach.attach, graphContext.separateDepthStencilLayouts, graph, recordContext );\n\t\t\tfor ( auto & [binding, attach] : pass.getUniforms() )\n\t\t\t\tprepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext );\n\t\t\tfor ( auto & [binding, attach] : pass.getInputs() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tprepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext );\n\t\t\t\telse\n\t\t\t\t\tprepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext );\n\t\t\tfor ( auto & [binding, attach] : pass.getInouts() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tprepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext );\n\t\t\t\telse\n\t\t\t\t\tprepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext );\n\t\t\tfor ( auto & [binding, attach] : pass.getOutputs() )\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t\tprepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext );\n\t\t\t\telse\n\t\t\t\t\tprepareBuffer( commandBuffer, index, *attach, callbacks.isComputePass(), graph, recordContext );\n\t\t\tfor ( auto & attach : pass.getTargets() )\n\t\t\t\tprepareImage( commandBuffer, index, *attach, graphContext.separateDepthStencilLayouts, graph, recordContext );\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tvoid checkUndefinedInput( std::string const & stepName\n\t\t, Attachment const & attach\n\t\t, ImageViewId const & view\n\t\t, ImageLayout currentLayout )\n\t{\n\t\tif ( !attach.isTransitionImageView() && attach.isInput() && currentLayout == ImageLayout::eUndefined )\n\t\t{\n\t\t\tauto passName = attach.pass ? attach.pass->getFullName() : attach.source.front().pass->getFullName();\n\t\t\tLogger::logWarning( stepName + \" - [\" + passName + \"]: Input view [\" + view.data->name + \"] is currently in undefined layout\" );\n\t\t}\n\t}\n\n\tvoid convert( SemaphoreWaitArray const & toWait\n\t\t, std::vector< VkSemaphore > & semaphores\n\t\t, std::vector< VkPipelineStageFlags > & dstStageMasks )\n\t{\n\t\tfor ( auto & wait : toWait )\n\t\t{\n\t\t\tif ( wait.semaphore\n\t\t\t\t&& semaphores.end() == std::find( semaphores.begin()\n\t\t\t\t\t, semaphores.end()\n\t\t\t\t\t, wait.semaphore ) )\n\t\t\t{\n\t\t\t\tsemaphores.push_back( wait.semaphore );\n\t\t\t\tdstStageMasks.push_back( getPipelineStageFlags( wait.dstStageMask ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tRunnablePass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, GetPipelineStateCallback getPipelineState )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( getPipelineState )\n\t\t\t, getDefaultV< RecordCallback >()\n\t\t\t, getDefaultV< GetPassIndexCallback >()\n\t\t\t, getDefaultV< IsEnabledCallback >()\n\t\t\t, getDefaultV< IsComputePassCallback >() }\n\t{\n\t}\n\n\tRunnablePass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, GetPipelineStateCallback getPipelineState\n\t\t, RecordCallback record )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( getPipelineState )\n\t\t\t, std::move( record )\n\t\t\t, getDefaultV< GetPassIndexCallback >()\n\t\t\t, getDefaultV< IsEnabledCallback >()\n\t\t\t, getDefaultV< IsComputePassCallback >() }\n\t{\n\t}\n\n\tRunnablePass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, GetPipelineStateCallback getPipelineState\n\t\t, RecordCallback record\n\t\t, GetPassIndexCallback getPassIndex )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( getPipelineState )\n\t\t\t, std::move( record )\n\t\t\t, std::move( getPassIndex )\n\t\t\t, getDefaultV< IsEnabledCallback >()\n\t\t\t, getDefaultV< IsComputePassCallback >() }\n\t{\n\t}\n\n\tRunnablePass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, GetPipelineStateCallback getPipelineState\n\t\t, RecordCallback record\n\t\t, GetPassIndexCallback getPassIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( getPipelineState )\n\t\t\t, std::move( record )\n\t\t\t, std::move( getPassIndex )\n\t\t\t, std::move( isEnabled )\n\t\t\t, getDefaultV< IsComputePassCallback >() }\n\t{\n\t}\n\n\tRunnablePass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, GetPipelineStateCallback getPipelineState\n\t\t, RecordCallback record\n\t\t, GetPassIndexCallback getPassIndex\n\t\t, IsEnabledCallback isEnabled\n\t\t, IsComputePassCallback isComputePass )\n\t\t: initialise{ std::move( initialise ) }\n\t\t, getPipelineState{ std::move( getPipelineState ) }\n\t\t, record{ std::move( record ) }\n\t\t, getPassIndex{ std::move( getPassIndex ) }\n\t\t, isEnabled{ std::move( isEnabled ) }\n\t\t, isComputePass{ std::move( isComputePass ) }\n\t{\n\t}\n\n\t//*********************************************************************************************\n\n\tFence::Fence( GraphContext & context\n\t\t, std::string const & name\n\t\t, VkFenceCreateInfo createInfo )\n\t\t: m_context{ &context }\n\t{\n\t\tif ( m_context->vkCreateFence )\n\t\t{\n\t\t\tauto res = m_context->vkCreateFence( m_context->device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context->allocator\n\t\t\t\t, &m_fence );\n\t\t\tcheckVkResult( res, name + \" - Fence creation\" );\n\t\t\tcrgRegisterObject( *m_context, name, m_fence );\n\t\t}\n\t}\n\n\tFence::Fence( Fence && rhs )noexcept\n\t\t: m_context{ rhs.m_context }\n\t\t, m_fence{ rhs.m_fence }\n\t\t, m_fenceWaited{ rhs.m_fenceWaited }\n\t{\n\t\trhs.m_context = {};\n\t\trhs.m_fence = {};\n\t}\n\n\tFence::~Fence()noexcept\n\t{\n\t\tif ( m_fence && m_context && m_context->vkDestroyFence )\n\t\t{\n\t\t\tcrgUnregisterObject( *m_context, m_fence );\n\t\t\tm_context->vkDestroyFence( m_context->device\n\t\t\t\t, m_fence\n\t\t\t\t, m_context->allocator );\n\t\t}\n\t}\n\n\tvoid Fence::reset()\n\t{\n\t\tif ( m_fence )\n\t\t{\n\t\t\tif ( !m_fenceWaited )\n\t\t\t{\n\t\t\t\twait( 0xFFFFFFFFFFFFFFFFULL );\n\t\t\t}\n\n\t\t\tm_context->vkResetFences( m_context->device\n\t\t\t\t, 1u\n\t\t\t\t, &m_fence );\n\t\t}\n\n\t\tm_fenceWaited = false;\n\t}\n\n\tVkResult Fence::wait( uint64_t timeout )\n\t{\n\t\tVkResult res = VK_SUCCESS;\n\n\t\tif ( m_fence )\n\t\t{\n\t\t\tres = m_context->vkWaitForFences( m_context->device\n\t\t\t\t, 1u\n\t\t\t\t, &m_fence\n\t\t\t\t, VK_TRUE\n\t\t\t\t, timeout );\n\t\t}\n\n\t\tm_fenceWaited = true;\n\t\treturn res;\n\t}\n\n\t//*********************************************************************************************\n\n\tRunnablePass::PassData::PassData( RunnableGraph & grh\n\t\t, GraphContext & ctx\n\t\t, std::string const & baseName )\n\t\t: graph{ grh }\n\t\t, context{ ctx }\n\t\t, fence{ context, baseName, { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT } }\n\t{\n\t\tif ( context.vkCreateSemaphore )\n\t\t{\n\t\t\tVkSemaphoreCreateInfo createInfo{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u };\n\t\t\tauto res = context.vkCreateSemaphore( context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, context.allocator\n\t\t\t\t, &semaphore );\n\t\t\tcheckVkResult( res, baseName + \" - Semaphore creation\" );\n\t\t\tcrgRegisterObject( context, baseName, semaphore );\n\t\t}\n\t}\n\n\tRunnablePass::PassData::~PassData()noexcept\n\t{\n\t\tif ( context.vkDestroySemaphore && semaphore )\n\t\t{\n\t\t\tcrgUnregisterObject( context, semaphore );\n\t\t\tcontext.vkDestroySemaphore( context.device\n\t\t\t\t, semaphore\n\t\t\t\t, context.allocator );\n\t\t}\n\n\t\tif ( context.vkFreeCommandBuffers && commandBuffer.commandBuffer )\n\t\t{\n\t\t\tcrgUnregisterObject( context, commandBuffer.commandBuffer );\n\t\t\tcontext.vkFreeCommandBuffers( context.device\n\t\t\t\t, graph.getCommandPool()\n\t\t\t\t, 1u\n\t\t\t\t, &commandBuffer.commandBuffer );\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tRunnablePass::RunnablePass( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Callbacks callbacks\n\t\t, ru::Config ruConfig )\n\t\t: m_pass{ pass }\n\t\t, m_context{ context }\n\t\t, m_graph{ graph }\n\t\t, m_callbacks{ std::move( callbacks ) }\n\t\t, m_ruConfig{ std::move( ruConfig ) }\n\t\t, m_pipelineState{ m_callbacks.getPipelineState() }\n\t\t, m_timer{ context, pass.getGroupName(), TimerScope::ePass, graph.getTimerQueryPool(), graph.getTimerQueryOffset() }\n\t{\n\t\tfor ( uint32_t i = 0u; i < m_ruConfig.maxPassCount; ++i )\n\t\t{\n\t\t\tm_passes.emplace_back( m_graph, m_context, m_pass.getGroupName() );\n\t\t\tm_passContexts.emplace_back( graph.getResources() );\n\t\t}\n\n\t\tdetails::registerResources( pass, m_callbacks, m_context\n\t\t\t, m_imageLayouts, m_bufferAccesses );\n\t}\n\n\tRunnablePass::~RunnablePass()noexcept\n\t{\n\t\tm_bufferAccesses.clear();\n\t\tm_passContexts.clear();\n\t\tm_passes.clear();\n\t}\n\n\tvoid RunnablePass::initialise( uint32_t passIndex )\n\t{\n\t\tassert( m_passes.size() > passIndex );\n\t\tauto & pass = m_passes[passIndex];\n\t\tm_callbacks.initialise( passIndex );\n\t\tpass.initialised = true;\n\t}\n\n\tuint32_t RunnablePass::recordCurrentInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer )\n\t{\n\t\tauto index = m_callbacks.getPassIndex();\n\t\trecordInto( commandBuffer\n\t\t\t, index\n\t\t\t, context );\n\t\treturn isEnabled() ? index : InvalidIndex;\n\t}\n\n\tuint32_t RunnablePass::reRecordCurrent()\n\t{\n\t\tassert( m_ruConfig.resettable );\n\t\tauto index = m_callbacks.getPassIndex();\n\n\t\tif ( index < m_passContexts.size() )\n\t\t{\n\t\t\tauto context = m_passContexts[index];\n\t\t\trecordOne( m_passes[index].commandBuffer\n\t\t\t\t, index\n\t\t\t\t, context );\n\t\t}\n\n\t\treturn isEnabled() ? index : InvalidIndex;\n\t}\n\n\tvoid RunnablePass::recordOne( CommandBuffer & enabled\n\t\t, uint32_t index\n\t\t, RecordContext & context )\n\t{\n\t\tif ( !enabled.commandBuffer )\n\t\t{\n\t\t\tenabled.commandBuffer = doCreateCommandBuffer( std::string{} );\n\t\t}\n\n\t\tassert( m_passes.size() > index );\n\t\tauto & pass = m_passes[index];\n\t\tpass.fence.wait( 0xFFFFFFFFFFFFFFFFULL );\n\t\tVkCommandBufferBeginInfo beginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\n\t\t\t, nullptr\n\t\t\t, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT\n\t\t\t, nullptr };\n\t\tm_context.vkBeginCommandBuffer( enabled.commandBuffer, &beginInfo );\n\t\trecordInto( enabled.commandBuffer, index, context );\n\t\tm_context.vkEndCommandBuffer( enabled.commandBuffer );\n\t}\n\n\tvoid RunnablePass::recordInto( VkCommandBuffer commandBuffer\n\t\t, uint32_t index\n\t\t, RecordContext & context )\n\t{\n\t\tif ( m_ruConfig.resettable )\n\t\t{\n\t\t\tm_passContexts[index] = context;\n\t\t}\n\n\t\tif ( isEnabled() )\n\t\t{\n\t\t\tassert( m_passes.size() > index );\n\n\t\t\tif ( auto const & pass = m_passes[index]; !pass.initialised )\n\t\t\t{\n\t\t\t\tinitialise( index );\n\t\t\t}\n\n\t\t\tauto block( m_timer.start() );\n\t\t\tm_timer.beginPass( commandBuffer, m_pass.getGroupName(), m_pass.getId() );\n\n\t\t\tdetails::prepareResources( commandBuffer, index, context\n\t\t\t\t, m_graph, m_pass, m_callbacks, m_context );\n\n\t\t\tfor ( auto const & action : m_ruConfig.prePassActions )\n\t\t\t{\n\t\t\t\taction( context, commandBuffer, index );\n\t\t\t}\n\n\t\t\tm_callbacks.record( context, commandBuffer, index );\n\n\t\t\tfor ( auto const & action : m_ruConfig.postPassActions )\n\t\t\t{\n\t\t\t\taction( context, commandBuffer, index );\n\t\t\t}\n\n\t\t\tm_timer.endPass( commandBuffer );\n\t\t}\n\n\t\tfor ( auto const & [view, action] : m_ruConfig.implicitImageActions )\n\t\t{\n\t\t\tcontext.registerImplicitTransition( *this, view, action );\n\t\t}\n\n\t\tfor ( auto const & [view, action] : m_ruConfig.implicitBufferActions )\n\t\t{\n\t\t\tcontext.registerImplicitTransition( *this, view, action );\n\t\t}\n\t}\n\n\tbool RunnablePass::resetCommandBuffer( uint32_t passIndex )\n\t{\n\t\tbool result{};\n\n\t\tif ( m_context.device )\n\t\t{\n\t\t\tassert( m_passes.size() > passIndex );\n\t\t\tauto & pass = m_passes[passIndex];\n\n\t\t\tif ( pass.commandBuffer.commandBuffer )\n\t\t\t{\n\t\t\t\tresult = true;\n\t\t\t\tpass.fence.wait( 0xFFFFFFFFFFFFFFFFULL );\n\t\t\t\tpass.commandBuffer.recorded = false;\n\t\t\t\tm_context.vkResetCommandBuffer( pass.commandBuffer.commandBuffer\n\t\t\t\t\t, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tvoid RunnablePass::notifyPassRender()\n\t{\n\t\tif ( isEnabled() )\n\t\t{\n\t\t\tm_timer.notifyPassRender( getIndex() );\n\t\t}\n\t}\n\n\tVkCommandBuffer RunnablePass::doCreateCommandBuffer( std::string const & suffix )\n\t{\n\t\tVkCommandBuffer result{};\n\n\t\tif ( m_context.vkAllocateCommandBuffers )\n\t\t{\n\t\t\tVkCommandBufferAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, m_graph.getCommandPool()\n\t\t\t\t, VK_COMMAND_BUFFER_LEVEL_PRIMARY\n\t\t\t\t, 1u };\n\t\t\tauto res = m_context.vkAllocateCommandBuffers( m_context.device\n\t\t\t\t, &allocateInfo\n\t\t\t\t, &result );\n\t\t\tcheckVkResult( res, m_pass.getGroupName() + suffix + \" - CommandBuffer allocation\" );\n\t\t\tcrgRegisterObject( m_context, m_pass.getGroupName() + suffix, result );\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/BufferCopy.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/BufferCopy.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tBufferCopy::BufferCopy( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, DeviceSize copyOffset\n\t\t, DeviceSize copyRange\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_copyOffset{ copyOffset }\n\t\t, m_copyRange{ copyRange }\n\t{\n\t\tassert( getPass().getInputs().size() == getPass().getOutputs().size() );\n\t}\n\n\tvoid BufferCopy::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto dstIt = getPass().getOutputs().begin();\n\n\t\twhile ( srcIt != getPass().getInputs().end()\n\t\t\t&& dstIt != getPass().getOutputs().end() )\n\t\t{\n\t\t\tauto srcView{ srcIt->second->buffer( index ) };\n\t\t\tauto dstView{ dstIt->second->buffer( index ) };\n\t\t\tauto srcBufferRange{ getSubresourceRange( srcView ) };\n\t\t\tauto dstBufferRange{ getSubresourceRange( dstView ) };\n\t\t\tauto srcBuffer{ getGraph().createBuffer( srcView.data->buffer ) };\n\t\t\tauto dstBuffer{ getGraph().createBuffer( dstView.data->buffer ) };\n\t\t\t// Copy source to target.\n\t\t\tVkBufferCopy copyRegion{ srcBufferRange.offset + m_copyOffset\n\t\t\t\t, dstBufferRange.offset + m_copyOffset\n\t\t\t\t, m_copyRange };\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, srcView\n\t\t\t\t, { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader }\n\t\t\t\t, { AccessFlags::eTransferRead, PipelineStageFlags::eTransfer } );\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, dstView\n\t\t\t\t, { AccessFlags::eTransferWrite, PipelineStageFlags::eTransfer } );\n\t\t\tcontext->vkCmdCopyBuffer( commandBuffer\n\t\t\t\t, srcBuffer\n\t\t\t\t, dstBuffer\n\t\t\t\t, 1u\n\t\t\t\t, &copyRegion );\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, dstView\n\t\t\t\t, { AccessFlags::eShaderRead, PipelineStageFlags::eComputeShader } );\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, srcView\n\t\t\t\t, { AccessFlags::eShaderWrite, PipelineStageFlags::eFragmentShader } );\n\t\t\t++srcIt;\n\t\t\t++dstIt;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/BufferToImageCopy.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/BufferToImageCopy.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tBufferToImageCopy::BufferToImageCopy( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Offset3D const & copyOffset\n\t\t, Extent3D const & copySize\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext const & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_copyOffset{ convert( copyOffset ) }\n\t\t, m_copySize{ convert( copySize ) }\n\t{\n\t\tassert( getPass().getInputs().size() == getPass().getOutputs().size() );\n\t}\n\n\tvoid BufferToImageCopy::doRecordInto( RecordContext const & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto dstIt = getPass().getOutputs().begin();\n\n\t\twhile ( srcIt != getPass().getInputs().end()\n\t\t\t&& dstIt != getPass().getOutputs().end() )\n\t\t{\n\t\t\tauto srcAttach{ srcIt->second->buffer( index ) };\n\t\t\tauto dstAttach{ dstIt->second->view( index ) };\n\t\t\tauto srcBuffer{ getGraph().createBuffer( srcAttach.data->buffer ) };\n\t\t\tauto dstImage{ getGraph().createImage( dstAttach.data->image ) };\n\t\t\t// Copy source to target.\n\t\t\tauto range = getSubresourceLayers( getSubresourceRange( dstAttach ) );\n\t\t\tVkBufferImageCopy copyRegion{ 0ULL\n\t\t\t\t, 0u\n\t\t\t\t, 0u\n\t\t\t\t, range\n\t\t\t\t, m_copyOffset\n\t\t\t\t, m_copySize };\n\t\t\tcontext->vkCmdCopyBufferToImage( commandBuffer\n\t\t\t\t, srcBuffer\n\t\t\t\t, dstImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t, 1u\n\t\t\t\t, &copyRegion );\n\t\t\t++srcIt;\n\t\t\t++dstIt;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/ComputePass.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/ComputePass.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tnamespace cppss\n\t{\n\t\tstatic bool isPtrEnabled( bool const * v )\n\t\t{\n\t\t\treturn v ? *v : true;\n\t\t}\n\t}\n\n\tComputePass::ComputePass( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, ru::Config const & ruConfig\n\t\t, cp::Config cpConfig )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { [this]( uint32_t index ){ doInitialise( index ); }\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eComputeShader ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, GetPassIndexCallback( [this](){ return doGetPassIndex(); } )\n\t\t\t\t, IsEnabledCallback( [this](){ return doIsEnabled(); } )\n\t\t\t\t, IsComputePassCallback( [](){ return true; } ) }\n\t\t\t, ruConfig }\n\t\t, m_cpConfig{ cpConfig.m_initialise ? std::move( *cpConfig.m_initialise ) : getDefaultV< RunnablePass::InitialiseCallback >()\n\t\t\t, cpConfig.m_enabled.has_value() ? std::move( *cpConfig.m_enabled ) : getDefaultV< bool const * >()\n\t\t\t, cpConfig.m_isEnabled\n\t\t\t, cpConfig.m_getPassIndex ? std::move( *cpConfig.m_getPassIndex ) : getDefaultV< RunnablePass::GetPassIndexCallback >()\n\t\t\t, cpConfig.m_recordInto ? std::move( *cpConfig.m_recordInto ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, cpConfig.m_end ? std::move( *cpConfig.m_end ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, cpConfig.m_groupCountX.has_value() ? *cpConfig.m_groupCountX : 1u\n\t\t\t, cpConfig.m_groupCountY.has_value() ? *cpConfig.m_groupCountY : 1u\n\t\t\t, cpConfig.m_groupCountZ.has_value() ? *cpConfig.m_groupCountZ : 1u\n\t\t\t, cpConfig.m_getGroupCountX ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountX ) ) : std::nullopt\n\t\t\t, cpConfig.m_getGroupCountY ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountY ) ) : std::nullopt\n\t\t\t, cpConfig.m_getGroupCountZ ? std::optional< cp::GetGroupCountCallback >( std::move( *cpConfig.m_getGroupCountZ ) ) : std::nullopt\n\t\t\t, cpConfig.m_indirectBuffer ? *cpConfig.m_indirectBuffer : getDefaultV < IndirectBuffer >() }\n\t\t, m_pipeline{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, std::move( cpConfig.m_baseConfig )\n\t\t\t, VK_PIPELINE_BIND_POINT_COMPUTE\n\t\t\t, ruConfig.maxPassCount }\n\t{\n\t}\n\n\tvoid ComputePass::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tresetCommandBuffer( index );\n\t\tm_pipeline.resetPipeline( std::move( config ), index );\n\t\tdoCreatePipeline( index );\n\t\treRecordCurrent();\n\t}\n\n\tVkPipelineLayout ComputePass::getPipelineLayout()const\n\t{\n\t\treturn m_pipeline.getPipelineLayout();\n\t}\n\n\tvoid ComputePass::doInitialise( uint32_t index )\n\t{\n\t\tm_pipeline.initialise();\n\t\tdoCreatePipeline( index );\n\t\tm_cpConfig.initialise( index );\n\t}\n\n\tuint32_t ComputePass::doGetPassIndex()const\n\t{\n\t\treturn m_cpConfig.getPassIndex();\n\t}\n\n\tbool ComputePass::doIsEnabled()const\n\t{\n\t\treturn ( m_cpConfig.isEnabled\n\t\t\t? ( *m_cpConfig.isEnabled )()\n\t\t\t: cppss::isPtrEnabled( m_cpConfig.enabled ) );\n\t}\n\n\tvoid ComputePass::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.recordInto( context, commandBuffer, index );\n\t\tm_cpConfig.recordInto( context, commandBuffer, index );\n\n\t\tif ( m_cpConfig.indirectBuffer != defaultV< IndirectBuffer > )\n\t\t{\n\t\t\tauto indirectBuffer = getGraph().createBuffer( m_cpConfig.indirectBuffer.buffer.data->buffer );\n\t\t\tcontext->vkCmdDispatchIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_cpConfig.indirectBuffer.buffer ).offset );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontext->vkCmdDispatch( commandBuffer\n\t\t\t\t, ( m_cpConfig.getGroupCountX ? ( *m_cpConfig.getGroupCountX )() : m_cpConfig.groupCountX )\n\t\t\t\t, ( m_cpConfig.getGroupCountY ? ( *m_cpConfig.getGroupCountY )() : m_cpConfig.groupCountY )\n\t\t\t\t, ( m_cpConfig.getGroupCountZ ? ( *m_cpConfig.getGroupCountZ )() : m_cpConfig.groupCountZ ) );\n\t\t}\n\n\t\tm_cpConfig.end( context, commandBuffer, index );\n\t}\n\n\tvoid ComputePass::doCreatePipeline( uint32_t index )\n\t{\n\t\tauto & program = m_pipeline.getProgram( index );\n\t\tVkComputePipelineCreateInfo createInfo{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, program.front()\n\t\t\t, getPipelineLayout()\n\t\t\t, VkPipeline{}\n\t\t\t, 0u };\n\t\tm_pipeline.createPipeline( index, createInfo );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/GenerateMipmaps.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/GenerateMipmaps.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tnamespace genMips\n\t{\n\t\ttemplate< typename T >\n\t\tstatic constexpr T getSubresourceDimension( T const & extent\n\t\t\t, uint32_t mipLevel )noexcept\n\t\t{\n\t\t\treturn std::max( T( 1 ), T( extent >> mipLevel ) );\n\t\t}\n\t}\n\n\tGenerateMipmaps::GenerateMipmaps( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, ImageLayout outputLayout\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_outputLayout{ makeLayoutState( outputLayout ) }\n\t{\n\t}\n\n\tvoid GenerateMipmaps::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tfor ( auto const & [_, view] : getPass().getInouts() )\n\t\t\tdoProcessImageView( context, commandBuffer, view->view( index ) );\n\t}\n\n\tvoid GenerateMipmaps::doProcessImageView( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, ImageViewId viewId )const\n\t{\n\t\tauto imageId{ viewId.data->image };\n\t\tauto image{ getGraph().createImage( imageId ) };\n\t\tauto extent = getExtent( imageId );\n\t\tauto format = getFormat( imageId );\n\t\tauto baseArrayLayer = getSubresourceRange( viewId ).baseArrayLayer;\n\t\tauto layerCount = getSubresourceRange( viewId ).layerCount;\n\t\tauto mipLevels = imageId.data->info.mipLevels;\n\t\tauto nextLayoutState = getGraph().getNextLayoutState( context\n\t\t\t, *this\n\t\t\t, viewId );\n\n\t\tauto const width = int32_t( extent.width );\n\t\tauto const height = int32_t( extent.height );\n\t\tauto const depth = int32_t( extent.depth );\n\t\tauto const aspectMask = getAspectMask( format );\n\n\t\tfor ( uint32_t i = 0u; i < layerCount; ++i )\n\t\t{\n\t\t\tauto layer = baseArrayLayer + i;\n\t\t\tImageSubresourceRange mipSubRange{ aspectMask\n\t\t\t\t, 0u\n\t\t\t\t, 1u\n\t\t\t\t, layer\n\t\t\t\t, 1u };\n\t\t\tVkImageBlit imageBlit{};\n\t\t\timageBlit.dstSubresource.aspectMask = getImageAspectFlags( aspectMask );\n\t\t\timageBlit.dstSubresource.baseArrayLayer = mipSubRange.baseArrayLayer;\n\t\t\timageBlit.dstSubresource.layerCount = 1;\n\t\t\timageBlit.dstSubresource.mipLevel = mipSubRange.baseMipLevel;\n\t\t\timageBlit.dstOffsets[0].x = 0;\n\t\t\timageBlit.dstOffsets[0].y = 0;\n\t\t\timageBlit.dstOffsets[0].z = 0;\n\t\t\timageBlit.dstOffsets[1].x = genMips::getSubresourceDimension( width, mipSubRange.baseMipLevel );\n\t\t\timageBlit.dstOffsets[1].y = genMips::getSubresourceDimension( height, mipSubRange.baseMipLevel );\n\t\t\timageBlit.dstOffsets[1].z = genMips::getSubresourceDimension( depth, mipSubRange.baseMipLevel );\n\n\t\t\t// Transition first mip level to transfer source for read in next iteration\n\t\t\tauto firstLayoutState = getGraph().getCurrentLayoutState( context\n\t\t\t\t, imageId\n\t\t\t\t, viewId.data->info.viewType\n\t\t\t\t, mipSubRange );\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, imageId\n\t\t\t\t, mipSubRange\n\t\t\t\t, firstLayoutState.layout\n\t\t\t\t, makeLayoutState( ImageLayout::eTransferSrc ) );\n\n\t\t\t// Copy down mips\n\t\t\twhile ( ++mipSubRange.baseMipLevel < mipLevels )\n\t\t\t{\n\t\t\t\t// Blit from previous level\n\t\t\t\t// Blit source is previous blit destination\n\t\t\t\timageBlit.srcSubresource = imageBlit.dstSubresource;\n\t\t\t\timageBlit.srcOffsets[0] = imageBlit.dstOffsets[0];\n\t\t\t\timageBlit.srcOffsets[1] = imageBlit.dstOffsets[1];\n\n\t\t\t\t// Update blit destination\n\t\t\t\timageBlit.dstSubresource.mipLevel = mipSubRange.baseMipLevel;\n\t\t\t\timageBlit.dstOffsets[1].x = genMips::getSubresourceDimension( width, mipSubRange.baseMipLevel );\n\t\t\t\timageBlit.dstOffsets[1].y = genMips::getSubresourceDimension( height, mipSubRange.baseMipLevel );\n\t\t\t\timageBlit.dstOffsets[1].z = genMips::getSubresourceDimension( depth, mipSubRange.baseMipLevel );\n\n\t\t\t\t// Transition current mip level to transfer dest\n\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t, imageId\n\t\t\t\t\t, mipSubRange\n\t\t\t\t\t, makeLayoutState( ImageLayout::eTransferDst ) );\n\n\t\t\t\t// Perform blit\n\t\t\t\tcontext->vkCmdBlitImage( commandBuffer \n\t\t\t\t\t, image\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t\t, image\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t\t, 1u\n\t\t\t\t\t, &imageBlit\n\t\t\t\t\t, VK_FILTER_LINEAR );\n\n\t\t\t\t// Transition previous mip level to wanted output layout\n\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t, imageId\n\t\t\t\t\t, { mipSubRange.aspectMask\n\t\t\t\t\t\t, mipSubRange.baseMipLevel - 1u\n\t\t\t\t\t\t, 1u\n\t\t\t\t\t\t, mipSubRange.baseArrayLayer\n\t\t\t\t\t\t, 1u }\n\t\t\t\t\t, ImageLayout::eTransferSrc\n\t\t\t\t\t, nextLayoutState );\n\n\t\t\t\tif ( mipSubRange.baseMipLevel == ( mipLevels - 1u ) )\n\t\t\t\t{\n\t\t\t\t\t// Transition final mip level to wanted output layout\n\t\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t\t, imageId\n\t\t\t\t\t\t, mipSubRange\n\t\t\t\t\t\t, ImageLayout::eTransferDst\n\t\t\t\t\t\t, nextLayoutState );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Transition current mip level to transfer source for read in next iteration\n\t\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t\t, imageId\n\t\t\t\t\t\t, mipSubRange\n\t\t\t\t\t\t, ImageLayout::eTransferDst\n\t\t\t\t\t\t, makeLayoutState( ImageLayout::eTransferSrc ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/ImageBlit.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/ImageBlit.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tImageBlit::ImageBlit( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Rect3D const & blitSrc\n\t\t, Rect3D const & blitDst\n\t\t, FilterMode filter\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext const & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_srcOffset{ convert( blitSrc.offset ) }\n\t\t, m_srcSize{ convert( blitSrc.extent ) }\n\t\t, m_dstOffset{ convert( blitDst.offset ) }\n\t\t, m_dstSize{ convert( blitDst.extent ) }\n\t\t, m_filter{ filter }\n\t{\n\t\tassert( getPass().getInputs().size() == getPass().getOutputs().size() );\n\t}\n\n\tvoid ImageBlit::doRecordInto( RecordContext const & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto dstIt = getPass().getOutputs().begin();\n\n\t\twhile ( srcIt != getPass().getInputs().end()\n\t\t\t&& dstIt != getPass().getOutputs().end() )\n\t\t{\n\t\t\tauto srcAttach{ srcIt->second->view( index ) };\n\t\t\tauto dstAttach{ dstIt->second->view( index ) };\n\t\t\tauto srcImage{ getGraph().createImage( srcAttach.data->image ) };\n\t\t\tauto dstImage{ getGraph().createImage( dstAttach.data->image ) };\n\t\t\tVkImageBlit blitRegion{ getSubresourceLayers( getSubresourceRange( srcAttach ) )\n\t\t\t\t, { m_srcOffset, VkOffset3D{ int32_t( m_srcSize.width ), int32_t( m_srcSize.height ), int32_t( m_srcSize.depth ) } }\n\t\t\t\t, getSubresourceLayers( getSubresourceRange( dstAttach ) )\n\t\t\t\t, { m_dstOffset, VkOffset3D{ int32_t( m_dstSize.width ), int32_t( m_dstSize.height ), int32_t( m_dstSize.depth ) } } };\n\t\t\tcontext->vkCmdBlitImage( commandBuffer\n\t\t\t\t, srcImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t, dstImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t, 1u\n\t\t\t\t, &blitRegion\n\t\t\t\t, convert( m_filter ) );\n\t\t\t++srcIt;\n\t\t\t++dstIt;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/ImageCopy.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/ImageCopy.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tImageCopy::ImageCopy( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Extent3D const & copySize\n\t\t, ImageLayout finalOutputLayout\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_copySize{ convert( copySize ) }\n\t\t, m_finalOutputLayout{ finalOutputLayout }\n\t{\n\t\tassert( getPass().getInputs().size() == getPass().getOutputs().size()\n\t\t\t|| getPass().getInputs().size() == 1u\n\t\t\t|| getPass().getOutputs().size() == 1u );\n\t}\n\n\tImageCopy::ImageCopy( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Extent3D const & copySize\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: ImageCopy{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, copySize\n\t\t\t, ImageLayout::eUndefined\n\t\t\t, std::move( ruConfig )\n\t\t\t, std::move( passIndex )\n\t\t\t, std::move( isEnabled ) }\n\t{\n\t\tassert( getPass().getInputs().size() == getPass().getOutputs().size()\n\t\t\t|| getPass().getInputs().size() == 1u\n\t\t\t|| getPass().getOutputs().size() == 1u );\n\t}\n\n\tvoid ImageCopy::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tif ( getPass().getInputs().size() == getPass().getOutputs().size() )\n\t\t\tdoRecordMultiToMulti( context, commandBuffer, index );\n\t\telse if ( getPass().getOutputs().size() == 1u )\n\t\t\tdoRecordMultiToSingle( context, commandBuffer, index );\n\t\telse if ( getPass().getInputs().size() == 1u )\n\t\t\tdoRecordSingleToMulti( context, commandBuffer, index );\n\t}\n\n\tvoid ImageCopy::doRecordMultiToMulti( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto dstIt = getPass().getOutputs().begin();\n\n\t\twhile ( srcIt != getPass().getInputs().end()\n\t\t\t&& dstIt != getPass().getOutputs().end() )\n\t\t{\n\t\t\tauto srcAttach{ srcIt->second->view( index ) };\n\t\t\tauto dstAttach{ dstIt->second->view( index ) };\n\t\t\tauto srcImage{ getGraph().createImage( srcAttach.data->image ) };\n\t\t\tauto dstImage{ getGraph().createImage( dstAttach.data->image ) };\n\t\t\t// Copy source to target.\n\t\t\tVkImageCopy copyRegion{ getSubresourceLayers( getSubresourceRange( srcAttach ) )\n\t\t\t\t, {}\n\t\t\t\t, getSubresourceLayers( getSubresourceRange( dstAttach ) )\n\t\t\t\t, {}\n\t\t\t, m_copySize };\n\t\t\tcontext->vkCmdCopyImage( commandBuffer\n\t\t\t\t, srcImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t, dstImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t, 1u\n\t\t\t\t, &copyRegion );\n\n\t\t\tif ( m_finalOutputLayout != ImageLayout::eUndefined )\n\t\t\t{\n\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t, dstAttach\n\t\t\t\t\t, crg::makeLayoutState( m_finalOutputLayout ) );\n\t\t\t}\n\n\t\t\t++srcIt;\n\t\t\t++dstIt;\n\t\t}\n\t}\n\n\tvoid ImageCopy::doRecordMultiToSingle( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tstd::vector< VkImageCopy > copyRegions;\n\t\tauto dstIt = getPass().getOutputs().begin();\n\t\tauto dstAttach{ dstIt->second->view( index ) };\n\t\tauto dstImage{ getGraph().createImage( dstAttach.data->image ) };\n\t\tauto dstSubresourceRange = getSubresourceLayers( getSubresourceRange( dstAttach ) );\n\t\tauto prvSrcImage{ getGraph().createImage( getPass().getInputs().begin()->second->view( index ).data->image ) };\n\n\t\tfor ( auto const & [_, attach] : getPass().getInputs() )\n\t\t{\n\t\t\tauto srcAttach{ attach->view( index ) };\n\n\t\t\tif ( auto srcImage{ getGraph().createImage( srcAttach.data->image ) };\n\t\t\t\tsrcImage != prvSrcImage )\n\t\t\t{\n\t\t\t\tcontext->vkCmdCopyImage( commandBuffer\n\t\t\t\t\t, prvSrcImage\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t\t, dstImage\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t\t, uint32_t( copyRegions.size() )\n\t\t\t\t\t, copyRegions.data() );\n\t\t\t\tcopyRegions.clear();\n\t\t\t\tprvSrcImage = srcImage;\n\t\t\t}\n\n\t\t\tcopyRegions.push_back( { getSubresourceLayers( getSubresourceRange( srcAttach ) )\n\t\t\t\t, {}\n\t\t\t\t, dstSubresourceRange\n\t\t\t\t, {}\n\t\t\t, m_copySize } );\n\t\t}\n\n\t\tif ( !copyRegions.empty() )\n\t\t{\n\t\t\tcontext->vkCmdCopyImage( commandBuffer\n\t\t\t\t, prvSrcImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t, dstImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t, uint32_t( copyRegions.size() )\n\t\t\t\t, copyRegions.data() );\n\t\t}\n\n\t\tif ( m_finalOutputLayout != ImageLayout::eUndefined )\n\t\t{\n\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t, dstAttach\n\t\t\t\t, crg::makeLayoutState( m_finalOutputLayout ) );\n\t\t}\n\t}\n\n\tvoid ImageCopy::doRecordSingleToMulti( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tstd::vector< VkImageCopy > copyRegions;\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto srcAttach{ srcIt->second->view( index ) };\n\t\tauto srcImage{ getGraph().createImage( srcAttach.data->image ) };\n\t\tauto srcSubresourceRange = getSubresourceLayers( getSubresourceRange( srcAttach ) );\n\t\tauto prvDstImage{ getGraph().createImage( getPass().getOutputs().begin()->second->view( index ).data->image ) };\n\n\t\tfor ( auto const & [_, attach] : getPass().getOutputs() )\n\t\t{\n\t\t\tauto dstAttach{ attach->view( index ) };\n\n\t\t\tif ( auto dstImage{ getGraph().createImage( dstAttach.data->image ) };\n\t\t\t\tdstImage != prvDstImage )\n\t\t\t{\n\t\t\t\tcontext->vkCmdCopyImage( commandBuffer\n\t\t\t\t\t, srcImage\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t\t, prvDstImage\n\t\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t\t, uint32_t( copyRegions.size() )\n\t\t\t\t\t, copyRegions.data() );\n\t\t\t\tcopyRegions.clear();\n\t\t\t\tprvDstImage = dstImage;\n\t\t\t}\n\n\t\t\tcopyRegions.push_back( { srcSubresourceRange\n\t\t\t\t, {}\n\t\t\t\t, getSubresourceLayers( getSubresourceRange( dstAttach ) )\n\t\t\t\t, {}\n\t\t\t, m_copySize } );\n\t\t}\n\n\t\tif ( !copyRegions.empty() )\n\t\t{\n\t\t\tcontext->vkCmdCopyImage( commandBuffer\n\t\t\t\t, srcImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t, prvDstImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\n\t\t\t\t, uint32_t( copyRegions.size() )\n\t\t\t\t, copyRegions.data() );\n\t\t}\n\n\t\tif ( m_finalOutputLayout != ImageLayout::eUndefined )\n\t\t{\n\t\t\tfor ( auto const & [_, attach] : getPass().getOutputs() )\n\t\t\t{\n\t\t\t\tauto dstAttach{ attach->view( index ) };\n\t\t\t\tcontext.memoryBarrier( commandBuffer\n\t\t\t\t\t, dstAttach\n\t\t\t\t\t, crg::makeLayoutState( m_finalOutputLayout ) );\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/ImageToBufferCopy.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/ImageToBufferCopy.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\tImageToBufferCopy::ImageToBufferCopy( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Offset3D const & copyOffset\n\t\t, Extent3D const & copySize\n\t\t, ru::Config ruConfig\n\t\t, GetPassIndexCallback passIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eTransfer ); } )\n\t\t\t\t, [this]( RecordContext const & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( passIndex )\n\t\t\t\t, std::move( isEnabled ) }\n\t\t\t, std::move( ruConfig ) }\n\t\t, m_copyOffset{ convert( copyOffset ) }\n\t\t, m_copySize{ convert( copySize ) }\n\t{\n\t}\n\n\tvoid ImageToBufferCopy::doRecordInto( RecordContext const & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tauto srcIt = getPass().getInputs().begin();\n\t\tauto dstIt = getPass().getOutputs().begin();\n\n\t\twhile ( srcIt != getPass().getInputs().end()\n\t\t\t&& dstIt != getPass().getOutputs().end() )\n\t\t{\n\t\t\tauto srcAttach{ srcIt->second->view( index ) };\n\t\t\tauto dstAttach{ dstIt->second->buffer( index ) };\n\t\t\tauto srcImage{ getGraph().createImage( srcAttach.data->image ) };\n\t\t\tauto dstBuffer{ getGraph().createBuffer( dstAttach.data->buffer ) };\n\t\t\t// Copy source to target.\n\t\t\tauto range = getSubresourceLayers( getSubresourceRange( srcAttach ) );\n\t\t\tVkBufferImageCopy copyRegion{ 0ULL\n\t\t\t\t, 0u\n\t\t\t\t, 0u\n\t\t\t\t, range\n\t\t\t\t, m_copyOffset\n\t\t\t\t, m_copySize };\n\t\t\tcontext->vkCmdCopyImageToBuffer( commandBuffer\n\t\t\t\t, srcImage\n\t\t\t\t, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\n\t\t\t\t, dstBuffer\n\t\t\t\t, 1u\n\t\t\t\t, &copyRegion );\n\t\t\t++srcIt;\n\t\t\t++dstIt;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/PipelineHolder.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/PipelineHolder.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n#include \"RenderGraph/RunnablePasses/RenderPass.hpp\"\n\n#include <cassert>\n\nnamespace crg\n{\n\tnamespace pphdr\n\t{\n\t\tstatic bool isDescriptor( Attachment const & attach )\n\t\t{\n\t\t\treturn attach.isStorageImageView() || attach.isSampledImageView()\n\t\t\t\t|| attach.isUniformBuffer() || attach.isStorageBuffer()\n\t\t\t\t|| attach.isUniformBufferView() || attach.isStorageBufferView();\n\t\t}\n\n\t\tstatic void createDescriptorWrites( std::map< uint32_t, FramePass::SampledAttachment > const & attaches\n\t\t\t, uint32_t index\n\t\t\t, RunnableGraph & graph\n\t\t\t, WriteDescriptorSetArray & writes )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : attaches )\n\t\t\t\twrites.push_back( graph.getDescriptorWrite( *attach.attach, attach.sampler, binding, index ) );\n\t\t}\n\t\t\n\t\tstatic void createDescriptorWrites( std::map< uint32_t, Attachment const * > const & attaches\n\t\t\t, uint32_t index\n\t\t\t, RunnableGraph & graph\n\t\t\t, WriteDescriptorSetArray & writes )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : attaches )\n\t\t\t{\n\t\t\t\tif ( isDescriptor( *attach ) )\n\t\t\t\t\twrites.push_back( graph.getDescriptorWrite( *attach, binding, index ) );\n\t\t\t}\n\t\t}\n\n\t\tstatic void createDescriptorBindings( std::map< uint32_t, FramePass::SampledAttachment > const & attaches\n\t\t\t, VkShaderStageFlags shaderStage\n\t\t\t, RunnableGraph const & graph\n\t\t\t, VkDescriptorSetLayoutBindingArray & descriptorBindings )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : attaches )\n\t\t\t{\n\t\t\t\tdescriptorBindings.push_back( { binding\n\t\t\t\t\t, graph.getDescriptorType( *attach.attach )\n\t\t\t\t\t, 1u, shaderStage, nullptr } );\n\t\t\t}\n\t\t}\n\n\t\tstatic void createDescriptorBindings( std::map< uint32_t, Attachment const * > const & attaches\n\t\t\t, VkShaderStageFlags shaderStage\n\t\t\t, RunnableGraph const & graph\n\t\t\t, VkDescriptorSetLayoutBindingArray & descriptorBindings )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : attaches )\n\t\t\t{\n\t\t\t\tif ( isDescriptor( *attach ) )\n\t\t\t\t\tdescriptorBindings.push_back( { binding\n\t\t\t\t\t\t, graph.getDescriptorType( *attach )\n\t\t\t\t\t\t, 1u, shaderStage, nullptr } );\n\t\t\t}\n\t\t}\n\t}\n\n\tPipelineHolder::PipelineHolder( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, pp::Config config\n\t\t, VkPipelineBindPoint bindingPoint\n\t\t, uint32_t maxPassCount )\n\t\t: m_pass{ pass }\n\t\t, m_context{ context }\n\t\t, m_graph{ graph }\n\t\t, m_baseConfig{ config.m_programs ? *config.m_programs : defaultV< std::vector< VkPipelineShaderStageCreateInfoArray > >\n\t\t\t, config.m_programCreator ? *config.m_programCreator : defaultV< ProgramCreator >\n\t\t\t, config.m_layouts ? *config.m_layouts : defaultV< std::vector< VkDescriptorSetLayout > >\n\t\t\t, config.m_pushConstants ? *config.m_pushConstants : defaultV< std::vector< VkPushConstantRange > > }\n\t\t, m_bindingPoint{ bindingPoint }\n\t{\n\t\tif ( m_baseConfig.m_programCreator.create )\n\t\t{\n\t\t\tm_pipelines.resize( m_baseConfig.m_programCreator.maxCount, VkPipeline{} );\n\t\t\tm_baseConfig.m_programs.resize( m_baseConfig.m_programCreator.maxCount );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_pipelines.resize( m_baseConfig.m_programs.size(), VkPipeline{} );\n\t\t}\n\n\t\tm_descriptorSets.resize( maxPassCount );\n\t}\n\n\tPipelineHolder::~PipelineHolder()noexcept\n\t{\n\t\tcleanup();\n\t}\n\n\tvoid PipelineHolder::initialise()\n\t{\n\t\tif ( !m_pipelineLayout )\n\t\t{\n\t\t\tdoFillDescriptorBindings();\n\t\t\tdoCreateDescriptorSetLayout();\n\t\t\tdoCreatePipelineLayout();\n\t\t\tdoCreateDescriptorPool();\n\t\t}\n\t}\n\n\tvoid PipelineHolder::cleanup()noexcept\n\t{\n\t\tm_descriptorBindings.clear();\n\n\t\tfor ( auto & descriptorSet : m_descriptorSets )\n\t\t{\n\t\t\tif ( descriptorSet.set )\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( m_context, descriptorSet.set );\n\t\t\t\tdescriptorSet.writes.clear();\n\t\t\t\tdescriptorSet.set = {};\n\t\t\t}\n\t\t}\n\n\t\tif ( m_descriptorSetPool )\n\t\t{\n\t\t\tcrgUnregisterObject( m_context, m_descriptorSetPool );\n\t\t\tm_context.vkDestroyDescriptorPool( m_context.device\n\t\t\t\t, m_descriptorSetPool\n\t\t\t\t, m_context.allocator );\n\t\t\tm_descriptorSetPool = {};\n\t\t}\n\n\t\tfor ( auto & pipeline : m_pipelines )\n\t\t{\n\t\t\tif ( pipeline != VkPipeline{} )\n\t\t\t{\n\t\t\t\tcrgUnregisterObject( m_context, pipeline );\n\t\t\t\tm_context.vkDestroyPipeline( m_context.device\n\t\t\t\t\t, pipeline\n\t\t\t\t\t, m_context.allocator );\n\t\t\t\tpipeline = {};\n\t\t\t}\n\t\t}\n\n\t\tif ( m_pipelineLayout )\n\t\t{\n\t\t\tcrgUnregisterObject( m_context, m_pipelineLayout );\n\t\t\tm_context.vkDestroyPipelineLayout( m_context.device\n\t\t\t\t, m_pipelineLayout\n\t\t\t\t, m_context.allocator );\n\t\t\tm_pipelineLayout = {};\n\t\t}\n\n\t\tif ( m_descriptorSetLayout )\n\t\t{\n\t\t\tcrgUnregisterObject( m_context, m_descriptorSetLayout );\n\t\t\tm_context.vkDestroyDescriptorSetLayout( m_context.device\n\t\t\t\t, m_descriptorSetLayout\n\t\t\t\t, m_context.allocator );\n\t\t\tm_descriptorSetLayout = {};\n\t\t}\n\t}\n\n\tVkPipelineShaderStageCreateInfoArray const & PipelineHolder::getProgram( uint32_t index )\n\t{\n\t\tif ( m_baseConfig.m_programCreator.create )\n\t\t{\n\t\t\tassert( m_baseConfig.m_programCreator.maxCount > index );\n\t\t\tm_baseConfig.m_programs[index] = m_baseConfig.m_programCreator.create( index );\n\t\t}\n\n\t\tif ( m_baseConfig.m_programs.size() == 1u )\n\t\t{\n\t\t\treturn m_baseConfig.m_programs[0];\n\t\t}\n\n\t\tassert( m_baseConfig.m_programs.size() > index );\n\t\treturn m_baseConfig.m_programs[index];\n\t}\n\n\tVkPipeline & PipelineHolder::getPipeline( uint32_t index )\n\t{\n\t\tif ( m_baseConfig.m_programs.size() == 1u )\n\t\t{\n\t\t\tassert( m_pipelines.size() == 1u );\n\t\t\treturn m_pipelines[0];\n\t\t}\n\n\t\tassert( m_pipelines.size() > index );\n\t\treturn m_pipelines[index];\n\t}\n\n\tvoid PipelineHolder::createPipeline( uint32_t index\n\t\t, std::string const & name\n\t\t, VkGraphicsPipelineCreateInfo const & createInfo )\n\t{\n\t\tif ( m_context.vkCreateGraphicsPipelines )\n\t\t{\n\t\t\tauto & pipeline = getPipeline( index );\n\t\t\tauto res = m_context.vkCreateGraphicsPipelines( m_context.device\n\t\t\t\t, m_context.cache\n\t\t\t\t, 1u\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &pipeline );\n\t\t\tcrg::checkVkResult( res, name + \" - Pipeline creation\" );\n\t\t\tcrgRegisterObject( m_context, name, pipeline );\n\t\t}\n\t}\n\n\tvoid PipelineHolder::createPipeline( uint32_t index\n\t\t, VkGraphicsPipelineCreateInfo const & createInfo )\n\t{\n\t\tcreatePipeline( index\n\t\t\t, m_pass.getGroupName()\n\t\t\t, createInfo );\n\t}\n\n\tvoid PipelineHolder::createPipeline( uint32_t index\n\t\t, std::string const & name\n\t\t, VkComputePipelineCreateInfo const & createInfo )\n\t{\n\t\tif ( m_context.vkCreateComputePipelines )\n\t\t{\n\t\t\tauto & pipeline = getPipeline( index );\n\t\t\tauto res = m_context.vkCreateComputePipelines( m_context.device\n\t\t\t\t, m_context.cache\n\t\t\t\t, 1u\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &pipeline );\n\t\t\tcheckVkResult( res, name + \" - Pipeline creation\" );\n\t\t\tcrgRegisterObject( m_context, name, pipeline );\n\t\t}\n\t}\n\n\tvoid PipelineHolder::createPipeline( uint32_t index\n\t\t, VkComputePipelineCreateInfo const & createInfo )\n\t{\n\t\tcreatePipeline( index\n\t\t\t, m_pass.getGroupName()\n\t\t\t, createInfo );\n\t}\n\n\tvoid PipelineHolder::recordInto( RecordContext const & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tcreateDescriptorSet( index );\n\t\tauto & pipeline = getPipeline( index );\n\t\tcontext->vkCmdBindPipeline( commandBuffer, m_bindingPoint, pipeline );\n\t\tcontext->vkCmdBindDescriptorSets( commandBuffer, m_bindingPoint, m_pipelineLayout, 0u, 1u, &m_descriptorSets[index].set, 0u, nullptr );\n\t}\n\n\tvoid PipelineHolder::resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t, VkPipelineShaderStageCreateInfoArray const & config )\n\t{\n\t\tbool hadPipelineLayout{};\n\t\tif ( m_pipelineLayout )\n\t\t{\n\t\t\thadPipelineLayout = true;\n\t\t\tauto pipelineLayout = m_pipelineLayout;\n\t\t\tm_context.delQueue.push( [pipelineLayout]( GraphContext & context )\n\t\t\t\t{\n\t\t\t\t\tcrgUnregisterObject( context, pipelineLayout );\n\t\t\t\t\tcontext.vkDestroyPipelineLayout( context.device\n\t\t\t\t\t\t, pipelineLayout\n\t\t\t\t\t\t, context.allocator );\n\t\t\t\t} );\n\t\t\tm_pipelineLayout = {};\n\t\t}\n\n\t\tm_baseConfig.layouts( layouts );\n\t\tm_baseConfig.pushConstants( ranges );\n\n\t\tif ( hadPipelineLayout )\n\t\t\tdoCreatePipelineLayout();\n\n\t\tauto count = uint32_t( m_pipelines.size() );\n\t\tfor ( uint32_t i = 0; i < count; ++i )\n\t\t\tresetPipeline( config, i );\n\t}\n\n\tvoid PipelineHolder::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tassert( m_pipelines.size() == 1u || index < m_pipelines.size() );\n\n\t\tif ( m_pipelines.size() == 1u )\n\t\t{\n\t\t\tindex = 0u;\n\t\t}\n\n\t\tif ( m_pipelines[index] )\n\t\t{\n\t\t\tauto pipeline = m_pipelines[index];\n\t\t\tm_context.delQueue.push( [pipeline]( GraphContext & context )\n\t\t\t\t{\n\t\t\t\t\tcrgUnregisterObject( context, pipeline );\n\t\t\t\t\tcontext.vkDestroyPipeline( context.device\n\t\t\t\t\t\t, pipeline\n\t\t\t\t\t\t, context.allocator );\n\t\t\t\t} );\n\t\t\tm_pipelines[index] = {};\n\t\t}\n\n\t\tif ( !config.empty() )\n\t\t{\n\t\t\tassert( m_baseConfig.m_programs.size() > index );\n\t\t\tm_baseConfig.m_programs[index] = std::move( config );\n\t\t}\n\t}\n\n\tvoid PipelineHolder::createDescriptorSet( uint32_t index )\n\t{\n\t\tauto & descriptorSet = m_descriptorSets[index];\n\n\t\tif ( descriptorSet.set != VkDescriptorSet{} )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tpphdr::createDescriptorWrites( m_pass.getUniforms(), index, m_graph, descriptorSet.writes );\n\t\tpphdr::createDescriptorWrites( m_pass.getSampled(), index, m_graph, descriptorSet.writes );\n\t\tpphdr::createDescriptorWrites( m_pass.getInputs(), index, m_graph, descriptorSet.writes );\n\t\tpphdr::createDescriptorWrites( m_pass.getInouts(), index, m_graph, descriptorSet.writes );\n\t\tpphdr::createDescriptorWrites( m_pass.getOutputs(), index, m_graph, descriptorSet.writes );\n\n\t\tVkDescriptorSetAllocateInfo allocateInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\n\t\t\t, nullptr\n\t\t\t, m_descriptorSetPool\n\t\t\t, 1u\n\t\t\t, &m_descriptorSetLayout };\n\t\tauto res = m_context.vkAllocateDescriptorSets( m_context.device\n\t\t\t, &allocateInfo\n\t\t\t, &descriptorSet.set );\n\t\tcheckVkResult( res, m_pass.getGroupName() + \" - DescriptorSet allocation\" );\n\t\tcrgRegisterObject( m_context, m_pass.getGroupName(), descriptorSet.set );\n\n\t\tfor ( auto const & write : descriptorSet.writes )\n\t\t{\n\t\t\twrite.update( descriptorSet.set );\n\t\t}\n\n\t\tauto descriptorWrites = makeVkArray< VkWriteDescriptorSet >( descriptorSet.writes );\n\t\tm_context.vkUpdateDescriptorSets( m_context.device\n\t\t\t, uint32_t( descriptorWrites.size() )\n\t\t\t, descriptorWrites.data()\n\t\t\t, 0u\n\t\t\t, nullptr );\n\t}\n\n\tvoid PipelineHolder::doFillDescriptorBindings()\n\t{\n\t\tm_descriptorBindings.clear();\n\t\tauto shaderStage = VkShaderStageFlags( ( VK_PIPELINE_BIND_POINT_COMPUTE == m_bindingPoint )\n\t\t\t? VK_SHADER_STAGE_COMPUTE_BIT\n\t\t\t: ( VK_SHADER_STAGE_VERTEX_BIT\n\t\t\t\t| VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT\n\t\t\t\t| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT\n\t\t\t\t| VK_SHADER_STAGE_GEOMETRY_BIT\n\t\t\t\t| VK_SHADER_STAGE_FRAGMENT_BIT ) );\n\n\t\tpphdr::createDescriptorBindings( m_pass.getUniforms(), shaderStage, m_graph, m_descriptorBindings );\n\t\tpphdr::createDescriptorBindings( m_pass.getSampled(), shaderStage, m_graph, m_descriptorBindings );\n\t\tpphdr::createDescriptorBindings( m_pass.getInputs(), shaderStage, m_graph, m_descriptorBindings );\n\t\tpphdr::createDescriptorBindings( m_pass.getInouts(), shaderStage, m_graph, m_descriptorBindings );\n\t\tpphdr::createDescriptorBindings( m_pass.getOutputs(), shaderStage, m_graph, m_descriptorBindings );\n\t}\n\n\tvoid PipelineHolder::doCreateDescriptorSetLayout()\n\t{\n\t\tif ( m_context.vkCreateDescriptorSetLayout )\n\t\t{\n\t\t\tVkDescriptorSetLayoutCreateInfo createInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, static_cast< uint32_t >( m_descriptorBindings.size() )\n\t\t\t\t, m_descriptorBindings.data() };\n\t\t\tauto res = m_context.vkCreateDescriptorSetLayout( m_context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &m_descriptorSetLayout );\n\t\t\tcheckVkResult( res, m_pass.getGroupName() + \" - DescriptorSetLayout creation\" );\n\t\t\tcrgRegisterObject( m_context, m_pass.getGroupName(), m_descriptorSetLayout );\n\t\t}\n\t}\n\n\tvoid PipelineHolder::doCreatePipelineLayout()\n\t{\n\t\tif ( m_context.vkCreatePipelineLayout )\n\t\t{\n\t\t\tstd::vector< VkDescriptorSetLayout > layouts;\n\t\t\tlayouts.push_back( m_descriptorSetLayout );\n\t\t\tlayouts.insert( layouts.end()\n\t\t\t\t, m_baseConfig.m_layouts.begin()\n\t\t\t\t, m_baseConfig.m_layouts.end() );\n\t\t\tVkPipelineLayoutCreateInfo createInfo{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, uint32_t( layouts.size() )\n\t\t\t\t, layouts.data()\n\t\t\t\t, uint32_t( m_baseConfig.m_pushConstants.size() )\n\t\t\t\t, m_baseConfig.m_pushConstants.data() };\n\t\t\tauto res = m_context.vkCreatePipelineLayout( m_context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &m_pipelineLayout );\n\t\t\tcheckVkResult( res, m_pass.getGroupName() + \" - PipeliineLayout creation\" );\n\t\t\tcrgRegisterObject( m_context, m_pass.getGroupName(), m_pipelineLayout );\n\t\t}\n\t}\n\n\tvoid PipelineHolder::doCreateDescriptorPool()\n\t{\n\t\tif ( m_context.vkCreateDescriptorPool )\n\t\t{\n\t\t\tassert( m_descriptorSetLayout );\n\t\t\tauto sizes = getBindingsSizes( m_descriptorBindings, uint32_t( m_descriptorSets.size() ) );\n\t\t\tVkDescriptorPoolCreateInfo createInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, uint32_t( m_descriptorSets.size() )\n\t\t\t\t, uint32_t( sizes.size() )\n\t\t\t\t, sizes.data() };\n\t\t\tauto res = m_context.vkCreateDescriptorPool( m_context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, &m_descriptorSetPool );\n\t\t\tcheckVkResult( res, m_pass.getGroupName() + \" - DescriptorPool creation\" );\n\t\t\tcrgRegisterObject( m_context, m_pass.getGroupName(), m_descriptorSetPool );\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderMesh.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderMesh.hpp\"\n\nnamespace crg\n{\n\tRenderMesh::RenderMesh( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, ru::Config const & ruConfig\n\t\t, rm::Config rmConfig )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eColorAttachmentOutput ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, GetPassIndexCallback( [this](){ return m_renderMesh.getPassIndex(); } )\n\t\t\t\t, IsEnabledCallback( [this](){ return m_renderMesh.isEnabled(); } ) }\n\t\t\t, { ruConfig.maxPassCount\n\t\t\t\t, true /*resettable*/\n\t\t\t\t, ruConfig.prePassActions\n\t\t\t\t, ruConfig.postPassActions\n\t\t\t\t, ruConfig.implicitImageActions\n\t\t\t\t, ruConfig.implicitBufferActions } }\n\t\t, m_renderMesh{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, std::move( rmConfig )\n\t\t\t, ruConfig.maxPassCount }\n\t\t, m_renderPass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, ruConfig.maxPassCount\n\t\t\t, m_renderMesh.getRenderSize() }\n\t{\n\t}\n\n\tvoid RenderMesh::resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t, uint32_t index )\n\t{\n\t\tbool hadCommandBuffer = resetCommandBuffer( index );\n\t\tm_renderMesh.resetPipelineLayout( layouts, ranges, config, index );\n\t\tif ( hadCommandBuffer )\n\t\t\treRecordCurrent();\n\t}\n\n\tvoid RenderMesh::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tresetCommandBuffer( index );\n\t\tm_renderMesh.resetPipeline( std::move( config ), index );\n\t\treRecordCurrent();\n\t}\n\n\tvoid RenderMesh::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tif ( m_renderPass.initialise( context, *this, index ) )\n\t\t{\n\t\t\tm_renderMesh.cleanup();\n\t\t\tm_renderMesh.initialise( m_renderPass.getRenderSize()\n\t\t\t\t, m_renderPass.getRenderPass( index )\n\t\t\t\t, m_renderPass.createBlendState()\n\t\t\t\t, index );\n\t\t}\n\n\t\tm_renderPass.begin( context, commandBuffer, VK_SUBPASS_CONTENTS_INLINE, index );\n\t\tm_renderMesh.record( context, commandBuffer, index );\n\t\tm_renderPass.end( context, commandBuffer );\n\t\tm_renderMesh.end( context, commandBuffer, index );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderMeshHolder.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderMeshHolder.hpp\"\n\nnamespace crg\n{\n\t//*********************************************************************************************\n\n\tRenderMeshHolder::RenderMeshHolder( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, rm::Config config\n\t\t, uint32_t maxPassCount )\n\t\t: m_graph{ graph }\n\t\t, m_config{ config.m_renderPosition ? std::move( *config.m_renderPosition ) : getDefaultV< Offset2D >()\n\t\t\t, config.m_depthStencilState ? std::move( *config.m_depthStencilState ) : getDefaultV< VkPipelineDepthStencilStateCreateInfo >()\n\t\t\t, config.m_getPassIndex ? std::move( *config.m_getPassIndex ) : getDefaultV< RunnablePass::GetPassIndexCallback >()\n\t\t\t, config.m_isEnabled ? std::move( *config.m_isEnabled ) : getDefaultV< RunnablePass::IsEnabledCallback >()\n\t\t\t, config.m_recordInto ? std::move( *config.m_recordInto ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, config.m_end ? std::move( *config.m_end ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, config.m_getPrimitiveCount ? std::move( *config.m_getPrimitiveCount ) : getDefaultV< GetPrimitiveCountCallback >()\n\t\t\t, config.m_getVertexCount ? std::move( *config.m_getVertexCount ) : getDefaultV< GetVertexCountCallback >()\n\t\t\t, config.m_getIndexType ? std::move( *config.m_getIndexType ) : getDefaultV< GetIndexTypeCallback >()\n\t\t\t, config.m_getCullMode ? std::move( *config.m_getCullMode ) : getDefaultV< GetCullModeCallback >()\n\t\t\t, config.m_vertexBuffer ? std::move( *config.m_vertexBuffer ) : getDefaultV< VertexBuffer >()\n\t\t\t, config.m_indexBuffer ? std::move( *config.m_indexBuffer ) : getDefaultV< IndexBuffer >()\n\t\t\t, config.m_indirectBuffer ? *config.m_indirectBuffer : getDefaultV< IndirectBuffer >() }\n\t\t, m_pipeline{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, config.m_baseConfig\n\t\t\t, VK_PIPELINE_BIND_POINT_GRAPHICS\n\t\t\t, maxPassCount }\n\t\t, m_renderSize{ config.m_renderSize ? *config.m_renderSize : getDefaultV< Extent2D >() }\n\t{\n\t\tm_iaState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\n\t\t\t, VK_FALSE };\n\t\tm_msState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_SAMPLE_COUNT_1_BIT\n\t\t\t, VK_FALSE\n\t\t\t, 0.0f\n\t\t\t, nullptr\n\t\t\t, VK_FALSE\n\t\t\t, VK_FALSE };\n\t\tm_rsState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_FALSE\n\t\t\t, VK_FALSE\n\t\t\t, VK_POLYGON_MODE_FILL\n\t\t\t, m_config.getCullMode()\n\t\t\t, VK_FRONT_FACE_COUNTER_CLOCKWISE\n\t\t\t, VK_FALSE\n\t\t\t, 0.0f\n\t\t\t, 0.0f\n\t\t\t, 0.0f\n\t\t\t, 0.0f };\n\t}\n\n\tvoid RenderMeshHolder::initialise( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.initialise();\n\n\t\tif ( !m_renderPass )\n\t\t{\n\t\t\tdoPreparePipelineStates( renderSize, renderPass, std::move( blendState ) );\n\t\t}\n\t\telse if ( m_renderPass != renderPass )\n\t\t{\n\t\t\tresetRenderPass( renderSize, renderPass, std::move( blendState ), index );\n\t\t}\n\n\t\tdoCreatePipeline( index );\n\t}\n\n\tvoid RenderMeshHolder::cleanup()\n\t{\n\t\tm_pipeline.cleanup();\n\t}\n\n\tvoid RenderMeshHolder::resetRenderPass( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipeline( {}, index );\n\t\tdoPreparePipelineStates( renderSize, renderPass, std::move( blendState ) );\n\t\tdoCreatePipeline( index );\n\t}\n\n\tvoid RenderMeshHolder::resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipelineLayout( layouts, ranges, config );\n\n\t\tif ( m_renderPass )\n\t\t{\n\t\t\tdoCreatePipeline( index );\n\t\t}\n\t}\n\n\tvoid RenderMeshHolder::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipeline( std::move( config ), index );\n\n\t\tif ( m_renderPass )\n\t\t{\n\t\t\tdoCreatePipeline( index );\n\t\t}\n\t}\n\n\tvoid RenderMeshHolder::record( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tdoCreatePipeline( index );\n\t\tm_pipeline.recordInto( context, commandBuffer, index );\n\t\tm_config.recordInto( context, commandBuffer, index );\n\n\t\tif ( m_config.vertexBuffer.buffer != BufferViewId{} )\n\t\t{\n\t\t\tauto vkBuffer = m_graph.createBuffer( m_config.vertexBuffer.buffer.data->buffer );\n\t\t\tcontext->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u, &vkBuffer, &getSubresourceRange( m_config.vertexBuffer.buffer ).offset );\n\t\t}\n\n\t\tif ( m_config.indirectBuffer != defaultV< IndirectBuffer > )\n\t\t{\n\t\t\tauto indirectBuffer = m_graph.createBuffer( m_config.indirectBuffer.buffer.data->buffer );\n\t\t\tif ( m_config.indexBuffer != defaultV< IndexBuffer > )\n\t\t\t{\n\t\t\t\tauto indexBuffer = m_graph.createBuffer( m_config.indexBuffer.buffer.data->buffer );\n\t\t\t\tcontext->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, getSubresourceRange( m_config.indexBuffer.buffer ).offset, m_config.getIndexType() );\n\t\t\t\tcontext->vkCmdDrawIndexedIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcontext->vkCmdDrawIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride );\n\t\t\t}\n\t\t}\n\t\telse if ( m_config.indexBuffer != defaultV< IndexBuffer > )\n\t\t{\n\t\t\tauto indexBuffer = m_graph.createBuffer( m_config.indexBuffer.buffer.data->buffer );\n\t\t\tcontext->vkCmdBindIndexBuffer( commandBuffer, indexBuffer, getSubresourceRange( m_config.indexBuffer.buffer ).offset, m_config.getIndexType() );\n\t\t\tcontext->vkCmdDrawIndexed( commandBuffer, m_config.getPrimitiveCount(), 1u, 0u, 0u, 0u );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontext->vkCmdDraw( commandBuffer, m_config.getVertexCount(), 1u, 0u, 0u );\n\t\t}\n\t}\n\n\tvoid RenderMeshHolder::end( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tm_config.end( context, commandBuffer, index );\n\t}\n\n\tuint32_t RenderMeshHolder::getPassIndex()const\n\t{\n\t\treturn m_config.getPassIndex();\n\t}\n\n\tbool RenderMeshHolder::isEnabled()const\n\t{\n\t\treturn m_config.isEnabled();\n\t}\n\n\tExtent2D RenderMeshHolder::getRenderSize()const\n\t{\n\t\treturn m_renderSize;\n\t}\n\n\tvoid RenderMeshHolder::doPreparePipelineStates( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState )\n\t{\n\t\tm_vpState = doCreateViewportState( renderSize, m_viewport, m_scissor );\n\t\tm_renderSize = renderSize;\n\t\tm_renderPass = renderPass;\n\t\tm_blendAttachs = { blendState.pAttachments, blendState.pAttachments + blendState.attachmentCount };\n\t\tm_blendState = std::move( blendState );\n\t\tm_blendState.pAttachments = m_blendAttachs.data();\n\t}\n\n\tvoid RenderMeshHolder::doCreatePipeline( uint32_t index )\n\t{\n\t\tif ( m_pipeline.getPipeline( index ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tauto & program = m_pipeline.getProgram( index );\n\t\tVkGraphicsPipelineCreateInfo createInfo{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, uint32_t( program.size() )\n\t\t\t, program.data()\n\t\t\t, &m_config.vertexBuffer.inputState\n\t\t\t, &m_iaState\n\t\t\t, nullptr\n\t\t\t, &m_vpState\n\t\t\t, &m_rsState\n\t\t\t, &m_msState\n\t\t\t, &m_config.depthStencilState\n\t\t\t, &m_blendState\n\t\t\t, nullptr\n\t\t\t, m_pipeline.getPipelineLayout()\n\t\t\t, m_renderPass\n\t\t\t, 0u\n\t\t\t, VkPipeline{}\n\t\t\t, 0u };\n\t\tm_pipeline.createPipeline( index, createInfo );\n\n\t}\n\n\tVkPipelineViewportStateCreateInfo RenderMeshHolder::doCreateViewportState( Extent2D const & renderSize\n\t\t, VkViewport & viewport\n\t\t, VkRect2D & scissor )const\n\t{\n\t\tviewport = { float( m_config.renderPosition.x )\n\t\t\t, float( m_config.renderPosition.y )\n\t\t\t, float( renderSize.width )\n\t\t\t, float( renderSize.height )\n\t\t\t, 0.0f\n\t\t\t, 1.0f };\n\t\tscissor = { { m_config.renderPosition.x, m_config.renderPosition.y }\n\t\t\t, { renderSize.width, renderSize.height } };\n\t\treturn { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, 1u\n\t\t\t, & viewport\n\t\t\t, 1u\n\t\t\t, & scissor };\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderPass.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderPass.hpp\"\n\n#include \"RenderGraph/Attachment.hpp\"\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\t//*********************************************************************************************\n\n\tVkDescriptorPoolSizeArray getBindingsSizes( VkDescriptorSetLayoutBindingArray const & bindings\n\t\t, uint32_t maxSets )\n\t{\n\t\tVkDescriptorPoolSizeArray result;\n\n\t\tfor ( auto & binding : bindings )\n\t\t{\n\t\t\tauto it = std::find_if( result.begin(), result.end()\n\t\t\t\t, [&binding]( VkDescriptorPoolSize const & lookup )\n\t\t\t\t{\n\t\t\t\t\treturn binding.descriptorType == lookup.type;\n\t\t\t\t} );\n\t\t\tif ( it == result.end() )\n\t\t\t\tresult.push_back( { binding.descriptorType, binding.descriptorCount * maxSets } );\n\t\t\telse\n\t\t\t\tit->descriptorCount += binding.descriptorCount * maxSets;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t//*********************************************************************************************\n\n\tRenderPass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, RecordCallback record )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( record )\n\t\t\t, getDefaultV< GetSubpassContentsCallback >()\n\t\t\t, getDefaultV< GetPassIndexCallback >()\n\t\t\t, getDefaultV< IsEnabledCallback >() }\n\t{\n\t}\n\n\tRenderPass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, RecordCallback record\n\t\t, GetSubpassContentsCallback getSubpassContents )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( record )\n\t\t\t, std::move( getSubpassContents )\n\t\t\t, getDefaultV< GetPassIndexCallback >()\n\t\t\t, getDefaultV< IsEnabledCallback >() }\n\t{\n\t}\n\n\tRenderPass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, RecordCallback record\n\t\t, GetSubpassContentsCallback getSubpassContents\n\t\t, GetPassIndexCallback getPassIndex )\n\t\t: Callbacks{ std::move( initialise )\n\t\t\t, std::move( record )\n\t\t\t, std::move( getSubpassContents )\n\t\t\t, std::move( getPassIndex )\n\t\t\t, getDefaultV< IsEnabledCallback >() }\n\t{\n\t}\n\n\tRenderPass::Callbacks::Callbacks( InitialiseCallback initialise\n\t\t, RecordCallback record\n\t\t, GetSubpassContentsCallback getSubpassContents\n\t\t, GetPassIndexCallback getPassIndex\n\t\t, IsEnabledCallback isEnabled )\n\t\t: initialise{ std::move( initialise ) }\n\t\t, record{ std::move( record ) }\n\t\t, getSubpassContents{ std::move( getSubpassContents ) }\n\t\t, getPassIndex{ std::move( getPassIndex ) }\n\t\t, isEnabled{ std::move( isEnabled ) }\n\t{\n\t}\n\n\t//*********************************************************************************************\n\n\tRenderPass::RenderPass( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, Callbacks callbacks\n\t\t, Extent2D size\n\t\t, ru::Config const & ruConfig )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eColorAttachmentOutput ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, std::move( callbacks.getPassIndex )\n\t\t\t\t, std::move( callbacks.isEnabled ) }\n\t\t\t, ruConfig }\n\t\t, m_rpCallbacks{ std::move( callbacks ) }\n\t\t, m_holder{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, ruConfig.maxPassCount\n\t\t\t, std::move( size ) }\n\t{\n\t}\n\n\tvoid RenderPass::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tif ( m_holder.initialise( context, *this, index ) )\n\t\t{\n\t\t\tm_rpCallbacks.initialise( index );\n\t\t}\n\n\t\tm_holder.begin( context\n\t\t\t, commandBuffer\n\t\t\t, m_rpCallbacks.getSubpassContents()\n\t\t\t, index );\n\t\tm_rpCallbacks.record( context\n\t\t\t, commandBuffer\n\t\t\t, index );\n\t\tm_holder.end( context\n\t\t\t, commandBuffer );\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderPassHolder.cpp",
    "content": "/*\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderPassHolder.hpp\"\n\n#include \"RenderGraph/Attachment.hpp\"\n#include \"RenderGraph/GraphContext.hpp\"\n#include \"RenderGraph/Log.hpp\"\n#include \"RenderGraph/RunnableGraph.hpp\"\n\n#include <array>\n\nnamespace crg\n{\n\t//*********************************************************************************************\n\n\tnamespace rpHolder\n\t{\n\t\tstatic VkAttachmentReference addAttach( RecordContext & context\n\t\t\t, Attachment const & attach\n\t\t\t, ImageViewId view\n\t\t\t, VkAttachmentDescriptionArray & attaches\n\t\t\t, std::vector< RenderPassHolder::Entry > & viewAttaches\n\t\t\t, std::vector< VkClearValue > & clearValues\n\t\t\t, LayoutState initialLayout\n\t\t\t, LayoutState finalLayout\n\t\t\t, bool separateDepthStencilLayouts )\n\t\t{\n\t\t\tVkAttachmentReference result{ uint32_t( attaches.size() )\n\t\t\t\t, convert( attach.getImageLayout( separateDepthStencilLayouts ) ) };\n\t\t\tattaches.push_back( { 0u\n\t\t\t\t, convert( view.data->info.format )\n\t\t\t\t, convert( view.data->image.data->info.samples )\n\t\t\t\t, convert( initialLayout.layout == ImageLayout::eUndefined\n\t\t\t\t\t? AttachmentLoadOp::eClear\n\t\t\t\t\t: attach.getLoadOp() )\n\t\t\t\t, convert( attach.getStoreOp() )\n\t\t\t\t, convert( attach.getStencilLoadOp() )\n\t\t\t\t, convert( attach.getStencilStoreOp() )\n\t\t\t\t, convert( initialLayout.layout )\n\t\t\t\t, convert( finalLayout.layout ) } );\n\t\t\tviewAttaches.emplace_back( view, initialLayout, finalLayout );\n\t\t\tclearValues.push_back( convert( attach.getClearValue() ) );\n\n\t\t\tif ( view.data->source.empty() )\n\t\t\t{\n\t\t\t\tcontext.setLayoutState( view, finalLayout );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor ( auto & source : view.data->source )\n\t\t\t\t{\n\t\t\t\t\tcontext.setLayoutState( source, finalLayout );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic VkAttachmentReference addAttach( RecordContext & context\n\t\t\t, Attachment const & attach\n\t\t\t, ImageViewId view\n\t\t\t, VkAttachmentDescriptionArray & attaches\n\t\t\t, std::vector< RenderPassHolder::Entry > & viewAttaches\n\t\t\t, std::vector< VkClearValue > & clearValues\n\t\t\t, VkPipelineColorBlendAttachmentStateArray & blendAttachs\n\t\t\t, LayoutState initialLayout\n\t\t\t, LayoutState finalLayout\n\t\t\t, bool separateDepthStencilLayouts )\n\t\t{\n\t\t\tblendAttachs.push_back( convert( attach.getBlendState() ) );\n\t\t\treturn addAttach( context\n\t\t\t\t, attach\n\t\t\t\t, view\n\t\t\t\t, attaches\n\t\t\t\t, viewAttaches\n\t\t\t\t, clearValues\n\t\t\t\t, initialLayout\n\t\t\t\t, finalLayout\n\t\t\t\t, separateDepthStencilLayouts );\n\t\t}\n\n\t\tstatic bool operator!=( LayoutState const & lhs, LayoutState const & rhs )\n\t\t{\n\t\t\treturn lhs.layout != rhs.layout\n\t\t\t\t|| lhs.state.access != rhs.state.access\n\t\t\t\t|| ( lhs.state.access != AccessFlags::eNone && lhs.state.pipelineStage != rhs.state.pipelineStage );\n\t\t}\n\n\t\tstatic bool checkAttaches( RecordContext const & context\n\t\t\t, std::vector< RenderPassHolder::Entry > const & attaches\n\t\t\t, uint32_t passIndex )\n\t\t{\n\t\t\tauto it = std::find_if( attaches.begin(), attaches.end()\n\t\t\t\t, [&context, passIndex]( RenderPassHolder::Entry const & lookup )\n\t\t\t\t{\n\t\t\t\t\tauto layout = context.getLayoutState( resolveView( lookup.view, passIndex ) );\n\t\t\t\t\treturn layout != lookup.input\n\t\t\t\t\t\t&& layout.layout != ImageLayout::eUndefined;\n\t\t\t\t} );\n\t\t\treturn it == attaches.end();\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tvoid RenderPassHolder::PassData::cleanup( crg::GraphContext & context )noexcept\n\t{\n\t\tattaches.clear();\n\t\tclearValues.clear();\n\n\t\tif ( frameBuffer )\n\t\t{\n\t\t\tcrgUnregisterObject( context, frameBuffer );\n\t\t\tcontext.vkDestroyFramebuffer( context.device\n\t\t\t\t, frameBuffer\n\t\t\t\t, context.allocator );\n\t\t\tframeBuffer = {};\n\t\t}\n\n\t\tif ( renderPass )\n\t\t{\n\t\t\tcrgUnregisterObject( context, renderPass );\n\t\t\tcontext.vkDestroyRenderPass( context.device\n\t\t\t\t, renderPass\n\t\t\t\t, context.allocator );\n\t\t\trenderPass = {};\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n\tRenderPassHolder::RenderPassHolder( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, uint32_t maxPassCount\n\t\t, Extent2D size )\n\t\t: m_pass{ pass }\n\t\t, m_context{ context }\n\t\t, m_graph{ graph }\n\t\t, m_size{ std::move( size ) }\n\t{\n\t\tm_passes.resize( maxPassCount );\n\t}\n\n\tRenderPassHolder::~RenderPassHolder()noexcept\n\t{\n\t\tfor ( auto & data : m_passes )\n\t\t{\n\t\t\tdata.cleanup( m_context );\n\t\t}\n\t}\n\n\tbool RenderPassHolder::initialise( RecordContext & context\n\t\t, crg::RunnablePass const & runnable\n\t\t, uint32_t passIndex )\n\t{\n\t\tauto & data = m_passes[passIndex];\n\t\tauto previousState = context.getPrevPipelineState();\n\t\tauto nextState = context.getNextPipelineState();\n\n\t\tif ( data.renderPass\n\t\t\t&& rpHolder::checkAttaches( context, data.attaches, passIndex )\n\t\t\t&& data.previousState == previousState\n\t\t\t&& data.nextState == nextState )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tdata.cleanup( m_context );\n\t\tdoCreateRenderPass( context\n\t\t\t, runnable\n\t\t\t, previousState\n\t\t\t, nextState\n\t\t\t, passIndex );\n\t\tdoInitialiseRenderArea( passIndex );\n\t\treturn true;\n\t}\n\n\tVkRenderPassBeginInfo RenderPassHolder::getBeginInfo( uint32_t index )const\n\t{\n\t\tauto frameBuffer = getFramebuffer( index );\n\t\treturn VkRenderPassBeginInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\n\t\t\t, nullptr\n\t\t\t, getRenderPass( index )\n\t\t\t, frameBuffer\n\t\t\t, convert( getRenderArea( index ) )\n\t\t\t, uint32_t( getClearValues( index ).size() )\n\t\t\t, getClearValues( index ).data() };\n\t}\n\n\tvoid RenderPassHolder::begin( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, VkSubpassContents subpassContents\n\t\t, uint32_t index )\n\t{\n\t\tm_index = index;\n\t\tm_currentPass = &m_passes[m_index];\n\n\t\tfor ( auto & attach : m_currentPass->attaches )\n\t\t{\n\t\t\tcontext.setLayoutState( resolveView( attach.view, m_index )\n\t\t\t\t, attach.input );\n\t\t}\n\n\t\tauto beginInfo = getBeginInfo( m_index );\n\t\tm_context.vkCmdBeginRenderPass( commandBuffer\n\t\t\t, &beginInfo\n\t\t\t, subpassContents );\n\t}\n\n\tvoid RenderPassHolder::end( RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer )\n\t{\n\t\tm_context.vkCmdEndRenderPass( commandBuffer );\n\n\t\tfor ( auto & attach : m_currentPass->attaches )\n\t\t{\n\t\t\tcontext.setLayoutState( resolveView( attach.view, m_index )\n\t\t\t\t, attach.output );\n\t\t}\n\n\t\tm_currentPass = nullptr;\n\t}\n\n\tvoid RenderPassHolder::doCreateRenderPass( RecordContext & context\n\t\t\t, crg::RunnablePass const & runnable\n\t\t\t, PipelineState const & previousState\n\t\t\t, PipelineState const & nextState\n\t\t\t, uint32_t passIndex )\n\t{\n\t\tVkAttachmentDescriptionArray attaches;\n\t\tVkAttachmentReferenceArray colorReferences;\n\t\tVkAttachmentReference depthReference{};\n\t\tauto & data = m_passes[passIndex];\n\t\tm_blendAttachs.clear();\n\n\t\tfor ( auto attach : m_pass.getTargets() )\n\t\t{\n\t\t\tauto view = attach->view( passIndex );\n\t\t\tauto resolved = resolveView( view, passIndex );\n\t\t\tauto currentLayout = m_graph.getCurrentLayoutState( context, resolved );\n\t\t\tauto nextLayout = m_graph.getNextLayoutState( context, runnable, resolved );\n\t\t\tauto from = ( !attach->isInput()\n\t\t\t\t? crg::makeLayoutState( ImageLayout::eUndefined )\n\t\t\t\t: currentLayout );\n\t\t\tcheckUndefinedInput( \"RenderPass\", *attach, resolved, from.layout );\n\n\t\t\tif ( attach->isDepthImageTarget() || attach->isStencilImageTarget() )\n\t\t\t{\n\t\t\t\tdepthReference = rpHolder::addAttach( context\n\t\t\t\t\t, *attach\n\t\t\t\t\t, view\n\t\t\t\t\t, attaches\n\t\t\t\t\t, data.attaches\n\t\t\t\t\t, data.clearValues\n\t\t\t\t\t, from\n\t\t\t\t\t, nextLayout\n\t\t\t\t\t, m_context.separateDepthStencilLayouts );\n\t\t\t}\n\t\t\telse if ( attach->isColourImageTarget() )\n\t\t\t{\n\t\t\t\tcolorReferences.push_back( rpHolder::addAttach( context\n\t\t\t\t\t, *attach\n\t\t\t\t\t, view\n\t\t\t\t\t, attaches\n\t\t\t\t\t, data.attaches\n\t\t\t\t\t, data.clearValues\n\t\t\t\t\t, m_blendAttachs\n\t\t\t\t\t, from\n\t\t\t\t\t, nextLayout\n\t\t\t\t\t, m_context.separateDepthStencilLayouts ) );\n\t\t\t}\n\t\t}\n\n\t\tVkSubpassDescription subpassDesc{ 0u\n\t\t\t, VK_PIPELINE_BIND_POINT_GRAPHICS\n\t\t\t, 0u\n\t\t\t, nullptr\n\t\t\t, uint32_t( colorReferences.size() )\n\t\t\t, colorReferences.data()\n\t\t\t, nullptr\n\t\t\t, depthReference.layout ? &depthReference : nullptr\n\t\t\t, 0u\n\t\t\t, nullptr };\n\t\tdata.previousState = previousState;\n\t\tdata.nextState = nextState;\n\t\tVkSubpassDependencyArray dependencies{\n\t\t\t{ VK_SUBPASS_EXTERNAL\n\t\t\t\t, 0u\n\t\t\t\t, getPipelineStageFlags( previousState.pipelineStage )\n\t\t\t\t, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\n\t\t\t\t, getAccessFlags( previousState.access )\n\t\t\t\t, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT\n\t\t\t\t, VK_DEPENDENCY_BY_REGION_BIT }\n\t\t\t, { 0u\n\t\t\t\t, VK_SUBPASS_EXTERNAL\n\t\t\t\t, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\n\t\t\t\t, getPipelineStageFlags( nextState.pipelineStage )\n\t\t\t\t, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT\n\t\t\t\t, getAccessFlags( nextState.access )\n\t\t\t\t, VK_DEPENDENCY_BY_REGION_BIT } };\n\t\tVkRenderPassCreateInfo createInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, uint32_t( attaches.size() )\n\t\t\t, attaches.data()\n\t\t\t, 1u\n\t\t\t, &subpassDesc\n\t\t\t, uint32_t( dependencies.size() )\n\t\t\t, dependencies.data() };\n\t\tauto res = m_context.vkCreateRenderPass( m_context.device\n\t\t\t, &createInfo\n\t\t\t, m_context.allocator\n\t\t\t, &data.renderPass );\n\t\tcheckVkResult( res, m_pass.getGroupName() + \" - RenderPass creation\" );\n\t\tcrgRegisterObject( m_context, m_pass.getGroupName() + std::to_string( m_count++ ), data.renderPass );\n\t}\n\n\tVkPipelineColorBlendStateCreateInfo RenderPassHolder::createBlendState()\n\t{\n\t\treturn { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_FALSE\n\t\t\t, VK_LOGIC_OP_COPY\n\t\t\t, uint32_t( m_blendAttachs.size() )\n\t\t\t, m_blendAttachs.data()\n\t\t\t, {} };\n\t}\n\n\tVkFramebuffer RenderPassHolder::getFramebuffer( uint32_t index )const\n\t{\n\t\treturn doCreateFramebuffer( index );\n\t}\n\n\tvoid RenderPassHolder::doInitialiseRenderArea( uint32_t index )\n\t{\n\t\tuint32_t width{ m_size.width };\n\t\tuint32_t height{ m_size.height };\n\t\tm_passes[index].attachments.clear();\n\t\tm_layers = 1u;\n\n\t\tfor ( auto attach : m_pass.getTargets() )\n\t\t{\n\t\t\tauto view = attach->view();\n\t\t\tm_passes[index].attachments.push_back( attach );\n\t\t\twidth = std::max( width\n\t\t\t\t, view.data->image.data->info.extent.width >> getSubresourceRange( view ).baseMipLevel );\n\t\t\theight = std::max( height\n\t\t\t\t, view.data->image.data->info.extent.height >> getSubresourceRange( view ).baseMipLevel );\n\t\t\tm_layers = std::max( m_layers\n\t\t\t\t, getSubresourceRange( view ).layerCount );\n\t\t}\n\n\t\tm_passes[index].renderArea.extent.width = width;\n\t\tm_passes[index].renderArea.extent.height = height;\n\t}\n\n\tVkFramebuffer RenderPassHolder::doCreateFramebuffer( uint32_t passIndex )const\n\t{\n\t\tauto & data = m_passes[passIndex];\n\t\tauto frameBuffer = &data.frameBuffer;\n\n\t\tif ( !*frameBuffer )\n\t\t{\n\t\t\tVkImageViewArray attachments;\n\n\t\t\tfor ( auto & attach : data.attachments )\n\t\t\t{\n\t\t\t\tattachments.push_back( m_graph.createImageView( attach->view( passIndex ) ) );\n\t\t\t}\n\n\t\t\tVkFramebufferCreateInfo createInfo{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\n\t\t\t\t, nullptr\n\t\t\t\t, 0u\n\t\t\t\t, data.renderPass\n\t\t\t\t, uint32_t( attachments.size() )\n\t\t\t\t, attachments.data()\n\t\t\t\t, data.renderArea.extent.width\n\t\t\t\t, data.renderArea.extent.height\n\t\t\t\t, m_layers };\n\t\t\tauto res = m_context.vkCreateFramebuffer( m_context.device\n\t\t\t\t, &createInfo\n\t\t\t\t, m_context.allocator\n\t\t\t\t, frameBuffer );\n\t\t\tauto name = m_pass.getGroupName() + std::string( \"[\" ) + std::to_string( passIndex ) + std::string( \"]\" );\n\t\t\tcheckVkResult( res, name + \" - Framebuffer creation\" );\n\t\t\tcrgRegisterObject( m_context, name, *frameBuffer );\n\t\t}\n\n\t\treturn *frameBuffer;\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderQuad.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderQuad.hpp\"\n\nnamespace crg\n{\n\tRenderQuad::RenderQuad( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, ru::Config const & ruConfig\n\t\t, rq::Config rqConfig )\n\t\t: RunnablePass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, { defaultV< InitialiseCallback >\n\t\t\t\t, GetPipelineStateCallback( [](){ return crg::getPipelineState( PipelineStageFlags::eColorAttachmentOutput ); } )\n\t\t\t\t, [this]( RecordContext & recContext, VkCommandBuffer cb, uint32_t i ){ doRecordInto( recContext, cb, i ); }\n\t\t\t\t, GetPassIndexCallback( [this](){ return m_renderQuad.getPassIndex(); } )\n\t\t\t\t, IsEnabledCallback( [this](){ return m_renderQuad.isEnabled(); } ) }\n\t\t\t, { ruConfig.maxPassCount\n\t\t\t\t, true /*resettable*/\n\t\t\t\t, ruConfig.prePassActions\n\t\t\t\t, ruConfig.postPassActions\n\t\t\t\t, ruConfig.implicitImageActions\n\t\t\t\t, ruConfig.implicitBufferActions } }\n\t\t, m_renderQuad{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, rqConfig\n\t\t\t, ruConfig.maxPassCount }\n\t\t, m_renderPass{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, ruConfig.maxPassCount\n\t\t\t, rqConfig.m_renderSize ? *rqConfig.m_renderSize : getDefaultV< Extent2D >() }\n\t{\n\t}\n\n\tvoid RenderQuad::resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t, uint32_t index )\n\t{\n\t\tbool hadCommandBuffer = resetCommandBuffer( index );\n\t\tm_renderQuad.resetPipelineLayout( layouts, ranges, config, index );\n\t\tif ( hadCommandBuffer )\n\t\t\treRecordCurrent();\n\t}\n\n\tvoid RenderQuad::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tresetCommandBuffer( index );\n\t\tm_renderQuad.resetPipeline( std::move( config ), index );\n\t\treRecordCurrent();\n\t}\n\n\tvoid RenderQuad::doRecordInto( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tif ( m_renderPass.initialise( context, *this, index ) )\n\t\t{\n\t\t\tm_renderQuad.initialise( m_renderPass.getRenderSize()\n\t\t\t\t, m_renderPass.getRenderPass( index )\n\t\t\t\t, m_renderPass.createBlendState()\n\t\t\t\t, index );\n\t\t}\n\n\t\tm_renderPass.begin( context, commandBuffer, VK_SUBPASS_CONTENTS_INLINE, index );\n\t\tm_renderQuad.record( context, commandBuffer, index );\n\t\tm_renderPass.end( context, commandBuffer );\n\t\tm_renderQuad.end( context, commandBuffer, index );\n\t}\n}\n"
  },
  {
    "path": "source/RenderGraph/RunnablePasses/RenderQuadHolder.cpp",
    "content": "/*\nThis file belongs to FrameGraph.\nSee LICENSE file in root folder.\n*/\n#include \"RenderGraph/RunnablePasses/RenderQuadHolder.hpp\"\n\n#include \"RenderGraph/GraphContext.hpp\"\n\nnamespace crg\n{\n\tnamespace rdqdhdr\n\t{\n\t\tstatic bool isPtrEnabled( bool const * v )\n\t\t{\n\t\t\treturn v ? *v : true;\n\t\t}\n\t}\n\n\tRenderQuadHolder::RenderQuadHolder( FramePass const & pass\n\t\t, GraphContext & context\n\t\t, RunnableGraph & graph\n\t\t, rq::Config config\n\t\t, uint32_t maxPassCount )\n\t\t: m_config{ config.m_texcoordConfig ? std::move( *config.m_texcoordConfig ) : getDefaultV< Texcoord >()\n\t\t\t, config.m_renderPosition ? std::move( *config.m_renderPosition ) : getDefaultV< Offset2D >()\n\t\t\t, config.m_depthStencilState ? std::move( *config.m_depthStencilState ) : getDefaultV< VkPipelineDepthStencilStateCreateInfo >()\n\t\t\t, config.m_passIndex.has_value() ? *config.m_passIndex : getDefaultV< uint32_t const * >()\n\t\t\t, config.m_enabled.has_value() ? *config.m_enabled : getDefaultV< bool const * >()\n\t\t\t, config.m_isEnabled\n\t\t\t, config.m_recordInto ? std::move( *config.m_recordInto ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, config.m_end ? std::move( *config.m_end ) : getDefaultV< RunnablePass::RecordCallback >()\n\t\t\t, config.m_instances.has_value() ? *config.m_instances : 1u\n\t\t\t, config.m_indirectBuffer ? *config.m_indirectBuffer : getDefaultV < IndirectBuffer >() }\n\t\t, m_graph{ graph }\n\t\t, m_pipeline{ pass\n\t\t\t, context\n\t\t\t, graph\n\t\t\t, config.m_baseConfig\n\t\t\t, VK_PIPELINE_BIND_POINT_GRAPHICS\n\t\t\t, maxPassCount }\n\t\t, m_useTexCoord{ config.m_texcoordConfig }\n\t{\n\t\tm_iaState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP\n\t\t\t, VK_FALSE };\n\t\tm_msState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_SAMPLE_COUNT_1_BIT\n\t\t\t, VK_FALSE\n\t\t\t, 0.0f\n\t\t\t, nullptr\n\t\t\t, VK_FALSE\n\t\t\t, VK_FALSE };\n\t\tm_rsState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\n\t\t\t, nullptr\n\t\t\t, 0u\n\t\t\t, VK_FALSE\n\t\t\t, VK_FALSE\n\t\t\t, VK_POLYGON_MODE_FILL\n\t\t\t, VK_CULL_MODE_NONE\n\t\t\t, VK_FRONT_FACE_COUNTER_CLOCKWISE\n\t\t\t, VK_FALSE\n\t\t\t, 0.0f\n\t\t\t, 0.0f\n\t\t\t, 0.0f\n\t\t\t, 0.0f };\n\t}\n\n\tvoid RenderQuadHolder::initialise( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t, uint32_t index )\n\t{\n\t\tif ( !m_vertexBuffer )\n\t\t{\n\t\t\tm_pipeline.initialise();\n\t\t\tm_vertexBuffer = &m_graph.createQuadTriVertexBuffer( m_useTexCoord\n\t\t\t\t, m_config.texcoordConfig );\n\t\t\tdoPreparePipelineStates( renderSize, renderPass, std::move( blendState ) );\n\t\t}\n\t\telse if ( m_renderPass != renderPass )\n\t\t{\n\t\t\tresetRenderPass( renderSize, renderPass, std::move( blendState ), index );\n\t\t}\n\n\t\tdoCreatePipeline( index );\n\t}\n\n\tvoid RenderQuadHolder::resetRenderPass( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipeline( {}, index );\n\t\tdoPreparePipelineStates( renderSize, renderPass, std::move( blendState ) );\n\t\tdoCreatePipeline( index );\n\t}\n\n\tvoid RenderQuadHolder::resetPipelineLayout( std::vector< VkDescriptorSetLayout > const & layouts\n\t\t, std::vector< VkPushConstantRange > const & ranges\n\t\t, VkPipelineShaderStageCreateInfoArray const & config\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipelineLayout( layouts, ranges, config );\n\n\t\tif ( m_renderPass )\n\t\t{\n\t\t\tdoCreatePipeline( index );\n\t\t}\n\t}\n\n\tvoid RenderQuadHolder::resetPipeline( VkPipelineShaderStageCreateInfoArray config\n\t\t, uint32_t index )\n\t{\n\t\tm_pipeline.resetPipeline( std::move( config ), index );\n\n\t\tif ( m_renderPass )\n\t\t{\n\t\t\tdoCreatePipeline( index );\n\t\t}\n\t}\n\n\tvoid RenderQuadHolder::record( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )\n\t{\n\t\tdoCreatePipeline( index );\n\t\tm_pipeline.recordInto( context, commandBuffer, index );\n\t\tm_config.recordInto( context, commandBuffer, index );\n\n\t\tif ( m_vertexBuffer )\n\t\t{\n\t\t\tauto vkBuffer = m_graph.createBuffer( m_vertexBuffer->buffer.data->buffer );\n\t\t\tcontext->vkCmdBindVertexBuffers( commandBuffer, 0u, 1u\n\t\t\t\t, &vkBuffer, &getSubresourceRange( m_vertexBuffer->buffer ).offset );\n\t\t}\n\n\t\tif ( m_config.indirectBuffer != defaultV< IndirectBuffer > )\n\t\t{\n\t\t\tauto indirectBuffer = m_graph.createBuffer( m_config.indirectBuffer.buffer.data->buffer );\n\t\t\tcontext->vkCmdDrawIndirect( commandBuffer, indirectBuffer, getSubresourceRange( m_config.indirectBuffer.buffer ).offset, 1u, m_config.indirectBuffer.stride );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontext->vkCmdDraw( commandBuffer, 3u, m_config.m_instances, 0u, 0u );\n\t\t}\n\t}\n\n\tvoid RenderQuadHolder::end( RecordContext & context\n\t\t, VkCommandBuffer commandBuffer\n\t\t, uint32_t index )const\n\t{\n\t\tm_config.end( context, commandBuffer, index );\n\t}\n\n\tuint32_t RenderQuadHolder::getPassIndex()const\n\t{\n\t\treturn ( m_config.passIndex\n\t\t\t? *m_config.passIndex\n\t\t\t: 0u );\n\t}\n\n\tbool RenderQuadHolder::isEnabled()const\n\t{\n\t\treturn ( m_config.isEnabled\n\t\t\t? ( *m_config.isEnabled )()\n\t\t\t: rdqdhdr::isPtrEnabled( m_config.enabled ) );\n\t}\n\n\tvoid RenderQuadHolder::doPreparePipelineStates( Extent2D const & renderSize\n\t\t, VkRenderPass renderPass\n\t\t, VkPipelineColorBlendStateCreateInfo blendState )\n\t{\n\t\tm_vpState = doCreateViewportState( renderSize, m_viewport, m_scissor );\n\t\tm_renderSize = renderSize;\n\t\tm_renderPass = renderPass;\n\t\tm_blendAttachs = { blendState.pAttachments, blendState.pAttachments + blendState.attachmentCount };\n\t\tm_blendState = std::move( blendState );\n\t\tm_blendState.pAttachments = m_blendAttachs.data();\n\t}\n\n\tvoid RenderQuadHolder::doCreatePipeline( uint32_t index )\n\t{\n\t\tif ( m_pipeline.getPipeline( index ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tauto & program = m_pipeline.getProgram( index );\n\t\tVkGraphicsPipelineCreateInfo createInfo{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, nullptr, 0u\n\t\t\t, uint32_t( program.size() ), program.data()\n\t\t\t, &getInputState(), &m_iaState, nullptr\n\t\t\t, &m_vpState, &m_rsState, &m_msState\n\t\t\t, &m_config.depthStencilState, &m_blendState, nullptr\n\t\t\t, m_pipeline.getPipelineLayout(), m_renderPass\n\t\t\t, 0u, VkPipeline{}, 0u };\n\t\tm_pipeline.createPipeline( index, createInfo );\n\t}\n\n\tVkPipelineViewportStateCreateInfo RenderQuadHolder::doCreateViewportState( Extent2D const & renderSize\n\t\t, VkViewport & viewport\n\t\t, VkRect2D & scissor )const\n\t{\n\t\tviewport = { float( m_config.renderPosition.x )\n\t\t\t, float( m_config.renderPosition.y )\n\t\t\t, float( renderSize.width )\n\t\t\t, float( renderSize.height )\n\t\t\t, 0.0f\n\t\t\t, 1.0f };\n\t\tscissor = { { m_config.renderPosition.x, m_config.renderPosition.y }\n\t\t\t, { renderSize.width, renderSize.height } };\n\t\treturn { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, nullptr, 0u\n\t\t\t, 1u, &viewport\n\t\t\t, 1u, &scissor };\n\t}\n}\n"
  },
  {
    "path": "test/BaseTest.cpp",
    "content": "#include \"BaseTest.hpp\"\n\n#include <RenderGraph/Log.hpp>\n\n#if defined( _WIN32 )\n#\tinclude <Windows.h>\n#elif defined( __APPLE__ )\n#\tinclude <string>\n#\tinclude <vector>\n#\tinclude <mach-o/dyld.h>\n#elif defined( __linux__ )\n#\tinclude <unistd.h>\n#\tinclude <dirent.h>\n#\tinclude <pwd.h>\n#endif\n\n#include <fmt/base.h>\n\n#include <array>\n#include <functional>\n#include <iomanip>\n#include <map>\n#include <sstream>\n#include <set>\n\nnamespace test\n{\n\tusing StringArray = std::vector< std::string >;\n\n\t//*********************************************************************************************\n\n\tnamespace\n\t{\n\t\ttemplate< typename LogStreambufTraits >\n\t\tclass LogStreambuf\n\t\t\t: public std::streambuf\n\t\t{\n\t\tpublic:\n\t\t\tusing string_type = std::string;\n\t\t\tusing ostream_type = std::ostream;\n\t\t\tusing streambuf_type = std::streambuf;\n\t\t\tusing int_type = std::streambuf::int_type;\n\t\t\tusing traits_type = std::streambuf::traits_type;\n\n\t\t\tLogStreambuf( LogStreambuf const & ) = delete;\n\t\t\tLogStreambuf & operator=( LogStreambuf const & ) = delete;\n\t\t\tLogStreambuf( LogStreambuf && ) = delete;\n\t\t\tLogStreambuf & operator=( LogStreambuf && ) = delete;\n\n\t\t\texplicit LogStreambuf( std::string const & name\n\t\t\t\t, std::ostream & stream )\n\t\t\t\t: m_stream{ stream }\n\t\t\t\t, m_fstream{ getExecutableDirectory() + name + \".log\" }\n\t\t\t{\n\t\t\t\tm_old = m_stream.rdbuf( this );\n\t\t\t}\n\n\t\t\t~LogStreambuf()noexcept override\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tm_stream.rdbuf( m_old );\n\t\t\t\t}\n\t\t\t\tcatch ( ... )\n\t\t\t\t{\n\t\t\t\t\t// What to do here ?\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint_type overflow( int_type c = traits_type::eof() )override\n\t\t\t{\n\t\t\t\tif ( traits_type::eq_int_type( c, traits_type::eof() ) )\n\t\t\t\t{\n\t\t\t\t\tdo_sync();\n\t\t\t\t}\n\t\t\t\telse if ( c == '\\n' )\n\t\t\t\t{\n\t\t\t\t\tdo_sync();\n\t\t\t\t}\n\t\t\t\telse if ( c == '\\r' )\n\t\t\t\t{\n\t\t\t\t\tm_buffer += '\\r';\n\t\t\t\t\tdo_sync_no_nl();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tm_buffer += traits_type::to_char_type( c );\n\t\t\t\t}\n\n\t\t\t\treturn c;\n\t\t\t}\n\n\t\t\tint do_sync()\n\t\t\t{\n\t\t\t\tLogStreambufTraits::log( m_fstream, m_buffer );\n\t\t\t\tm_buffer.clear();\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tint do_sync_no_nl()\n\t\t\t{\n\t\t\t\tLogStreambufTraits::logNoNL( m_fstream, m_buffer );\n\t\t\t\tm_buffer.clear();\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstring_type m_buffer;\n\t\t\tostream_type & m_stream;\n\t\t\tstreambuf_type * m_old;\n\t\t\tstd::ofstream m_fstream;\n\t\t};\n\n\t\tstruct DebugLogStreambufTraits\n\t\t{\n\t\t\tstatic void log( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << \"DEBUG: \" << text << std::endl;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\n\t\t\tstatic void logNoNL( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << \"DEBUG: \" << text;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\t\t};\n\n\t\tstruct InfoLogStreambufTraits\n\t\t{\n\t\t\tstatic void log( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << text << std::endl;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\n\t\t\tstatic void logNoNL( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << text;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\t\t};\n\n\t\tstruct ErrorLogStreambufTraits\n\t\t{\n\t\t\tstatic void log( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << \"ERROR: \" << text << std::endl;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\n\t\t\tstatic void logNoNL( std::ostream & stream\n\t\t\t\t, std::string const & text )\n\t\t\t{\n\t\t\t\tstream << \"ERROR: \" << text;\n\t\t\t\tfmt::print( \"{}\\n\", text );\n\t\t\t}\n\t\t};\n\n#if defined( _WIN32 )\n\t\tchar constexpr PathSeparator = '\\\\';\n#else\n\t\tchar constexpr PathSeparator = '/';\n#endif\n\n\t\tstd::string getPath( std::string_view path )\n\t\t{\n\t\t\treturn std::string{ path.substr( 0, path.find_last_of( PathSeparator ) ) };\n\t\t}\n\n\t\tstd::string findMissing( StringArray const & lhsLines\n\t\t\t, StringArray const & rhsLines\n\t\t\t, std::string_view const & op )\n\t\t{\n\t\t\tstd::string result;\n\n\t\t\tfor ( auto & lhsLine : lhsLines )\n\t\t\t{\n\t\t\t\tif ( rhsLines.end() == std::find( rhsLines.begin()\n\t\t\t\t\t, rhsLines.end()\n\t\t\t\t\t, lhsLine ) )\n\t\t\t\t{\n\t\t\t\t\tresult += std::string{ op } + lhsLine + \"\\n\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t//*********************************************************************************************\n\n#if defined( _WIN32 )\n\n\tstd::string getExecutableDirectory()\n\t{\n\t\tstd::string result;\n\t\tstd::array< char, FILENAME_MAX > path{};\n\n\t\tif ( DWORD res = ::GetModuleFileNameA( nullptr\n\t\t\t, path.data()\n\t\t\t, sizeof( path ) ) )\n\t\t{\n\t\t\tresult = path.data();\n\t\t}\n\n\t\tresult = getPath( result ) + PathSeparator;\n\t\treturn result;\n\t}\n\n#elif defined( __APPLE__ )\n\n\tstd::string getExecutableDirectory()\n\t{\n\t\tstd::string result;\n\t\tstd::array< char, FILENAME_MAX > path{};\n\t\tuint32_t size = FILENAME_MAX;\n\n\t\tif ( _NSGetExecutablePath( path.data(), &size ) == 0 )\n\t\t{\n\t\t\tchar realPath[FILENAME_MAX]{};\n\t\t\trealpath( path.data(), realPath );\n\t\t\tresult = std::string{ realPath };\n\t\t}\n\n\t\tresult = getPath( result ) + PathSeparator;\n\t\treturn result;\n\t}\n\t\n#else\n\n\tstd::string getExecutableDirectory()\n\t{\n\t\tstd::string result;\n\t\tstd::array< char, FILENAME_MAX > path{};\n\t\tchar buffer[32];\n\t\tsprintf( buffer, \"/proc/%d/exe\", getpid() );\n\t\tint bytes = std::min< std::size_t >( readlink( buffer\n\t\t\t, path.data()\n\t\t\t, path.size() )\n\t\t\t, path.size() - 1 );\n\n\t\tif ( bytes > 0 )\n\t\t{\n\t\t\tpath[bytes] = '\\0';\n\t\t\tresult = path.data();\n\t\t}\n\n\t\tresult = getPath( result ) + PathSeparator;\n\t\treturn result;\n\t}\n\n#endif\n\n\t//*********************************************************************************************\n\n\tStringArray splitInLines( std::string const & value )\n\t{\n\t\tStringArray lines;\n\t\tstd::stringstream iss( value );\n\n\t\twhile ( iss.good() )\n\t\t{\n\t\t\tstd::string line;\n\t\t\tstd::getline( iss, line );\n\t\t\tlines.push_back( line );\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tstd::string TestCounts::diffLines( std::string const & check\n\t\t, std::string const & ref )\n\t{\n\t\tauto checkLines = splitInLines( check );\n\t\tauto refLines = splitInLines( ref );\n\t\tstd::string result;\n\t\tresult += findMissing( checkLines, refLines, \"+\" );\n\t\tresult += findMissing( refLines, checkLines, \"-\" );\n\t\treturn result;\n\t}\n\n\t//*********************************************************************************************\n\n\tTestSuite::TestSuite( std::string const & name )\n\t\t: tclog{ std::make_unique< test::LogStreambuf< test::DebugLogStreambufTraits > >( name, std::clog ) }\n\t\t, tcout{ std::make_unique< test::LogStreambuf< test::InfoLogStreambufTraits > >( name, std::cout ) }\n\t\t, tcerr{ std::make_unique< test::LogStreambuf< test::ErrorLogStreambufTraits > >( name, std::cerr ) }\n\t{\n\t\tcrg::Logger::setTraceCallback( []( std::string_view, bool )noexcept\n\t\t\t{\n\t\t\t\t// Don't log trace\n\t\t\t} );\n\t\tcrg::Logger::setDebugCallback( []( std::string_view msg, bool newLine )noexcept\n\t\t\t{\n\t\t\t\tstd::clog << msg.data();\n\t\t\t\tif ( newLine )\n\t\t\t\t\tstd::clog << \"\\n\";\n\t\t\t} );\n\t\tcrg::Logger::setInfoCallback( []( std::string_view msg, bool newLine )noexcept\n\t\t\t{\n\t\t\t\tstd::cout << msg.data();\n\t\t\t\tif ( newLine )\n\t\t\t\t\tstd::cout << \"\\n\";\n\t\t\t} );\n\t\tcrg::Logger::setWarningCallback( []( std::string_view msg, bool newLine )noexcept\n\t\t\t{\n\t\t\t\tstd::cout << msg.data();\n\t\t\t\tif ( newLine )\n\t\t\t\t\tstd::cout << \"\\n\";\n\t\t\t} );\n\t\tcrg::Logger::setErrorCallback( []( std::string_view msg, bool newLine )noexcept\n\t\t\t{\n\t\t\t\tstd::cerr << msg.data();\n\t\t\t\tif ( newLine )\n\t\t\t\t\tstd::cerr << \"\\n\";\n\t\t\t} );\n\t}\n\n\t//*********************************************************************************************\n\n\tint testsMain( int argc, char ** argv, std::string_view testSuiteName )\n\t{\n\t\tstd::locale::global( std::locale{ \"C\" } );\n\t\ttesting::InitGoogleTest( &argc, argv );\n\t\tauto suite = std::make_unique< test::TestSuite >( std::string{ testSuiteName } );\n\t\ttesting::AddGlobalTestEnvironment( suite.release() );\n\t\treturn RUN_ALL_TESTS();\n\t}\n\n\tstd::string sortLines( std::string const & value )\n\t{\n\t\tstd::stringstream stream{ value };\n\t\tstd::multiset< std::string, std::less<> > sorted;\n\t\tstd::string line;\n\n\t\twhile ( std::getline( stream, line ) )\n\t\t{\n\t\t\tsorted.insert( line );\n\t\t}\n\n\t\tstd::stringstream result;\n\n\t\tfor ( auto & v : sorted )\n\t\t{\n\t\t\tresult << v << std::endl;\n\t\t}\n\n\t\treturn result.str();\n\t}\n\n\t//*********************************************************************************************\n}\n"
  },
  {
    "path": "test/BaseTest.hpp",
    "content": "#pragma once\n\n#include <fstream>\n#include <iostream>\n#include <memory>\n#include <stdexcept>\n\n#include <RenderGraph/Exception.hpp>\n\n#include <gtest/gtest.h>\n\nnamespace test\n{\n\tstd::string getExecutableDirectory();\n\n\tstruct TestCounts\n\t{\n\t\texplicit TestCounts( std::string const & testName )\n\t\t\t: testName{ testName }\n\t\t{\n\t\t}\n\n\t\tstatic std::string diffLines( std::string const & check\n\t\t\t, std::string const & ref );\n\n\t\tstd::string testName;\n\t};\n\n\tclass Exception\n\t\t: public std::runtime_error\n\t{\n\tpublic:\n\t\tusing std::runtime_error::runtime_error;\n\t};\n\n\tclass TestSuite\n\t\t: public ::testing::Environment\n\t{\n\tpublic:\n\t\texplicit TestSuite( std::string const & name );\n\n\tprivate:\n\t\tstd::unique_ptr< std::streambuf > tclog;\n\t\tstd::unique_ptr< std::streambuf > tcout;\n\t\tstd::unique_ptr< std::streambuf > tcerr;\n\t};\n\n\tint testsMain( int argc, char ** argv, std::string_view testSuiteName );\n\n\tstd::string sortLines( std::string const & value );\n\n#define testStringify( x )\\\n\t#x\n\n#define nameConcat( X, Y ) nameConcat_( X, Y )\n#define nameConcat_( X, Y ) X ## Y\n\n#define testBegin( name )\\\n\ttest::TestCounts testCounts{ name };\n\n#define testEnd()\n\n#define require( x )\\\n\ttry\\\n\t{\\\n\t\tif ( !( x ) )\\\n\t\t{\\\n\t\t\tthrow test::Exception{ std::string{ testStringify( x ) } };\\\n\t\t}\\\n\t}\\\n\tcatch ( test::Exception & exc )\\\n\t{\\\n\t\tGTEST_FATAL_FAILURE_( ( std::string{ testStringify( x )\" failed.\" } + exc.what() ).c_str() );\\\n\t}\\\n\tcatch ( ... )\\\n\t{\\\n\t\tGTEST_FATAL_FAILURE_( \"Unknown unhandled exception.\" );\\\n\t}\n\n#define check( x )\\\n\tEXPECT_TRUE( x );\n\n#define checkEqual( x, y )\\\n\tEXPECT_EQ( x, y );\n\n#define checkEqualSortedLines( x, y )\\\n\ttry\\\n\t{\\\n\t\tauto diff = test::TestCounts::diffLines( test::sortLines( x ), test::sortLines( y ) );\\\n\t\tif ( !diff.empty() )\\\n\t\t{\\\n\t\t\tthrow test::Exception{ \"LHS(\\n\" + std::string{ x } + \" )\\nRHS(\\n\" + std::string{ y } + \" )\\nDIFF(\\n\" + diff + \" )\" };\\\n\t\t}\\\n\t}\\\n\tcatch ( test::Exception & exc )\\\n\t{\\\n\t\tGTEST_FATAL_FAILURE_( ( std::string{ #x\" failed.\" } + exc.what() ).c_str() );\\\n\t}\\\n\tcatch ( crg::Exception & exc )\\\n\t{\\\n\t\tGTEST_FATAL_FAILURE_( ( std::string{ #x\" failed.\" } + exc.what() ).c_str() );\\\n\t}\\\n\tcatch ( ... )\\\n\t{\\\n\t\tGTEST_FATAL_FAILURE_( \"Unknown unhandled exception.\" );\\\n\t}\n\n#define checkThrow( x, excType )\\\n\tEXPECT_THROW( x, excType );\n\n#define checkNoThrow( x )\\\n\tEXPECT_NO_THROW( x );\n\n#define testSuiteMain()\\\n\tint main( int argc, char ** argv )\\\n\t{\\\n\t\treturn test::testsMain( argc, argv, CRG_TestSuiteNameString );\\\n\t}\n}\n"
  },
  {
    "path": "test/CMakeLists.txt",
    "content": "enable_testing()\n\nset( GTest_DIR ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/gtest )\nfind_package( GTest CONFIG REQUIRED GTest::gtest GTest::gtest_main )\nfind_package( fmt CONFIG REQUIRED )\n\nset( TEST_NAME TestCommon )\n\nset( ${TEST_NAME}_HEADER_FILES\n\t${CMAKE_CURRENT_SOURCE_DIR}/BaseTest.hpp\n\t${CMAKE_CURRENT_SOURCE_DIR}/Common.hpp\n)\nset( ${TEST_NAME}_SOURCE_FILES\n\t${CMAKE_CURRENT_SOURCE_DIR}/BaseTest.cpp\n\t${CMAKE_CURRENT_SOURCE_DIR}/Common.cpp\n)\n\nadd_library( ${TEST_NAME}\n\tSTATIC\n\t${${TEST_NAME}_HEADER_FILES}\n\t${${TEST_NAME}_SOURCE_FILES}\n)\nadd_library( crg::${TEST_NAME}\n\tALIAS\n\t\t${TEST_NAME}\n)\ntarget_sources( ${TEST_NAME} \n\tPRIVATE\n\t\t${CRG_EDITORCONFIG_FILE}\n)\ntarget_link_libraries( ${TEST_NAME}\n\tPUBLIC\n\t\tcrg::RenderGraph\n\t\tGTest::gtest\n\t\tfmt::fmt\n)\ntarget_include_directories( ${TEST_NAME}\n\tPUBLIC\n\t\t${VULKAN_HEADERS_INCLUDE_DIRS}\n)\nset_target_properties( ${TEST_NAME}\n\tPROPERTIES\n\t\tCXX_STANDARD 20\n\t\tFOLDER \"Tests/${MAIN_PROJECT_NAME}\"\n)\n\nfile( GLOB TEST_FILES\n\t${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp\n)\n\nforeach ( TEST_FILE ${TEST_FILES} )\n\tget_filename_component( TEST_NAME ${TEST_FILE} NAME_WE )\n\tadd_executable( ${TEST_NAME}\n\t\t${TEST_FILE}\n\t)\n\ttarget_sources( ${TEST_NAME} \n\t\tPRIVATE\n\t\t\t${CRG_EDITORCONFIG_FILE}\n\t)\n\ttarget_link_libraries( ${TEST_NAME}\n\t\tPRIVATE\n\t\t\tcrg::TestCommon\n\t)\n\tset_target_properties( ${TEST_NAME}\n\t\tPROPERTIES\n\t\t\tCXX_STANDARD 20\n\t\t\tFOLDER \"Tests/${MAIN_PROJECT_NAME}\"\n\t)\n\ttarget_compile_definitions( ${TEST_NAME}\n\t\tPRIVATE\n\t\t\tCRG_TestSuiteName=${TEST_NAME}\n\t\t\tCRG_TestSuiteNameString=\"${TEST_NAME}\"\n\t)\n\ttarget_include_directories( ${TEST_NAME}\n\t\tPRIVATE\n\t\t\t${VULKAN_HEADERS_INCLUDE_DIRS}\n\t)\n\ttarget_add_coverage_flags( ${TEST_NAME} )\n\tif ( NOT CRG_BUILD_STATIC )\n\t\tif ( WIN32 )\n\t\t\ttarget_link_libraries( ${TEST_NAME}\n\t\t\t\tPRIVATE\n\t\t\t\t\tDbghelp\n\t\t\t)\n\t\telse ()\n\t\t\ttarget_link_libraries( ${TEST_NAME}\n\t\t\t\tPRIVATE\n\t\t\t\t\tdl\n\t\t\t)\n\t\tendif ()\n\tendif ()\n\tif ( MSVC )\n\t\ttarget_compile_options( ${TEST_NAME} PRIVATE\n\t\t\t-bigobj\n\t\t)\n\tendif ()\n\tif ( PROJECTS_COVERAGE )\n\t\tcoverage_add_target( ${TEST_NAME}\n\t\t\tMODULES\n\t\t\t\t$<TARGET_FILE_NAME:RenderGraph>\n\t\t\t\t$<TARGET_FILE_NAME:${TEST_NAME}>\n\t\t\tSOURCES\n\t\t\t\t${CRG_SOURCE_DIR}/include\n\t\t\t\t${CRG_SOURCE_DIR}/source\n\t\t\tEXCLUDES\n\t\t\t\tDotExport\n\t\t)\n\tendif ()\n\tadd_test(\n\t\tNAME ${TEST_NAME}\n\t\tCOMMAND ${TEST_NAME}\n\t)\n\tinstall(\n\t\tTARGETS ${TEST_NAME}\n\t\tCOMPONENT ${TEST_NAME}\n\t\tEXPORT ${TEST_NAME}\n\t\tRUNTIME DESTINATION bin\n\t)\nendforeach ()\n\nif ( PROJECTS_COVERAGE )\n\tcoverage_add_merge_target( RenderGraphCoverage\n\t\t${PROJECTS_DOCUMENTATION_OUTPUT_DIR}/RenderGraphCoverage\n\t)\nendif ()\n"
  },
  {
    "path": "test/Common.cpp",
    "content": "#include \"Common.hpp\"\n#include \"BaseTest.hpp\"\n\n#include <RenderGraph/DotExport.hpp>\n#include <RenderGraph/GraphContext.hpp>\n#include <RenderGraph/GraphVisitor.hpp>\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/RunnableGraph.hpp>\n\n#include <atomic>\n#include <functional>\n#include <map>\n#include <sstream>\n#include <cstring>\n\nnamespace test\n{\n\tnamespace\n\t{\n\t\tvoid displayTransitions( TestCounts const & testCounts\n\t\t\t, std::ostream & stream\n\t\t\t, crg::RunnableGraph const & value\n\t\t\t, crg::dot::Config cfg )\n\t\t{\n\t\t\tcfg.toRemove = testCounts.testName + \"/\";\n\t\t\tcrg::dot::displayTransitions( stream, value, cfg );\n\t\t\tstd::ofstream file{ testCounts.testName + \".dot\" };\n\t\t\tcrg::dot::displayTransitions( file, value, { true, true, true, false, cfg.toRemove } );\n\t\t}\n\n\t\tcrg::ImageViewType getViewType( crg::ImageType type\n\t\t\t, crg::ImageCreateFlags flags\n\t\t\t, uint32_t layerCount )\n\t\t{\n\t\t\tswitch ( type )\n\t\t\t{\n\t\t\tcase crg::ImageType::e1D:\n\t\t\t\treturn layerCount > 1u\n\t\t\t\t\t? crg::ImageViewType::e1DArray\n\t\t\t\t\t: crg::ImageViewType::e1D;\n\t\t\tcase crg::ImageType::e3D:\n\t\t\t\treturn crg::ImageViewType::e3D;\n\t\t\tdefault:\n\t\t\t\tif ( layerCount > 1u )\n\t\t\t\t{\n\t\t\t\t\tif ( ( ( layerCount % 6u ) == 0u ) && checkFlag( flags, crg::ImageCreateFlags::eCubeCompatible ) )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn ( layerCount > 6u )\n\t\t\t\t\t\t\t? crg::ImageViewType::eCubeArray\n\t\t\t\t\t\t\t: crg::ImageViewType::eCube;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn crg::ImageViewType::e2DArray;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn crg::ImageViewType::e2D;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid checkRunnable( TestCounts const & testCounts\n\t\t\t, crg::RunnableGraph * runnable\n\t\t\t, std::stringstream & stream )\n\t\t{\n\t\t\trequire( runnable )\n\t\t\ttest::display( testCounts, stream, *runnable );\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t}\n\n\tcrg::BufferData createBuffer( std::string name )\n\t{\n\t\treturn crg::BufferData{ std::move( name )\n\t\t\t, crg::BufferCreateFlags::eNone\n\t\t\t, 1024\n\t\t\t, ( crg::BufferUsageFlags::eUniformBuffer\n\t\t\t\t| crg::BufferUsageFlags::eStorageBuffer\n\t\t\t\t| crg::BufferUsageFlags::eUniformTexelBuffer\n\t\t\t\t| crg::BufferUsageFlags::eStorageTexelBuffer ) };\n\t}\n\n\tcrg::BufferViewData createView( std::string name\n\t\t, crg::BufferId buffer\n\t\t, crg::PixelFormat format )\n\t{\n\t\treturn createView( std::move( name )\n\t\t\t, buffer\n\t\t\t, 0u, buffer.data->info.size\n\t\t\t, format );\n\t}\n\n\tcrg::BufferViewData createView( std::string name\n\t\t, crg::BufferId buffer\n\t\t, crg::DeviceSize offset, crg::DeviceSize size\n\t\t, crg::PixelFormat format )\n\t{\n\t\treturn crg::BufferViewData{ std::move( name )\n\t\t\t, buffer\n\t\t\t, { offset, size }\n\t\t\t, format };\n\t}\n\n\tcrg::ImageData createImage( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels\n\t\t, uint32_t arrayLayers )\n\t{\n\t\treturn crg::ImageData{ std::move( name )\n\t\t\t, crg::ImageCreateFlags::eNone\n\t\t\t, crg::ImageType::e2D\n\t\t\t, format\n\t\t\t, { 1024, 1024 }\n\t\t\t, ( crg::ImageUsageFlags::eColorAttachment\n\t\t\t\t| crg::ImageUsageFlags::eSampled )\n\t\t\t, mipLevels\n\t\t\t, arrayLayers };\n\t}\n\n\tcrg::ImageData createImage1D( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels\n\t\t, uint32_t arrayLayers )\n\t{\n\t\treturn crg::ImageData{ std::move( name )\n\t\t\t, crg::ImageCreateFlags::eNone\n\t\t\t, crg::ImageType::e1D\n\t\t\t, format\n\t\t\t, { 1024 }\n\t\t\t, ( crg::ImageUsageFlags::eColorAttachment\n\t\t\t\t| crg::ImageUsageFlags::eSampled )\n\t\t\t, mipLevels\n\t\t\t, arrayLayers };\n\t}\n\n\tcrg::ImageData createImage3D( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels\n\t\t, uint32_t arrayLayers )\n\t{\n\t\treturn crg::ImageData{ std::move( name )\n\t\t\t, crg::ImageCreateFlags::eNone\n\t\t\t, crg::ImageType::e3D\n\t\t\t, format\n\t\t\t, { 1024, 1024u, 64u }\n\t\t\t, ( crg::ImageUsageFlags::eColorAttachment\n\t\t\t\t| crg::ImageUsageFlags::eSampled )\n\t\t\t, mipLevels\n\t\t\t, arrayLayers };\n\t}\n\n\tcrg::ImageData createImageCube( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels\n\t\t, uint32_t arrayLayers )\n\t{\n\t\treturn crg::ImageData{ std::move( name )\n\t\t\t, crg::ImageCreateFlags::eCubeCompatible\n\t\t\t, crg::ImageType::e2D\n\t\t\t, format\n\t\t\t, { 1024, 1024u }\n\t\t\t, ( crg::ImageUsageFlags::eColorAttachment\n\t\t\t\t| crg::ImageUsageFlags::eSampled )\n\t\t\t, mipLevels\n\t\t\t, arrayLayers * 6u };\n\t}\n\n\tcrg::ImageViewData createView( std::string name\n\t\t, crg::ImageId image\n\t\t, uint32_t baseMipLevel\n\t\t, uint32_t levelCount\n\t\t, uint32_t baseArrayLayer\n\t\t, uint32_t layerCount )\n\t{\n\t\treturn createView( std::move( name )\n\t\t\t, image\n\t\t\t, image.data->info.format\n\t\t\t, baseMipLevel\n\t\t\t, levelCount\n\t\t\t, baseArrayLayer\n\t\t\t, layerCount );\n\t}\n\n\tcrg::ImageViewData createView( std::string name\n\t\t, crg::ImageId image\n\t\t, crg::PixelFormat format\n\t\t, uint32_t baseMipLevel\n\t\t, uint32_t levelCount\n\t\t, uint32_t baseArrayLayer\n\t\t, uint32_t layerCount )\n\t{\n\t\treturn crg::ImageViewData{ std::move( name )\n\t\t\t, image\n\t\t\t, crg::ImageViewCreateFlags::eNone\n\t\t\t, getViewType( getImageType( image ), getImageCreateFlags( image ), layerCount )\n\t\t\t, format\n\t\t\t, { getAspectMask( format ), baseMipLevel, levelCount, baseArrayLayer, layerCount } };\n\t}\n\n\tcrg::GraphContext & getDummyContext()\n\t{\n\t\tstatic VkPhysicalDeviceMemoryProperties const MemoryProperties = []()\n\t\t\t{\n\t\t\t\tVkPhysicalDeviceMemoryProperties result{};\n\n\t\t\t\t// Emulate one device local heap\n\t\t\t\tresult.memoryHeaps[result.memoryHeapCount++] = { ~0ULL, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT };\n\t\t\t\t// and one host visible heap\n\t\t\t\tresult.memoryHeaps[result.memoryHeapCount++] = { ~0ULL, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT };\n\n\t\t\t\t// Emulate few combinations of device local memory types\n\t\t\t\tresult.memoryTypes[result.memoryTypeCount++] = { VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0u };\n\t\t\t\tresult.memoryTypes[result.memoryTypeCount++] = { VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 1u };\n\t\t\t\tresult.memoryTypes[result.memoryTypeCount++] = { VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, 1u };\n\n\t\t\t\treturn result;\n\t\t\t}();\n\t\tstatic VkPhysicalDeviceProperties const Properties = []()\n\t\t\t{\n\t\t\t\tstd::string name{ \"Test\" };\n\n\t\t\t\tVkPhysicalDeviceProperties result{};\n#if defined( _MSC_VER )\n\t\t\t\tstrncpy_s( result.deviceName\n\t\t\t\t\t, name.c_str()\n\t\t\t\t\t, std::min( name.size() + 1u, size_t( VK_MAX_PHYSICAL_DEVICE_NAME_SIZE - 1u ) ) );\n#else\n\t\t\t\tstrncpy( result.deviceName\n\t\t\t\t\t, name.c_str()\n\t\t\t\t\t, std::min( name.size() + 1u, size_t( VK_MAX_PHYSICAL_DEVICE_NAME_SIZE - 1u ) ) );\n#endif\n\t\t\t\tresult.deviceID = 0u;\n\t\t\t\tresult.vendorID = 0u;\n\t\t\t\tresult.driverVersion = VK_MAKE_VERSION( 1, 0, 0 );\n\t\t\t\tresult.apiVersion = VK_MAKE_VERSION( 1, 0, 0 );\n\t\t\t\tresult.deviceType = VK_PHYSICAL_DEVICE_TYPE_CPU;\n\n\t\t\t\tresult.limits.maxImageDimension1D = 16384u;\n\t\t\t\tresult.limits.maxImageDimension2D = 16384u;\n\t\t\t\tresult.limits.maxImageDimension3D = 2048u;\n\t\t\t\tresult.limits.maxImageDimensionCube = 16384u;\n\t\t\t\tresult.limits.maxImageArrayLayers = 2048u;\n\t\t\t\tresult.limits.maxTexelBufferElements = 134217728u;\n\t\t\t\tresult.limits.maxUniformBufferRange = 65536u;\n\t\t\t\tresult.limits.maxStorageBufferRange = 4294967295u;\n\t\t\t\tresult.limits.maxPushConstantsSize = 256u;\n\t\t\t\tresult.limits.maxMemoryAllocationCount = 4096u;\n\t\t\t\tresult.limits.maxSamplerAllocationCount = 4000u;\n\t\t\t\tresult.limits.bufferImageGranularity = 1024u;\n\t\t\t\tresult.limits.sparseAddressSpaceSize = 18446744073709551615u;\n\t\t\t\tresult.limits.maxBoundDescriptorSets = 8u;\n\t\t\t\tresult.limits.maxPerStageDescriptorSamplers = 1048576u;\n\t\t\t\tresult.limits.maxPerStageDescriptorUniformBuffers = 15u;\n\t\t\t\tresult.limits.maxPerStageDescriptorStorageBuffers = 1048576u;\n\t\t\t\tresult.limits.maxPerStageDescriptorSampledImages = 1048576u;\n\t\t\t\tresult.limits.maxPerStageDescriptorStorageImages = 1048576u;\n\t\t\t\tresult.limits.maxPerStageDescriptorInputAttachments = 1048576u;\n\t\t\t\tresult.limits.maxPerStageResources = 4294967295u;\n\t\t\t\tresult.limits.maxDescriptorSetSamplers = 1048576u;\n\t\t\t\tresult.limits.maxDescriptorSetUniformBuffers = 90u;\n\t\t\t\tresult.limits.maxDescriptorSetUniformBuffersDynamic = 15u;\n\t\t\t\tresult.limits.maxDescriptorSetStorageBuffers = 1048576u;\n\t\t\t\tresult.limits.maxDescriptorSetStorageBuffersDynamic = 16u;\n\t\t\t\tresult.limits.maxDescriptorSetSampledImages = 1048576u;\n\t\t\t\tresult.limits.maxDescriptorSetStorageImages = 1048576u;\n\t\t\t\tresult.limits.maxDescriptorSetInputAttachments = 1048576u;\n\t\t\t\tresult.limits.maxVertexInputAttributes = 32u;\n\t\t\t\tresult.limits.maxVertexInputBindings = 32u;\n\t\t\t\tresult.limits.maxVertexInputAttributeOffset = 2047u;\n\t\t\t\tresult.limits.maxVertexInputBindingStride = 2048u;\n\t\t\t\tresult.limits.maxVertexOutputComponents = 128u;\n\t\t\t\tresult.limits.maxTessellationGenerationLevel = 64u;\n\t\t\t\tresult.limits.maxTessellationPatchSize = 32u;\n\t\t\t\tresult.limits.maxTessellationControlPerVertexInputComponents = 128u;\n\t\t\t\tresult.limits.maxTessellationControlPerVertexOutputComponents = 128u;\n\t\t\t\tresult.limits.maxTessellationControlPerPatchOutputComponents = 120u;\n\t\t\t\tresult.limits.maxTessellationControlTotalOutputComponents = 4216u;\n\t\t\t\tresult.limits.maxTessellationEvaluationInputComponents = 128u;\n\t\t\t\tresult.limits.maxTessellationEvaluationOutputComponents = 128u;\n\t\t\t\tresult.limits.maxGeometryShaderInvocations = 32u;\n\t\t\t\tresult.limits.maxGeometryInputComponents = 128u;\n\t\t\t\tresult.limits.maxGeometryOutputComponents = 128u;\n\t\t\t\tresult.limits.maxGeometryOutputVertices = 1024u;\n\t\t\t\tresult.limits.maxGeometryTotalOutputComponents = 1024u;\n\t\t\t\tresult.limits.maxFragmentInputComponents = 128u;\n\t\t\t\tresult.limits.maxFragmentOutputAttachments = 8u;\n\t\t\t\tresult.limits.maxFragmentDualSrcAttachments = 1u;\n\t\t\t\tresult.limits.maxFragmentCombinedOutputResources = 16u;\n\t\t\t\tresult.limits.maxComputeSharedMemorySize = 49152u;\n\t\t\t\tresult.limits.maxComputeWorkGroupCount[0] = 2147483647u;\n\t\t\t\tresult.limits.maxComputeWorkGroupCount[1] = 65535u;\n\t\t\t\tresult.limits.maxComputeWorkGroupCount[2] = 65535u;\n\t\t\t\tresult.limits.maxComputeWorkGroupInvocations = 1536u;\n\t\t\t\tresult.limits.maxComputeWorkGroupSize[0] = 1536u;\n\t\t\t\tresult.limits.maxComputeWorkGroupSize[1] = 1024u;\n\t\t\t\tresult.limits.maxComputeWorkGroupSize[2] = 64u;\n\t\t\t\tresult.limits.subPixelPrecisionBits = 8u;\n\t\t\t\tresult.limits.subTexelPrecisionBits = 8u;\n\t\t\t\tresult.limits.mipmapPrecisionBits = 8u;\n\t\t\t\tresult.limits.maxDrawIndexedIndexValue = 4294967295u;\n\t\t\t\tresult.limits.maxDrawIndirectCount = 4294967295u;\n\t\t\t\tresult.limits.maxSamplerLodBias = 15.0f;\n\t\t\t\tresult.limits.maxSamplerAnisotropy = 16.0f;\n\t\t\t\tresult.limits.maxViewports = 16u;\n\t\t\t\tresult.limits.maxViewportDimensions[0] = 16384u;\n\t\t\t\tresult.limits.maxViewportDimensions[1] = 16384u;\n\t\t\t\tresult.limits.viewportBoundsRange[0] = -32768.0f;\n\t\t\t\tresult.limits.viewportBoundsRange[1] = 32768.0f;\n\t\t\t\tresult.limits.viewportSubPixelBits = 8u;\n\t\t\t\tresult.limits.minMemoryMapAlignment = 64u;\n\t\t\t\tresult.limits.minTexelBufferOffsetAlignment = 16u;\n\t\t\t\tresult.limits.minUniformBufferOffsetAlignment = 256u;\n\t\t\t\tresult.limits.minStorageBufferOffsetAlignment = 32u;\n\t\t\t\tresult.limits.minTexelOffset = -8;\n\t\t\t\tresult.limits.maxTexelOffset = 7u;\n\t\t\t\tresult.limits.minTexelGatherOffset = -32;\n\t\t\t\tresult.limits.maxTexelGatherOffset = 31u;\n\t\t\t\tresult.limits.minInterpolationOffset = -0.5f;\n\t\t\t\tresult.limits.maxInterpolationOffset = 0.4375f;\n\t\t\t\tresult.limits.subPixelInterpolationOffsetBits = 4u;\n\t\t\t\tresult.limits.maxFramebufferWidth = 16384u;\n\t\t\t\tresult.limits.maxFramebufferHeight = 16384u;\n\t\t\t\tresult.limits.maxFramebufferLayers = 2048u;\n\t\t\t\tresult.limits.framebufferColorSampleCounts = 15u;\n\t\t\t\tresult.limits.framebufferDepthSampleCounts = 15u;\n\t\t\t\tresult.limits.framebufferStencilSampleCounts = 31u;\n\t\t\t\tresult.limits.framebufferNoAttachmentsSampleCounts = 31u;\n\t\t\t\tresult.limits.maxColorAttachments = 8u;\n\t\t\t\tresult.limits.sampledImageColorSampleCounts = 15u;\n\t\t\t\tresult.limits.sampledImageIntegerSampleCounts = 15u;\n\t\t\t\tresult.limits.sampledImageDepthSampleCounts = 15u;\n\t\t\t\tresult.limits.sampledImageStencilSampleCounts = 31u;\n\t\t\t\tresult.limits.storageImageSampleCounts = 15u;\n\t\t\t\tresult.limits.maxSampleMaskWords = 1u;\n\t\t\t\tresult.limits.timestampComputeAndGraphics = true;\n\t\t\t\tresult.limits.timestampPeriod = 1.0f;\n\t\t\t\tresult.limits.maxClipDistances = 8u;\n\t\t\t\tresult.limits.maxCullDistances = 8u;\n\t\t\t\tresult.limits.maxCombinedClipAndCullDistances = 8u;\n\t\t\t\tresult.limits.discreteQueuePriorities = 2u;\n\t\t\t\tresult.limits.pointSizeRange[0] = 1.0f;\n\t\t\t\tresult.limits.pointSizeRange[1] = 189.875f;\n\t\t\t\tresult.limits.lineWidthRange[0] = 0.5f;\n\t\t\t\tresult.limits.lineWidthRange[1] = 10.0f;\n\t\t\t\tresult.limits.pointSizeGranularity = 0.125f;\n\t\t\t\tresult.limits.lineWidthGranularity = 0.125f;\n\t\t\t\tresult.limits.strictLines = true;\n\t\t\t\tresult.limits.standardSampleLocations = true;\n\t\t\t\tresult.limits.optimalBufferCopyOffsetAlignment = 1u;\n\t\t\t\tresult.limits.optimalBufferCopyRowPitchAlignment = 1u;\n\t\t\t\tresult.limits.nonCoherentAtomSize = 64ULL;\n\n\t\t\t\tresult.sparseProperties.residencyAlignedMipSize = true;\n\t\t\t\tresult.sparseProperties.residencyNonResidentStrict = true;\n\t\t\t\tresult.sparseProperties.residencyStandard2DBlockShape = true;\n\t\t\t\tresult.sparseProperties.residencyStandard2DMultisampleBlockShape = true;\n\t\t\t\tresult.sparseProperties.residencyStandard3DBlockShape = true;\n\n\t\t\t\treturn result;\n\t\t\t}();\n\t\tstatic crg::GraphContext context{ nullptr\n\t\t\t, nullptr\n\t\t\t, nullptr\n\t\t\t, MemoryProperties\n\t\t\t, Properties\n\t\t\t, false\n\t\t\t, nullptr };\n\t\tstatic std::atomic< uintptr_t > counter{};\n\t\tcontext.device = VkDevice( counter.load() );\n\t\t++counter;\n\t\tcontext.vkCreateGraphicsPipelines = PFN_vkCreateGraphicsPipelines( []( VkDevice, VkPipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline * pPipelines )\n\t\t\t{\n\t\t\t\tfor ( uint32_t i = 0u; i < createInfoCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tpPipelines[i] = VkPipeline( counter.load() );\n\t\t\t\t\t++counter;\n\t\t\t\t}\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateComputePipelines = PFN_vkCreateComputePipelines( []( VkDevice, VkPipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline * pPipelines )\n\t\t\t{\n\t\t\t\tfor ( uint32_t i = 0u; i < createInfoCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tpPipelines[i] = VkPipeline( counter.load() );\n\t\t\t\t\t++counter;\n\t\t\t\t}\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreatePipelineLayout = PFN_vkCreatePipelineLayout( []( VkDevice, const VkPipelineLayoutCreateInfo *, const VkAllocationCallbacks *, VkPipelineLayout * pPipelineLayout )\n\t\t\t{\n\t\t\t\t*pPipelineLayout = VkPipelineLayout( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateDescriptorSetLayout = PFN_vkCreateDescriptorSetLayout( []( VkDevice, const VkDescriptorSetLayoutCreateInfo *, const VkAllocationCallbacks *, VkDescriptorSetLayout * pSetLayout )\n\t\t\t{\n\t\t\t\t*pSetLayout = VkDescriptorSetLayout( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateDescriptorPool = PFN_vkCreateDescriptorPool( []( VkDevice, const VkDescriptorPoolCreateInfo *, const VkAllocationCallbacks *, VkDescriptorPool * pDescriptorPool )\n\t\t\t{\n\t\t\t\t*pDescriptorPool = VkDescriptorPool( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkAllocateDescriptorSets = PFN_vkAllocateDescriptorSets( []( VkDevice, const VkDescriptorSetAllocateInfo * pAllocateInfo, VkDescriptorSet * pDescriptorSets )\n\t\t\t{\n\t\t\t\tif ( !pAllocateInfo )\n\t\t\t\t\treturn VK_ERROR_UNKNOWN;\n\n\t\t\t\tfor ( uint32_t i = 0u; i < pAllocateInfo->descriptorSetCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tpDescriptorSets[i] = VkDescriptorSet( counter.load() );\n\t\t\t\t\t++counter;\n\t\t\t\t}\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateBuffer = PFN_vkCreateBuffer( []( VkDevice, const VkBufferCreateInfo *, const VkAllocationCallbacks *, VkBuffer * pBuffer )\n\t\t\t{\n\t\t\t\t*pBuffer = VkBuffer( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateBufferView = PFN_vkCreateBufferView( []( VkDevice, const VkBufferViewCreateInfo *, const VkAllocationCallbacks *, VkBufferView * pBuffer )\n\t\t\t{\n\t\t\t\t*pBuffer = VkBufferView( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkAllocateMemory = PFN_vkAllocateMemory( []( VkDevice, const VkMemoryAllocateInfo *, const VkAllocationCallbacks *, VkDeviceMemory * pMemory )\n\t\t\t{\n\t\t\t\t*pMemory = VkDeviceMemory( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateRenderPass = PFN_vkCreateRenderPass( []( VkDevice, const VkRenderPassCreateInfo *, const VkAllocationCallbacks *, VkRenderPass * pRenderPass )\n\t\t\t{\n\t\t\t\t*pRenderPass = VkRenderPass( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateFramebuffer = PFN_vkCreateFramebuffer( []( VkDevice, const VkFramebufferCreateInfo *, const VkAllocationCallbacks *, VkFramebuffer * pFramebuffer )\n\t\t\t{\n\t\t\t\t*pFramebuffer = VkFramebuffer( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateImage = PFN_vkCreateImage( []( VkDevice, const VkImageCreateInfo *, const VkAllocationCallbacks *, VkImage * pImage )\n\t\t\t{\n\t\t\t\t*pImage = VkImage( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateImageView = PFN_vkCreateImageView( []( VkDevice, const VkImageViewCreateInfo *, const VkAllocationCallbacks *, VkImageView * pView )\n\t\t\t{\n\t\t\t\t*pView = VkImageView( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateSampler = PFN_vkCreateSampler( []( VkDevice, const VkSamplerCreateInfo *, const VkAllocationCallbacks *, VkSampler * pSampler )\n\t\t\t{\n\t\t\t\t*pSampler = VkSampler( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateCommandPool = PFN_vkCreateCommandPool( []( VkDevice, const VkCommandPoolCreateInfo *, const VkAllocationCallbacks *, VkCommandPool * pCommandPool )\n\t\t\t{\n\t\t\t\t*pCommandPool = VkCommandPool( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkAllocateCommandBuffers = PFN_vkAllocateCommandBuffers( []( VkDevice, const VkCommandBufferAllocateInfo * pAllocateInfo, VkCommandBuffer * pCommandBuffers )\n\t\t\t{\n\t\t\t\tif ( !pAllocateInfo )\n\t\t\t\t\treturn VK_ERROR_UNKNOWN;\n\n\t\t\t\tfor ( uint32_t i = 0u; i < pAllocateInfo->commandBufferCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tpCommandBuffers[i] = VkCommandBuffer( counter.load() );\n\t\t\t\t\t++counter;\n\t\t\t\t}\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateSemaphore = PFN_vkCreateSemaphore( []( VkDevice, const VkSemaphoreCreateInfo *, const VkAllocationCallbacks *, VkSemaphore * pSemaphore )\n\t\t\t{\n\t\t\t\t*pSemaphore = VkSemaphore( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateQueryPool = PFN_vkCreateQueryPool( []( VkDevice, const VkQueryPoolCreateInfo *, const VkAllocationCallbacks *, VkQueryPool * pQueryPool )\n\t\t\t{\n\t\t\t\t*pQueryPool = VkQueryPool( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateEvent = PFN_vkCreateEvent( []( VkDevice, const VkEventCreateInfo *, const VkAllocationCallbacks *, VkEvent * pEvent )\n\t\t\t{\n\t\t\t\t*pEvent = VkEvent( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkCreateFence = PFN_vkCreateFence( []( VkDevice, const VkFenceCreateInfo *, const VkAllocationCallbacks *, VkFence * pFence )\n\t\t\t{\n\t\t\t\t*pFence = VkFence( counter.load() );\n\t\t\t\t++counter;\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\n\t\tcontext.vkDestroyPipeline = PFN_vkDestroyPipeline( []( VkDevice, VkPipeline, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyPipelineLayout = PFN_vkDestroyPipelineLayout( []( VkDevice, VkPipelineLayout, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyDescriptorSetLayout = PFN_vkDestroyDescriptorSetLayout( []( VkDevice, VkDescriptorSetLayout, const VkAllocationCallbacks* ){} );\n\t\tcontext.vkDestroyDescriptorPool = PFN_vkDestroyDescriptorPool( []( VkDevice, VkDescriptorPool, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkFreeDescriptorSets = PFN_vkFreeDescriptorSets( []( VkDevice, VkDescriptorPool, uint32_t, const VkDescriptorSet * ){ return VK_SUCCESS; } );\n\t\tcontext.vkDestroyBuffer = PFN_vkDestroyBuffer( []( VkDevice, VkBuffer, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyBufferView = PFN_vkDestroyBufferView( []( VkDevice, VkBufferView, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkFreeMemory = PFN_vkFreeMemory( []( VkDevice, VkDeviceMemory, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyRenderPass = PFN_vkDestroyRenderPass( []( VkDevice, VkRenderPass, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyFramebuffer = PFN_vkDestroyFramebuffer( []( VkDevice, VkFramebuffer, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyImage = PFN_vkDestroyImage( []( VkDevice, VkImage, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyImageView = PFN_vkDestroyImageView( []( VkDevice, VkImageView, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroySampler = PFN_vkDestroySampler( []( VkDevice, VkSampler, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyCommandPool = PFN_vkDestroyCommandPool( []( VkDevice, VkCommandPool, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkFreeCommandBuffers = PFN_vkFreeCommandBuffers( []( VkDevice, VkCommandPool, uint32_t, const VkCommandBuffer * ){} );\n\t\tcontext.vkDestroySemaphore = PFN_vkDestroySemaphore( []( VkDevice, VkSemaphore, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyQueryPool = PFN_vkDestroyQueryPool( []( VkDevice, VkQueryPool, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyEvent = PFN_vkDestroyEvent( []( VkDevice, VkEvent, const VkAllocationCallbacks * ){} );\n\t\tcontext.vkDestroyFence = PFN_vkDestroyFence( []( VkDevice, VkFence, const VkAllocationCallbacks * ){} );\n\n\t\tcontext.vkGetBufferMemoryRequirements = PFN_vkGetBufferMemoryRequirements( []( VkDevice, VkBuffer, VkMemoryRequirements * pMemoryRequirements )\n\t\t\t{\n\t\t\t\tpMemoryRequirements->memoryTypeBits = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;\n\t\t\t\tpMemoryRequirements->size = 1024u;\n\t\t\t\tpMemoryRequirements->alignment = 1u;\n\t\t\t} );\n\t\tcontext.vkGetImageMemoryRequirements = PFN_vkGetImageMemoryRequirements( []( VkDevice, VkImage, VkMemoryRequirements * pMemoryRequirements )\n\t\t\t{\n\t\t\t\tpMemoryRequirements->memoryTypeBits = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;\n\t\t\t\tpMemoryRequirements->size = 1024u * 1024 * 64;\n\t\t\t\tpMemoryRequirements->alignment = 4u;\n\t\t\t} );\n\t\tcontext.vkBindBufferMemory = PFN_vkBindBufferMemory( []( VkDevice, VkBuffer, VkDeviceMemory, VkDeviceSize ){ return VK_SUCCESS; } );\n\t\tcontext.vkBindImageMemory = PFN_vkBindImageMemory( []( VkDevice, VkImage, VkDeviceMemory, VkDeviceSize ){ return VK_SUCCESS; } );\n\t\tcontext.vkMapMemory = PFN_vkMapMemory( []( VkDevice, VkDeviceMemory, VkDeviceSize, VkDeviceSize, VkMemoryMapFlags, void ** ppData )\n\t\t\t{\n\t\t\t\tthread_local std::vector< uint8_t > data( 1024u * 1024u * 64u );\n\t\t\t\t*ppData = data.data();\n\t\t\t\treturn VK_SUCCESS;\n\t\t\t} );\n\t\tcontext.vkUnmapMemory = PFN_vkUnmapMemory( []( VkDevice, VkDeviceMemory ){} );\n\t\tcontext.vkFlushMappedMemoryRanges = PFN_vkFlushMappedMemoryRanges( []( VkDevice, uint32_t , const VkMappedMemoryRange * ){ return VK_SUCCESS; } );\n\t\tcontext.vkInvalidateMappedMemoryRanges = PFN_vkInvalidateMappedMemoryRanges( []( VkDevice, uint32_t , const VkMappedMemoryRange * ){ return VK_SUCCESS; } );\n\t\tcontext.vkUpdateDescriptorSets = PFN_vkUpdateDescriptorSets( []( VkDevice, uint32_t, const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet * ){} );\n\t\tcontext.vkBeginCommandBuffer = PFN_vkBeginCommandBuffer( []( VkCommandBuffer, const VkCommandBufferBeginInfo * ){ return VK_SUCCESS; } );\n\t\tcontext.vkEndCommandBuffer = PFN_vkEndCommandBuffer( []( VkCommandBuffer ){ return VK_SUCCESS; } );\n\t\tcontext.vkQueueSubmit = PFN_vkQueueSubmit( []( VkQueue, uint32_t, const VkSubmitInfo *, VkFence ){ return VK_SUCCESS; } );\n\t\tcontext.vkGetQueryPoolResults = PFN_vkGetQueryPoolResults( []( VkDevice, VkQueryPool, uint32_t, uint32_t, size_t, void *, VkDeviceSize, VkQueryResultFlags ){ return VK_SUCCESS; } );\n\t\tcontext.vkResetCommandBuffer = PFN_vkResetCommandBuffer( []( VkCommandBuffer, VkCommandBufferResetFlags ){ return VK_SUCCESS; } );\n\t\tcontext.vkResetEvent = PFN_vkResetEvent( []( VkDevice, VkEvent ){ return VK_SUCCESS; } );\n\t\tcontext.vkSetEvent = PFN_vkSetEvent( []( VkDevice, VkEvent ){ return VK_SUCCESS; } );\n\t\tcontext.vkGetEventStatus = PFN_vkGetEventStatus( []( VkDevice, VkEvent ){ return VK_SUCCESS; } );\n\t\tcontext.vkGetFenceStatus = PFN_vkGetFenceStatus( []( VkDevice, VkFence ){ return VK_SUCCESS; } );\n\t\tcontext.vkWaitForFences = PFN_vkWaitForFences( []( VkDevice, uint32_t, const VkFence *, VkBool32, uint64_t ){ return VK_SUCCESS; } );\n\t\tcontext.vkResetFences = PFN_vkResetFences( []( VkDevice, uint32_t, const VkFence * ){ return VK_SUCCESS; } );\n\n\t\tcontext.vkCmdBindPipeline = PFN_vkCmdBindPipeline( []( VkCommandBuffer, VkPipelineBindPoint, VkPipeline ){} );\n\t\tcontext.vkCmdBindDescriptorSets = PFN_vkCmdBindDescriptorSets( []( VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkDescriptorSet *, uint32_t, const uint32_t * ){} );\n\t\tcontext.vkCmdBindVertexBuffers = PFN_vkCmdBindVertexBuffers( []( VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize * ){} );\n\t\tcontext.vkCmdBindIndexBuffer = PFN_vkCmdBindIndexBuffer( []( VkCommandBuffer, VkBuffer, VkDeviceSize, VkIndexType ){} );\n\t\tcontext.vkCmdClearColorImage = PFN_vkCmdClearColorImage( []( VkCommandBuffer, VkImage, VkImageLayout, const VkClearColorValue *, uint32_t, const VkImageSubresourceRange * ){} );\n\t\tcontext.vkCmdClearDepthStencilImage = PFN_vkCmdClearDepthStencilImage( []( VkCommandBuffer, VkImage, VkImageLayout, const VkClearDepthStencilValue *, uint32_t, const VkImageSubresourceRange * ){} );\n\t\tcontext.vkCmdDispatch = PFN_vkCmdDispatch( []( VkCommandBuffer, uint32_t, uint32_t, uint32_t ){} );\n\t\tcontext.vkCmdDispatchIndirect = PFN_vkCmdDispatchIndirect( []( VkCommandBuffer, VkBuffer, VkDeviceSize ){} );\n\t\tcontext.vkCmdDraw = PFN_vkCmdDraw( []( VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t ){} );\n\t\tcontext.vkCmdDrawIndexed = PFN_vkCmdDrawIndexed( []( VkCommandBuffer, uint32_t, uint32_t, uint32_t, int32_t, uint32_t ){} );\n\t\tcontext.vkCmdDrawIndexedIndirect = PFN_vkCmdDrawIndexedIndirect( []( VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t ){} );\n\t\tcontext.vkCmdDrawIndirect = PFN_vkCmdDrawIndirect( []( VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t ){} );\n\t\tcontext.vkCmdBeginRenderPass = PFN_vkCmdBeginRenderPass( []( VkCommandBuffer, const VkRenderPassBeginInfo *, VkSubpassContents ){} );\n\t\tcontext.vkCmdEndRenderPass = PFN_vkCmdEndRenderPass( []( VkCommandBuffer ){} );\n\t\tcontext.vkCmdPushConstants = PFN_vkCmdPushConstants( []( VkCommandBuffer, VkPipelineLayout, VkShaderStageFlags, uint32_t, uint32_t, const void * ){} );\n\t\tcontext.vkCmdResetQueryPool = PFN_vkCmdResetQueryPool( []( VkCommandBuffer, VkQueryPool, uint32_t, uint32_t ){} );\n\t\tcontext.vkCmdWriteTimestamp = PFN_vkCmdWriteTimestamp( []( VkCommandBuffer, VkPipelineStageFlagBits, VkQueryPool, uint32_t ){} );\n\t\tcontext.vkCmdPipelineBarrier = PFN_vkCmdPipelineBarrier( []( VkCommandBuffer, VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier * ){} );\n\t\tcontext.vkCmdBlitImage = PFN_vkCmdBlitImage( []( VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageBlit *, VkFilter ){} );\n\t\tcontext.vkCmdCopyBuffer = PFN_vkCmdCopyBuffer( []( VkCommandBuffer, VkBuffer, VkBuffer, uint32_t, const VkBufferCopy * ){} );\n\t\tcontext.vkCmdCopyBufferToImage = PFN_vkCmdCopyBufferToImage( []( VkCommandBuffer, VkBuffer, VkImage, VkImageLayout, uint32_t, const VkBufferImageCopy * ){} );\n\t\tcontext.vkCmdCopyImage = PFN_vkCmdCopyImage( []( VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageCopy * ){} );\n\t\tcontext.vkCmdCopyImageToBuffer = PFN_vkCmdCopyImageToBuffer( []( VkCommandBuffer, VkImage, VkImageLayout, VkBuffer, uint32_t, const VkBufferImageCopy * ){} );\n\t\tcontext.vkCmdExecuteCommands = PFN_vkCmdExecuteCommands( []( VkCommandBuffer, uint32_t, const VkCommandBuffer * ){} );\n\t\tcontext.vkCmdResetEvent = PFN_vkCmdResetEvent( []( VkCommandBuffer, VkEvent, VkPipelineStageFlags ){} );\n\t\tcontext.vkCmdSetEvent = PFN_vkCmdSetEvent( []( VkCommandBuffer, VkEvent, VkPipelineStageFlags ){} );\n\t\tcontext.vkCmdWaitEvents = PFN_vkCmdWaitEvents( []( VkCommandBuffer, uint32_t, const VkEvent *, VkPipelineStageFlags, VkPipelineStageFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier * ){} );\n\t\tcontext.vkCmdFillBuffer = PFN_vkCmdFillBuffer( []( VkCommandBuffer, VkBuffer, VkDeviceSize, VkDeviceSize, uint32_t ){} );\n\n#if VK_EXT_debug_utils || VK_EXT_debug_marker\n#\tif VK_EXT_debug_utils\n\t\tcontext.vkSetDebugUtilsObjectNameEXT = PFN_vkSetDebugUtilsObjectNameEXT( []( VkDevice, const VkDebugUtilsObjectNameInfoEXT* ){ return VK_SUCCESS; } );\n\t\tcontext.vkCmdBeginDebugUtilsLabelEXT = PFN_vkCmdBeginDebugUtilsLabelEXT( []( VkCommandBuffer, const VkDebugUtilsLabelEXT * ){} );\n\t\tcontext.vkCmdEndDebugUtilsLabelEXT = PFN_vkCmdEndDebugUtilsLabelEXT( []( VkCommandBuffer ){} );\n#\tendif\n#\tif VK_EXT_debug_marker\n\t\tcontext.vkDebugMarkerSetObjectNameEXT = PFN_vkDebugMarkerSetObjectNameEXT( []( VkDevice, const VkDebugMarkerObjectNameInfoEXT * ){ return VK_SUCCESS; } );\n\t\tcontext.vkCmdDebugMarkerBeginEXT = PFN_vkCmdDebugMarkerBeginEXT( []( VkCommandBuffer, const VkDebugMarkerMarkerInfoEXT * ){} );\n\t\tcontext.vkCmdDebugMarkerEndEXT = PFN_vkCmdDebugMarkerEndEXT( []( VkCommandBuffer ){} );\n#\tendif\n#endif\n\t\tcontext.setCallstackCallback( []()\n\t\t\t{\n\t\t\t\treturn \"coin !!\";\n\t\t\t} );\n\t\treturn context;\n\t}\n\n\tstd::string checkRunnable( TestCounts const & testCounts\n\t\t, crg::RunnableGraph * runnable )\n\t{\n\t\tstd::stringstream result;\n\t\tcheckRunnable( testCounts, runnable, result );\n\t\treturn result.str();\n\t}\n\n\tvoid display( TestCounts const & testCounts\n\t\t, std::ostream & stream\n\t\t, crg::RunnableGraph const & value\n\t\t, bool withColours\n\t\t, bool withIds\n\t\t, bool withGroups )\n\t{\n\t\tstd::stringstream tmp;\n\t\tcrg::dot::displayTransitions( tmp, value, { true, true, true, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, true, true, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, true, false, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, true, false, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, false, true, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, false, true, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, false, false, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { true, false, false, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, true, true, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, true, true, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, true, false, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, true, false, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, false, true, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, false, true, false } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, false, false, true } );\n\t\tcrg::dot::displayTransitions( tmp, value, { false, false, false, false } );\n\n\t\tdisplayTransitions( testCounts, stream, value, { withColours, withIds, withGroups } );\n\t}\n\n\tvoid display( TestCounts const & testCounts\n\t\t, crg::RunnableGraph const & value\n\t\t, bool withColours\n\t\t, bool withIds\n\t\t, bool withGroups )\n\t{\n\t\tdisplay( testCounts, std::cout, value, withColours, withIds, withGroups );\n\t}\n\n\tclass DummyRunnable\n\t\t: public crg::RunnablePass\n\t{\n\tpublic:\n\t\tDummyRunnable( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph\n\t\t\t, test::TestCounts & testCounts\n\t\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t\t, CheckViews checkViews\n\t\t\t, uint32_t index\n\t\t\t, bool enabled\n\t\t\t, crg::ru::Config config )\n\t\t\t: crg::RunnablePass{ framePass\n\t\t\t\t, context\n\t\t\t\t, runGraph\n\t\t\t\t, { crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t, crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } )\n\t\t\t\t\t, crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } )\n\t\t\t\t\t, crg::RunnablePass::GetPassIndexCallback( [index](){ return index; } )\n\t\t\t\t\t, crg::RunnablePass::IsEnabledCallback( [enabled](){ return enabled; } ) }\n\t\t\t\t, std::move( config ) }\n\t\t\t, m_testCounts{ testCounts }\n\t\t\t, m_pipelineStageFlags{ pipelineStageFlags }\n\t\t\t, m_checkViews{ std::move( checkViews ) }\n\t\t{\n\t\t}\n\n\t\tDummyRunnable( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph\n\t\t\t, test::TestCounts & testCounts\n\t\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t\t, CheckViews checkViews\n\t\t\t, uint32_t index\n\t\t\t, crg::ru::Config config )\n\t\t\t: crg::RunnablePass{ framePass\n\t\t\t\t, context\n\t\t\t\t, runGraph\n\t\t\t\t, { crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t, crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } )\n\t\t\t\t\t, crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } )\n\t\t\t\t\t, crg::RunnablePass::GetPassIndexCallback( [index](){ return index; } ) }\n\t\t\t\t, std::move( config ) }\n\t\t\t, m_testCounts{ testCounts }\n\t\t\t, m_pipelineStageFlags{ pipelineStageFlags }\n\t\t\t, m_checkViews{ std::move( checkViews ) }\n\t\t{\n\t\t}\n\n\t\tDummyRunnable( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph\n\t\t\t, test::TestCounts & testCounts\n\t\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t\t, CheckViews checkViews\n\t\t\t, crg::ru::Config config )\n\t\t\t: crg::RunnablePass{ framePass\n\t\t\t\t, context\n\t\t\t\t, runGraph\n\t\t\t\t, { crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t, crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } )\n\t\t\t\t\t, crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } ) }\n\t\t\t\t, std::move( config ) }\n\t\t\t, m_testCounts{ testCounts }\n\t\t\t, m_pipelineStageFlags{ pipelineStageFlags }\n\t\t\t, m_checkViews{ std::move( checkViews ) }\n\t\t{\n\t\t}\n\n\t\tDummyRunnable( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph\n\t\t\t, test::TestCounts & testCounts\n\t\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t\t, crg::ru::Config config )\n\t\t\t: crg::RunnablePass{ framePass\n\t\t\t\t, context\n\t\t\t\t, runGraph\n\t\t\t\t, { crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t, crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } )\n\t\t\t\t\t, crg::RunnablePass::RecordCallback( [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordTargetsInto( ctx, cb, i ); } ) }\n\t\t\t\t, std::move( config ) }\n\t\t\t, m_testCounts{ testCounts }\n\t\t\t, m_pipelineStageFlags{ pipelineStageFlags }\n\t\t{\n\t\t}\n\n\tprivate:\n\t\tvoid doRecordInto( crg::RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )\n\t\t{\n\t\t\tfor ( auto & [binding, attach] : getPass().getUniforms() )\n\t\t\t{\n\t\t\t\tauto buffer = crg::resolveView( attach->buffer( index ), index );\n\t\t\t\tcontext.setAccessState( buffer\n\t\t\t\t\t, { attach->getAccessMask(), attach->getPipelineStageFlags( checkFlag( m_pipelineStageFlags, crg::PipelineStageFlags::eComputeShader ) ) } );\n\t\t\t}\n\t\t\tfor ( auto & [binding, attach] : getPass().getSampled() )\n\t\t\t{\n\t\t\t\tauto view = attach.attach->view( index );\n\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t, crg::makeLayoutState( attach.attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t}\n\t\t\tfor ( auto & [binding, attach] : getPass().getInputs() )\n\t\t\t{\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t{\n\t\t\t\t\tauto view = attach->view( index );\n\t\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t\t, crg::makeLayoutState( attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto buffer = crg::resolveView( attach->buffer( index ), index );\n\t\t\t\t\tcontext.setAccessState( buffer\n\t\t\t\t\t\t, { attach->getAccessMask(), attach->getPipelineStageFlags( checkFlag( m_pipelineStageFlags, crg::PipelineStageFlags::eComputeShader ) ) } );\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor ( auto & [binding, attach] : getPass().getInouts() )\n\t\t\t{\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t{\n\t\t\t\t\tauto view = attach->view( index );\n\t\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t\t, crg::makeLayoutState( attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto buffer = crg::resolveView( attach->buffer( index ), index );\n\t\t\t\t\tcontext.setAccessState( buffer\n\t\t\t\t\t\t, { attach->getAccessMask(), attach->getPipelineStageFlags( checkFlag( m_pipelineStageFlags, crg::PipelineStageFlags::eComputeShader ) ) } );\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor ( auto & [binding, attach] : getPass().getOutputs() )\n\t\t\t{\n\t\t\t\tif ( attach->isImage() )\n\t\t\t\t{\n\t\t\t\t\tauto view = attach->view( index );\n\t\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t\t, crg::makeLayoutState( attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto buffer = crg::resolveView( attach->buffer( index ), index );\n\t\t\t\t\tcontext.setAccessState( buffer\n\t\t\t\t\t\t, { attach->getAccessMask(), attach->getPipelineStageFlags( checkFlag( m_pipelineStageFlags, crg::PipelineStageFlags::eComputeShader ) ) } );\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor ( auto attach : getPass().getTargets() )\n\t\t\t{\n\t\t\t\tauto view = attach->view( index );\n\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t, crg::makeLayoutState( attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t}\n\n\t\t\tm_checkViews( m_testCounts\n\t\t\t\t, getPass()\n\t\t\t\t, getGraph()\n\t\t\t\t, context\n\t\t\t\t, index );\n\t\t}\n\n\t\tvoid doRecordTargetsInto( crg::RecordContext & context\n\t\t\t, VkCommandBuffer commandBuffer\n\t\t\t, uint32_t index )const\n\t\t{\n\t\t\tfor ( auto attach : getPass().getTargets() )\n\t\t\t{\n\t\t\t\tauto view = attach->view( index );\n\t\t\t\tcontext.runImplicitTransition( commandBuffer, index, view );\n\t\t\t\tcontext.setLayoutState( crg::resolveView( view, index )\n\t\t\t\t\t, crg::makeLayoutState( attach->getImageLayout( context->separateDepthStencilLayouts ) ) );\n\t\t\t}\n\t\t}\n\n\t\ttest::TestCounts & m_testCounts;\n\t\tcrg::PipelineStageFlags m_pipelineStageFlags;\n\t\tCheckViews m_checkViews;\n\t};\n\n\tclass DummyRunnableNoRecord\n\t\t: public crg::RunnablePass\n\t{\n\tpublic:\n\t\tDummyRunnableNoRecord( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph\n\t\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t\t, crg::ru::Config config )\n\t\t\t: crg::RunnablePass{ framePass\n\t\t\t\t, context\n\t\t\t\t, runGraph\n\t\t\t\t, { crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t, crg::RunnablePass::GetPipelineStateCallback( [this](){ return crg::getPipelineState( m_pipelineStageFlags ); } ) }\n\t\t\t\t, std::move( config ) }\n\t\t\t, m_pipelineStageFlags{ pipelineStageFlags }\n\t\t{\n\t\t}\n\n\t\tcrg::PipelineStageFlags m_pipelineStageFlags;\n\t};\n\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, uint32_t index\n\t\t, bool enabled\n\t\t, crg::ru::Config config )\n\t{\n\t\treturn std::make_unique< DummyRunnable >( framePass\n\t\t\t, context\n\t\t\t, runGraph\n\t\t\t, testCounts\n\t\t\t, pipelineStageFlags\n\t\t\t, checkViews\n\t\t\t, index\n\t\t\t, enabled\n\t\t\t, std::move( config ) );\n\t}\n\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, uint32_t index\n\t\t, crg::ru::Config config )\n\t{\n\t\treturn std::make_unique< DummyRunnable >( framePass\n\t\t\t, context\n\t\t\t, runGraph\n\t\t\t, testCounts\n\t\t\t, pipelineStageFlags\n\t\t\t, checkViews\n\t\t\t, index\n\t\t\t, std::move( config ) );\n\t}\n\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, crg::ru::Config config )\n\t{\n\t\treturn std::make_unique< DummyRunnable >( framePass\n\t\t\t, context\n\t\t\t, runGraph\n\t\t\t, testCounts\n\t\t\t, pipelineStageFlags\n\t\t\t, std::move( checkViews )\n\t\t\t, std::move( config ) );\n\t}\n\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, crg::ru::Config config )\n\t{\n\t\treturn std::make_unique< DummyRunnable >( framePass\n\t\t\t, context\n\t\t\t, runGraph\n\t\t\t, testCounts\n\t\t\t, pipelineStageFlags\n\t\t\t, std::move( config ) );\n\t}\n\n\tcrg::RunnablePassPtr createDummyNoRecord( crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, crg::ru::Config config )\n\t{\n\t\treturn std::make_unique< DummyRunnableNoRecord >( framePass\n\t\t\t, context\n\t\t\t, runGraph\n\t\t\t, pipelineStageFlags\n\t\t\t, std::move( config ) );\n\t}\n\n\tvoid checkDummy( [[maybe_unused]] test::TestCounts const & testCounts\n\t\t, [[maybe_unused]] crg::FramePass const & framePass\n\t\t, [[maybe_unused]] crg::RunnableGraph const & graph\n\t\t, [[maybe_unused]] crg::RecordContext const & context\n\t\t, [[maybe_unused]] uint32_t index )\n\t{\n\t\t// Nothing checked yet...\n\t}\n\n\ttemplate< typename EnumT >\n\tstatic void condAppendEnumFlag( std::ostream & stream, std::string & sep, EnumT const & v, EnumT const & t, std::string_view s )\n\t{\n\t\tif ( checkFlag( v, t ) )\n\t\t{\n\t\t\tstream << sep << s;\n\t\t\tsep = \" | \";\n\t\t}\n\t}\n}\n\nnamespace crg\n{\n\tstd::ostream & operator<<( std::ostream & stream, AccessFlags const & v )\n\t{\n\t\tstd::string sep;\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eIndirectCommandRead, \"IndirectCommandRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eIndexRead, \"IndexRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eVertexAttributeRead, \"VertexAttributeRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eUniformRead, \"UniformRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eInputAttachmentRead, \"InputAttachmentRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eShaderRead, \"ShaderRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eShaderWrite, \"ShaderWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentRead, \"ColorAttachmentRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentWrite, \"ColorAttachmentWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eDepthStencilAttachmentRead, \"DepthStencilAttachmentRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eDepthStencilAttachmentWrite, \"DepthStencilAttachmentWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransferRead, \"TransferRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransferWrite, \"TransferWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eHostRead, \"HostRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eHostWrite, \"HostWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eMemoryRead, \"MemoryRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eMemoryWrite, \"MemoryWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackWrite, \"TransformFeedbackWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackCounterRead, \"TransformFeedbackCounterRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eTransformFeedbackCounterWrite, \"TransformFeedbackCounterWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eConditionalRenderingRead, \"ConditionalRenderingRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eColorAttachmentReadNonCoherent, \"ColorAttachmentReadNonCoherent\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eAccelerationStructureRead, \"AccelerationStructureRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eAccelerationStructureWrite, \"AccelerationStructureWrite\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eFragmentDensityMapRead, \"FragmentDensityMapRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eFragmentShadingRateAttachmentRead, \"FragmentShadingRateAttachmentRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eCommandPreprocessRead, \"CommandPreprocessRead\" );\n\t\ttest::condAppendEnumFlag( stream, sep, v, AccessFlags::eCommandPreprocessWrite, \"CommandPreprocessWrite\" );\n\t\treturn stream;\n\t}\n\n\tstd::ostream & operator<<( std::ostream & stream, ImageLayout const & v )\n\t{\n\t\tswitch ( v )\n\t\t{\n\t\tcase ImageLayout::eUndefined: stream << \"Undefined\"; break;\n\t\tcase ImageLayout::eGeneral: stream << \"General\"; break;\n\t\tcase ImageLayout::eColorAttachment: stream << \"ColorAttachment\"; break;\n\t\tcase ImageLayout::eDepthStencilAttachment: stream << \"DepthStencilAttachment\"; break;\n\t\tcase ImageLayout::eDepthStencilReadOnly: stream << \"DepthStencilReadOnly\"; break;\n\t\tcase ImageLayout::eShaderReadOnly: stream << \"ShaderReadOnly\"; break;\n\t\tcase ImageLayout::eTransferSrc: stream << \"TransferSrc\"; break;\n\t\tcase ImageLayout::eTransferDst: stream << \"TransferDst\"; break;\n\t\tcase ImageLayout::ePreinitialized: stream << \"Preinitialized\"; break;\n\t\tcase ImageLayout::eDepthReadOnlyStencilAttachment: stream << \"DepthReadOnlyStencilAttachment\"; break;\n\t\tcase ImageLayout::eDepthAttachmentStencilReadOnly: stream << \"DepthAttachmentStencilReadOnly\"; break;\n\t\tcase ImageLayout::eDepthAttachment: stream << \"DepthAttachment\"; break;\n\t\tcase ImageLayout::eDepthReadOnly: stream << \"DepthReadOnly\"; break;\n\t\tcase ImageLayout::eStencilAttachment: stream << \"StencilAttachment\"; break;\n\t\tcase ImageLayout::eStencilReadOnly: stream << \"StencilReadOnly\"; break;\n\t\tcase ImageLayout::eReadOnly: stream << \"ReadOnly\"; break;\n\t\tcase ImageLayout::eAttachment: stream << \"Attachment\"; break;\n\t\tcase ImageLayout::eRenderingLocalRead: stream << \"RenderingLocalRead\"; break;\n\t\tcase ImageLayout::ePresentSrc: stream << \"PresentSrc\"; break;\n\t\tcase ImageLayout::eVideoDecodeDst: stream << \"VideoDecodeDst\"; break;\n\t\tcase ImageLayout::eVideoDecodeSrc: stream << \"VideoDecodeSrc\"; break;\n\t\tcase ImageLayout::eVideoDecodeDpb: stream << \"VideoDecodeDpb\"; break;\n\t\tcase ImageLayout::eSharedPresent: stream << \"SharedPresent\"; break;\n\t\tcase ImageLayout::eFragmentDensityMap: stream << \"FragmentDensityMap\"; break;\n\t\tcase ImageLayout::eFragmentShadingRateAttachment: stream << \"FragmentShadingRateAttachment\"; break;\n\t\tcase ImageLayout::eVideoEncodeDst: stream << \"VideoEncodeDst\"; break;\n\t\tcase ImageLayout::eVideoEncodeSrc: stream << \"VideoEncodeSrc\"; break;\n\t\tcase ImageLayout::eVideoEncodeDpb: stream << \"VideoEncodeDpb\"; break;\n\t\tcase ImageLayout::eAttachmentFeedbackLoop: stream << \"AttachmentFeedbackLoop\"; break;\n\t\tcase ImageLayout::eVideoEncodeQuantizationMap: stream << \"VideoEncodeQuantizationMap\"; break;\n\t\t}\n\t\treturn stream;\n\t}\n\n\tstd::ostream & operator<<( std::ostream & stream, AttachmentLoadOp const & v )\n\t{\n\t\tswitch ( v )\n\t\t{\n\t\tcase AttachmentLoadOp::eLoad: stream << \"Load\"; break;\n\t\tcase AttachmentLoadOp::eClear: stream << \"Clear\"; break;\n\t\tcase AttachmentLoadOp::eDontCare: stream << \"DontCare\"; break;\n\t\tcase AttachmentLoadOp::eNone: stream << \"None\"; break;\n\t\t}\n\t\treturn stream;\n\t}\n\n\tstd::ostream & operator<<( std::ostream & stream, AttachmentStoreOp const & v )\n\t{\n\t\tswitch ( v )\n\t\t{\n\t\tcase AttachmentStoreOp::eStore: stream << \"eStore\"; break;\n\t\tcase AttachmentStoreOp::eDontCare: stream << \"DontCare\"; break;\n\t\tcase AttachmentStoreOp::eNone: stream << \"None\"; break;\n\t\t}\n\t\treturn stream;\n\t}\n}\n"
  },
  {
    "path": "test/Common.hpp",
    "content": "#pragma once\n\n#include <RenderGraph/FrameGraphPrerequisites.hpp>\n#include <RenderGraph/RunnablePass.hpp>\n\n#include \"BaseTest.hpp\"\n\n#include <sstream>\n\nnamespace test\n{\n\tcrg::BufferData createBuffer( std::string name );\n\tcrg::BufferViewData createView( std::string name\n\t\t, crg::BufferId buffer\n\t\t, crg::PixelFormat format = crg::PixelFormat::eUNDEFINED );\n\tcrg::BufferViewData createView( std::string name\n\t\t, crg::BufferId buffer\n\t\t, crg::DeviceSize offset, crg::DeviceSize size\n\t\t, crg::PixelFormat format = crg::PixelFormat::eUNDEFINED );\n\tcrg::ImageData createImage( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels = 1u\n\t\t, uint32_t arrayLayers = 1u );\n\tcrg::ImageData createImage1D( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels = 1u\n\t\t, uint32_t arrayLayers = 1u );\n\tcrg::ImageData createImage3D( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels = 1u\n\t\t, uint32_t arrayLayers = 1u );\n\tcrg::ImageData createImageCube( std::string name\n\t\t, crg::PixelFormat format\n\t\t, uint32_t mipLevels = 1u\n\t\t, uint32_t arrayLayers = 1u );\n\tcrg::ImageViewData createView( std::string name\n\t\t, crg::ImageId image\n\t\t, uint32_t baseMipLevel = 0u\n\t\t, uint32_t levelCount = 1u\n\t\t, uint32_t baseArrayLayer = 0u\n\t\t, uint32_t layerCount = 1u );\n\tcrg::ImageViewData createView( std::string name\n\t\t, crg::ImageId image\n\t\t, crg::PixelFormat format\n\t\t, uint32_t baseMipLevel = 0u\n\t\t, uint32_t levelCount = 1u\n\t\t, uint32_t baseArrayLayer = 0u\n\t\t, uint32_t layerCount = 1u );\n\tcrg::GraphContext & getDummyContext();\n\tstd::string checkRunnable( TestCounts const & testCounts\n\t\t, crg::RunnableGraph * runnable );\n\n\tinline std::string checkRunnable( TestCounts const & testCounts\n\t\t, crg::RunnableGraphPtr const & runnable )\n\t{\n\t\treturn checkRunnable( testCounts, runnable.get() );\n\t}\n\n\tvoid display( TestCounts const & testCounts\n\t\t, std::ostream & stream\n\t\t, crg::RunnableGraph const & value\n\t\t, bool withColours = {}\n\t\t, bool withIds = {}\n\t\t, bool withGroups = {} );\n\tvoid display( TestCounts const & testCounts\n\t\t, crg::RunnableGraph const & value\n\t\t, bool withColours = {}\n\t\t, bool withIds = {}\n\t\t, bool withGroups = {} );\n\n\ttemplate< typename TypeT >\n\tcrg::Id< TypeT > makeId( [[maybe_unused]] TypeT const & data )\n\t{\n\t\treturn { 0u, nullptr };\n\t}\n\n\tusing CheckViews = std::function< void( test::TestCounts &\n\t\t, crg::FramePass const &\n\t\t, crg::RunnableGraph const &\n\t\t, crg::RecordContext &\n\t\t, uint32_t ) >;\n\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, uint32_t index\n\t\t, bool enabled\n\t\t, crg::ru::Config config = {} );\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, uint32_t index\n\t\t, crg::ru::Config config = {} );\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, CheckViews checkViews\n\t\t, crg::ru::Config config = {} );\n\tcrg::RunnablePassPtr createDummy( test::TestCounts & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, crg::ru::Config config = {} );\n\tcrg::RunnablePassPtr createDummyNoRecord( crg::FramePass const & framePass\n\t\t, crg::GraphContext & context\n\t\t, crg::RunnableGraph & runGraph\n\t\t, crg::PipelineStageFlags pipelineStageFlags\n\t\t, crg::ru::Config config = {} );\n\tvoid checkDummy( test::TestCounts const & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::RunnableGraph const & graph\n\t\t, crg::RecordContext const & context\n\t\t, uint32_t index );\n}\n\nnamespace crg\n{\n\tstd::ostream & operator<<( std::ostream & stream, AccessFlags const & v );\n\tstd::ostream & operator<<( std::ostream & stream, ImageLayout const & v );\n\tstd::ostream & operator<<( std::ostream & stream, AttachmentLoadOp const & v );\n\tstd::ostream & operator<<( std::ostream & stream, AttachmentStoreOp const & v );\n}\n"
  },
  {
    "path": "test/TestAttachment.cpp",
    "content": "#include \"Common.hpp\"\n\n#include <RenderGraph/Attachment.hpp>\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/FramePass.hpp>\n#include <RenderGraph/ResourceHandler.hpp>\n\nnamespace\n{\n\tconstexpr crg::SamplerDesc defaultSamplerDesc{};\n\n\tenum class Binding\n\t{\n\t\teUniform,\n\t\teSampled,\n\t\teStorage,\n\t};\n\n\tTEST( Attachment, SampledAttachment )\n\t{\n\t\ttestBegin( \"testSampledAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto tmpAttach1 = crg::Attachment::createDefault( view );\n\t\tauto tmpAttach2 = crg::Attachment::createDefault( view );\n\t\ttmpAttach2 = std::move( tmpAttach1 );\n\t\ttmpAttach1 = tmpAttach2;\n\t\tauto viewAttach = std::move( tmpAttach2 );\n\t\tpass.addInputSampled( viewAttach, 1u );\n\t\trequire( pass.getSampled().size() == 1u )\n\t\tauto attachIt = pass.getSampled().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment.attach->isImage() )\n\t\tcheck( attachment.attach->isInput() )\n\t\tcheck( !attachment.attach->isOutput() )\n\t\tcheck( !attachment.attach->isClearable() )\n\t\tcheck( !attachment.attach->isTransitionImageView() )\n\t\tcheck( !attachment.attach->isTransferImageView() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilOutputTarget() )\n\t\tcheck( attachment.attach->name == pass.getGroupName() + \"/\" + view.data->name + \"/Spl\" )\n\t\tcheckEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment.attach->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheck( attachment.sampler == defaultSamplerDesc )\n\t\tcheckEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly )\n\t\tcheckEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, SampledAttachmentT )\n\t{\n\t\ttestBegin( \"testSampledAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto tmpAttach1 = crg::Attachment::createDefault( view );\n\t\tauto tmpAttach2 = crg::Attachment::createDefault( view );\n\t\ttmpAttach2 = std::move( tmpAttach1 );\n\t\ttmpAttach1 = tmpAttach2;\n\t\tauto viewAttach = std::move( tmpAttach2 );\n\t\tpass.addInputSampledT( viewAttach, Binding::eSampled );\n\t\trequire( pass.getSampled().size() == 1u )\n\t\tauto attachIt = pass.getSampled().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment.attach->isImage() )\n\t\tcheck( attachment.attach->isInput() )\n\t\tcheck( !attachment.attach->isOutput() )\n\t\tcheck( !attachment.attach->isClearable() )\n\t\tcheck( !attachment.attach->isTransitionImageView() )\n\t\tcheck( !attachment.attach->isTransferImageView() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilOutputTarget() )\n\t\tcheck( attachment.attach->name == pass.getGroupName() + \"/\" + view.data->name + \"/Spl\" )\n\t\tcheckEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment.attach->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eSampled ) )\n\t\tcheck( attachment.sampler == defaultSamplerDesc )\n\t\tcheckEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly )\n\t\tcheckEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, SampledImage )\n\t{\n\t\ttestBegin( \"testSampledImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputSampledImage( view, 1u );\n\t\trequire( pass.getSampled().size() == 1u )\n\t\tauto attachIt = pass.getSampled().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment.attach->isImage() )\n\t\tcheck( attachment.attach->isInput() )\n\t\tcheck( !attachment.attach->isOutput() )\n\t\tcheck( !attachment.attach->isClearable() )\n\t\tcheck( !attachment.attach->isTransitionImageView() )\n\t\tcheck( !attachment.attach->isTransferImageView() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilOutputTarget() )\n\t\tcheck( attachment.attach->name == pass.getGroupName() + \"/\" + view.data->name + \"/Spl\" )\n\t\tcheckEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment.attach->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheck( attachment.sampler == defaultSamplerDesc )\n\t\tcheckEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly )\n\t\tcheckEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, SampledImageT )\n\t{\n\t\ttestBegin( \"testSampledImageT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputSampledImageT( view, Binding::eSampled );\n\t\trequire( pass.getSampled().size() == 1u )\n\t\tauto attachIt = pass.getSampled().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment.attach->isImage() )\n\t\tcheck( attachment.attach->isInput() )\n\t\tcheck( !attachment.attach->isOutput() )\n\t\tcheck( !attachment.attach->isClearable() )\n\t\tcheck( !attachment.attach->isTransitionImageView() )\n\t\tcheck( !attachment.attach->isTransferImageView() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment.attach->imageAttach.isStencilOutputTarget() )\n\t\tcheck( attachment.attach->name == pass.getGroupName() + \"/\" + view.data->name + \"/Spl\" )\n\t\tcheckEqual( attachment.attach->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment.attach->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment.attach->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eSampled ) )\n\t\tcheck( attachment.sampler == defaultSamplerDesc )\n\t\tcheckEqual( attachment.attach->getImageLayout( false ), crg::ImageLayout::eShaderReadOnly )\n\t\tcheckEqual( attachment.attach->getImageLayout( true ), crg::ImageLayout::eShaderReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImplicitColourAttachment )\n\t{\n\t\ttestBegin( \"testImplicitColourAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( crg::ImageData{ \"Test\", crg::ImageCreateFlags::eNone, crg::ImageType::e3D, crg::PixelFormat::eR32G32B32A32_SFLOAT, { 1024, 1024, 1024 }, crg::ImageUsageFlags::eSampled, 1u, 1u } );\n\t\tauto range = crg::getVirtualRange( image, crg::ImageViewType::e3D, { crg::ImageAspectFlags::eColor, 0u, 1u, 0u, 1u } );\n\t\tcheck( range.baseArrayLayer == 0 )\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tauto imageLayout = crg::ImageLayout::eShaderReadOnly;\n\t\tpass.addImplicit( viewAttach, imageLayout );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/Impl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), imageLayout )\n\t\tcheckEqual( attachment->getImageLayout( true ), imageLayout )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImplicitDepthAttachment )\n\t{\n\t\ttestBegin( \"testImplicitDepthAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tauto imageLayout = crg::ImageLayout::ePreinitialized;\n\t\tpass.addImplicit( viewAttach, imageLayout );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/Impl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), imageLayout )\n\t\tcheckEqual( attachment->getImageLayout( true ), imageLayout )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImplicitDepthStencilAttachment )\n\t{\n\t\ttestBegin( \"testImplicitDepthStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tauto imageLayout = crg::ImageLayout::eShaderReadOnly;\n\t\tpass.addImplicit( viewAttach, imageLayout );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/Impl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), imageLayout )\n\t\tcheckEqual( attachment->getImageLayout( true ), imageLayout )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageAttachment )\n\t{\n\t\ttestBegin( \"testInStorageAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputStorage( viewAttach, 1u );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageAttachmentT )\n\t{\n\t\ttestBegin( \"testInStorageAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputStorageT( viewAttach, Binding::eStorage );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageImage )\n\t{\n\t\ttestBegin( \"testInStorageImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputStorageImage( view, 1u );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageImageT )\n\t{\n\t\ttestBegin( \"testInStorageImageT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputStorageImageT( view, Binding::eStorage );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageBuffer )\n\t{\n\t\ttestBegin( \"testInStorageBuffer\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputStorageBuffer( view, 1u );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->bufferAttach.isStorage() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/SB\" )\n\t\tcheck( attachment->buffer() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStorageBufferT )\n\t{\n\t\ttestBegin( \"testInStorageBufferT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputStorageBufferT( view, Binding::eStorage );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->bufferAttach.isStorage() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/SB\" )\n\t\tcheck( attachment->buffer() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformAttachment )\n\t{\n\t\ttestBegin( \"testUniformAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tcheck( &pass.getGraph() == &graph )\n\t\tauto tmpAttach1 = crg::Attachment::createDefault( view );\n\t\tauto tmpAttach2 = crg::Attachment::createDefault( view );\n\t\ttmpAttach2 = std::move( tmpAttach1 );\n\t\ttmpAttach1 = tmpAttach2;\n\t\tauto viewAttach = std::move( tmpAttach2 );\n\t\tpass.addInputUniform( viewAttach, 1u );\n\t\trequire( pass.getUniforms().size() == 1u )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( !attachment->bufferAttach.isStorage() )\n\t\tcheck( attachment->bufferAttach.isUniform() )\n\t\tcheck( attachment->name == pass.getGroupName() + \"/\" + view.data->name + \"/UB\" )\n\t\tcheck( attachIt->first == 1u )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformAttachmentT )\n\t{\n\t\ttestBegin( \"testUniformAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto tmpAttach1 = crg::Attachment::createDefault( view );\n\t\tauto tmpAttach2 = crg::Attachment::createDefault( view );\n\t\ttmpAttach2 = std::move( tmpAttach1 );\n\t\ttmpAttach1 = tmpAttach2;\n\t\tauto viewAttach = std::move( tmpAttach2 );\n\t\tpass.addInputUniformT( viewAttach, Binding::eUniform );\n\t\trequire( pass.getUniforms().size() == 1u )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( !attachment->bufferAttach.isStorage() )\n\t\tcheck( attachment->bufferAttach.isUniform() )\n\t\tcheck( attachment->name == pass.getGroupName() + \"/\" + view.data->name + \"/UB\" )\n\t\tcheck( attachIt->first == uint32_t( Binding::eUniform ) )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutStorageAttachment )\n\t{\n\t\ttestBegin( \"testOutStorageAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputStorageImage( view, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/OStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutStorageAttachmentT )\n\t{\n\t\ttestBegin( \"testOutStorageAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputStorageImageT( view, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/OStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearOutStorageAttachment )\n\t{\n\t\ttestBegin( \"testClearOutStorageAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addClearableOutputStorageImage( view, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/COStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearOutStorageAttachmentT )\n\t{\n\t\ttestBegin( \"testClearOutStorageAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addClearableOutputStorageImageT( view, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/COStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageAttachment )\n\t{\n\t\ttestBegin( \"testInOutStorageAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutStorage( viewAttach, 1u );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IOStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageAttachmentT )\n\t{\n\t\ttestBegin( \"testInOutStorageAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutStorageT( viewAttach, Binding::eStorage );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IOStr\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eGeneral )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eGeneral )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InTransferAttachment )\n\t{\n\t\ttestBegin( \"testInTransferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputTransfer( viewAttach );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ITrf\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferSrc )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferSrc )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InTransferImage )\n\t{\n\t\ttestBegin( \"testInTransferImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputTransferImage( view );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ITrf\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferSrc )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferSrc )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InTransferBuffer )\n\t{\n\t\ttestBegin( \"testInTransferBuffer\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputTransferBuffer( view );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->isTransferBuffer() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ITrf\" )\n\t\tcheck( attachment->buffer() == view )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutTransferAttachment )\n\t{\n\t\ttestBegin( \"testOutTransferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputTransferImage( view );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/OT\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferDst )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferDst )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutTransferAttachment )\n\t{\n\t\ttestBegin( \"testInOutTransferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutTransfer( viewAttach );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IOTrf\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eTransferDst )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eTransferDst )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InColourAttachment )\n\t{\n\t\ttestBegin( \"testInColourAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputColourTarget( viewAttach );\n\t\trequire( pass.getTargets().size() == 1u )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRcl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InColourImage )\n\t{\n\t\ttestBegin( \"testInColourImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputColourTargetImage( view );\n\t\trequire( pass.getTargets().size() == 1u )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRcl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutColourAttachment )\n\t{\n\t\ttestBegin( \"testOutColourAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputColourTarget( view );\n\t\trequire( pass.getTargets().size() == 1u )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ORcl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutColourAttachment )\n\t{\n\t\ttestBegin( \"testInOutColourAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutColourTarget( viewAttach );\n\t\trequire( pass.getTargets().size() == 1u )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( attachment->isColourImageTarget() )\n\t\tcheck( attachment->isColourInOutImageTarget() )\n\t\tcheck( attachment->isColourInputImageTarget() )\n\t\tcheck( attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IORcl\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eColorAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eColorAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InDepthAttachment )\n\t{\n\t\ttestBegin( \"testInDepthAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputDepthTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRdp\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InDepthImage )\n\t{\n\t\ttestBegin( \"testInDepthImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputDepthTargetImage( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRdp\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutDepthAttachment )\n\t{\n\t\ttestBegin( \"testOutDepthAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputDepthTarget( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ORdp\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutDepthAttachment )\n\t{\n\t\ttestBegin( \"testInOutDepthAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutDepthTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IORdp\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthAttachment )\n\t\tcheck( attachment->view() == view )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InDepthStencilAttachment )\n\t{\n\t\ttestBegin( \"testInDepthStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputDepthStencilTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRds\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InDepthStencilImage )\n\t{\n\t\ttestBegin( \"testInDepthStencilImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputDepthStencilTargetImage( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRds\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutDepthStencilAttachment )\n\t{\n\t\ttestBegin( \"testOutDepthStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputDepthStencilTarget( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ORds\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eClear )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eClear )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutDepthStencilAttachment )\n\t{\n\t\ttestBegin( \"testInOutDepthStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutDepthStencilTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IORds\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eDepthStencilAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStencilAttachment )\n\t{\n\t\ttestBegin( \"testInStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eS8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInputStencilTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRst\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InStencilImage )\n\t{\n\t\ttestBegin( \"testInStencilImage\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eS8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addInputStencilTargetImage( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IRst\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilReadOnly )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilReadOnly )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutStencilAttachment )\n\t{\n\t\ttestBegin( \"testOutStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eS8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tpass.addOutputStencilTarget( view );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/ORst\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eClear )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStencilAttachment )\n\t{\n\t\ttestBegin( \"testInOutStencilAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eS8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto viewAttach = crg::Attachment::createDefault( view );\n\t\tpass.addInOutStencilTarget( viewAttach );\n\t\trequire( !pass.getTargets().empty() )\n\t\tauto const & attachment = pass.getTargets()[0];\n\t\tcheck( attachment->isImage() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isClearable() )\n\t\tcheck( !attachment->isColourImageTarget() )\n\t\tcheck( !attachment->isColourInOutImageTarget() )\n\t\tcheck( !attachment->isColourInputImageTarget() )\n\t\tcheck( !attachment->isColourOutputImageTarget() )\n\t\tcheck( !attachment->isTransitionImageView() )\n\t\tcheck( !attachment->isTransferImageView() )\n\t\tcheck( !attachment->imageAttach.isColourTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment->imageAttach.isDepthTarget() )\n\t\tcheck( attachment->imageAttach.isStencilTarget() )\n\t\tcheck( attachment->imageAttach.isStencilInputTarget() )\n\t\tcheck( attachment->imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + view.data->name + \"/IORst\" )\n\t\tcheckEqual( attachment->getLoadOp(), crg::AttachmentLoadOp::eDontCare )\n\t\tcheckEqual( attachment->getStoreOp(), crg::AttachmentStoreOp::eDontCare )\n\t\tcheckEqual( attachment->getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment->getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheck( attachment->view() == view )\n\t\tcheckEqual( attachment->getImageLayout( false ), crg::ImageLayout::eDepthStencilAttachment )\n\t\tcheckEqual( attachment->getImageLayout( true ), crg::ImageLayout::eStencilAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImageAttachment )\n\t{\n\t\ttestBegin( \"testImageAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto image = graph.createImage( test::createImage( \"Test\", crg::PixelFormat::eS8_UINT ) );\n\t\tauto view = graph.createView( test::createView( \"Test\", image ) );\n\t\tauto const attachment = crg::Attachment::createDefault( view );\n\t\tcheck( attachment.isImage() )\n\t\tcheck( !attachment.isInput() )\n\t\tcheck( !attachment.isOutput() )\n\t\tcheck( !attachment.isClearable() )\n\t\tcheck( attachment.isColourImageTarget() )\n\t\tcheck( !attachment.isColourInOutImageTarget() )\n\t\tcheck( !attachment.isColourInputImageTarget() )\n\t\tcheck( !attachment.isColourOutputImageTarget() )\n\t\tcheck( !attachment.isTransitionImageView() )\n\t\tcheck( !attachment.isTransferImageView() )\n\t\tcheck( attachment.imageAttach.isColourTarget() )\n\t\tcheck( !attachment.imageAttach.isDepthStencilTarget() )\n\t\tcheck( !attachment.imageAttach.isDepthTarget() )\n\t\tcheck( !attachment.imageAttach.isStencilTarget() )\n\t\tcheck( !attachment.imageAttach.isStencilInputTarget() )\n\t\tcheck( !attachment.imageAttach.isStencilOutputTarget() )\n\t\tcheckEqual( attachment.getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment.getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheckEqual( attachment.getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\tcheckEqual( attachment.getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\tcheck( attachment.view() == view )\n\t\tcheckEqual( attachment.getImageLayout( false ), crg::ImageLayout::eColorAttachment )\n\t\tcheckEqual( attachment.getImageLayout( true ), crg::ImageLayout::eColorAttachment )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImplicitBufferAttachment )\n\t{\n\t\ttestBegin( \"testImplicitBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tcrg::AccessState accessState{};\n\t\tpass.addImplicit( bufferAttach, accessState );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheckEqual( getSize( buffer ), 1024u )\n\t\tcheckEqual( getSize( bufferv ), 1024u )\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/Impl\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\tcheckEqual( attachment->getAccessMask(), accessState.access )\n\t\tcheckEqual( attachment->getPipelineStageFlags( true ), accessState.pipelineStage )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformBufferAttachment )\n\t{\n\t\ttestBegin( \"testUniformBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addInputUniformBuffer( bufferv, 1u );\n\t\trequire( pass.getUniforms().size() == 1u )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/UB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformBufferAttachmentT )\n\t{\n\t\ttestBegin( \"testUniformBufferAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addInputUniformBufferT( bufferv, Binding::eUniform );\n\t\trequire( pass.getUniforms().size() == 1u )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eUniform ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/UB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InputStorageBufferAttachment )\n\t{\n\t\ttestBegin( \"testInputStorageBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInputStorage( bufferAttach, 1u );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InputStorageBufferAttachmentT )\n\t{\n\t\ttestBegin( \"testInputStorageBufferAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInputStorageT( bufferAttach, Binding::eStorage );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutputStorageBufferAttachment )\n\t{\n\t\ttestBegin( \"testOutputStorageBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addOutputStorageBuffer( bufferv, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutputStorageBufferAttachmentT )\n\t{\n\t\ttestBegin( \"testOutputStorageBufferAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addOutputStorageBufferT( bufferv, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearableOutputStorageBufferAttachment )\n\t{\n\t\ttestBegin( \"testClearableOutputStorageBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addClearableOutputStorageBuffer( bufferv, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearableOutputStorageBufferAttachmentT )\n\t{\n\t\ttestBegin( \"testClearableOutputStorageBufferAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addClearableOutputStorageBufferT( bufferv, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageBufferAttachment )\n\t{\n\t\ttestBegin( \"testInOutStorageBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInOutStorage( bufferAttach, 1u );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IOStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageBufferAttachmentT )\n\t{\n\t\ttestBegin( \"testInOutStorageBufferAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInOutStorageT( bufferAttach, Binding::eStorage );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IOStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ImplicitBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testImplicitBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addImplicit( bufferAttach, crg::AccessState{} );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( attachment->isTransitionBuffer() )\n\t\tcheck( attachment->isTransitionBufferView() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/Impl\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testUniformBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addInputUniformBuffer( bufferv, 1u );\n\t\trequire( !pass.getUniforms().empty() )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/UB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, UniformBufferViewAttachmentT )\n\t{\n\t\ttestBegin( \"testUniformBufferViewAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addInputUniformBufferT( bufferv, Binding::eUniform );\n\t\trequire( !pass.getUniforms().empty() )\n\t\tauto attachIt = pass.getUniforms().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( attachment->isUniformBuffer() )\n\t\tcheck( attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eUniform ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/UB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InputStorageBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testInputStorageBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInputStorage( bufferAttach, 1u );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InputStorageBufferViewAttachmentT )\n\t{\n\t\ttestBegin( \"testInputStorageBufferViewAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInputStorageT( bufferAttach, Binding::eStorage );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutputStorageBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testOutputStorageBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addOutputStorageBuffer( bufferv, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutputStorageBufferViewAttachmentT )\n\t{\n\t\ttestBegin( \"testOutputStorageBufferViewAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addOutputStorageBufferT( bufferv, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearableOutputStorageBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testClearableOutputStorageBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addClearableOutputStorageBuffer( bufferv, 1u );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, ClearableOutputStorageBufferViewAttachmentT )\n\t{\n\t\ttestBegin( \"testClearableOutputStorageBufferViewAttachmentT\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tpass.addClearableOutputStorageBufferT( bufferv, Binding::eStorage );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OSB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageBufferViewAttachment )\n\t{\n\t\ttestBegin( \"testInOutStorageBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInOutStorage( bufferAttach, 1u );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == 1u )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IOStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutStorageBufferViewAttachmentT )\n\t{\n\t\ttestBegin( \"testInOutStorageBufferViewAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInOutStorageT( bufferAttach, Binding::eStorage );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( attachment->isBufferView() )\n\t\tcheck( !attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( attachment->isStorageBuffer() )\n\t\tcheck( attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheck( attachIt->first == uint32_t( Binding::eStorage ) )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IOStr\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InputTransferBufferAttachment )\n\t{\n\t\ttestBegin( \"testInputTransferBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInputTransfer( bufferAttach );\n\t\trequire( pass.getInputs().size() == 1u )\n\t\tauto attachIt = pass.getInputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( !attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/ITrf\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, OutputTransferBufferAttachment )\n\t{\n\t\ttestBegin( \"testOutputTransferBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tpass.addOutputTransferBuffer( bufferv );\n\t\trequire( pass.getOutputs().size() == 1u )\n\t\tauto attachIt = pass.getOutputs().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( !attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/OTB\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, InOutTransferBufferAttachment )\n\t{\n\t\ttestBegin( \"testInOutTransferBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcrg::FramePass & pass = graph.createPass( \"test\", crg::RunnablePassCreator{} );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto bufferAttach = crg::Attachment::createDefault( bufferv );\n\t\tpass.addInOutTransfer( bufferAttach );\n\t\trequire( pass.getInouts().size() == 1u )\n\t\tauto attachIt = pass.getInouts().begin();\n\t\tauto const & attachment = attachIt->second;\n\t\tcheck( attachment->isBuffer() )\n\t\tcheck( attachment->isInput() )\n\t\tcheck( attachment->isOutput() )\n\t\tcheck( !attachment->isBufferView() )\n\t\tcheck( attachment->isTransferBuffer() )\n\t\tcheck( !attachment->isClearableBuffer() )\n\t\tcheck( !attachment->isStorageBuffer() )\n\t\tcheck( !attachment->isStorageBufferView() )\n\t\tcheck( !attachment->isUniformBuffer() )\n\t\tcheck( !attachment->isUniformBufferView() )\n\t\tcheck( !attachment->isTransitionBuffer() )\n\t\tcheck( !attachment->isTransitionBufferView() )\n\t\tcheckEqual( attachment->name, pass.getGroupName() + \"/\" + buffer.data->name + \"/IOTrf\" )\n\t\tcheck( attachment->buffer() == bufferv )\n\t\tcheck( attachment->bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, BufferAttachment )\n\t{\n\t\ttestBegin( \"testBufferAttachment\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"Test\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"Test\", buffer ) );\n\t\tauto attachment = crg::Attachment::createDefault( bufferv );\n\t\tcheck( attachment.isBuffer() )\n\t\tcheck( !attachment.isInput() )\n\t\tcheck( !attachment.isOutput() )\n\t\tcheck( !attachment.isBufferView() )\n\t\tcheck( !attachment.isTransferBuffer() )\n\t\tcheck( !attachment.isClearableBuffer() )\n\t\tcheck( !attachment.isStorageBuffer() )\n\t\tcheck( !attachment.isStorageBufferView() )\n\t\tcheck( !attachment.isUniformBuffer() )\n\t\tcheck( !attachment.isUniformBufferView() )\n\t\tcheck( !attachment.isTransitionBuffer() )\n\t\tcheck( !attachment.isTransitionBufferView() )\n\t\tcheck( attachment.buffer() == bufferv )\n\t\tcheck( attachment.bufferAttach.buffer() == bufferv )\n\t\ttestEnd()\n\t}\n\n\tTEST( Attachment, AttachmentMerge )\n\t{\n\t\ttestBegin( \"testAttachmentMerge\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer, 0u, 512u ) );\n\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer, 512u, 512u ) );\n\t\tauto image = graph.createImage( test::createImage( \"image1\", crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u, 2u ) );\n\t\tauto image1v = graph.createView( test::createView( \"image1v\", image, 0u, 1u, 0u, 1u ) );\n\t\tauto image2v = graph.createView( test::createView( \"image2v\", image, 1u, 1u, 1u, 1u ) );\n\t\t{\n\t\t\t// Empty attachment list\n\t\t\tcheck( graph.mergeAttachments( {} ) == nullptr )\n\t\t}\n\t\t{\n\t\t\t// Single buffer attachment in list\n\t\t\tauto attachment = crg::Attachment::createDefault( buffer1v );\n\t\t\tcheckThrow( attachment.getSource( 1u ), crg::Exception )\n\t\t\tcheck( attachment.getSource( 0u ) == &attachment )\n\t\t\tcheck( graph.mergeAttachments( { &attachment } ) == &attachment )\n\t\t}\n\t\t{\n\t\t\t// Single image attachment in list\n\t\t\tauto attachment = crg::Attachment::createDefault( image1v );\n\t\t\tcheck( graph.mergeAttachments( { &attachment } ) == &attachment )\n\t\t}\n\t\t{\n\t\t\t// Mixed attachments in list\n\t\t\tauto attachment1 = crg::Attachment::createDefault( image1v );\n\t\t\tauto attachment2 = crg::Attachment::createDefault( buffer1v );\n\t\t\tcheckThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception )\n\t\t}\n\t\t{\n\t\t\t// Empty image attachments in list\n\t\t\tauto attachment1 = crg::Attachment::createDefault( image1v );\n\t\t\tattachment1.imageAttach.views.clear();\n\t\t\tauto attachment2 = crg::Attachment::createDefault( image2v );\n\t\t\tattachment2.imageAttach.views.clear();\n\t\t\tcheckThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception )\n\t\t}\n\t\t{\n\t\t\t// Empty buffer attachments in list\n\t\t\tauto attachment1 = crg::Attachment::createDefault( buffer1v );\n\t\t\tattachment1.bufferAttach.buffers.clear();\n\t\t\tauto attachment2 = crg::Attachment::createDefault( buffer2v );\n\t\t\tattachment2.bufferAttach.buffers.clear();\n\t\t\tcheckThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception )\n\t\t}\n\t\t{\n\t\t\t// Image attachments with different pass count\n\t\t\tauto attachment1 = crg::Attachment::createDefault( image1v );\n\t\t\tauto attachment2 = crg::Attachment::createDefault( image2v );\n\t\t\tattachment2.imageAttach.views.clear();\n\t\t\tcheckThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception )\n\t\t}\n\t\t{\n\t\t\t// Buffer attachments with different pass count\n\t\t\tauto attachment1 = crg::Attachment::createDefault( buffer1v );\n\t\t\tauto attachment2 = crg::Attachment::createDefault( buffer2v );\n\t\t\tattachment2.bufferAttach.buffers.clear();\n\t\t\tcheckThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ), crg::Exception )\n\t\t}\n\t\t{\n\t\t\t// Image attachments\n\t\t\tauto attachment1 = crg::Attachment::createDefault( image1v );\n\t\t\tauto attachment2 = crg::Attachment::createDefault( image2v );\n\t\t\tcheckNoThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ) )\n\t\t\tauto & attachment = *graph.mergeAttachments( { &attachment1, &attachment2 } );\n\t\t\tcheck( attachment.isImage() )\n\t\t\tcheck( !attachment.isInput() )\n\t\t\tcheck( !attachment.isOutput() )\n\t\t\tcheck( !attachment.isClearable() )\n\t\t\tcheck( attachment.isColourImageTarget() )\n\t\t\tcheck( !attachment.isColourInOutImageTarget() )\n\t\t\tcheck( !attachment.isColourInputImageTarget() )\n\t\t\tcheck( !attachment.isColourOutputImageTarget() )\n\t\t\tcheck( !attachment.isTransitionImageView() )\n\t\t\tcheck( !attachment.isTransferImageView() )\n\t\t\tcheck( attachment.imageAttach.isColourTarget() )\n\t\t\tcheck( !attachment.imageAttach.isDepthStencilTarget() )\n\t\t\tcheck( !attachment.imageAttach.isDepthTarget() )\n\t\t\tcheck( !attachment.imageAttach.isStencilTarget() )\n\t\t\tcheck( !attachment.imageAttach.isStencilInputTarget() )\n\t\t\tcheck( !attachment.imageAttach.isStencilOutputTarget() )\n\t\t\tcheckEqual( attachment.getLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\t\tcheckEqual( attachment.getStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\t\tcheckEqual( attachment.getStencilLoadOp(), crg::AttachmentLoadOp::eLoad )\n\t\t\tcheckEqual( attachment.getStencilStoreOp(), crg::AttachmentStoreOp::eStore )\n\t\t\tcheck( attachment.getImageLayout( false ) == crg::ImageLayout::eColorAttachment )\n\t\t\tcheck( attachment.getImageLayout( true ) == crg::ImageLayout::eColorAttachment )\n\t\t\tcheck( attachment.pass == nullptr )\n\t\t\tcheck( attachment.view().data->source.size() == 2u )\n\t\t\tcheck( attachment.view().data->source[0] == image1v )\n\t\t\tcheck( attachment.view().data->source[1] == image2v )\n\t\t}\n\t\t{\n\t\t\t// Buffer attachments\n\t\t\tauto attachment1 = crg::Attachment::createDefault( buffer1v );\n\t\t\tauto attachment2 = crg::Attachment::createDefault( buffer2v );\n\t\t\tcheckNoThrow( graph.mergeAttachments( { &attachment1, &attachment2 } ) )\n\t\t\tauto & attachment = *graph.mergeAttachments( { &attachment1, &attachment2 } );\n\t\t\tcheck( attachment.isBuffer() )\n\t\t\tcheck( !attachment.isInput() )\n\t\t\tcheck( !attachment.isOutput() )\n\t\t\tcheck( !attachment.isBufferView() )\n\t\t\tcheck( !attachment.isTransferBuffer() )\n\t\t\tcheck( !attachment.isClearableBuffer() )\n\t\t\tcheck( !attachment.isStorageBuffer() )\n\t\t\tcheck( !attachment.isStorageBufferView() )\n\t\t\tcheck( !attachment.isUniformBuffer() )\n\t\t\tcheck( !attachment.isUniformBufferView() )\n\t\t\tcheck( !attachment.isTransitionBuffer() )\n\t\t\tcheck( !attachment.isTransitionBufferView() )\n\t\t\tcheck( attachment.pass == nullptr )\n\t\t\tcheck( attachment.buffer().data->source.size() == 2u )\n\t\t\tcheck( attachment.buffer().data->source[0] == buffer1v )\n\t\t\tcheck( attachment.buffer().data->source[1] == buffer2v )\n\t\t}\n\t\ttestEnd()\n\t}\n}\n\ntestSuiteMain()\n"
  },
  {
    "path": "test/TestBases.cpp",
    "content": "#include \"Common.hpp\"\n\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/FramePassTimer.hpp>\n#include <RenderGraph/ImageData.hpp>\n#include <RenderGraph/Log.hpp>\n#include <RenderGraph/ResourceHandler.hpp>\n#include <RenderGraph/RunnableGraph.hpp>\n#include <RenderGraph/RunnablePass.hpp>\n#include <RenderGraph/RunnablePasses/GenerateMipmaps.hpp>\n#include <RenderGraph/RunnablePasses/RenderMeshConfig.hpp>\n\n#include <sstream>\n#include <thread>\n\nnamespace\n{\n\tcrg::GraphContext & getContext()\n\t{\n\t\treturn test::getDummyContext();\n\t}\n}\n\nTEST( Bases, BaseFuncs )\n{\n\ttestBegin( \"testBaseFuncs\" )\n\tcrg::ResourceHandler handler;\n\tauto image = handler.createImageId( test::createImage( \"image\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) );\n\tauto view = handler.createViewId( test::createView( \"view\", image, crg::PixelFormat::eR16G16B16A16_SFLOAT, 4u, 2u, 2u, 3u ) );\n\tgetMipExtent( view );\n\tauto type = getImageType( image );\n\tcheck( getImageType( view ) == type )\n\tcheck( getImageViewType( view ) == view.data->info.viewType )\n\tcheck( getImageCreateFlags( view ) == getImageCreateFlags( image ) )\n\tcheck( getMipLevels( image ) == 8u )\n\tcheck( getMipLevels( view ) == 2u )\n\tcheck( getArrayLayers( image ) == 6u )\n\tcheck( getArrayLayers( view ) == 3u )\n\tcheck( crg::getAccessMask( crg::ImageLayout::ePresentSrc ) == crg::AccessFlags::eMemoryRead )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eSharedPresent ) == crg::AccessFlags::eMemoryRead )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eColorAttachment ) == crg::AccessFlags::eColorAttachmentWrite )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::AccessFlags::eDepthStencilAttachmentWrite )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::AccessFlags::eDepthStencilAttachmentRead )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eShaderReadOnly ) == crg::AccessFlags::eShaderRead )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eTransferSrc ) == crg::AccessFlags::eTransferRead )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eTransferDst ) == crg::AccessFlags::eTransferWrite )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) )\n\tcheck( crg::getAccessMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == ( crg::AccessFlags::eDepthStencilAttachmentRead | crg::AccessFlags::eDepthStencilAttachmentWrite ) )\n#ifdef VK_NV_shading_rate_image\n\tcheck( crg::getAccessMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::AccessFlags::eFragmentShadingRateAttachmentRead )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShadingRateAttachment ).access == crg::AccessFlags::eFragmentShadingRateAttachmentRead )\n\tcheck( crg::getStageMask( crg::ImageLayout::eFragmentShadingRateAttachment ) == crg::PipelineStageFlags::eFragmentShadingRateAttachment )\n#endif\n#ifdef VK_EXT_fragment_density_map\n\tcheck( crg::getAccessMask( crg::ImageLayout::eFragmentDensityMap ) == crg::AccessFlags::eFragmentDensityMapRead )\n\tcheck( crg::getStageMask( crg::ImageLayout::eFragmentDensityMap ) == crg::PipelineStageFlags::eFragmentShader )\n#endif\n\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eBottomOfPipe ).access == crg::AccessFlags::eMemoryRead )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eColorAttachmentOutput ).access == ( crg::AccessFlags::eColorAttachmentWrite | crg::AccessFlags::eColorAttachmentRead ) )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eLateFragmentTests ).access == ( crg::AccessFlags::eDepthStencilAttachmentWrite | crg::AccessFlags::eDepthStencilAttachmentRead ) )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eFragmentShader ).access == crg::AccessFlags::eShaderRead )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eTransfer ).access == ( crg::AccessFlags::eTransferRead | crg::AccessFlags::eTransferWrite ) )\n\tcheck( crg::getPipelineState( crg::PipelineStageFlags::eComputeShader ).access == crg::AccessFlags::eShaderRead )\n\n\tcheck( crg::getStageMask( crg::ImageLayout::eUndefined ) == crg::PipelineStageFlags::eHost )\n\tcheck( crg::getStageMask( crg::ImageLayout::eGeneral ) == crg::PipelineStageFlags::eBottomOfPipe )\n\tcheck( crg::getStageMask( crg::ImageLayout::ePresentSrc ) == crg::PipelineStageFlags::eBottomOfPipe )\n\tcheck( crg::getStageMask( crg::ImageLayout::eSharedPresent ) == crg::PipelineStageFlags::eBottomOfPipe )\n\tcheck( crg::getStageMask( crg::ImageLayout::eDepthStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests )\n\tcheck( crg::getStageMask( crg::ImageLayout::eDepthReadOnlyStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests )\n\tcheck( crg::getStageMask( crg::ImageLayout::eDepthAttachmentStencilReadOnly ) == crg::PipelineStageFlags::eLateFragmentTests )\n\tcheck( crg::getStageMask( crg::ImageLayout::eDepthStencilAttachment ) == crg::PipelineStageFlags::eLateFragmentTests )\n\tcheck( crg::getStageMask( crg::ImageLayout::eColorAttachment ) == crg::PipelineStageFlags::eColorAttachmentOutput )\n\tcheck( crg::getStageMask( crg::ImageLayout::eShaderReadOnly ) == crg::PipelineStageFlags::eFragmentShader )\n\tcheck( crg::getStageMask( crg::ImageLayout::eTransferSrc ) == crg::PipelineStageFlags::eTransfer )\n\tcheck( crg::getStageMask( crg::ImageLayout::eTransferDst ) == crg::PipelineStageFlags::eTransfer )\n\n\tfor ( uint32_t i = 0; i <= uint32_t( crg::PixelFormat::eASTC_12x12_SRGB_BLOCK ); ++i )\n\t\tcheckNoThrow( getName( crg::PixelFormat( i ) ) )\n\n\tfor ( uint32_t i = 0; i <= uint32_t( crg::FilterMode::eLinear ); ++i )\n\t\tcheckNoThrow( getName( crg::FilterMode( i ) ) )\n\n\tfor ( uint32_t i = 0; i <= uint32_t( crg::MipmapMode::eLinear ); ++i )\n\t\tcheckNoThrow( getName( crg::MipmapMode( i ) ) )\n\n\tfor ( uint32_t i = 0; i <= uint32_t( crg::WrapMode::eMirrorClampToEdge ); ++i )\n\t\tcheckNoThrow( getName( crg::WrapMode( i ) ) )\n\n\tauto vb1 = crg::VertexBuffer{ handler.createViewId( test::createView( \"vtx1\", handler.createBufferId( test::createBuffer( \"vtx1\" ) ) ) ) };\n\tauto vb2 = crg::VertexBuffer{ handler.createViewId( test::createView( \"vtx2\", handler.createBufferId( test::createBuffer( \"vtx2\" ) ) ) ) };\n\tvb2 = std::move( vb1 );\n\tvb1 = vb2;\n\tcrg::VertexBuffer vb3{ vb1 };\n\tcrg::VertexBuffer vb4{ std::move( vb1 ) };\n\n\tcrg::GetPrimitiveCountCallback cb0;\n\tcrg::GetPrimitiveCountCallback cb1;\n\tcb1 = cb0;\n\n\ttestEnd()\n}\n\nTEST( Bases, ClearValues )\n{\n\ttestBegin( \"testClearValues\" )\n\tcrg::ClearColorValue clearColorInt32{ std::array< int32_t, 4u >{ 1, 2, 3, 4 } };\n\tcrg::ClearColorValue clearColorUInt32{ std::array< uint32_t, 4u >{ 1u, 2u, 3u, 4u } };\n\tcrg::ClearColorValue clearColorFloat32{ std::array< float, 4u >{ 1.0f, 2.0f, 3.0f, 4.0f } };\n\tcrg::ClearDepthStencilValue clearDepthStencil{ 1.0f, 255u };\n\n\tcheckNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearColorFloat32 } ) )\n\tcheckNoThrow( getClearColorValue( crg::ClearValue{ clearDepthStencil } ) )\n\tcheckNoThrow( getClearColorValue( crg::ClearValue{ clearColorFloat32 } ) )\n\tcheckNoThrow( getClearDepthStencilValue( crg::ClearValue{ clearDepthStencil } ) )\n\tcheckNoThrow( convert( crg::ClearValue{ clearColorFloat32 } ) )\n\tcheckNoThrow( convert( crg::ClearValue{ clearDepthStencil } ) )\n\tcheck( clearColorFloat32.isFloat32() )\n\tcheck( !clearColorFloat32.isInt32() )\n\tcheck( !clearColorFloat32.isUInt32() )\n\tcheck( !clearColorUInt32.isFloat32() )\n\tcheck( !clearColorUInt32.isInt32() )\n\tcheck( clearColorUInt32.isUInt32() )\n\tcheck( !clearColorInt32.isFloat32() )\n\tcheck( clearColorInt32.isInt32() )\n\tcheck( !clearColorInt32.isUInt32() )\n\tcheck( crg::ClearValue{ clearColorFloat32 }.isColor() )\n\tcheck( !crg::ClearValue{ clearColorFloat32 }.isDepthStencil() )\n\tcheck( !crg::ClearValue{ clearDepthStencil }.isColor() )\n\tcheck( crg::ClearValue{ clearDepthStencil }.isDepthStencil() )\n\t{\n\t\tauto vkClearColorFloat32 = crg::convert( clearColorFloat32 );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorFloat32.float32[i] == clearColorFloat32.float32()[i] )\n\t}\n\t{\n\t\tauto vkClearColorFloat32 = crg::convert( crg::ClearValue{ clearColorFloat32 } );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorFloat32.color.float32[i] == clearColorFloat32.float32()[i] )\n\t}\n\t{\n\t\tauto vkClearColorInt32 = crg::convert( clearColorInt32 );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorInt32.int32[i] == clearColorInt32.int32()[i] )\n\t}\n\t{\n\t\tauto vkClearColorInt32 = crg::convert( crg::ClearValue{ clearColorInt32 } );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorInt32.color.int32[i] == clearColorInt32.int32()[i] )\n\t}\n\t{\n\t\tauto vkClearColorUInt32 = crg::convert( clearColorUInt32 );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorUInt32.uint32[i] == clearColorUInt32.uint32()[i] )\n\t}\n\t{\n\t\tauto vkClearColorUInt32 = crg::convert( crg::ClearValue{ clearColorUInt32 } );\n\t\tfor ( uint32_t i = 0; i < 4u; ++i )\n\t\t\tcheck( vkClearColorUInt32.color.uint32[i] == clearColorUInt32.uint32()[i] )\n\t}\n\t{\n\t\tauto vkClearDepthStencil = crg::convert( clearDepthStencil );\n\t\tcheck( vkClearDepthStencil.depth == clearDepthStencil.depth )\n\t\tcheck( vkClearDepthStencil.stencil == clearDepthStencil.stencil )\n\t}\n\t{\n\t\tauto vkClearDepthStencil = crg::convert( crg::ClearValue{ clearDepthStencil } );\n\t\tcheck( vkClearDepthStencil.depthStencil.depth == clearDepthStencil.depth )\n\t\tcheck( vkClearDepthStencil.depthStencil.stencil == clearDepthStencil.stencil )\n\t}\n\n\ttestEnd()\n}\n\nTEST( Bases, Signal )\n{\n\ttestBegin( \"testSignal\" )\n\t{\n\t\tusing DummyFunc = std::function< void() >;\n\t\tusing OnDummy = crg::Signal< DummyFunc >;\n\t\tOnDummy onDummy;\n\n\t\tauto connection = onDummy.connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\tonDummy();\n\t\tconnection.disconnect();\n\t\tonDummy();\n\t\tconnection = onDummy.connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\tonDummy();\n\t\tconnection = onDummy.connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\tonDummy();\n\t\tauto connection2 = onDummy.connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\tonDummy();\n\t}\n\t{\n\t\tusing DummyFunc = std::function< void() >;\n\t\tusing OnDummy = crg::Signal< DummyFunc >;\n\t\tauto onDummy = std::make_unique< OnDummy >();\n\n\t\tauto connection = onDummy->connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\t( *onDummy )();\n\t\tauto connection2 = onDummy->connect( []()\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\t( *onDummy )();\n\n\t\tonDummy.reset();\n\t}\n\t{\n\t\tusing DummyFunc = std::function< void( bool ) >;\n\t\tusing OnDummy = crg::Signal< DummyFunc >;\n\t\tusing OnDummyConnection = crg::SignalConnection< OnDummy >;\n\t\tauto onDummy = std::make_unique< OnDummy >();\n\t\tOnDummyConnection tmpConn;\n\n\t\tauto connection = onDummy->connect( []( bool )\n\t\t\t{\n\t\t\t\t// Nothing to do here...\n\t\t\t} );\n\t\t( *onDummy )( false );\n\t\tauto connection2 = onDummy->connect( [&tmpConn, &onDummy]( bool )\n\t\t\t{\n\t\t\t\ttmpConn = onDummy->connect( []( bool )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Nothing to do here...\n\t\t\t\t\t} );\n\t\t\t} );\n\t\t( *onDummy )( true );\n\n\t\tonDummy.reset();\n\t}\n\ttestEnd()\n}\n\nTEST( Bases, Exception )\n{\n\ttestBegin( \"testException\" )\n\ttry\n\t{\n\t\tCRG_Exception( \"Coin !!\" );\n\t}\n\tcatch ( crg::Exception & exc )\n\t{\n\t\tcrg::Logger::logInfo( exc.what() );\n\t}\n\ttestEnd()\n}\n\nTEST( Bases, Fence )\n{\n\ttestBegin( \"testFence\" )\n\tauto & context = getContext();\n\t{\n\t\tcrg::Fence fence{ context, \"test\", {} };\n\t\tfence.reset();\n\t\tfence.wait( 0xFFFFFFFFFFFFFFFFULL );\n\t\tfence.reset();\n\t}\n\ttestEnd()\n}\n\nTEST( Bases, FramePassTimer )\n{\n\ttestBegin( \"testFramePassTimer\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tcrg::RunnablePass * runPass{};\n\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = graph.createView( test::createView( \"bufferv\", buffer ) );\n\tauto & testPass = graph.createPass( \"Mesh\"\n\t\t, [&testCounts, &runPass]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\tauto res = createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\trunPass = res.get();\n\t\t\treturn res;\n\t\t} );\n\ttestPass.addClearableOutputStorageBuffer( bufferv, 1u );\n\n\tcrg::FramePassNode node1{ testPass };\n\tcrg::FramePassNode node2{ testPass };\n\tnode2 = std::move( node1 );\n\n\tcheckThrow( crg::checkVkResult( VK_ERROR_VALIDATION_FAILED_EXT, std::string{ \"Test\" } ), crg::Exception )\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\t{\n\t\tauto & timer = runPass->getTimer();\n\t\tauto save = timer.getCpuTime();\n\t\t{\n\t\t\tauto block = timer.start();\n\t\t\tstd::this_thread::sleep_for( std::chrono::milliseconds{ 10u } );\n\t\t}\n\t\ttimer.retrieveGpuTime();\n\t\tauto end = timer.getCpuTime();\n\t\tauto total = ( end - save ) + timer.getGpuTime();\n\t\tcheck( total >= std::chrono::milliseconds{ 10u } )\n\t\ttimer.reset();\n\t\tcheck( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } )\n\t\tcheck( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } )\n\t}\n\t{\n\t\tcrg::FramePassTimer timer{ getContext(), \"test\", crg::TimerScope::eUpdate };\n\t\tauto save = timer.getCpuTime();\n\t\t{\n\t\t\tauto block = std::make_unique< crg::FramePassTimerBlock >( timer.start() );\n\t\t\tstd::this_thread::sleep_for( std::chrono::milliseconds{ 10u } );\n\t\t\tblock.reset();\n\t\t}\n\t\ttimer.retrieveGpuTime();\n\t\tauto end = timer.getCpuTime();\n\t\tauto total = ( end - save ) + timer.getGpuTime();\n\t\tcheck( total >= std::chrono::milliseconds{ 10u } )\n\t\ttimer.reset();\n\t\tcheck( timer.getCpuTime() >= std::chrono::milliseconds{ 0u } )\n\t\tcheck( timer.getGpuTime() >= std::chrono::milliseconds{ 0u } )\n\t}\n\t{\n\t\tauto timer = std::make_unique< crg::FramePassTimer >( getContext(), \"test\", crg::TimerScope::eUpdate );\n\t\tauto connection = timer->onDestroy.connect( []( crg::FramePassTimer const & thisTimer )\n\t\t\t{\n\t\t\t\tif ( thisTimer.getScope() == crg::TimerScope::eUpdate )\n\t\t\t\t{\n\t\t\t\t\tCRG_Exception( \"WTF???\" );\n\t\t\t\t}\n\t\t\t} );\n\t\ttimer.reset();\n\t}\n\ttestEnd()\n}\n\nTEST( Bases, ImplicitActions )\n{\n\ttestBegin( \"testImplicitActions\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto depth1 = graph.createImage( test::createImage( \"depth1\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth1v = graph.createView( test::createView( \"depth1v\", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto depth2 = graph.createImage( test::createImage( \"depth2\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth2v = graph.createView( test::createView( \"depth2v\", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto colour1 = graph.createImage( test::createImage( \"colour1\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour1v = graph.createView( test::createView( \"colour1v\", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour2 = graph.createImage( test::createImage( \"colour2\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour2v = graph.createView( test::createView( \"colour2v\", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour3 = graph.createImage( test::createImage( \"colour3\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour3v = graph.createView( test::createView( \"colour3v\", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour4 = graph.createImage( test::createImage( \"colour4\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour4v = graph.createView( test::createView( \"colour4v\", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto buffer1 = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer1 ) );\n\tauto buffer2 = graph.createBuffer( test::createBuffer( \"buffer2\" ) );\n\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer2 ) );\n\tauto buffer3 = graph.createBuffer( test::createBuffer( \"buffer3\" ) );\n\tauto buffer3v = graph.createView( test::createView( \"buffer3v\", buffer3 ) );\n\tauto buffer4 = graph.createBuffer( test::createBuffer( \"buffer4\" ) );\n\tauto buffer4v = graph.createView( test::createView( \"buffer4v\", buffer4 ) );\n\tauto & testPass1 = graph.createPass( \"Mesh\"\n\t\t, [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v, buffer1v, buffer2v, buffer3v]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\tauto depthIt = framePass.getTargets().begin();\n\t\t\tauto colourIt = std::next( depthIt );\n\t\t\tauto extent3D = getExtent( colour2v );\n\t\t\tauto extent2D = crg::Extent2D{ extent3D.width, extent3D.height };\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, 0u\n\t\t\t\t, false\n\t\t\t\t, crg::ru::Config{}\n\t\t\t\t\t.implicitAction( ( *depthIt )->view(), crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.implicitAction( depth2v, crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.implicitAction( ( *colourIt )->view(), crg::RecordContext::clearAttachment( **colourIt ) )\n\t\t\t\t\t.implicitAction( colour4v, crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{}, crg::ImageLayout::eShaderReadOnly ) )\n\t\t\t\t\t.implicitAction( colour2v, crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) )\n\t\t\t\t\t.implicitAction( colour3v, crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) )\n\t\t\t\t\t.implicitAction( buffer1v, crg::RecordContext::clearBuffer( buffer1v, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) )\n\t\t\t\t\t.implicitAction( buffer2v, crg::RecordContext::clearBuffer( buffer2v, 18u, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) )\n\t\t\t\t\t.implicitAction( buffer3v, crg::RecordContext::copyBuffer( buffer1v, buffer3v, 0u, 0u, 48u, { crg::AccessFlags::eShaderWrite, crg::PipelineStageFlags::eFragmentShader } ) ) );\n\t\t} );\n\tauto depth1a = testPass1.addOutputDepthStencilTarget( depth1v );\n\tauto colour1a = testPass1.addOutputColourTarget( colour1v );\n\tauto colour2a = testPass1.addOutputColourTarget( colour2v );\n\tauto colour3a = testPass1.addOutputColourTarget( colour3v );\n\tauto colour4a = testPass1.addOutputColourTarget( colour4v );\n\tauto depth2a = testPass1.addOutputStorageImage( depth2v, 0u );\n\tauto buffer2a = testPass1.addOutputStorageBuffer( buffer2v, 1 );\n\tauto buffer3a = testPass1.addOutputStorageBuffer( buffer3v, 2 );\n\tauto buffer4a = testPass1.addOutputStorageBuffer( buffer4v, 3 );\n\tauto buffer1a = testPass1.addOutputStorageBuffer( buffer1v, 4 );\n\n\tauto & testPass2 = graph.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, 0u );\n\t\t} );\n\ttestPass2.addInOutDepthStencilTarget( *depth1a );\n\ttestPass2.addInOutColourTarget( *colour1a );\n\ttestPass2.addInOutColourTarget( *colour2a );\n\ttestPass2.addInOutColourTarget( *colour3a );\n\ttestPass2.addInOutColourTarget( *colour4a );\n\ttestPass2.addInOutStorage( *depth2a, 0u );\n\ttestPass2.addInOutStorage( *buffer2a, 1 );\n\ttestPass2.addInOutStorage( *buffer3a, 2 );\n\ttestPass2.addInOutStorage( *buffer4a, 3 );\n\ttestPass2.addInOutStorage( *buffer1a, 4 );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( Bases, PrePassActions )\n{\n\ttestBegin( \"testPrePassActions\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto depth1 = graph.createImage( test::createImage( \"depth1\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth1v = graph.createView( test::createView( \"depth1v\", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto depth2 = graph.createImage( test::createImage( \"depth2\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth2v = graph.createView( test::createView( \"depth2v\", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto colour1 = graph.createImage( test::createImage( \"colour1\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour1v = graph.createView( test::createView( \"colour1v\", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour2 = graph.createImage( test::createImage( \"colour2\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour2v = graph.createView( test::createView( \"colour2v\", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour3 = graph.createImage( test::createImage( \"colour3\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour3v = graph.createView( test::createView( \"colour3v\", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour4 = graph.createImage( test::createImage( \"colour4\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour4v = graph.createView( test::createView( \"colour4v\", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto & testPass1 = graph.createPass( \"Mesh\"\n\t\t, [&testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\tauto depthIt = framePass.getTargets().begin();\n\t\t\tauto colourIt = std::next( depthIt );\n\t\t\tauto extent3D = getExtent( colour2v );\n\t\t\tauto extent2D = crg::Extent2D{ extent3D.width, extent3D.height };\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, crg::ru::Config{}\n\t\t\t\t\t.prePassAction( crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.prePassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.prePassAction( crg::RecordContext::clearAttachment( **colourIt ) )\n\t\t\t\t\t.prePassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) )\n\t\t\t\t\t.prePassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) )\n\t\t\t\t\t.prePassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) );\n\t\t} );\n\tauto depth1a = testPass1.addOutputDepthStencilTarget( depth1v );\n\tauto colour1a = testPass1.addOutputColourTarget( colour1v );\n\tauto colour2a = testPass1.addOutputColourTarget( colour2v );\n\tauto colour3a = testPass1.addOutputColourTarget( colour3v );\n\tauto colour4a = testPass1.addOutputColourTarget( colour4v );\n\tauto depth2a = testPass1.addOutputStorageImage( depth2v, 0u );\n\n\tauto & testPass2 = graph.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, 0u );\n\t\t} );\n\ttestPass2.addInOutDepthStencilTarget( *depth1a );\n\ttestPass2.addInOutColourTarget( *colour1a );\n\ttestPass2.addInOutColourTarget( *colour2a );\n\ttestPass2.addInOutColourTarget( *colour3a );\n\ttestPass2.addInOutColourTarget( *colour4a );\n\ttestPass2.addInOutStorage( *depth2a, 0u );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( Bases, PostPassActions )\n{\n\ttestBegin( \"testPrePassActions\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto depth1 = graph.createImage( test::createImage( \"depth1\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth1v = graph.createView( test::createView( \"depth1v\", depth1, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto depth2 = graph.createImage( test::createImage( \"depth2\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depth2v = graph.createView( test::createView( \"depth2v\", depth2, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\tauto colour1 = graph.createImage( test::createImage( \"colour1\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour1v = graph.createView( test::createView( \"colour1v\", colour1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour2 = graph.createImage( test::createImage( \"colour2\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour2v = graph.createView( test::createView( \"colour2v\", colour2, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour3 = graph.createImage( test::createImage( \"colour3\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour3v = graph.createView( test::createView( \"colour3v\", colour3, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto colour4 = graph.createImage( test::createImage( \"colour4\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colour4v = graph.createView( test::createView( \"colour4v\", colour4, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tcrg::RunnablePass const * runPass{};\n\tauto & testPass1 = graph.createPass( \"Mesh\"\n\t\t, [&runPass , &testCounts, depth2v, colour1v, colour2v, colour3v, colour4v]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\tauto depthIt = framePass.getTargets().begin();\n\t\t\tauto colourIt = std::next( depthIt );\n\t\t\tauto extent3D = getExtent( colour2v );\n\t\t\tauto extent2D = crg::Extent2D{ extent3D.width, extent3D.height };\n\t\t\tauto res = createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, crg::ru::Config{ 1u, true }\n\t\t\t\t\t.postPassAction( crg::RecordContext::clearAttachment( **depthIt, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.postPassAction( crg::RecordContext::clearAttachment( depth2v, crg::ClearDepthStencilValue{}, crg::ImageLayout::eDepthStencilAttachment ) )\n\t\t\t\t\t.postPassAction( crg::RecordContext::clearAttachment( **colourIt ) )\n\t\t\t\t\t.postPassAction( crg::RecordContext::clearAttachment( colour4v, crg::ClearColorValue{} ) )\n\t\t\t\t\t.postPassAction( crg::RecordContext::blitImage( colour1v, colour2v, { {}, extent2D }, { {}, extent2D }, crg::FilterMode::eLinear, crg::ImageLayout::eShaderReadOnly ) )\n\t\t\t\t\t.postPassAction( crg::RecordContext::copyImage( colour2v, colour3v, extent2D, crg::ImageLayout::eShaderReadOnly ) ) );\n\t\t\trunPass = res.get();\n\t\t\treturn res;\n\t\t} );\n\tauto depth1a = testPass1.addOutputDepthStencilTarget( depth1v );\n\tauto colour1a = testPass1.addOutputColourTarget( colour1v );\n\tauto colour2a = testPass1.addOutputColourTarget( colour2v );\n\tauto colour3a = testPass1.addOutputColourTarget( colour3v );\n\tauto colour4a = testPass1.addOutputColourTarget( colour4v );\n\tauto depth2a = testPass1.addOutputStorageImage( depth2v, 0u );\n\n\tauto & testPass2 = graph.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, test::checkDummy\n\t\t\t\t, 0u );\n\t\t} );\n\ttestPass2.addInOutDepthStencilTarget( *depth1a );\n\ttestPass2.addInOutColourTarget( *colour1a );\n\ttestPass2.addInOutColourTarget( *colour2a );\n\ttestPass2.addInOutColourTarget( *colour3a );\n\ttestPass2.addInOutColourTarget( *colour4a );\n\ttestPass2.addInOutStorage( *depth2a, 0u );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( Bases, GraphDeps )\n{\n\ttestBegin( \"testGraphDeps\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph1{ handler, testCounts.testName + \"1\" };\n\tauto colour = graph1.createImage( test::createImage( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colourv = graph1.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto iocolour = graph1.createImage( test::createImage( \"iocolour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto iocolourv = graph1.createView( test::createView( \"iocolourv\", iocolour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto buffer = graph1.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = graph1.createView( test::createView( \"bufferv\", buffer ) );\n\tauto & testPass1 = graph1.createPass( \"Mesh\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto coloura = testPass1.addOutputColourTarget( colourv );\n\tauto iocoloura = testPass1.addOutputColourTarget( iocolourv );\n\ttestPass1.addOutputStorageBuffer( bufferv, 0u );\n\tgraph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tgraph1.addOutput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) );\n\tcheck( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly )\n\n\tcrg::FrameGraph graph2{ handler, testCounts.testName + \"2\" };\n\tgraph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tgraph2.addInput( iocolourv, crg::makeLayoutState( crg::ImageLayout::eColorAttachment ) );\n\tcheck( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly )\n\tgraph2.addDependency( graph1 );\n\tauto & testPass2 = graph2.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\ttestPass2.addInputSampled( *coloura, 0u );\n\ttestPass2.addInOutColourTarget( *iocoloura );\n\n\tauto runnable1 = graph1.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable1 );\n\n\tauto runnable2 = graph2.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable2 );\n\ttestEnd()\n}\n\nTEST( Bases, 2PassGraphDeps )\n{\n\ttestBegin( \"test2PassGraphDeps\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph1{ handler, testCounts.testName + \"1\" };\n\tauto buffer = graph1.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = graph1.createView( test::createView( \"bufferv\", buffer ) );\n\tauto colour = graph1.createImage( test::createImage( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colourv = graph1.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\n\tauto & testPass11 = graph1.createPass( \"Pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto coloura = testPass11.addOutputColourTarget( colourv );\n\tauto bufferAttach = testPass11.addOutputStorageBuffer( bufferv, 0u );\n\n\tauto & testPass12 = graph1.createPass( \"Pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tbufferAttach = testPass12.addInOutStorage( *bufferAttach, 0u );\n\tcoloura = testPass12.addInOutStorage( *coloura, 1u );\n\n\tgraph1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tcheck( graph1.getOutputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly )\n\n\tcrg::FrameGraph graph2{ handler, testCounts.testName + \"2\" };\n\tgraph2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tcheck( graph2.getInputLayoutState( colourv ).layout == crg::ImageLayout::eShaderReadOnly )\n\tgraph2.addDependency( graph1 );\n\t{\n\t\tauto & testPass21 = graph2.createPass( \"Pass1\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\ttestPass21.addInputSampled( *coloura, 0u );\n\n\t\tauto & testPass22 = graph2.createPass( \"Pass2\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\ttestPass22.addInputStorage( *bufferAttach, 0u );\n\t}\n\n\tauto runnable1 = graph1.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable1 );\n\n\tauto runnable2 = graph2.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable2 );\n\ttestEnd()\n}\n\nTEST( Bases, PassGroupDeps )\n{\n\ttestBegin( \"testPassGroupDeps\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph1{ handler, testCounts.testName + \"1\" };\n\tauto & group1 = graph1.getDefaultGroup();\n\tauto colour = group1.createImage( test::createImage( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colourv = group1.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto buffer = graph1.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = graph1.createView( test::createView( \"bufferv\", buffer ) );\n\tauto & testPass1 = group1.createPass( \"Mesh\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto coloura = testPass1.addOutputColourTarget( colourv );\n\ttestPass1.addOutputStorageBuffer( bufferv, 0u );\n\tgroup1.addOutput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tgroup1.addGroupOutput( colourv );\n\n\tcrg::FrameGraph graph2{ handler, testCounts.testName + \"2\" };\n\tauto & group2 = graph2.getDefaultGroup();\n\tgroup2.addInput( colourv, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tgroup2.addGroupInput( colourv );\n\tgraph2.addDependency( graph1 );\n\tauto & testPass2 = group2.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\ttestPass2.addInputSampled( *coloura, 0u );\n\n\tauto runnable1 = graph1.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable1 );\n\n\tauto runnable2 = graph2.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable2 );\n\ttestEnd()\n}\n\nTEST( Bases, PassGroups )\n{\n\ttestBegin( \"testPassGroups\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto & group1 = graph.createPassGroup( \"First\" );\n\tauto colour = group1.createImage( test::createImage( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colourv = group1.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\tauto buffer = group1.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = group1.createView( test::createView( \"bufferv\", buffer ) );\n\tauto & testPass1 = group1.createPass( \"Mesh\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto coloura = testPass1.addOutputColourTarget( colourv );\n\tauto bufferAttach = testPass1.addOutputStorageBuffer( bufferv, 0u );\n\tgroup1.addGroupOutput( colourv );\n\n\tauto & group2 = graph.createPassGroup( \"Second\" ).createPassGroup( \"Third\" );\n\tgroup2.addGroupInput( colourv );\n\tauto & testPass2 = group2.createPass( \"Pass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\ttestPass2.addInputSampled( *coloura, 0u );\n\ttestPass2.addInputStorage( *bufferAttach, 0u );\n\n\tauto runnable2 = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable2 );\n\ttestEnd()\n}\n\nTEST( Bases, ResourcesCache )\n{\n\ttestBegin( \"testResourcesCache\" )\n\t{\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::RecordContext context( handler );\n\t\tcheckThrow( context.getContext(), crg::Exception )\n\t}\n\tauto & context = getContext();\n\tcrgUnregisterObject( context, VkBuffer( 1 ) );\n\tcheckThrow( context.deduceMemoryType( 0u, 0u ), crg::Exception )\n\t{\n\t\tcrg::ResourceHandler handler;\n\t\tauto sampled = handler.createImageId( test::createImage( \"sampled\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto sampledv = handler.createViewId( test::createView( \"sampledv\", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto buffer = handler.createBufferId( test::createBuffer( \"buffer\" ) );\n\t\tauto bufferv = handler.createViewId( test::createView( \"bufferv\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\thandler.createImage( context, sampled );\n\t\thandler.createImageView( context, sampledv );\n\t\thandler.createBuffer( context, buffer );\n\t\thandler.createBufferView( context, bufferv );\n\t\thandler.createQuadTriVertexBuffer( context, \"test\", false, {} );\n\t\thandler.createQuadTriVertexBuffer( context, \"test\", true, {} );\n\t\thandler.createSampler( context, \"test\", crg::SamplerDesc{} );\n\t}\n\tcrg::ResourceHandler handler;\n\tcrg::ResourcesCache resources{ handler };\n\t{\n\t\tauto sampled = handler.createImageId( test::createImage( \"sampled\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto sampledv = handler.createViewId( test::createView( \"sampledv\", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tresources.createImage( context, sampled );\n\t\tresources.createImageView( context, sampledv );\n\t\tresources.destroyImageView( context, sampledv );\n\t\tresources.destroyImage( context, sampled );\n\t\tauto buffer = handler.createBufferId( test::createBuffer( \"buffer\" ) );\n\t\tauto bufferv = handler.createViewId( test::createView( \"bufferv\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tresources.createBuffer( context, buffer );\n\t\tresources.createBufferView( context, bufferv );\n\t\tresources.destroyBufferView( context, bufferv );\n\t\tresources.destroyBuffer( context, buffer );\n\t}\n\t{\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tresources.createImage( context, result );\n\t\tresources.createImageView( context, resultv );\n\t\tresources.destroyImageView( resultv );\n\t\tresources.destroyImage( result );\n\t\tauto buffer = handler.createBufferId( test::createBuffer( \"resbuffer\" ) );\n\t\tauto bufferv = handler.createViewId( test::createView( \"resbufferv\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tresources.createBuffer( context, buffer );\n\t\tresources.createBufferView( context, bufferv );\n\t\tresources.destroyBufferView( bufferv );\n\t\tresources.destroyBuffer( buffer );\n\t}\n\t{\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tresources.createImage( context, result );\n\t\tresources.createImageView( context, resultv );\n\t\tresources.createSampler( context, crg::SamplerDesc{} );\n\t\tresources.createQuadTriVertexBuffer( context, false, {} );\n\t\tresources.createQuadTriVertexBuffer( context, true, {} );\n\t\tauto buffer = handler.createBufferId( test::createBuffer( \"resbuffer\" ) );\n\t\tauto bufferv = handler.createViewId( test::createView( \"resbufferv\", buffer, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tresources.createBuffer( context, buffer );\n\t\tresources.createBufferView( context, bufferv );\n\t\tresources.destroyBufferView( context, bufferv );\n\t\tresources.destroyBuffer( context, buffer );\n\t}\n\ttestEnd()\n}\n\nTEST( Bases, GraphNodes )\n{\n\ttestBegin( \"testGraphNodes\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tcrg::RootNode root{ graph };\n\tcheck( getFramePass( root ) == nullptr )\n\n\tauto const & testPass = graph.createPass( \"testPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tcrg::FramePassNode node{ testPass };\n\tcheck( getFramePass( node ) == &testPass )\n\ttestEnd()\n}\n\ntestSuiteMain()\n"
  },
  {
    "path": "test/TestRenderGraph.cpp",
    "content": "#include \"Common.hpp\"\n\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/ImageData.hpp>\n#include <RenderGraph/ResourceHandler.hpp>\n#include <RenderGraph/RunnableGraph.hpp>\n#include <RenderGraph/RunnablePass.hpp>\n#include <RenderGraph/RunnablePasses/GenerateMipmaps.hpp>\n\n#include <sstream>\n\nnamespace\n{\n\tcrg::GraphContext & getContext()\n\t{\n\t\treturn test::getDummyContext();\n\t}\n\n\tvoid checkTargetColourIsShaderReadOnly( [[maybe_unused]] test::TestCounts const & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::RunnableGraph const &\n\t\t, crg::RecordContext const & context\n\t\t, uint32_t index )\n\t{\n\t\tfor ( auto attach : framePass.getTargets() )\n\t\t{\n\t\t\tauto view = attach->view( index );\n\n\t\t\tif ( attach->isColourOutputImageTarget() )\n\t\t\t{\n\t\t\t\tauto resolved = crg::resolveView( view, index );\n\t\t\t\tcheckEqual( context.getNextLayoutState( resolved ).layout, crg::ImageLayout::eShaderReadOnly )\n\t\t\t\tcheckEqual( context.getNextLayoutState( resolved.data->image\n\t\t\t\t\t, resolved.data->info.viewType\n\t\t\t\t\t, getSubresourceRange( resolved ) ).layout, crg::ImageLayout::eShaderReadOnly )\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid checkSampledIsShaderReadOnly( [[maybe_unused]] test::TestCounts const & testCounts\n\t\t, crg::FramePass const & framePass\n\t\t, crg::RunnableGraph const &\n\t\t, crg::RecordContext const & context\n\t\t, uint32_t index )\n\t{\n\t\tfor ( auto & [binding, attach] : framePass.getSampled() )\n\t\t{\n\t\t\tauto view = attach.attach->view( index );\n\t\t\tcheckEqual( context.getLayoutState( crg::resolveView( view, index ) ).layout, crg::ImageLayout::eShaderReadOnly )\n\t\t}\n\t}\n\n\tcrg::FrameGraph buildNoPassGraph( test::TestCounts const & testCounts\n\t\t, crg::ResourceHandler & handler )\n\t{\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tcheckThrow( graph.compile( getContext() ), crg::Exception )\n\t\treturn graph;\n\t}\n}\n\nTEST( RenderGraph, NoPass )\n{\n\ttestBegin( \"testNoPass\" )\n\tcrg::ResourceHandler handler;\n\tauto graph1 = buildNoPassGraph( testCounts, handler );\n\tcrg::FrameGraph graph{ std::move( graph1 ) };\n\n\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\tauto & pass = graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass.addOutputColourTarget( rtv );\n\ttestEnd()\n}\n\nTEST( RenderGraph, OnePass )\n{\n\ttestBegin( \"testOnePass\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\tauto & pass = graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass.addOutputColourTarget(  rtv );\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, DuplicateName )\n{\n\ttestBegin( \"testDuplicateName\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tcheckNoThrow( graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} ) )\n\tcheckThrow( graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} ), crg::Exception )\n\ttestEnd()\n}\n\nTEST( RenderGraph, OneDependency )\n{\n\ttestBegin( \"testOneDependency\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u, 4u ) );\n\tauto dep = graph.createImage( test::createImage( \"dep\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto rtv0 = graph.createView( test::createView( \"rtv0\", rt, 0u, 1u, 0u, 1u ) );\n\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt, 0u, 1u, 1u, 1u ) );\n\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt, 0u, 1u, 2u, 1u ) );\n\tauto rtv3 = graph.createView( test::createView( \"rtv3\", rt, 0u, 1u, 3u, 1u ) );\n\tauto depv = graph.createView( test::createView( \"depv\", dep ) );\n\tauto buf = graph.createBuffer( test::createBuffer( \"buf\" ) );\n\tauto bufv = graph.createView( test::createView( \"bufv\", buf ) );\n\tauto & pass1 = graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputUniformBuffer( bufv, 1u );\n\tauto rta = pass1.addOutputColourTarget( graph.mergeViews( { rtv0, rtv1, rtv2, rtv3 } ) );\n\tauto depa = pass1.addOutputDepthStencilTarget( depv );\n\n\tauto out = graph.createImage( test::createImage( \"out\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto outv = graph.createView( test::createView( \"outv\", out ) );\n\tauto & pass2 = graph.createPass( \"pass2C\"\n\t\t, []( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn test::createDummyNoRecord( framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *rta, 0u );\n\tpass2.addInputUniformBuffer( bufv, 1u );\n\tpass2.addOutputColourTarget( outv );\n\tpass2.addInputDepthStencilTarget( *depa );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"pass1C\" [ shape=ellipse ];\n  \"pass2C\" [ shape=ellipse ];\n  \"Transition to\\npass2C/rt/Spl0\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/rt/Spl0\" [ label=\"rtv0\" ];\n  \"Transition to\\npass2C/rt/Spl0\" -> \"pass2C\" [ label=\"rtv0\" ];\n  \"Transition to\\npass2C/rt/Spl1\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/rt/Spl1\" [ label=\"rtv1\" ];\n  \"Transition to\\npass2C/rt/Spl1\" -> \"pass2C\" [ label=\"rtv1\" ];\n  \"Transition to\\npass2C/rt/Spl2\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/rt/Spl2\" [ label=\"rtv2\" ];\n  \"Transition to\\npass2C/rt/Spl2\" -> \"pass2C\" [ label=\"rtv2\" ];\n  \"Transition to\\npass2C/rt/Spl3\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/rt/Spl3\" [ label=\"rtv3\" ];\n  \"Transition to\\npass2C/rt/Spl3\" -> \"pass2C\" [ label=\"rtv3\" ];\n  \"Transition to\\npass2C/depv/IRds\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/depv/IRds\" [ label=\"depv\" ];\n  \"Transition to\\npass2C/depv/IRds\" -> \"pass2C\" [ label=\"depv\" ];\n  \"ExternalSource\" [ shape=ellipse ];\n  \"Transition to\\npass1C/bufv/UB\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\npass1C/bufv/UB\" [ label=\"bufv\" ];\n  \"Transition to\\npass1C/bufv/UB\" -> \"pass1C\" [ label=\"bufv\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, CycleDependency )\n{\n\ttestBegin( \"testCycleDependency\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\tauto & pass1 = graph.createPass( \"pass1C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto rta = pass1.addOutputColourTarget( rtv );\n\n\tauto out = graph.createImage( test::createImage( \"out\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto outv = graph.createView( test::createView( \"outv\", out ) );\n\tauto & pass2 = graph.createPass( \"pass2C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *rta, 0u );\n\tauto outa = pass2.addOutputColourTarget( outv );\n\n\tauto & pass3 = graph.createPass( \"pass3C\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass3.addInputSampled( *rta, 0u );\n\tpass3.addInOutColourTarget( *outa );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"pass1C\" [ shape=ellipse ];\n  \"pass2C\" [ shape=ellipse ];\n  \"Transition to\\npass2C/rtv/Spl\" [ shape=box ];\n  \"pass1C\" -> \"Transition to\\npass2C/rtv/Spl\" [ label=\"rtv\" ];\n  \"Transition to\\npass2C/rtv/Spl\" -> \"pass2C\" [ label=\"rtv\" ];\n  \"pass3C\" [ shape=ellipse ];\n  \"Transition to\\npass3C/outv/IORcl\" [ shape=box ];\n  \"pass2C\" -> \"Transition to\\npass3C/outv/IORcl\" [ label=\"outv\" ];\n  \"Transition to\\npass3C/outv/IORcl\" -> \"pass3C\" [ label=\"outv\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, ChainedDependencies )\n{\n\ttestBegin( \"testChainedDependencies\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto d0 = graph.createImage( test::createImage( \"d0\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto d0v = graph.createView( test::createView( \"d0v\", d0 ) );\n\tauto & pass0 = graph.createPass( \"pass0\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto d0a = pass0.addOutputColourTarget( d0v );\n\n\tauto d1 = graph.createImage( test::createImage( \"d1\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto d1v = graph.createView( test::createView( \"d1v\", d1 ) );\n\tauto & pass1 = graph.createPass( \"pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputSampled( *d0a, 0u );\n\tauto d1a = pass1.addOutputColourTarget( d1v );\n\n\tauto buf = graph.createBuffer( test::createBuffer( \"buf\" ) );\n\tauto bufv = graph.createView( test::createView( \"bufv\", buf ) );\n\tauto & pass2 = graph.createPass( \"pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *d1a, 0u );\n\tpass2.addInputUniformBuffer( bufv, 1u );\n\tpass2.addInputColourTarget( *d1a );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"pass1\" [ shape=ellipse ];\n  \"pass2\" [ shape=ellipse ];\n  \"Transition to\\npass2/d1v/Spl\" [ shape=box ];\n  \"pass1\" -> \"Transition to\\npass2/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\npass2/d1v/Spl\" -> \"pass2\" [ label=\"d1v\" ];\n  \"Transition to\\npass2/d1v/IRcl\" [ shape=box ];\n  \"pass1\" -> \"Transition to\\npass2/d1v/IRcl\" [ label=\"d1v\" ];\n  \"Transition to\\npass2/d1v/IRcl\" -> \"pass2\" [ label=\"d1v\" ];\n  \"pass0\" [ shape=ellipse ];\n  \"Transition to\\npass1/d0v/Spl\" [ shape=box ];\n  \"pass0\" -> \"Transition to\\npass1/d0v/Spl\" [ label=\"d0v\" ];\n  \"Transition to\\npass1/d0v/Spl\" -> \"pass1\" [ label=\"d0v\" ];\n  \"ExternalSource\" [ shape=ellipse ];\n  \"Transition to\\npass2/bufv/UB\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\npass2/bufv/UB\" [ label=\"bufv\" ];\n  \"Transition to\\npass2/bufv/UB\" -> \"pass2\" [ label=\"bufv\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, SharedDependencies )\n{\n\ttestBegin( \"testSharedDependencies\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto d = graph.createImage( test::createImage( \"d\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto dstv1 = graph.createView( test::createView( \"dstv1\", d ) );\n\tauto buf = graph.createBuffer( test::createBuffer( \"buf\" ) );\n\tauto bufv1 = graph.createView( test::createView( \"bufv1\", buf ) );\n\tauto d0 = graph.createImage( test::createImage( \"d0\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto d0v = graph.createView( test::createView( \"d0v\", d0 ) );\n\tauto & pass0 = graph.createPass( \"pass0\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto attach = pass0.addOutputStorageBuffer( bufv1, 0 );\n\tpass0.addOutputDepthTarget( dstv1 );\n\tauto d0a = pass0.addOutputColourTarget( d0v );\n\n\tauto dstv2 = graph.createView( test::createView( \"dstv2\", d ) );\n\tauto bufv2 = graph.createView( test::createView( \"bufv2\", buf ) );\n\tauto d1 = graph.createImage( test::createImage( \"d1\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto d1v = graph.createView( test::createView( \"d1v\", d1 ) );\n\tauto & pass1 = graph.createPass( \"pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputSampled( *d0a, 0 );\n\tpass0.addOutputStorageBuffer( bufv2, 0 );\n\tauto dsta = pass1.addOutputDepthTarget ( dstv2 );\n\tauto d1a = pass1.addOutputColourTarget( d1v );\n\n\tauto d2 = graph.createImage( test::createImage( \"d2\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto d2v = graph.createView( test::createView( \"d2v\", d2 ) );\n\tauto & pass2 = graph.createPass( \"pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *d1a, 0 );\n\tpass2.addInputDepthTarget( *dsta );\n\tpass2.addOutputColourTarget( d2v );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\trunnable->getDescriptorWriteT( *attach, 0u );\n\trunnable->getContext();\n\t{\n\t\tcrg::RunnableGraph const & rn = *runnable;\n\t\tauto const & fence = rn.getFence();\n\t\tfence.getInternal();\n\t\tauto const & timer = rn.getTimer();\n\t\ttimer.getName();\n\t}\n\t{\n\t\tcrg::RunnableGraph & rn = *runnable;\n\t\tauto & fence = rn.getFence();\n\t\tfence.reset();\n\t\tauto & timer = rn.getTimer();\n\t\ttimer.reset();\n\t}\n\tcheck( runnable->getName() == graph.getName() )\n\tstd::string ref = R\"(digraph {\n  \"pass2\" [ shape=ellipse ];\n  \"pass1\" [ shape=ellipse ];\n  \"Transition to\\npass2/d1v/Spl\" [ shape=box ];\n  \"pass1\" -> \"Transition to\\npass2/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\npass2/d1v/Spl\" -> \"pass2\" [ label=\"d1v\" ];\n  \"Transition to\\npass2/dstv1/IRdp\" [ shape=box ];\n  \"pass1\" -> \"Transition to\\npass2/dstv1/IRdp\" [ label=\"dstv1\" ];\n  \"Transition to\\npass2/dstv1/IRdp\" -> \"pass2\" [ label=\"dstv1\" ];\n  \"pass0\" [ shape=ellipse ];\n  \"Transition to\\npass1/d0v/Spl\" [ shape=box ];\n  \"pass0\" -> \"Transition to\\npass1/d0v/Spl\" [ label=\"d0v\" ];\n  \"Transition to\\npass1/d0v/Spl\" -> \"pass1\" [ label=\"d0v\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, 2MipDependencies )\n{\n\ttestBegin( \"test2MipDependencies\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto lp = graph.createImage( test::createImage( \"lp\", crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) );\n\tauto m0v = graph.createView( test::createView( \"m0v\", lp, 0u ) );\n\tauto m1v = graph.createView( test::createView( \"m1v\", lp, 1u ) );\n\tauto m0a = crg::Attachment::createDefault( m0v );\n\tgraph.addInput( m0v, makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\tauto & ssaoMinifyPass1 = graph.createPass( \"ssaoMinifyPass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass1.addInputSampled( m0a, 0 );\n\tauto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v );\n\n\tauto m2v = graph.createView( test::createView( \"m2v\", lp, 2u ) );\n\tauto & ssaoMinifyPass2 = graph.createPass( \"ssaoMinifyPass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass2.addInputSampled( *m1a, 0 );\n\tssaoMinifyPass2.addOutputColourTarget( m2v );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ExternalSource\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, 3MipDependencies )\n{\n\ttestBegin( \"test3MipDependencies\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto lp = graph.createImage( test::createImage( \"lp\", crg::PixelFormat::eR32G32B32_SFLOAT, 4u ) );\n\tauto m0v = graph.createView( test::createView( \"m0v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 0u ) );\n\tauto m1v = graph.createView( test::createView( \"m1v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 1u ) );\n\tauto m0a = crg::Attachment::createDefault( m0v );\n\tauto & ssaoMinifyPass1 = graph.createPass( \"ssaoMinifyPass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass1.addInputSampled( m0a, 0 );\n\tauto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v );\n\n\tauto m2v = graph.createView( test::createView( \"m2v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) );\n\tauto & ssaoMinifyPass2 = graph.createPass( \"ssaoMinifyPass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass2.addInputSampled( *m1a, 0 );\n\tauto m2a = ssaoMinifyPass2.addOutputColourTarget( m2v );\n\n\tauto m3v = graph.createView( test::createView( \"m3v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) );\n\tauto & ssaoMinifyPass3 = graph.createPass( \"ssaoMinifyPass3\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass3.addInputSampled( *m2a, 0 );\n\tssaoMinifyPass3.addOutputColourTarget( m3v );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ExternalSource\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, LoopDependencies )\n{\n\ttestBegin( \"testLoopDependencies\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto a = graph.createImage( test::createImage( \"a\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto av = graph.createView( test::createView( \"av\", a, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto b = graph.createImage( test::createImage( \"b\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto bv = graph.createView( test::createView( \"bv\", b, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto ba = crg::Attachment::createDefault( bv );\n\tauto & pass1 = graph.createPass( \"pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputSampled( ba, 0 );\n\tauto aa = pass1.addOutputColourTarget( av );\n\n\tauto & pass2 = graph.createPass( \"pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *aa, 0 );\n\tpass2.addOutputColourTarget( bv );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( RenderGraph, LoopDependenciesWithRoot )\n{\n\ttestBegin( \"testLoopDependenciesWithRoot\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto b = graph.createImage( test::createImage( \"b\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto bv = graph.createView( test::createView( \"bv\", b, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & pass0 = graph.createPass( \"pass0\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto ba = pass0.addOutputColourTarget( bv );\n\n\tauto a = graph.createImage( test::createImage( \"a\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto av = graph.createView( test::createView( \"av\", a, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & pass1 = graph.createPass( \"pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputSampled( *ba, 0 );\n\tauto aa = pass1.addOutputColourTarget( av );\n\n\tauto & pass2 = graph.createPass( \"pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *aa, 0 );\n\tpass2.addOutputColourTarget( bv );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( RenderGraph, LoopDependenciesWithRootAndLeaf )\n{\n\ttestBegin( \"testLoopDependenciesWithRootAndLeaf\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto c = graph.createImage( test::createImage( \"c\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto cv = graph.createView( test::createView( \"cv\", c, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & pass0 = graph.createPass( \"pass0\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto ca = pass0.addOutputColourTarget( cv );\n\n\tauto a = graph.createImage( test::createImage( \"a\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto av = graph.createView( test::createView( \"av\", a, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto b = graph.createImage( test::createImage( \"b\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto bv = graph.createView( test::createView( \"bv\", b, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto ba = crg::Attachment::createDefault( bv );\n\tauto & pass1 = graph.createPass( \"pass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass1.addInputSampled( ba, 0 );\n\tpass1.addInputSampled( *ca, 1 );\n\tauto aa = pass1.addOutputColourTarget( av );\n\n\tauto & pass2 = graph.createPass( \"pass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass2.addInputSampled( *aa, 0 );\n\tpass2.addInputSampled( *ca, 1 );\n\tpass2.addOutputColourTarget( bv );\n\n\tauto buf = graph.createBuffer( test::createBuffer( \"buf\" ) );\n\tauto bufv = graph.createView( test::createView( \"bufv\", buf ) );\n\tauto & pass3 = graph.createPass( \"pass3\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tpass3.addInputSampled( *ca, 0 );\n\tpass3.addInputUniformBuffer( bufv, 1 );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"pass1\" [ shape=ellipse ];\n  \"pass2\" [ shape=ellipse ];\n  \"Transition to\\npass2/av/Spl\" [ shape=box ];\n  \"pass1\" -> \"Transition to\\npass2/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\npass2/av/Spl\" -> \"pass2\" [ label=\"av\" ];\n  \"pass0\" [ shape=ellipse ];\n  \"Transition to\\npass1/cv/Spl\" [ shape=box ];\n  \"pass0\" -> \"Transition to\\npass1/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\npass1/cv/Spl\" -> \"pass1\" [ label=\"cv\" ];\n  \"pass3\" [ shape=ellipse ];\n  \"ExternalSource\" [ shape=ellipse ];\n  \"Transition to\\npass1/bv/Spl\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\npass1/bv/Spl\" [ label=\"bv\" ];\n  \"Transition to\\npass1/bv/Spl\" -> \"pass1\" [ label=\"bv\" ];\n  \"Transition to\\npass3/bufv/UB\" [ shape=box ];\n  \"ExternalSource\" -> \"Transition to\\npass3/bufv/UB\" [ label=\"bufv\" ];\n  \"Transition to\\npass3/bufv/UB\" -> \"pass3\" [ label=\"bufv\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\ncrg::Attachment const * buildSsaoPass( test::TestCounts & testCounts\n\t, crg::Attachment const & lda\n\t, crg::FrameGraph & graph )\n{\n\tauto lp = graph.createImage( test::createImage( \"lp\", crg::PixelFormat::eR32_SFLOAT, 4u ) );\n\tauto m0v = graph.createView( test::createView( \"m0v\", lp, crg::PixelFormat::eR32_SFLOAT, 0u ) );\n\tauto & ssaoLinearisePass = graph.createPass( \"ssaoLinearisePass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoLinearisePass.addInputSampled( lda, 0 );\n\tauto m0a = ssaoLinearisePass.addOutputColourTarget( m0v );\n\n\tauto m1v = graph.createView( test::createView( \"m1v\", lp, crg::PixelFormat::eR32_SFLOAT, 1u ) );\n\tauto & ssaoMinifyPass1 = graph.createPass( \"ssaoMinifyPass1\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass1.addInputSampled( *m0a, 0 );\n\tauto m1a = ssaoMinifyPass1.addOutputColourTarget( m1v );\n\n\tauto m2v = graph.createView( test::createView( \"m2v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 2u ) );\n\tauto & ssaoMinifyPass2 = graph.createPass( \"ssaoMinifyPass2\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass2.addInputSampled( *m1a, 0 );\n\tauto m2a = ssaoMinifyPass2.addOutputColourTarget( m2v );\n\n\tauto m3v = graph.createView( test::createView( \"m3v\", lp, crg::PixelFormat::eR32G32B32_SFLOAT, 3u ) );\n\tauto & ssaoMinifyPass3 = graph.createPass( \"ssaoMinifyPass3\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoMinifyPass3.addInputSampled( *m2a, 0 );\n\tauto m3a = ssaoMinifyPass3.addOutputColourTarget( m3v );\n\n\tauto rs = graph.createImage( test::createImage( \"rs\", crg::PixelFormat::eR32_SFLOAT ) );\n\tauto rsv = graph.createView( test::createView( \"rsv\", rs, crg::PixelFormat::eR32_SFLOAT ) );\n\tauto & ssaoRawPass = graph.createPass( \"ssaoRawPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoRawPass.addInputSampled( *graph.mergeAttachments( { m0a, m1a, m2a, m3a } ), 0 );\n\tssaoRawPass.addInputSampled( *m3a, 1 );\n\tauto rsa = ssaoRawPass.addOutputColourTarget( rsv );\n\n\tauto bl = graph.createImage( test::createImage( \"b1\", crg::PixelFormat::eR32_SFLOAT ) );\n\tauto blv = graph.createView( test::createView( \"b1v\", bl, crg::PixelFormat::eR32_SFLOAT ) );\n\tauto & ssaoBlurPass = graph.createPass( \"ssaoBlurPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tssaoBlurPass.addInputSampled( *rsa, 0 );\n\tssaoBlurPass.addInputSampled( *m3a, 1 );\n\treturn ssaoBlurPass.addOutputColourTarget( blv );\n}\n\nTEST( RenderGraph, SsaoPass )\n{\n\ttestBegin( \"testSsaoPass\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto d = graph.createImage( test::createImage( \"d\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto dtv = graph.createView( test::createView( \"dtv\", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto ld = graph.createImage( test::createImage( \"ld\", crg::PixelFormat::eR32_SFLOAT ) );\n\tauto ldv = graph.createView( test::createView( \"ldv\", ld, crg::PixelFormat::eR32_SFLOAT ) );\n\tauto v = graph.createImage( test::createImage( \"v\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto vv = graph.createView( test::createView( \"vv\", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d1 = graph.createImage( test::createImage( \"d1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto d1v = graph.createView( test::createView( \"d1v\", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto d2 = graph.createImage( test::createImage( \"d2\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d2v = graph.createView( test::createView( \"d2v\", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d3 = graph.createImage( test::createImage( \"d3\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d3v = graph.createView( test::createView( \"d3v\", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d4 = graph.createImage( test::createImage( \"d4\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d4v = graph.createView( test::createView( \"d4v\", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto & geometryPass = graph.createPass( \"geometryPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto d1a = geometryPass.addOutputColourTarget( d1v );\n\tauto d2a = geometryPass.addOutputColourTarget( d2v );\n\tauto d3a = geometryPass.addOutputColourTarget( d3v );\n\tauto d4a = geometryPass.addOutputColourTarget( d4v );\n\tauto lda = geometryPass.addOutputColourTarget( ldv );\n\tgeometryPass.addOutputColourTarget( vv );\n\tgeometryPass.addOutputDepthStencilTarget( dtv );\n\n\tauto ssaoa = buildSsaoPass( testCounts\n\t\t, *lda\n\t\t, graph );\n\n\tauto of = graph.createImage( test::createImage( \"of\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto ofv = graph.createView( test::createView( \"ofv\", of, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & ambientPass = graph.createPass( \"ambientPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tambientPass.addInputSampled( *lda, 0 );\n\tambientPass.addInputSampled( *d1a, 1 );\n\tambientPass.addInputSampled( *d2a, 2 );\n\tambientPass.addInputSampled( *d3a, 3 );\n\tambientPass.addInputSampled( *d4a, 4 );\n\tambientPass.addInputSampled( *ssaoa, 5 );\n\tambientPass.addOutputColourTarget( ofv );\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref = R\"(digraph {\n  \"ambientPass\" [ shape=ellipse ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nambientPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nambientPass/d1v/Spl\" -> \"ambientPass\" [ label=\"d1v\" ];\n  \"Transition to\\nambientPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nambientPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nambientPass/d2v/Spl\" -> \"ambientPass\" [ label=\"d2v\" ];\n  \"Transition to\\nambientPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nambientPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nambientPass/d3v/Spl\" -> \"ambientPass\" [ label=\"d3v\" ];\n  \"Transition to\\nambientPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nambientPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nambientPass/d4v/Spl\" -> \"ambientPass\" [ label=\"d4v\" ];\n  \"ssaoBlurPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/b1v/Spl\" [ shape=box ];\n  \"ssaoBlurPass\" -> \"Transition to\\nambientPass/b1v/Spl\" [ label=\"b1v\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" -> \"ambientPass\" [ label=\"b1v\" ];\n  \"ssaoRawPass\" [ shape=ellipse ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" [ shape=box ];\n  \"ssaoRawPass\" -> \"Transition to\\nssaoBlurPass/rsv/Spl\" [ label=\"rsv\" ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" -> \"ssaoBlurPass\" [ label=\"rsv\" ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" [ shape=box ];\n  \"ssaoMinifyPass3\" -> \"Transition to\\nssaoRawPass/lp/Spl3\" [ label=\"m3v\" ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" -> \"ssaoRawPass\" [ label=\"m3v\" ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ssaoLinearisePass\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ssaoLinearisePass\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoLinearisePass/ldv/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nssaoLinearisePass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nssaoLinearisePass/ldv/Spl\" -> \"ssaoLinearisePass\" [ label=\"ldv\" ];\n}\n)\";\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, BloomPostEffect )\n{\n\ttestBegin( \"testBloomPostEffect\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto scene = graph.createImage( test::createImage( \"scene\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto scenev = graph.createView( test::createView( \"scenev\", scene, crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto scenea = crg::Attachment::createDefault( scenev );\n\tauto output = graph.createImage( test::createImage( \"output\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto outputv = graph.createView( test::createView( \"outputv\", output, crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto hi = graph.createImage( test::createImage( \"hi\", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) );\n\tauto hi0v = graph.createView( test::createView( \"hi0v\", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) );\n\tauto hi1v = graph.createView( test::createView( \"hi1v\", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) );\n\tauto hi2v = graph.createView( test::createView( \"hi2v\", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) );\n\tauto hi3v = graph.createView( test::createView( \"hi3v\", hi, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) );\n\tauto bl = graph.createImage( test::createImage( \"bl\", crg::PixelFormat::eR32G32B32A32_SFLOAT, 4u ) );\n\tauto bl0v = graph.createView( test::createView( \"bl0v\", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 0u ) );\n\tauto bl1v = graph.createView( test::createView( \"bl1v\", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 1u ) );\n\tauto bl2v = graph.createView( test::createView( \"bl2v\", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 2u ) );\n\tauto bl3v = graph.createView( test::createView( \"bl3v\", bl, crg::PixelFormat::eR32G32B32A32_SFLOAT, 3u ) );\n\n\tauto & hiPass = graph.createPass( \"hiPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\thiPass.addInputSampled( scenea, 0u );\n\tauto hia = hiPass.addOutputColourTarget( graph.mergeViews( { hi0v, hi1v, hi2v, hi3v } ) );\n\trequire( hia->source.size() == 4u );\n\n\tauto & blurPass0X = graph.createPass( \"blurPass0X\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass0X.addInputSampled( *hia->getSource( 0 ), 0u );\n\tauto bl0a = blurPass0X.addOutputColourTarget( bl0v );\n\tauto & blurPass0Y = graph.createPass( \"blurPass0Y\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass0Y.addInputSampled( *bl0a, 0u );\n\tauto hi0a = blurPass0Y.addOutputColourTarget( hi0v );\n\n\tauto & blurPass1X = graph.createPass( \"blurPass1X\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass1X.addInputSampled( *hia->getSource( 1 ), 0u );\n\tauto bl1a = blurPass1X.addOutputColourTarget( bl1v );\n\tauto & blurPass1Y = graph.createPass( \"blurPass1Y\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass1Y.addInputSampled( *bl1a, 0u );\n\tauto hi1a = blurPass1Y.addOutputColourTarget( hi1v );\n\n\tauto & blurPass2X = graph.createPass( \"blurPass2X\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass2X.addInputSampled( *hia->getSource( 2 ), 0u );\n\tauto bl2a = blurPass2X.addOutputColourTarget( bl2v );\n\tauto & blurPass2Y = graph.createPass( \"blurPass2Y\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass2Y.addInputSampled( *bl2a, 0u );\n\tauto hi2a = blurPass2Y.addOutputColourTarget( hi2v );\n\n\tauto & blurPass3X = graph.createPass( \"blurPass3X\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass3X.addInputSampled( *hia->getSource( 3 ), 0u );\n\tauto bl3a = blurPass3X.addOutputColourTarget( bl3v );\n\tauto & blurPass3Y = graph.createPass( \"blurPass3Y\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tblurPass3Y.addInputSampled( *bl3a, 0u );\n\tauto hi3a = blurPass3Y.addOutputColourTarget( hi3v );\n\n\tauto & combinePass = graph.createPass( \"combinePass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tcombinePass.addInputSampled( scenea, 0u );\n\tcombinePass.addInputSampled( *graph.mergeAttachments( { hi0a, hi1a, hi2a, hi3a } ), 1u );\n\tcombinePass.addOutputColourTarget( outputv );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\ntemplate< bool EnableSsao >\ncrg::Attachment const * buildDeferred( test::TestCounts & testCounts\n\t, crg::Attachment const *& lda\n\t, crg::Attachment const *& dta\n\t, crg::ImageViewId const & ldv\n\t, crg::ImageViewId const & dtv\n\t, crg::ImageViewId const & vtv\n\t, crg::FrameGraph & graph )\n{\n\tauto d1 = graph.createImage( test::createImage( \"d1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto d1v = graph.createView( test::createView( \"d1v\", d1, crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\tauto d2 = graph.createImage( test::createImage( \"d2\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d2v = graph.createView( test::createView( \"d2v\", d2, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d3 = graph.createImage( test::createImage( \"d3\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d3v = graph.createView( test::createView( \"d3v\", d3, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d4 = graph.createImage( test::createImage( \"d4\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto d4v = graph.createView( test::createView( \"d4v\", d4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto & geometryPass = graph.createPass( \"geometryPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\n\tauto d1a = geometryPass.addOutputColourTarget( d1v );\n\tauto d2a = geometryPass.addOutputColourTarget( d2v );\n\tauto d3a = geometryPass.addOutputColourTarget( d3v );\n\tauto d4a = geometryPass.addOutputColourTarget( d4v );\n\tif ( !lda )\n\t\tlda = geometryPass.addOutputColourTarget( ldv );\n\tgeometryPass.addOutputColourTarget( vtv );\n\tif ( dta )\n\t\tgeometryPass.addInputDepthStencilTarget( *dta );\n\telse\n\t\tdta = geometryPass.addOutputDepthStencilTarget( dtv );\n\n\tauto df = graph.createImage( test::createImage( \"df\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto dfv = graph.createView( test::createView( \"dfv\", df, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto sp = graph.createImage( test::createImage( \"sp\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto spv = graph.createView( test::createView( \"spv\", sp, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & lightingPass = graph.createPass( \"lightingPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tlightingPass.addInputSampled( *lda, 0 );\n\tlightingPass.addInputSampled( *d1a, 1 );\n\tlightingPass.addInputSampled( *d2a, 2 );\n\tlightingPass.addInputSampled( *d3a, 3 );\n\tlightingPass.addInputSampled( *d4a, 4 );\n\tauto dfa = lightingPass.addOutputColourTarget( dfv );\n\tauto spa = lightingPass.addOutputColourTarget( spv );\n\n\tauto of = graph.createImage( test::createImage( \"of\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto ofv = graph.createView( test::createView( \"ofv\", of, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\n\tif constexpr ( EnableSsao )\n\t{\n\t\tauto ssaoa = buildSsaoPass( testCounts\n\t\t\t, *lda\n\t\t\t, graph );\n\t\tauto & ambientPass = graph.createPass( \"ambientPass\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tambientPass.addInputSampled( *lda, 0 );\n\t\tambientPass.addInputSampled( *d1a, 1 );\n\t\tambientPass.addInputSampled( *d2a, 2 );\n\t\tambientPass.addInputSampled( *d3a, 3 );\n\t\tambientPass.addInputSampled( *d4a, 4 );\n\t\tambientPass.addInputSampled( *dfa, 5 );\n\t\tambientPass.addInputSampled( *spa, 6 );\n\t\tambientPass.addInputSampled( *ssaoa, 7 );\n\t\treturn ambientPass.addOutputColourTarget( ofv );\n\t}\n\telse\n\t{\n\t\tauto & ambientPass = graph.createPass( \"ambientPass\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tambientPass.addInputSampled( *lda, 0 );\n\t\tambientPass.addInputSampled( *d1a, 1 );\n\t\tambientPass.addInputSampled( *d2a, 2 );\n\t\tambientPass.addInputSampled( *d3a, 3 );\n\t\tambientPass.addInputSampled( *d4a, 4 );\n\t\tambientPass.addInputSampled( *dfa, 5 );\n\t\tambientPass.addInputSampled( *spa, 6 );\n\t\treturn ambientPass.addOutputColourTarget( ofv );\n\t}\n}\n\ncrg::Attachment const * buildWeightedBlended( test::TestCounts & testCounts\n\t, crg::Attachment const *& dta\n\t, crg::Attachment const * lda\n\t, crg::ImageViewId const & dtv\n\t, crg::FrameGraph & graph )\n{\n\tauto a = graph.createImage( test::createImage( \"a\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto av = graph.createView( test::createView( \"av\", a, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto r = graph.createImage( test::createImage( \"r\", crg::PixelFormat::eR16_SFLOAT ) );\n\tauto rv = graph.createView( test::createView( \"rv\", r, crg::PixelFormat::eR16_SFLOAT ) );\n\tauto & accumulationPass = graph.createPass( \"accumulationPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto aa = accumulationPass.addOutputColourTarget( av );\n\tauto ra = accumulationPass.addOutputColourTarget( rv );\n\tif ( dta )\n\t\taccumulationPass.addInputDepthStencilTarget( *dta );\n\telse\n\t\tdta = accumulationPass.addOutputDepthStencilTarget( dtv );\n\n\tauto c = graph.createImage( test::createImage( \"c\", crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto cv = graph.createView( test::createView( \"cv\", c, crg::PixelFormat::eR32G32B32_SFLOAT ) );\n\tauto & combinePass = graph.createPass( \"combinePass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tif ( lda )\n\t\tcombinePass.addInputSampled( *lda, 0u );\n\tcombinePass.addInputSampled( *aa, 1u );\n\tcombinePass.addInputSampled( *ra, 2u );\n\treturn combinePass.addOutputColourTarget( cv );\n}\n\ntemplate< bool EnableDepthPrepass\n\t, bool EnableOpaque\n\t, bool EnableSsao\n\t, bool EnableTransparent >\nstruct ParamsT\n{\n\tstatic constexpr bool EnableDepthPrepassT = EnableDepthPrepass;\n\tstatic constexpr bool EnableOpaqueT = EnableOpaque;\n\tstatic constexpr bool EnableSsaoT = EnableSsao;\n\tstatic constexpr bool EnableTransparentT = EnableTransparent;\n};\n\nusing ParamTypes = testing::Types< ParamsT< false, false, false, false >\n\t, ParamsT< false, false, false, true >\n\t, ParamsT< false, true, false, false >\n\t, ParamsT< false, true, false, true >\n\t, ParamsT< false, true, true, false >\n\t, ParamsT< false, true, true, true >\n\t, ParamsT< true, false, false, false >\n\t, ParamsT< true, false, false, true >\n\t, ParamsT< true, true, false, false >\n\t, ParamsT< true, true, false, true >\n\t, ParamsT< true, true, true, false >\n\t, ParamsT< true, true, true, true > >;\n\nclass ParamTypeNames\n{\npublic:\n\ttemplate< typename T >\n\tstatic std::string GetName( int )\n\t{\n\t\tstatic constexpr bool EnableDepthPrepass = T::EnableDepthPrepassT;\n\t\tstatic constexpr bool EnableOpaque = T::EnableOpaqueT;\n\t\tstatic constexpr bool EnableSsao = T::EnableSsaoT;\n\t\tstatic constexpr bool EnableTransparent = T::EnableTransparentT;\n\t\treturn ( EnableDepthPrepass ? std::string{ \"Prepass\" } : std::string{} )\n\t\t\t+ ( EnableOpaque ? std::string{ \"Opaque\" } : std::string{} )\n\t\t\t+ ( EnableSsao ? std::string{ \"Ssao\" } : std::string{} )\n\t\t\t+ ( EnableTransparent ? std::string{ \"Transparent\" } : std::string{} );\n\t}\n};\n\ntemplate< typename ParamT >\nstruct RenderGraphT : public ::testing::Test\n{\n};\n\nTYPED_TEST_SUITE( RenderGraphT, ParamTypes, ParamTypeNames );\n\nTYPED_TEST( RenderGraphT, Render )\n{\n\tstatic constexpr bool EnableDepthPrepass = TypeParam::EnableDepthPrepassT;\n\tstatic constexpr bool EnableOpaque = TypeParam::EnableOpaqueT;\n\tstatic constexpr bool EnableSsao = TypeParam::EnableSsaoT;\n\tstatic constexpr bool EnableTransparent = TypeParam::EnableTransparentT;\n\ttestBegin( \"testRender\"\n\t\t+ ( EnableDepthPrepass ? std::string{ \"Prepass\" } : std::string{} )\n\t\t+ ( EnableOpaque ? std::string{ \"Opaque\" } : std::string{} )\n\t\t+ ( EnableSsao ? std::string{ \"Ssao\" } : std::string{} )\n\t\t+ ( EnableTransparent ? std::string{ \"Transparent\" } : std::string{} ) )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto d = graph.createImage( test::createImage( \"d\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto dtv = graph.createView( test::createView( \"dtv\", d, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto ld = graph.createImage( test::createImage( \"ld\", crg::PixelFormat::eR32_SFLOAT ) );\n\tauto ldv = graph.createView( test::createView( \"ldv\", ld, crg::PixelFormat::eR32_SFLOAT ) );\n\tcrg::Attachment const * dta{};\n\tcrg::Attachment const * lda{};\n\n\tif constexpr ( EnableDepthPrepass )\n\t{\n\t\tauto & depthPrepass = graph.createPass( \"depthPrepass\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tlda = depthPrepass.addOutputColourTarget ( ldv );\n\t\tdta = depthPrepass.addOutputDepthTarget ( dtv );\n\t}\n\n\tauto o = graph.createImage( test::createImage( \"o\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto otv = graph.createView( test::createView( \"otv\", o, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\n\tif constexpr ( EnableOpaque )\n\t{\n\t\tauto v = graph.createImage( test::createImage( \"v\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto vv = graph.createView( test::createView( \"vv\", v, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto dca = buildDeferred< EnableSsao >( testCounts\n\t\t\t, lda\n\t\t\t, dta\n\t\t\t, ldv\n\t\t\t, dtv\n\t\t\t, vv\n\t\t\t, graph );\n\n\t\tif constexpr ( EnableTransparent )\n\t\t{\n\t\t\tauto wbcsa = buildWeightedBlended( testCounts\n\t\t\t\t, dta\n\t\t\t\t, lda\n\t\t\t\t, dtv\n\t\t\t\t, graph );\n\t\t\tauto & finalCombinePass = graph.createPass( \"finalCombinePass\"\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t\t} );\n\t\t\tfinalCombinePass.addInputSampled( *lda, 0 );\n\t\t\tfinalCombinePass.addInputSampled( *dca, 1 );\n\t\t\tfinalCombinePass.addInputSampled( *wbcsa, 2 );\n\t\t\tfinalCombinePass.addOutputColourTarget( otv );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto & finalCombinePass = graph.createPass( \"finalCombinePass\"\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t\t} );\n\t\t\tfinalCombinePass.addInputSampled( *lda, 0 );\n\t\t\tfinalCombinePass.addInputSampled( *dca, 1 );\n\t\t\tfinalCombinePass.addOutputColourTarget( otv );\n\t\t}\n\t\t\t\n\t}\n\telse if constexpr ( EnableTransparent )\n\t{\n\t\tauto wba = buildWeightedBlended( testCounts\n\t\t\t, dta\n\t\t\t, lda\n\t\t\t, dtv\n\t\t\t, graph );\n\t\tauto & finalCombinePass = graph.createPass( \"finalCombinePass\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tif ( lda )\n\t\t\tfinalCombinePass.addInputSampled( *lda, 0 );\n\t\tfinalCombinePass.addInputSampled( *wba, 1 );\n\t\tfinalCombinePass.addOutputColourTarget( otv );\n\t}\n\telse\n\t{\n\t\tauto & finalCombinePass = graph.createPass( \"finalCombinePass\"\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tif ( lda )\n\t\t\tfinalCombinePass.addInputSampled( *lda, 0 );\n\t\tfinalCombinePass.addOutputColourTarget( otv );\n\t}\n\n\tauto runnable = graph.compile( getContext() );\n\tauto stream = test::checkRunnable( testCounts, runnable );\n\tstd::string ref;\n\n\tif constexpr ( EnableDepthPrepass )\n\t{\n\t\tif constexpr ( EnableOpaque )\n\t\t{\n\t\t\tif constexpr ( EnableSsao )\n\t\t\t{\n\t\t\t\tif constexpr ( EnableTransparent )\n\t\t\t\t{\n\t\t\t\t\tref = R\"(digraph {\n  \"depthPrepass\" [ shape=ellipse ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\ngeometryPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" -> \"geometryPass\" [ label=\"dtv\" ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"combinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"ssaoBlurPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" [ shape=box ];\n  \"ssaoBlurPass\" -> \"Transition to\\nambientPass/b1v/Spl\" [ label=\"b1v\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" -> \"ambientPass\" [ label=\"b1v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"ssaoRawPass\" [ shape=ellipse ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" [ shape=box ];\n  \"ssaoRawPass\" -> \"Transition to\\nssaoBlurPass/rsv/Spl\" [ label=\"rsv\" ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" -> \"ssaoBlurPass\" [ label=\"rsv\" ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" [ shape=box ];\n  \"ssaoMinifyPass3\" -> \"Transition to\\nssaoRawPass/lp/Spl3\" [ label=\"m3v\" ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" -> \"ssaoRawPass\" [ label=\"m3v\" ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ssaoLinearisePass\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ssaoLinearisePass\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n}\n)\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tref = R\"(digraph {\n  \"depthPrepass\" [ shape=ellipse ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\ngeometryPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" -> \"geometryPass\" [ label=\"dtv\" ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"ssaoBlurPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" [ shape=box ];\n  \"ssaoBlurPass\" -> \"Transition to\\nambientPass/b1v/Spl\" [ label=\"b1v\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" -> \"ambientPass\" [ label=\"b1v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"ssaoRawPass\" [ shape=ellipse ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" [ shape=box ];\n  \"ssaoRawPass\" -> \"Transition to\\nssaoBlurPass/rsv/Spl\" [ label=\"rsv\" ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" -> \"ssaoBlurPass\" [ label=\"rsv\" ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" [ shape=box ];\n  \"ssaoMinifyPass3\" -> \"Transition to\\nssaoRawPass/lp/Spl3\" [ label=\"m3v\" ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" -> \"ssaoRawPass\" [ label=\"m3v\" ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ssaoLinearisePass\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ssaoLinearisePass\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n}\n)\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr ( EnableTransparent )\n\t\t\t{\n\t\t\t\tref = R\"(digraph {\n  \"depthPrepass\" [ shape=ellipse ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\ngeometryPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" -> \"geometryPass\" [ label=\"dtv\" ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"combinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n}\n)\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tref = R\"(digraph {\n  \"depthPrepass\" [ shape=ellipse ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\ngeometryPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\ngeometryPass/dtv/IRds\" -> \"geometryPass\" [ label=\"dtv\" ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n}\n)\";\n\t\t\t}\n\t\t}\n\t\telse if constexpr ( EnableTransparent )\n\t\t{\n\t\t\tref = R\"(digraph {\n  \"combinePass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n  \"depthPrepass\" [ shape=ellipse ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"Transition to\\ncombinePass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\ncombinePass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\ncombinePass/ldv/Spl\" -> \"combinePass\" [ label=\"ldv\" ];\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" [ shape=box ];\n  \"depthPrepass\" -> \"Transition to\\naccumulationPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" -> \"accumulationPass\" [ label=\"dtv\" ];\n}\n)\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tref = R\"(digraph {\n  \"Transition to\\nfinalCombinePass/ldv/Spl\" [ shape=box ];\n  \"depthPrepass\" [ shape=ellipse ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"depthPrepass\" -> \"Transition to\\nfinalCombinePass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nfinalCombinePass/ldv/Spl\" -> \"finalCombinePass\" [ label=\"ldv\" ];\n}\n)\";\n\t\t}\n\t}\n\telse\n\t{\n\t\tif constexpr ( EnableOpaque )\n\t\t{\n\t\t\tif constexpr ( EnableSsao )\n\t\t\t{\n\t\t\t\tif constexpr ( EnableTransparent )\n\t\t\t\t{\n\t\t\t\t\tref = R\"(digraph {\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"ssaoBlurPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/b1v/Spl\" [ shape=box ];\n  \"ssaoBlurPass\" -> \"Transition to\\nambientPass/b1v/Spl\" [ label=\"b1v\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" -> \"ambientPass\" [ label=\"b1v\" ];\n  \"ssaoRawPass\" [ shape=ellipse ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" [ shape=box ];\n  \"ssaoRawPass\" -> \"Transition to\\nssaoBlurPass/rsv/Spl\" [ label=\"rsv\" ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" -> \"ssaoBlurPass\" [ label=\"rsv\" ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" [ shape=box ];\n  \"ssaoMinifyPass3\" -> \"Transition to\\nssaoRawPass/lp/Spl3\" [ label=\"m3v\" ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" -> \"ssaoRawPass\" [ label=\"m3v\" ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ssaoLinearisePass\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ssaoLinearisePass\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n  \"combinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\naccumulationPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" -> \"accumulationPass\" [ label=\"dtv\" ];\n}\n)\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tref = R\"(digraph {\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"ssaoBlurPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/b1v/Spl\" [ shape=box ];\n  \"ssaoBlurPass\" -> \"Transition to\\nambientPass/b1v/Spl\" [ label=\"b1v\" ];\n  \"Transition to\\nambientPass/b1v/Spl\" -> \"ambientPass\" [ label=\"b1v\" ];\n  \"ssaoRawPass\" [ shape=ellipse ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" [ shape=box ];\n  \"ssaoRawPass\" -> \"Transition to\\nssaoBlurPass/rsv/Spl\" [ label=\"rsv\" ];\n  \"Transition to\\nssaoBlurPass/rsv/Spl\" -> \"ssaoBlurPass\" [ label=\"rsv\" ];\n  \"ssaoMinifyPass3\" [ shape=ellipse ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" [ shape=box ];\n  \"ssaoMinifyPass3\" -> \"Transition to\\nssaoRawPass/lp/Spl3\" [ label=\"m3v\" ];\n  \"Transition to\\nssaoRawPass/lp/Spl3\" -> \"ssaoRawPass\" [ label=\"m3v\" ];\n  \"ssaoMinifyPass2\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass2\" -> \"Transition to\\nssaoMinifyPass3/m2v/Spl\" [ label=\"m2v\" ];\n  \"Transition to\\nssaoMinifyPass3/m2v/Spl\" -> \"ssaoMinifyPass3\" [ label=\"m2v\" ];\n  \"ssaoMinifyPass1\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ shape=box ];\n  \"ssaoMinifyPass1\" -> \"Transition to\\nssaoMinifyPass2/m1v/Spl\" [ label=\"m1v\" ];\n  \"Transition to\\nssaoMinifyPass2/m1v/Spl\" -> \"ssaoMinifyPass2\" [ label=\"m1v\" ];\n  \"ssaoLinearisePass\" [ shape=ellipse ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ shape=box ];\n  \"ssaoLinearisePass\" -> \"Transition to\\nssaoMinifyPass1/m0v/Spl\" [ label=\"m0v\" ];\n  \"Transition to\\nssaoMinifyPass1/m0v/Spl\" -> \"ssaoMinifyPass1\" [ label=\"m0v\" ];\n}\n)\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if constexpr ( EnableTransparent )\n\t\t\t{\n\t\t\t\tref = R\"(digraph {\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"combinePass\" [ shape=ellipse ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\naccumulationPass/dtv/IRds\" [ label=\"dtv\" ];\n  \"Transition to\\naccumulationPass/dtv/IRds\" -> \"accumulationPass\" [ label=\"dtv\" ];\n}\n)\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tref = R\"(digraph {\n  \"Transition to\\nlightingPass/d1v/Spl\" [ shape=box ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"lightingPass\" [ shape=ellipse ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d1v/Spl\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d1v/Spl\" -> \"lightingPass\" [ label=\"d1v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d2v/Spl\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d2v/Spl\" -> \"lightingPass\" [ label=\"d2v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" [ shape=box ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d3v/Spl\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d3v/Spl\" -> \"lightingPass\" [ label=\"d3v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" [ shape=box ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/d4v/Spl\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/d4v/Spl\" -> \"lightingPass\" [ label=\"d4v\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" [ shape=box ];\n  \"geometryPass\" [ shape=ellipse ];\n  \"geometryPass\" -> \"Transition to\\nlightingPass/ldv/Spl\" [ label=\"ldv\" ];\n  \"Transition to\\nlightingPass/ldv/Spl\" -> \"lightingPass\" [ label=\"ldv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" [ shape=box ];\n  \"ambientPass\" [ shape=ellipse ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/dfv/Spl\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/dfv/Spl\" -> \"ambientPass\" [ label=\"dfv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" [ shape=box ];\n  \"lightingPass\" -> \"Transition to\\nambientPass/spv/Spl\" [ label=\"spv\" ];\n  \"Transition to\\nambientPass/spv/Spl\" -> \"ambientPass\" [ label=\"spv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" [ shape=box ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"ambientPass\" -> \"Transition to\\nfinalCombinePass/ofv/Spl\" [ label=\"ofv\" ];\n  \"Transition to\\nfinalCombinePass/ofv/Spl\" -> \"finalCombinePass\" [ label=\"ofv\" ];\n  \"geometryPass\" [ shape=ellipse ];\n}\n)\";\n\t\t\t}\n\t\t}\n\t\telse if constexpr ( EnableTransparent )\n\t\t{\n\t\t\tref = R\"(digraph {\n  \"Transition to\\ncombinePass/av/Spl\" [ shape=box ];\n  \"accumulationPass\" [ shape=ellipse ];\n  \"combinePass\" [ shape=ellipse ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/av/Spl\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/av/Spl\" -> \"combinePass\" [ label=\"av\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" [ shape=box ];\n  \"accumulationPass\" -> \"Transition to\\ncombinePass/rv/Spl\" [ label=\"rv\" ];\n  \"Transition to\\ncombinePass/rv/Spl\" -> \"combinePass\" [ label=\"rv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" [ shape=box ];\n  \"finalCombinePass\" [ shape=ellipse ];\n  \"combinePass\" -> \"Transition to\\nfinalCombinePass/cv/Spl\" [ label=\"cv\" ];\n  \"Transition to\\nfinalCombinePass/cv/Spl\" -> \"finalCombinePass\" [ label=\"cv\" ];\n}\n)\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tref = R\"(digraph {\n}\n)\";\n\t\t}\n\t}\n\n\tcheckEqualSortedLines( stream, ref )\n\ttestEnd()\n}\n\nTEST( RenderGraph, VarianceShadowMap )\n{\n\ttestBegin( \"testVarianceShadowMap\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\n\tauto & dirGroup = graph.createPassGroup( \"Directional\" );\n\tauto dirShadowMap = dirGroup.createImage( test::createImage( \"dirShadowMap\", crg::PixelFormat::eX8_D24_UNORM, 1u, 4u ) );\n\tauto dirVarianceMap = dirGroup.createImage( test::createImage( \"dirVarianceMap\", crg::PixelFormat::eR32G32_SFLOAT, 1u, 4u ) );\n\tauto buffer = dirGroup.createBuffer( test::createBuffer( \"buffer\" ) );\n\tauto bufferv = dirGroup.createView( test::createView( \"bufferv\", buffer ) );\n\tcrg::AttachmentArray dirShadows;\n\tcrg::AttachmentArray dirVariances;\n\t{\n\t\tauto intermediate = dirGroup.createImage( test::createImage( \"dirIntermediate\", crg::PixelFormat::eR32G32_SFLOAT ) );\n\t\tauto intermediatev = dirGroup.createView( test::createView( \"dirIntermediatev\", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) );\n\n\t\tfor ( uint32_t index = 0u; index < 4u; ++index )\n\t\t{\n\t\t\tauto shadowMapv = dirGroup.createView( test::createView( \"dirShadowMapv\" + std::to_string( index ), dirShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) );\n\t\t\tauto varianceMapv = dirGroup.createView( test::createView( \"dirVarianceMapv\" + std::to_string( index ), dirVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) );\n\t\t\tauto & shadowPass = dirGroup.createPass( \"dirShadowPass\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t\t} );\n\t\t\tauto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u );\n\t\t\tauto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv );\n\t\t\tauto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv );\n\t\t\tdirShadows.push_back( shadowMapa );\n\n\t\t\tauto & blurPassX = dirGroup.createPass( \"dirBlurPassX\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassX.addInputStorage( *buffera, 0u );\n\t\t\tblurPassX.addInputSampled( *varianceMapa, 1u );\n\t\t\tauto intermediatea = blurPassX.addOutputColourTarget( intermediatev );\n\n\t\t\tauto & blurPassY = dirGroup.createPass( \"dirBlurPassY\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassY.addInputStorage( *buffera, 0u );\n\t\t\tblurPassY.addInputSampled( *intermediatea, 1u );\n\t\t\tvarianceMapa = blurPassY.addOutputColourTarget( varianceMapv );\n\t\t\tdirGroup.addGroupOutput( varianceMapv );\n\t\t\tdirVariances.push_back( varianceMapa );\n\t\t}\n\t}\n\tauto & pntGroup = graph.createPassGroup( \"Point\" );\n\tauto pntShadowMap = pntGroup.createImage( test::createImage( \"pntShadowMap\", crg::PixelFormat::eX8_D24_UNORM, 1u, 36u ) );\n\tauto pntVarianceMap = pntGroup.createImage( test::createImage( \"pntVarianceMap\", crg::PixelFormat::eR32G32_SFLOAT, 1u, 36u ) );\n\tcrg::AttachmentArray pntShadows;\n\tcrg::AttachmentArray pntVariances;\n\t{\n\t\tauto intermediate = pntGroup.createImage( test::createImage( \"pntIntermediate\", crg::PixelFormat::eR32G32_SFLOAT ) );\n\t\tauto intermediatev = pntGroup.createView( test::createView( \"pntIntermediatev\", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) );\n\n\t\tfor ( uint32_t index = 0u; index < 36u; ++index )\n\t\t{\n\t\t\tauto shadowMapv = pntGroup.createView( test::createView( \"pntShadowMapv\" + std::to_string( index ), pntShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) );\n\t\t\tauto varianceMapv = pntGroup.createView( test::createView( \"pntVarianceMapv\" + std::to_string( index ), pntVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) );\n\t\t\tauto & shadowPass = pntGroup.createPass( \"pntShadowPass\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t\t} );\n\t\t\tauto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u );\n\t\t\tauto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv );\n\t\t\tauto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv );\n\t\t\tpntShadows.push_back( shadowMapa );\n\n\t\t\tauto & blurPassX = pntGroup.createPass( \"pntBlurPassX\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassX.addInputStorage( *buffera, 0u );\n\t\t\tblurPassX.addInputSampled( *varianceMapa, 1u );\n\t\t\tauto intermediatea = blurPassX.addOutputColourTarget( intermediatev );\n\n\t\t\tauto & blurPassY = pntGroup.createPass( \"pntBlurPassY\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassY.addInputStorage( *buffera, 0u );\n\t\t\tblurPassY.addInputSampled( *intermediatea, 1u );\n\t\t\tvarianceMapa = blurPassY.addOutputColourTarget( varianceMapv );\n\t\t\tpntVariances.push_back( varianceMapa );\n\t\t\tpntGroup.addGroupOutput( varianceMapv );\n\t\t}\n\t}\n\tauto & sptGroup = graph.createPassGroup( \"Spot\" );\n\tauto sptShadowMap = sptGroup.createImage( test::createImage( \"sptShadowMap\", crg::PixelFormat::eX8_D24_UNORM, 1u, 10u ) );\n\tauto sptVarianceMap = sptGroup.createImage( test::createImage( \"pntVarianceMap\", crg::PixelFormat::eR32G32_SFLOAT, 1u, 10u ) );\n\tcrg::AttachmentArray sptShadows;\n\tcrg::AttachmentArray sptVariances;\n\t{\n\t\tauto intermediate = sptGroup.createImage( test::createImage( \"sptIntermediate\", crg::PixelFormat::eR32G32_SFLOAT ) );\n\t\tauto intermediatev = sptGroup.createView( test::createView( \"sptIntermediatev\", intermediate, crg::PixelFormat::eR32G32_SFLOAT ) );\n\n\t\tfor ( uint32_t index = 0u; index < 10u; ++index )\n\t\t{\n\t\t\tauto shadowMapv = sptGroup.createView( test::createView( \"sptShadowMapv\" + std::to_string( index ), sptShadowMap, crg::PixelFormat::eX8_D24_UNORM, 0u, 1u, index ) );\n\t\t\tauto varianceMapv = sptGroup.createView( test::createView( \"sptVarianceMapv\" + std::to_string( index ), sptVarianceMap, crg::PixelFormat::eR32G32_SFLOAT, 0u, 1u, index ) );\n\t\t\tauto & shadowPass = sptGroup.createPass( \"sptShadowPass\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkTargetColourIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tauto buffera = shadowPass.addClearableOutputStorageBuffer( bufferv, 0u );\n\t\t\tauto shadowMapa = shadowPass.addOutputDepthTarget( shadowMapv );\n\t\t\tauto varianceMapa = shadowPass.addOutputColourTarget( varianceMapv );\n\t\t\tsptShadows.push_back( shadowMapa );\n\n\t\t\tauto & blurPassX = sptGroup.createPass( \"sptBlurPassX\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassX.addInputStorage( *buffera, 0u );\n\t\t\tblurPassX.addInputSampled( *varianceMapa, 1u );\n\t\t\tauto intermediatea = blurPassX.addOutputColourTarget( intermediatev );\n\n\t\t\tauto & blurPassY = sptGroup.createPass( \"sptBlurPassY\" + std::to_string( index )\n\t\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t\t\t} );\n\t\t\tblurPassY.addInputStorage( *buffera, 0u );\n\t\t\tblurPassY.addInputSampled( *intermediatea, 1u );\n\t\t\tvarianceMapa = blurPassY.addOutputColourTarget( varianceMapv );\n\t\t\tsptVariances.push_back( varianceMapa );\n\t\t\tsptGroup.addGroupOutput( varianceMapv );\n\t\t}\n\t}\n\n\tauto & objGroup = graph.createPassGroup( \"Objects\" );\n\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto depthv = graph.createView( test::createView( \"depthv\", depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\tauto & depthPrepass = graph.createPass( \"depthPrepass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tauto deptha = depthPrepass.addOutputDepthTarget ( depthv );\n\n\tauto colour = graph.createImage( test::createImage( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto colourv = graph.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\tauto & backgroundPass = graph.createPass( \"backgroundPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\tbackgroundPass.addInputDepthTarget( *deptha );\n\tauto coloura = backgroundPass.addOutputColourTarget( colourv );\n\tobjGroup.addOutput( colourv\n\t\t, crg::makeLayoutState( crg::ImageLayout::eShaderReadOnly ) );\n\n\tauto & opaquePass = objGroup.createPass( \"opaquePass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t, checkSampledIsShaderReadOnly );\n\t\t} );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( dirShadows ), 0u );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( dirVariances ), 1u );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( pntShadows ), 2u );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( pntVariances ), 3u );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( sptShadows ), 4u );\n\topaquePass.addInputSampled( *objGroup.mergeAttachments( sptVariances ), 5u );\n\topaquePass.addInputDepthTarget( *deptha );\n\tcoloura = opaquePass.addInOutColourTarget( *coloura );\n\n\tauto & transparentPass = objGroup.createPass( \"transparentPass\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t} );\n\ttransparentPass.addInputDepthTarget( *deptha );\n\ttransparentPass.addInOutColourTarget( *coloura );\n\n\tcrg::ResourcesCache cache{ handler };\n\tauto & context = getContext();\n\tVkDeviceMemory bufferMemory;\n\tcache.createBuffer( context, buffer, bufferMemory );\n\tcache.createBufferView( context, bufferv );\n\tVkDeviceMemory imageMemory;\n\tcache.createImage( context, depth, imageMemory );\n\tcache.createImageView( context, depthv );\n\n\thandler.createBuffer( context, buffer );\n\thandler.createBufferView( context, bufferv );\n\n\tauto runnable = graph.compile( context );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\nTEST( RenderGraph, EnvironmentMap )\n{\n\ttestBegin( \"testEnvironmentMap\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) );\n\tauto cube = graph.createImage( test::createImageCube( \"cube\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) );\n\tauto cubev = graph.createView( test::createView( \"cubev\", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) );\n\tauto cubes = graph.createImage( test::createImageCube( \"cubes\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) );\n\tauto cubesv = graph.createView( test::createView( \"cubesv\", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) );\n\tauto colour = graph.createImage( test::createImage1D( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) );\n\tauto colourv = graph.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) );\n\tcrg::AttachmentArray colourViews;\n\tcrg::AttachmentArray cubeViews;\n\tcrg::AttachmentArray cubesViews;\n\n\tfor ( auto index = 0u; index < 6u; ++index )\n\t{\n\t\tauto strIndex = std::to_string( index );\n\t\tauto colourvn = graph.createView( test::createView( \"colourv\" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) );\n\t\tauto cubevn = graph.createView( test::createView( \"cubev\" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) );\n\t\tauto cubesvn = graph.createView( test::createView( \"cubesv\" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) );\n\t\tauto depthvn = graph.createView( test::createView( \"depthv\" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) );\n\t\tauto & opaquePass = graph.createPass( \"EnvOpaquePass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tauto depthan = opaquePass.addOutputDepthTarget( depthvn );\n\t\tauto colouran = opaquePass.addOutputColourTarget( colourvn );\n\t\tauto cubean = opaquePass.addOutputColourTarget( cubevn );\n\t\tauto cubesan = opaquePass.addOutputColourTarget( cubesvn );\n\n\t\tauto & backgroundPass = graph.createPass( \"EnvBackgroundPass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tbackgroundPass.addInputDepthTarget( *depthan );\n\t\tcolouran = backgroundPass.addInOutColourTarget( *colouran );\n\t\tcubean = backgroundPass.addInOutColourTarget( *cubean );\n\t\tcubesan = backgroundPass.addInOutColourTarget( *cubesan );\n\n\t\tauto & transparentPass = graph.createPass( \"EnvTransparentPass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\ttransparentPass.addInputDepthTarget( *depthan );\n\t\tcolourViews.push_back( transparentPass.addInOutColourTarget( *colouran ) );\n\t\tcubeViews.push_back( transparentPass.addInOutColourTarget( *cubean ) );\n\t\tcubesViews.push_back( transparentPass.addInOutColourTarget( *cubesan ) );\n\t}\n\n\tauto & mipsGen = graph.createPass( \"EnvMips\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eTransfer );\n\t\t} );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( colourViews ) );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( cubeViews ) );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( cubesViews ) );\n\tauto attach = mipsGen.addOutputTransferImage( colourv );\n\tmipsGen.addOutputTransferImage( cubev );\n\tmipsGen.addOutputTransferImage( cubesv );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\n\trunnable->getDescriptorWriteT( *attach, crg::SamplerDesc{}, 0u, 0u );\n\n\ttestEnd()\n}\n\nTEST( RenderGraph, DisabledPasses )\n{\n\ttestBegin( \"testDisabledPasses\" )\n\tcrg::ResourceHandler handler;\n\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT_S8_UINT, 1u, 6u ) );\n\tauto cube = graph.createImage( test::createImageCube( \"cube\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 1u ) );\n\tauto cubev = graph.createView( test::createView( \"cubev\", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 6u ) );\n\tauto cubes = graph.createImage( test::createImageCube( \"cubes\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) );\n\tauto cubesv = graph.createView( test::createView( \"cubesv\", cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0, 8u, 0u, 36u ) );\n\tauto colour = graph.createImage( test::createImage1D( \"colour\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 8u, 6u ) );\n\tauto colourv = graph.createView( test::createView( \"colourv\", colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 8u, 0u, 6u ) );\n\tcrg::AttachmentArray colourViews;\n\tcrg::AttachmentArray cubeViews;\n\tcrg::AttachmentArray cubesViews;\n\n\tfor ( auto index = 0u; index < 6u; ++index )\n\t{\n\t\tauto strIndex = std::to_string( index );\n\t\tauto colourvn = graph.createView( test::createView( \"colourv\" + strIndex, colour, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) );\n\t\tauto cubevn = graph.createView( test::createView( \"cubev\" + strIndex, cube, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index, 1u ) );\n\t\tauto cubesvn = graph.createView( test::createView( \"cubesv\" + strIndex, cubes, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, index * 6u, 6u ) );\n\t\tauto depthvn = graph.createView( test::createView( \"depthv\" + strIndex, depth, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, index, 1u ) );\n\t\tauto & opaquePass = graph.createPass( \"EnvOpaquePass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader );\n\t\t\t} );\n\t\tauto depthan = opaquePass.addOutputDepthTarget( depthvn );\n\t\tauto colouran = opaquePass.addOutputColourTarget( colourvn );\n\t\tauto cubean = opaquePass.addOutputColourTarget( cubevn );\n\t\tauto cubesan = opaquePass.addOutputColourTarget( cubesvn );\n\n\t\tauto & backgroundPass = graph.createPass( \"EnvBackgroundPass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t, test::checkDummy, 0u, false );\n\t\t\t} );\n\t\tbackgroundPass.addInputDepthTarget( *depthan );\n\t\tcolouran = backgroundPass.addInOutColourTarget( *colouran );\n\t\tcubean = backgroundPass.addInOutColourTarget( *cubean );\n\t\tcubesan = backgroundPass.addInOutColourTarget( *cubesan );\n\n\t\tauto & transparentPass = graph.createPass( \"EnvTransparentPass\" + strIndex\n\t\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn createDummy( testCounts\n\t\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eFragmentShader\n\t\t\t\t\t, test::checkDummy, 0u, false );\n\t\t\t} );\n\t\ttransparentPass.addInputDepthTarget( *depthan );\n\t\tcolourViews.push_back( transparentPass.addInOutColourTarget( *colouran ) );\n\t\tcubeViews.push_back( transparentPass.addInOutColourTarget( *cubean ) );\n\t\tcubesViews.push_back( transparentPass.addInOutColourTarget( *cubesan ) );\n\t}\n\n\tauto & mipsGen = graph.createPass( \"EnvMips\"\n\t\t, [&testCounts]( crg::FramePass const & framePass\n\t\t\t, crg::GraphContext & context\n\t\t\t, crg::RunnableGraph & runGraph )\n\t\t{\n\t\t\treturn createDummy( testCounts\n\t\t\t\t, framePass, context, runGraph, crg::PipelineStageFlags::eTransfer );\n\t\t} );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( colourViews ) );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( cubeViews ) );\n\tmipsGen.addInputTransfer( *graph.mergeAttachments( cubesViews ) );\n\tmipsGen.addOutputTransferImage( colourv );\n\tmipsGen.addOutputTransferImage( cubev );\n\tmipsGen.addOutputTransferImage( cubesv );\n\n\tauto runnable = graph.compile( getContext() );\n\ttest::checkRunnable( testCounts, runnable );\n\ttestEnd()\n}\n\ntestSuiteMain()\n"
  },
  {
    "path": "test/TestRenderPass.cpp",
    "content": "#include \"Common.hpp\"\n\n#include <RenderGraph/Attachment.hpp>\n#include <RenderGraph/FramePass.hpp>\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/ImageData.hpp>\n#include <RenderGraph/Log.hpp>\n#include <RenderGraph/ResourceHandler.hpp>\n\n#include <fmt/base.h>\n\nnamespace\n{\n\tTEST( FramePass, Log )\n\t{\n\t\ttestBegin( \"testLog\" )\n\t\tauto callback = []( std::string_view msg, bool newLine )noexcept\n\t\t\t{\n\t\t\t\tif ( newLine )\n\t\t\t\t\tfmt::print( \"{} Callback\\n\", msg.data() );\n\t\t\t\telse\n\t\t\t\t\tfmt::print( \"{} Callback \", msg.data() );\n\t\t\t};\n\n\t\tcrg::Logger::setTraceCallback( callback );\n\t\tcrg::Logger::setDebugCallback( callback );\n\t\tcrg::Logger::setInfoCallback( callback );\n\t\tcrg::Logger::setWarningCallback( callback );\n\t\tcrg::Logger::setErrorCallback( callback );\n\n\t\tcrg::Logger::logTrace( \"traceCoinNoNL \", false );\n\t\tcrg::Logger::logTrace( \"traceCoinNL\" );\n\t\tcrg::Logger::logDebug( \"debugCoinNoNL \", false );\n\t\tcrg::Logger::logDebug( \"debugCoinNL\" );\n\t\tcrg::Logger::logInfo( \"infoCoinNoNL \", false );\n\t\tcrg::Logger::logInfo( \"infoCoinNL\" );\n\t\tcrg::Logger::logWarning( \"warningCoinNoNL \", false );\n\t\tcrg::Logger::logWarning( \"warningCoinNL\" );\n\t\tcrg::Logger::logError( \"errorCoinNoNL \", false );\n\t\tcrg::Logger::logError( \"errorCoinNL\" );\n\n\t\tcrg::Logger::setTraceCallback( nullptr );\n\t\tcrg::Logger::setDebugCallback( nullptr );\n\t\tcrg::Logger::setInfoCallback( nullptr );\n\t\tcrg::Logger::setWarningCallback( nullptr );\n\t\tcrg::Logger::setErrorCallback( nullptr );\n\n\t\tcrg::Logger::logTrace( \"No callback traceCoinNoNL \", false );\n\t\tcrg::Logger::logTrace( \"No callback traceCoinNL\" );\n\t\tcrg::Logger::logDebug( \"No callback debugCoinNoNL \", false );\n\t\tcrg::Logger::logDebug( \"No callback debugCoinNL\" );\n\t\tcrg::Logger::logInfo( \"No callback infoCoinNoNL \", false );\n\t\tcrg::Logger::logInfo( \"No callback infoCoinNL\" );\n\t\tcrg::Logger::logWarning( \"No callback warningCoinNoNL \", false );\n\t\tcrg::Logger::logWarning( \"No callback warningCoinNL\" );\n\t\tcrg::Logger::logError( \"No callback errorCoinNoNL \", false );\n\t\tcrg::Logger::logError( \"No callback errorCoinNL\" );\n\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C )\n\t{\n\t\ttestBegin( \"testRenderPass_1C\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tcheck( pass.getName() == \"1C\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C )\n\t{\n\t\ttestBegin( \"testRenderPass_2C\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tcheck( pass.getName() == \"2C\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[1]->view() == rtv2 )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_0C_1I )\n\t{\n\t\ttestBegin( \"testRenderPass_0C_1I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"0C_1I\", crg::RunnablePassCreator{} );\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tcheck( pass.getName() == \"0C_1I\" )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_0C_2I )\n\t{\n\t\ttestBegin( \"testRenderPass_0C_2I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"0C_2I\", crg::RunnablePassCreator{} );\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tcheck( pass.getName() == \"0C_2I\" )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C_1I )\n\t{\n\t\ttestBegin( \"testRenderPass_1C_1I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C_1I\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tcheck( pass.getName() == \"1C_1I\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C_2I )\n\t{\n\t\ttestBegin( \"testRenderPass_1C_2I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C_2I\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tcheck( pass.getName() == \"1C_2I\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C_1I )\n\t{\n\t\ttestBegin( \"testRenderPass_2C_1I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C_1I\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tcheck( pass.getName() == \"2C_1I\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[1]->view() == rtv2 )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C_2I )\n\t{\n\t\ttestBegin( \"testRenderPass_2C_2I\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C_2I\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tcheck( pass.getName() == \"2C_2I\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[1]->view() == rtv2 )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n\t\n\tTEST( FramePass, RenderPass_0C_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_0C_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"0C_DS\", crg::RunnablePassCreator{} );\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"0C_DS\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_1C_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"1C_DS\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_2C_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"2C_DS\" )\n\t\tcheck( pass.getTargets().size() == 3u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[2]->view() == rtv2 )\n\t\ttestEnd()\n\t}\n\t\n\tTEST( FramePass, RenderPass_0C_1I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_0C_1I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"0C_1I_DS\", crg::RunnablePassCreator{} );\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"0C_1I_DS\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_0C_2I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_0C_2I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"0C_2I_DS\", crg::RunnablePassCreator{} );\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"0C_2I_DS\" )\n\t\tcheck( pass.getTargets().size() == 1u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C_1I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_1C_1I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C_1I_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"1C_1I_DS\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_1C_2I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_1C_2I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"1C_2I_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt = graph.createImage( test::createImage( \"rt\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv = graph.createView( test::createView( \"rtv\", rt ) );\n\t\tpass.addOutputColourTarget( rtv );\n\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"1C_2I_DS\" )\n\t\tcheck( pass.getTargets().size() == 2u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C_1I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_2C_1I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C_1I_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tauto in = graph.createImage( test::createImage( \"in\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv = graph.createView( test::createView( \"inv\", in ) );\n\t\tauto attach = crg::Attachment::createDefault( inv );\n\t\tpass.addInputSampled( attach, 1u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"2C_1I_DS\" )\n\t\tcheck( pass.getTargets().size() == 3u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[2]->view() == rtv2 )\n\t\tcheck( pass.getSampled().size() == 1u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv )\n\t\ttestEnd()\n\t}\n\n\tTEST( FramePass, RenderPass_2C_2I_DS )\n\t{\n\t\ttestBegin( \"testRenderPass_2C_2I_DS\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto & pass = graph.createPass( \"2C_2I_DS\", crg::RunnablePassCreator{} );\n\t\tauto rt1 = graph.createImage( test::createImage( \"rt1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv1 = graph.createView( test::createView( \"rtv1\", rt1 ) );\n\t\tpass.addOutputColourTarget( rtv1 );\n\n\t\tauto rt2 = graph.createImage( test::createImage( \"rt2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto rtv2 = graph.createView( test::createView( \"rtv2\", rt2 ) );\n\t\tpass.addOutputColourTarget( rtv2 );\n\n\t\tauto in1 = graph.createImage( test::createImage( \"in1\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv1 = graph.createView( test::createView( \"inv1\", in1 ) );\n\t\tauto attach1 = crg::Attachment::createDefault( inv1 );\n\t\tpass.addInputSampled( attach1, 1u );\n\n\t\tauto in2 = graph.createImage( test::createImage( \"in2\", crg::PixelFormat::eR32G32B32A32_SFLOAT ) );\n\t\tauto inv2 = graph.createView( test::createView( \"inv2\", in2 ) );\n\t\tauto attach2 = crg::Attachment::createDefault( inv2 );\n\t\tpass.addInputSampled( attach2, 2u );\n\n\t\tauto ds = graph.createImage( test::createImage( \"ds\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto dsv = graph.createView( test::createView( \"dsv\", ds ) );\n\t\tpass.addOutputDepthStencilTarget( dsv );\n\n\t\tcheck( pass.getName() == \"2C_2I_DS\" )\n\t\tcheck( pass.getTargets().size() == 3u )\n\t\tcheck( pass.getTargets()[0]->view() == dsv )\n\t\tcheck( pass.getTargets()[1]->view() == rtv1 )\n\t\tcheck( pass.getTargets()[2]->view() == rtv2 )\n\t\tcheck( pass.getSampled().size() == 2u )\n\t\tcheck( pass.getSampled().begin()->second.attach->view() == inv1 )\n\t\tcheck( pass.getSampled().rbegin()->second.attach->view() == inv2 )\n\t\ttestEnd()\n\t}\n}\n\ntestSuiteMain()\n"
  },
  {
    "path": "test/TestRunnablePass.cpp",
    "content": "#include \"Common.hpp\"\n\n#include <RenderGraph/Attachment.hpp>\n#include <RenderGraph/FramePass.hpp>\n#include <RenderGraph/FrameGraph.hpp>\n#include <RenderGraph/ImageData.hpp>\n#include <RenderGraph/ResourceHandler.hpp>\n#include <RenderGraph/RunnablePasses/BufferCopy.hpp>\n#include <RenderGraph/RunnablePasses/BufferToImageCopy.hpp>\n#include <RenderGraph/RunnablePasses/ComputePass.hpp>\n#include <RenderGraph/RunnablePasses/GenerateMipmaps.hpp>\n#include <RenderGraph/RunnablePasses/ImageBlit.hpp>\n#include <RenderGraph/RunnablePasses/ImageCopy.hpp>\n#include <RenderGraph/RunnablePasses/ImageToBufferCopy.hpp>\n#include <RenderGraph/RunnablePasses/RenderMesh.hpp>\n#include <RenderGraph/RunnablePasses/RenderPass.hpp>\n#include <RenderGraph/RunnablePasses/RenderQuad.hpp>\n\n#include <sstream>\n\nnamespace\n{\n\tcrg::GraphContext & getContext()\n\t{\n\t\treturn test::getDummyContext();\n\t}\n\n\tTEST( RunnablePass, BufferCopy_I_O )\n\t{\n\t\ttestBegin( \"testBufferCopy_I_O\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto buffer1 = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\t\t\tauto buffer2 = graph.createBuffer( test::createBuffer( \"buffer2\" ) );\n\t\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer1 ) );\n\t\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer2 ) );\n\t\t\tauto buffer1a = crg::Attachment::createDefault( buffer1v );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::BufferCopy >( pass, context, runGraph\n\t\t\t\t\t\t, 0u, 1024u );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( buffer1a );\n\t\t\ttestPass.addOutputTransferBuffer( buffer2v );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, BufferCopy_IO_IO )\n\t{\n\t\ttestBegin( \"testBufferCopy_IO_IO\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto buffer1 = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\t\t\tauto buffer2 = graph.createBuffer( test::createBuffer( \"buffer2\" ) );\n\t\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer1 ) );\n\t\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer2 ) );\n\t\t\tauto buffer1a = crg::Attachment::createDefault( buffer1v );\n\t\t\tauto buffer2a = crg::Attachment::createDefault( buffer2v );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::BufferCopy >( pass, context, runGraph\n\t\t\t\t\t\t, 0u, 512u );\n\t\t\t\t} );\n\t\t\ttestPass.addInOutTransfer( buffer1a );\n\t\t\ttestPass.addInOutTransfer( buffer2a );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, BufferToImageCopy )\n\t{\n\t\ttestBegin( \"testBufferToImageCopy\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer\" ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto bufferv = graph.createView( test::createView( \"bufferv\", buffer ) );\n\t\tauto buffera = crg::Attachment::createDefault( bufferv );\n\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn std::make_unique< crg::BufferToImageCopy >( pass, context, runGraph\n\t\t\t\t\t, crg::Offset3D{}, crg::Extent3D{ 1024, 1024, 1u } );\n\t\t\t} );\n\t\ttestPass.addInputTransfer( buffera );\n\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, GenerateMipmaps )\n\t{\n\t\ttestBegin( \"testGenerateMipmaps\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 10u ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 10u, 0u, 1u ) );\n\t\tauto resulta = crg::Attachment::createDefault( resultv );\n\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn std::make_unique< crg::GenerateMipmaps >( pass, context, runGraph );\n\t\t\t} );\n\t\ttestPass.addInOutTransfer( resulta );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageBlit )\n\t{\n\t\ttestBegin( \"testImageBlit\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t, [inputv, resultv]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn std::make_unique< crg::ImageBlit >( pass, context, runGraph\n\t\t\t\t\t, crg::Rect3D{ crg::Offset3D{}, getExtent( inputv ) }\n\t\t\t\t\t, crg::Rect3D{ crg::Offset3D{}, getExtent( resultv ) }\n\t\t\t\t\t, crg::FilterMode::eLinear );\n\t\t\t} );\n\t\ttestPass.addInputTransfer( inputa );\n\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, Image3DBlit )\n\t{\n\t\ttestBegin( \"testImage3DBlit\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto input = graph.createImage( test::createImage3D( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto result = graph.createImage( test::createImage3D( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t, [inputv, resultv]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn std::make_unique< crg::ImageBlit >( pass, context, runGraph\n\t\t\t\t\t, crg::Rect3D{ crg::Offset3D{}, getExtent( inputv ) }\n\t\t\t\t\t, crg::Rect3D{ crg::Offset3D{}, getExtent( resultv ) }\n\t\t\t\t\t, crg::FilterMode::eLinear );\n\t\t\t} );\n\t\ttestPass.addInputTransfer( inputa );\n\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_Base )\n\t{\n\t\ttestBegin( \"testImageCopy_Base\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv ) );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( inputa );\n\t\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_SingleInputMultipleOutputsSameImage )\n\t{\n\t\ttestBegin( \"ImageCopy_SingleInputMultipleOutputsSameImage\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 6u ) );\n\t\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto resultv0 = graph.createView( test::createView( \"result0v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto resultv1 = graph.createView( test::createView( \"result1v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto resultv2 = graph.createView( test::createView( \"result2v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto resultv3 = graph.createView( test::createView( \"result3v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 3u, 1u ) );\n\t\t\tauto resultv4 = graph.createView( test::createView( \"result4v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 4u, 1u ) );\n\t\t\tauto resultv5 = graph.createView( test::createView( \"result5v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 5u, 1u ) );\n\t\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv ), crg::ImageLayout::eShaderReadOnly );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( inputa );\n\t\t\ttestPass.addOutputTransferImage( resultv0 );\n\t\t\ttestPass.addOutputTransferImage( resultv1 );\n\t\t\ttestPass.addOutputTransferImage( resultv2 );\n\t\t\ttestPass.addOutputTransferImage( resultv3 );\n\t\t\ttestPass.addOutputTransferImage( resultv4 );\n\t\t\ttestPass.addOutputTransferImage( resultv5 );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_SingleInputMultipleOutputsDifferentImage )\n\t{\n\t\ttestBegin( \"ImageCopy_SingleInputMultipleOutputsDifferentImage\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto result0 = graph.createImage( test::createImage( \"result0\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) );\n\t\t\tauto result1 = graph.createImage( test::createImage( \"result1\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) );\n\t\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto result0v0 = graph.createView( test::createView( \"result0v\", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto result0v1 = graph.createView( test::createView( \"result1v\", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto result0v2 = graph.createView( test::createView( \"result2v\", result0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto result1v0 = graph.createView( test::createView( \"result3v\", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto result1v1 = graph.createView( test::createView( \"result4v\", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto result1v2 = graph.createView( test::createView( \"result5v\", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv ) );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( inputa );\n\t\t\ttestPass.addOutputTransferImage( result0v0 );\n\t\t\ttestPass.addOutputTransferImage( result0v1 );\n\t\t\ttestPass.addOutputTransferImage( result0v2 );\n\t\t\ttestPass.addOutputTransferImage( result1v0 );\n\t\t\ttestPass.addOutputTransferImage( result1v1 );\n\t\t\ttestPass.addOutputTransferImage( result1v2 );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_MultipleInputsSameImageSingleOutput )\n\t{\n\t\ttestBegin( \"ImageCopy_SingleInputMultipleOutputsSameImage\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 6u ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto inputv0 = graph.createView( test::createView( \"inputv0\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto inputv1 = graph.createView( test::createView( \"inputv1\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto inputv2 = graph.createView( test::createView( \"inputv2\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto inputv3 = graph.createView( test::createView( \"inputv3\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 3u, 1u ) );\n\t\t\tauto inputv4 = graph.createView( test::createView( \"inputv4\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 4u, 1u ) );\n\t\t\tauto inputv5 = graph.createView( test::createView( \"inputv5\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 5u, 1u ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv0]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv0 ), crg::ImageLayout::eShaderReadOnly );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransferImage( inputv0 );\n\t\t\ttestPass.addInputTransferImage( inputv1 );\n\t\t\ttestPass.addInputTransferImage( inputv2 );\n\t\t\ttestPass.addInputTransferImage( inputv3 );\n\t\t\ttestPass.addInputTransferImage( inputv4 );\n\t\t\ttestPass.addInputTransferImage( inputv5 );\n\t\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_MultipleInputsDifferentImageSingleOutput )\n\t{\n\t\ttestBegin( \"ImageCopy_MultipleInputsDifferentImageSingleOutput\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input0 = graph.createImage( test::createImage( \"input0\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) );\n\t\t\tauto input1 = graph.createImage( test::createImage( \"input1\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 3u ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto input0v0 = graph.createView( test::createView( \"input0v0\", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto input0v1 = graph.createView( test::createView( \"input0v1\", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto input0v2 = graph.createView( test::createView( \"input0v2\", input0, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto input1v0 = graph.createView( test::createView( \"input1v0\", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto input1v1 = graph.createView( test::createView( \"input1v1\", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto input1v2 = graph.createView( test::createView( \"input1v2\", input1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 2u, 1u ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [result]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( result ) );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransferImage( input0v0 );\n\t\t\ttestPass.addInputTransferImage( input0v1 );\n\t\t\ttestPass.addInputTransferImage( input0v2 );\n\t\t\ttestPass.addInputTransferImage( input1v0 );\n\t\t\ttestPass.addInputTransferImage( input1v1 );\n\t\t\ttestPass.addInputTransferImage( input1v2 );\n\t\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_OutputLayout )\n\t{\n\t\ttestBegin( \"testImageCopy_OutputLayout\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv )\n\t\t\t\t\t\t\t, crg::ImageLayout::eShaderReadOnly );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( inputa );\n\t\t\ttestPass.addOutputTransferImage( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageCopy_BackAndForth )\n\t{\n\t\ttestBegin( \"testImageCopy_BackAndForth\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\t\tauto resulta = crg::Attachment::createDefault( resultv );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::ImageCopy >( pass, context, runGraph\n\t\t\t\t\t\t\t, getExtent( inputv )\n\t\t\t\t\t\t\t, crg::ImageLayout::eShaderReadOnly );\n\t\t\t\t} );\n\t\t\ttestPass.addInputTransfer( inputa );\n\t\t\ttestPass.addOutputTransferImage( resultv );\n\t\t\ttestPass.addInputTransfer( resulta );\n\t\t\ttestPass.addOutputTransferImage( inputv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ImageToBufferCopy )\n\t{\n\t\ttestBegin( \"testImageToBufferCopy\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\tauto input = graph.createImage( test::createImage( \"input\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer\" ) );\n\t\tauto inputv = graph.createView( test::createView( \"inputv\", input, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto bufferv = graph.createView( test::createView( \"bufferv\", buffer ) );\n\t\tauto inputa = crg::Attachment::createDefault( inputv );\n\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t, [inputv]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\treturn std::make_unique< crg::ImageToBufferCopy >( pass, context, runGraph\n\t\t\t\t\t, crg::Offset3D{}, getExtent( inputv ) );\n\t\t\t} );\n\t\ttestPass.addInputTransfer( inputa );\n\t\ttestPass.addOutputTransferBuffer( bufferv );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ComputePass )\n\t{\n\t\ttestBegin( \"testComputePass\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, \"/\" + testCounts.testName };\n\t\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer\" ) );\n\t\tauto bufferv = graph.createView( test::createView( \"bufferv\", buffer ) );\n\t\tauto indirect = graph.createBuffer( test::createBuffer( \"indirect\" ) );\n\t\tauto indirectv = graph.createView( test::createView( \"indirectv\", indirect ) );\n\t\tauto & testPass1 = graph.createPass( \"Pass1\"\n\t\t\t, [&indirectv]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\tcfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } );\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\treturn std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{}, std::move( cfg ) );\n\t\t\t} );\n\t\tauto buffera = testPass1.addClearableOutputStorageBuffer( bufferv, 1u );\n\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto depthStencil = graph.createImage( test::createImage( \"depthStencil\", crg::PixelFormat::eD32_SFLOAT_S8_UINT ) );\n\t\tauto buffer1 = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto depthv = graph.createView( test::createView( \"depthv\", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto depthStencilv = graph.createView( test::createView( \"depthStencilv\", depthStencil, crg::PixelFormat::eD32_SFLOAT_S8_UINT, 0u, 1u, 0u, 1u ) );\n\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer1 ) );\n\t\tcrg::ComputePass * computePass{};\n\t\tauto & testPass2 = graph.createPass( \"Pass2\"\n\t\t\t, [&computePass]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\tauto res = std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\tcomputePass = res.get();\n\t\t\t\treturn res;\n\t\t\t} );\n\t\ttestPass2.addInputUniformBuffer( buffer1v, 0u );\n\t\ttestPass2.addInputUniform( *buffera, 1u );\n\t\tauto resulta = testPass2.addClearableOutputStorageImage( resultv, 2u );\n\t\tauto deptha = testPass2.addClearableOutputStorageImage( depthv, 3u );\n\n\t\tauto buffer2 = graph.createBuffer( test::createBuffer( \"buffer2\" ) );\n\t\tauto buffer3 = graph.createBuffer( test::createBuffer( \"buffer3\" ) );\n\t\tauto buffer4 = graph.createBuffer( test::createBuffer( \"buffer4\" ) );\n\t\tauto buffer5 = graph.createBuffer( test::createBuffer( \"buffer5\" ) );\n\t\tauto buffer6 = graph.createBuffer( test::createBuffer( \"buffer6\" ) );\n\t\tauto buffer7 = graph.createBuffer( test::createBuffer( \"buffer7\" ) );\n\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer2 ) );\n\t\tauto buffer3v = graph.createView( test::createView( \"buffer3v\", buffer3 ) );\n\t\tauto buffer4v = graph.createView( test::createView( \"buffer4v\", buffer4, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer5v = graph.createView( test::createView( \"buffer5v\", buffer5, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer6v = graph.createView( test::createView( \"buffer6v\", buffer6, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer7v = graph.createView( test::createView( \"buffer7v\", buffer7, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto buffer2a = crg::Attachment::createDefault( buffer2v );\n\t\tauto buffer3a = crg::Attachment::createDefault( buffer3v );\n\t\tauto buffer5a = crg::Attachment::createDefault( buffer5v );\n\t\tauto buffer7a = crg::Attachment::createDefault( buffer7v );\n\t\tauto depthStencila = crg::Attachment::createDefault( depthStencilv );\n\t\tauto & testPass3 = graph.createPass( \"Pass3\"\n\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\treturn std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{}, std::move( cfg ) );\n\t\t\t} );\n\t\ttestPass3.addInputStorage( buffer2a, 2u );\n\t\ttestPass3.addInOutStorage( buffer3a, 3u );\n\n\t\ttestPass3.addInputUniformBuffer( buffer4v, 4u );\n\t\ttestPass3.addInputStorage( buffer5a, 5u );\n\t\ttestPass3.addOutputStorageBuffer( buffer6v, 6u );\n\t\ttestPass3.addInOutStorage( buffer7a, 7u );\n\n\t\ttestPass3.addImplicit( *resulta, crg::ImageLayout::eShaderReadOnly );\n\t\ttestPass3.addImplicit( *deptha, crg::ImageLayout::eShaderReadOnly );\n\t\ttestPass3.addImplicit( depthStencila, crg::ImageLayout::eShaderReadOnly );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\trequire( computePass )\n\t\tcheckNoThrow( computePass->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\tcheckNoThrow( computePass->resetCommandBuffer( 0u ) )\n\t\tcheckNoThrow( runnable->record() )\n\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\tcheckNoThrow( graph.getFinalAccessState( buffer1v ) )\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, ComputePassTransitions )\n\t{\n\t\ttestBegin( \"testComputePassTransitions\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, \"/\" + testCounts.testName };\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\tauto buffer1 = graph.createBuffer( test::createBuffer( \"buffer1\" ) );\n\t\tauto buffer2 = graph.createBuffer( test::createBuffer( \"buffer2\" ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto depthv = graph.createView( test::createView( \"depthv\", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer1 ) );\n\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer2 ) );\n\t\tauto & testPass1 = graph.createPass( \"Pass1\"\n\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\treturn std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t} );\n\t\tauto resulta = testPass1.addClearableOutputStorageImage( resultv, 0u );\n\t\tauto deptha = testPass1.addClearableOutputStorageImage( depthv, 1u );\n\t\tauto buffer1a = testPass1.addClearableOutputStorageBuffer( buffer1v, 2u );\n\t\tauto buffer2a = testPass1.addClearableOutputStorageBuffer( buffer2v, 3u );\n\n\t\tauto & testPass2 = graph.createPass( \"Pass2\"\n\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\treturn std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{}, std::move( cfg ) );\n\t\t\t} );\n\t\ttestPass2.addImplicit( *resulta, crg::ImageLayout::eShaderReadOnly );\n\t\ttestPass2.addImplicit( *deptha, crg::ImageLayout::eShaderReadOnly );\n\t\ttestPass2.addInputStorage( *buffer1a, 1u );\n\t\ttestPass2.addImplicit( *buffer2a, crg::AccessState{} );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto sampled = graph.createImage( test::createImage( \"sampled\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto sampledv = graph.createView( test::createView( \"sampledv\", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback > } );\n\t\t\t\t} );\n\t\t\ttestPass.addInputSampledImage( sampledv, 0u );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_ORcl_DefCont )\n\t{\n\t\ttestBegin( \"testRenderPass_ORcl_DefCont\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_MergedImageViews_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_MergedImageViews_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto & group = graph.createPassGroup( \"testGroup\" );\n\t\t\tauto result = group.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) );\n\t\t\tauto result1v = group.createView( test::createView( \"result1v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto result2v = group.createView( test::createView( \"result2v\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto resultv = group.mergeViews( { result1v, result2v } );\n\t\t\tauto & testPass = group.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tcheckEqual( graph.getFinalLayoutState( resultv ).layout, crg::ImageLayout::eColorAttachment )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_MergedImageViews_CubeARray_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_MergedImageViews_CubeARray_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto & group = graph.createPassGroup( \"testGroup\" );\n\t\t\tauto result = group.createImage( test::createImageCube( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 12u ) );\n\t\t\tauto result1v = group.createView( crg::ImageViewData{ \"result1v\"\n\t\t\t\t, result\n\t\t\t\t, crg::ImageViewCreateFlags::eNone\n\t\t\t\t, crg::ImageViewType::e2D\n\t\t\t\t, getFormat( result )\n\t\t\t\t, { getAspectMask( getFormat( result ) ), 0u, 1u, 0u, 6u } } );\n\t\t\tauto result2v = group.createView( crg::ImageViewData{ \"result2v\"\n\t\t\t\t, result\n\t\t\t\t, crg::ImageViewCreateFlags::eNone\n\t\t\t\t, crg::ImageViewType::e2D\n\t\t\t\t, getFormat( result )\n\t\t\t\t, { getAspectMask( getFormat( result ) ), 0u, 1u, 6u, 6u } } );\n\t\t\tauto resultv = group.mergeViews( { result1v, result2v } );\n\t\t\tauto & testPass = group.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tcheckEqual( graph.getFinalLayoutState( resultv ).layout, crg::ImageLayout::eColorAttachment )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_MergedBufferViews_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_MergedBufferViews_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto & group = graph.createPassGroup( \"testGroup\" );\n\t\t\tauto result = group.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto buffer = group.createBuffer( test::createBuffer( \"buffer\" ) );\n\t\t\tauto resultv = group.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto buffer1v = group.createView( test::createView( \"buffer1v\", buffer, 0, 512u ) );\n\t\t\tauto buffer2v = group.createView( test::createView( \"buffer2v\", buffer, 512u, 512u ) );\n\t\t\tauto bufferv = group.mergeViews( { buffer1v, buffer2v } );\n\t\t\tauto & testPass = group.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputStorageBuffer( bufferv, 0u );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tcheckEqual( graph.getFinalAccessState( bufferv ).access, crg::AccessFlags::eShaderWrite )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_MergedImageAttachs_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_MergedImageAttachs_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto intermediate = graph.createImage( test::createImage( \"intermediate\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) );\n\t\t\tauto intermediate1v = graph.createView( test::createView( \"intermediate1v\", intermediate, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto intermediate2v = graph.createView( test::createView( \"intermediate2v\", intermediate, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 1u, 1u ) );\n\t\t\tauto & testPass1 = graph.createPass( \"Pass1\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\tauto intermediate1a = testPass1.addOutputColourTarget( intermediate1v );\n\t\t\tauto intermediate2a = testPass1.addOutputColourTarget( intermediate2v );\n\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto & testPass2 = graph.createPass( \"Pass2\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\tauto intermediatea = graph.mergeAttachments( { intermediate1a, intermediate2a } );\n\t\t\ttestPass2.addInputSampled( *intermediatea, 0u );\n\t\t\ttestPass2.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tcheckEqual( graph.getFinalLayoutState( intermediatea->view() ).layout, crg::ImageLayout::eShaderReadOnly )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_MergedBufferAttachs_ORcl )\n\t{\n\t\ttestBegin( \"testRenderPass_MergedBufferAttachs_ORcl\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto buffer = graph.createBuffer( test::createBuffer( \"buffer\" ) );\n\t\t\tauto buffer1v = graph.createView( test::createView( \"buffer1v\", buffer, 0u, 512u ) );\n\t\t\tauto buffer2v = graph.createView( test::createView( \"buffer2v\", buffer, 512u, 512u ) );\n\t\t\tauto & testPass1 = graph.createPass( \"Pass1\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::cp::Config cfg;\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\treturn std::make_unique< crg::ComputePass >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\t} );\n\t\t\tauto buffer1a = testPass1.addOutputStorageBuffer( buffer1v, 0u );\n\t\t\tauto buffer2a = testPass1.addOutputStorageBuffer( buffer2v, 1u );\n\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto & testPass2 = graph.createPass( \"Pass2\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback  > } );\n\t\t\t\t} );\n\t\t\tauto buffera = graph.mergeAttachments( { buffer1a, buffer2a } );\n\t\t\ttestPass2.addInputStorage( *buffera, 0u );\n\t\t\ttestPass2.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tcheckEqual( graph.getFinalAccessState( buffera->buffer() ).access, crg::AccessFlags::eShaderRead )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_ORdp )\n\t{\n\t\ttestBegin( \"testRenderPass_ORdp\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\t\tauto depthv = graph.createView( test::createView( \"depthv\", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputDepthTarget ( depthv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass_ORcl_ORdp )\n\t{\n\t\ttestBegin( \"testRenderPass_ORcl_ORdp\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tuint32_t passIndex{};\n\t\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto depth = graph.createImage( test::createImage( \"depth\", crg::PixelFormat::eD32_SFLOAT ) );\n\t\t\tauto depthv = graph.createView( test::createView( \"depthv\", depth, crg::PixelFormat::eD32_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tcrg::Extent2D extent{ getExtent( resultv ).width, getExtent( resultv ).height };\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&passIndex, extent]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RenderPass::GetSubpassContentsCallback >\n\t\t\t\t\t\t\t, crg::RenderPass::GetPassIndexCallback( [passIndex](){ return passIndex; } ) }\n\t\t\t\t\t\t, extent\n\t\t\t\t\t\t, crg::ru::Config{ 2u } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\t\t\ttestPass.addOutputDepthTarget ( depthv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\tpassIndex = 1u - passIndex;\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderPass )\n\t{\n\t\ttestBegin( \"testRenderPass\" )\n\t\t{\n\t\t\tcrg::ResourceHandler handler;\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto result1 = graph.createImage( test::createImage( \"result1\", crg::PixelFormat::eR16G16B16A16_SFLOAT, 1u, 2u ) );\n\t\t\tauto result1v = graph.createView( test::createView( \"result1v\", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto result2v = graph.createView( test::createView( \"result2v\", result1, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, []( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\treturn std::make_unique< crg::RenderPass >( pass, context, runGraph\n\t\t\t\t\t\t, crg::RenderPass::Callbacks{ crg::defaultV< crg::RunnablePass::InitialiseCallback >\n\t\t\t\t\t\t\t, crg::defaultV< crg::RunnablePass::RecordCallback > } );\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v } ) );\n\t\t\ttestPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, false, true ) );\n\t\t\ttestPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, true, false ) );\n\t\t\ttestPass.addOutputColourTarget( graph.mergeViews( { result1v, result2v }, false, false ) );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderQuad )\n\t{\n\t\ttestBegin( \"testRenderQuad\" )\n\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tcrg::RenderQuad * renderQuad{};\n\t\t\tuint32_t passIndex{};\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderQuad, &passIndex]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rq::Config cfg;\n\t\t\t\t\tcfg.passIndex( &passIndex );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 2u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderQuad >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 2u, true }, std::move( cfg ) );\n\t\t\t\t\trenderQuad = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderQuad )\n\t\t\tpassIndex = 1u - passIndex;\n\t\t\tcheckNoThrow( renderQuad->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderQuad_Indirect )\n\t{\n\t\ttestBegin( \"testRenderQuad_Indirect\" )\n\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tcrg::RenderQuad * renderQuad{};\n\t\t\tauto indirect = graph.createBuffer( test::createBuffer( \"indirect\" ) );\n\t\t\tauto indirectv = graph.createView( test::createView( \"indirectv\", indirect ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderQuad, &indirectv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rq::Config cfg;\n\t\t\t\t\tcfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderQuad >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 2u, true }, std::move( cfg ) );\n\t\t\t\t\trenderQuad = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderQuad )\n\t\t\tcheckNoThrow( renderQuad->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderMesh )\n\t{\n\t\ttestBegin( \"testRenderMesh\" )\n\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tcrg::RenderMesh * renderMesh{};\n\t\t\tuint32_t passIndex{};\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderMesh, &passIndex]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\t\tcfg.getPassIndex( crg::RunnablePass::GetPassIndexCallback( [&passIndex](){ return passIndex; } ) );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 2u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 2u, true }, std::move( cfg ) );\n\t\t\t\t\trenderMesh = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderMesh )\n\t\t\tpassIndex = 1u - passIndex;\n\t\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderMesh_Vertex )\n\t{\n\t\ttestBegin( \"testRenderMesh_Vertex\" )\n\t\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tcrg::RenderMesh * renderMesh{};\n\t\t\tauto vertex = graph.createBuffer( test::createBuffer( \"vertex\" ) );\n\t\t\tauto vertexv = graph.createView( test::createView( \"vertexv\", vertex ) );\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderMesh, &vertexv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\t\tcfg.vertexBuffer( crg::VertexBuffer{ vertexv } );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programs( { crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\t\trenderMesh = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderMesh )\n\t\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderMesh_Vertex_Index )\n\t{\n\t\ttestBegin( \"testRenderMesh_Vertex_Index\" )\n\t\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto vertex = graph.createBuffer( test::createBuffer( \"vertex\" ) );\n\t\t\tauto index = graph.createBuffer( test::createBuffer( \"index\" ) );\n\t\t\tauto vertexv = graph.createView( test::createView( \"vertexv\", vertex ) );\n\t\t\tauto indexv = graph.createView( test::createView( \"indexv\", index ) );\n\t\t\tcrg::RenderMesh * renderMesh{};\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderMesh, &vertexv, &indexv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\t\tauto vb = crg::VertexBuffer{ vertexv };\n\t\t\t\t\tcfg.vertexBuffer( std::move( vb ) );\n\t\t\t\t\tcfg.indexBuffer( crg::IndexBuffer{ indexv } );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\t\trenderMesh = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderMesh )\n\t\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderMesh_Indirect )\n\t{\n\t\ttestBegin( \"testRenderMesh_Indirect\" )\n\t\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto indirect = graph.createBuffer( test::createBuffer( \"indirect\" ) );\n\t\t\tauto indirectv = graph.createView( test::createView( \"indirectv\", indirect ) );\n\t\t\tcrg::RenderMesh * renderMesh{};\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderMesh, &indirectv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\t\tcfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndirectCommand ) } );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\t\trenderMesh = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderMesh )\n\t\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderMesh_Indirect_Index )\n\t{\n\t\ttestBegin( \"testRenderMesh_Indirect_Index\" )\n\t\t\tcrg::ResourceHandler handler;\n\t\tauto result = handler.createImageId( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = handler.createViewId( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\t{\n\t\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\t\t\tauto indirect = graph.createBuffer( test::createBuffer( \"indirect\" ) );\n\t\t\tauto index = graph.createBuffer( test::createBuffer( \"index\" ) );\n\t\t\tauto indirectv = graph.createView( test::createView( \"indirectv\", indirect ) );\n\t\t\tauto indexv = graph.createView( test::createView( \"indexv\", index ) );\n\t\t\tcrg::RenderMesh * renderMesh{};\n\t\t\tauto & testPass = graph.createPass( \"Pass\"\n\t\t\t\t, [&renderMesh, &indirectv, &indexv]( crg::FramePass const & pass\n\t\t\t\t\t, crg::GraphContext & context\n\t\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t\t{\n\t\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\t\tcfg.indirectBuffer( crg::IndirectBuffer{ indirectv, sizeof( VkDrawIndexedIndirectCommand ) } );\n\t\t\t\t\tcfg.indexBuffer( crg::IndexBuffer{ indexv } );\n\t\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t\t, []( uint32_t ){ return crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }; } } ) );\n\t\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\t\trenderMesh = res.get();\n\t\t\t\t\treturn res;\n\t\t\t\t} );\n\t\t\ttestPass.addOutputColourTarget( resultv );\n\n\t\t\tauto runnable = graph.compile( getContext() );\n\t\t\ttest::checkRunnable( testCounts, runnable );\n\t\t\trequire( renderMesh )\n\t\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\t\tcheckNoThrow( runnable->record() )\n\t\t\tcheckNoThrow( runnable->run( VkQueue{} ) )\n\t\t}\n\t\ttestEnd()\n\t}\n\n\tTEST( RunnablePass, RenderTexturedMesh )\n\t{\n\t\ttestBegin( \"testRenderTexturedMesh\" )\n\t\tcrg::ResourceHandler handler;\n\t\tcrg::FrameGraph graph{ handler, testCounts.testName };\n\n\t\tauto sampled = graph.createImage( test::createImage( \"sampled\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto sampledv = graph.createView( test::createView( \"sampledv\", sampled, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tcrg::RenderQuad * renderQuad{};\n\t\tauto & testQuad = graph.createPass( \"Quad\"\n\t\t\t, [&renderQuad]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::rq::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} };\n\t\t\t\t\t\t} } ) );\n\t\t\t\tauto res = std::make_unique< crg::RenderQuad >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{ 2u, true }, std::move( cfg ) );\n\t\t\t\trenderQuad = res.get();\n\t\t\t\treturn res;\n\t\t\t} );\n\t\tauto sampledAttach = testQuad.addOutputColourTarget( sampledv );\n\n\t\tauto result = graph.createImage( test::createImage( \"result\", crg::PixelFormat::eR16G16B16A16_SFLOAT ) );\n\t\tauto resultv = graph.createView( test::createView( \"resultv\", result, crg::PixelFormat::eR16G16B16A16_SFLOAT, 0u, 1u, 0u, 1u ) );\n\t\tcrg::RenderMesh * renderMesh{};\n\t\tauto & testMesh = graph.createPass( \"Mesh\"\n\t\t\t, [&renderMesh]( crg::FramePass const & pass\n\t\t\t\t, crg::GraphContext & context\n\t\t\t\t, crg::RunnableGraph & runGraph )\n\t\t\t{\n\t\t\t\tcrg::rm::Config cfg;\n\t\t\t\tcfg.baseConfig( crg::pp::Config{}\n\t\t\t\t\t.programCreator( crg::ProgramCreator{ 1u\n\t\t\t\t\t\t, []( uint32_t )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} };\n\t\t\t\t\t\t} } ) );\n\t\t\t\tauto res = std::make_unique< crg::RenderMesh >( pass, context, runGraph\n\t\t\t\t\t, crg::ru::Config{ 1u, true }, std::move( cfg ) );\n\t\t\t\trenderMesh = res.get();\n\t\t\t\treturn res;\n\t\t\t} );\n\t\ttestMesh.addOutputColourTarget( resultv );\n\t\ttestMesh.addInputSampled( *sampledAttach, 0u );\n\n\t\tauto runnable = graph.compile( getContext() );\n\t\ttest::checkRunnable( testCounts, runnable );\n\t\trequire( renderQuad )\n\t\trequire( renderMesh )\n\t\tcheckNoThrow( renderQuad->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\tcheckNoThrow( renderQuad->resetPipelineLayout( {}, {}, crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\tcheckNoThrow( renderMesh->resetPipeline( crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\tcheckNoThrow( renderMesh->resetPipelineLayout( {}, {}, crg::VkPipelineShaderStageCreateInfoArray{ VkPipelineShaderStageCreateInfo{} }, 0u ) )\n\t\tcheckNoThrow( runnable->record() )\n\t\tcheckNoThrow( runnable->run( crg::SemaphoreWait{ VkSemaphore( 1 ), crg::PipelineStageFlags::eAllGraphics }, VkQueue{} ) )\n\t\tcheckEqual( graph.getFinalLayoutState( sampledv, 0u ).layout,  crg::ImageLayout::eShaderReadOnly )\n\t\tcheckEqual( graph.getDefaultGroup().getFinalLayoutState( sampledv, 0u ).layout,  crg::ImageLayout::eShaderReadOnly )\n\t\ttestEnd()\n\t}\n}\n\ntestSuiteMain()\n"
  },
  {
    "path": "vcpkg.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json\",\n  \"name\": \"rendergraph\",\n  \"version\": \"1.4.1\",\n  \"builtin-baseline\": \"e140b1fde236eb682b0d47f905e65008a191800f\",\n  \"dependencies\": [\n    \"vulkan-headers\"\n  ],\n  \"features\": {\n    \"tests\": {\n      \"description\": \"Unit tests.\",\n      \"dependencies\": [\n        \"fmt\",\n        \"gtest\"\n      ]\n    }\n  }\n}\n"
  }
]