diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab12c4c..c336e46 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,10 +33,10 @@ jobs: } # note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here: # (not that ubuntu-latest (20.04) only supports >= v1.2.148 via apt) - vulkan-sdk: ["latest", "1.3.216"] + vulkan-sdk: ["latest", "1.3.216", "1.2.198"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail - - vulkan-sdk: "1.2.176" + - vulkan-sdk: "1.3.204" vma: "ON" steps: @@ -91,7 +91,7 @@ jobs: shell: bash working-directory: ${{ runner.workspace }}/build # Execute the build. You can specify a specific target with "--target " - run: cmake --build . + run: cmake --build . --config $BUILD_TYPE windows: name: ${{ matrix.config.name }}, windows-2019, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} @@ -151,6 +151,9 @@ jobs: $env:CC="${{ matrix.config.cc }}" $env:CXX="${{ matrix.config.cxx }}" $env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\" + $env:VULKAN_SDK="${{ env.vulkan_sdk }}" + $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" + $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC ${{ runner.workspace }}/${{ github.event.repository.name }} -Davk_UseVMA=${{ matrix.vma }} -G "Visual Studio 16 2019" -A x64 @@ -160,7 +163,7 @@ jobs: # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build # Execute the build. You can specify a specific target with "--target " - run: cmake --build . + run: cmake --build . --config $BUILD_TYPE windows-latest: name: ${{ matrix.config.name }}, windows-latest, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} @@ -176,8 +179,8 @@ jobs: cc: "cl", cxx: "cl" } - # note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here: - vulkan-sdk: ["latest", "1.3.216.0", "1.2.198.1"] + # note: if a specific vulkan version needs testing, you can add it here: + vulkan-sdk: ["latest", "1.3.204.1", "1.3.216.0"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail - vulkan-sdk: "1.2.198" @@ -223,6 +226,9 @@ jobs: $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" $env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\" + $env:VULKAN_SDK="${{ env.vulkan_sdk }}" + $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" + $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC ${{ runner.workspace }}/${{ github.event.repository.name }} -Davk_UseVMA=${{ matrix.vma }} -G "Visual Studio 17 2022" -A x64 @@ -232,4 +238,4 @@ jobs: # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build # Execute the build. You can specify a specific target with "--target " - run: cmake --build . + run: cmake --build . --config $BUILD_TYPE diff --git a/README.md b/README.md index 7cc489a..3168498 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ I.e., the big, important concepts, which make Vulkan as performant as it can be- # Setup _Auto-Vk_ requires -* A Vulkan 1.2 SDK or a Vulkan 1.3 SDK +* A Vulkan 1.3 SDK * [Vulkan-Hpp](https://github.com/KhronosGroup/Vulkan-Hpp) * A C++20 compiler diff --git a/include/avk/commands.hpp b/include/avk/commands.hpp index 0d85fab..571fef2 100644 --- a/include/avk/commands.hpp +++ b/include/avk/commands.hpp @@ -630,6 +630,142 @@ namespace avk bind_vertex_buffer(aHandlePtr + 1, aOffsetPtr + 1, aRest...); } + /** Draw vertices with vertex buffer bindings starting at BUFFER-BINDING #0 top to the number of total buffers passed -1. + * "BUFFER-BINDING" means that it corresponds to the binding specified in `input_binding_location_data::from_buffer_at_binding`. + * There can be no gaps between buffer bindings. + * @param aFurtherBuffers Multiple const-references to buffers, or tuples of const-references to buffers + offsets. + * First case: Pass const buffer_t& types! + * Second case: Pass tuples of type std::tuple! + * Hint: std::forward_as_tuple might be useful to get that reference into a std::tuple. + * Example: avk::buffer myVertexBuffer; + * auto myTuple = std::forward_as_tuple(myVertexBuffer.get(), size_t{0}); + */ + template + action_type_command draw_vertices_indirect(const buffer_t& aParametersBuffer, vk::DeviceSize aParametersOffset, uint32_t aParametersStride, uint32_t aDrawCount, const Bfrs&... aFurtherBuffers) + { + constexpr size_t N = sizeof...(aFurtherBuffers); + + if constexpr (N == 0) { + return action_type_command{ + avk::sync::sync_hint { + {{ // DESTINATION dependencies for previous commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eInputAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // SOURCE dependencies for subsequent commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, // no resource-specific sync hints + [ + lParametersBufferHandle = aParametersBuffer.handle(), aParametersOffset, aParametersStride, aDrawCount + ](avk::command_buffer_t& cb) { + cb.handle().drawIndirect(lParametersBufferHandle, aParametersOffset, aDrawCount, aParametersStride); + } + }; + } + else { + std::array handles; + std::array offsets; + bind_vertex_buffer(&handles[0], &offsets[0], aFurtherBuffers...); + + return action_type_command{ + avk::sync::sync_hint { + {{ // DESTINATION dependencies for previous commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eInputAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // SOURCE dependencies for subsequent commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, // no resource-specific sync hints + [ + lBindingCount = static_cast(N), + lParametersBufferHandle = aParametersBuffer.handle(), aParametersOffset, aParametersStride, aDrawCount, + handles, offsets + ](avk::command_buffer_t& cb) { + cb.handle().bindVertexBuffers( + 0u, // TODO: Should the first binding really always be 0? + static_cast(N), handles.data(), offsets.data() + ); + cb.handle().drawIndirect(lParametersBufferHandle, aParametersOffset, aDrawCount, aParametersStride); + } + }; + } + } + + /** Draw vertices with vertex buffer bindings starting at BUFFER-BINDING #0 top to the number of total buffers passed -1. + * "BUFFER-BINDING" means that it corresponds to the binding specified in `input_binding_location_data::from_buffer_at_binding`. + * There can be no gaps between buffer bindings. + * @param aFurtherBuffers Multiple const-references to buffers, or tuples of const-references to buffers + offsets. + * First case: Pass const buffer_t& types! + * Second case: Pass tuples of type std::tuple! + * Hint: std::forward_as_tuple might be useful to get that reference into a std::tuple. + * Example: avk::buffer myVertexBuffer; + * auto myTuple = std::forward_as_tuple(myVertexBuffer.get(), size_t{0}); + */ + template + action_type_command draw_vertices_indirect_count(const buffer_t& aParametersBuffer, vk::DeviceSize aParametersOffset, uint32_t aParametersStride, const buffer_t& aDrawCountBuffer, vk::DeviceSize aDrawCountOffset, uint32_t aMaxNumberOfDraws, const Bfrs&... aFurtherBuffers) + { + constexpr size_t N = sizeof...(aFurtherBuffers); + + if constexpr (N == 0) { + return action_type_command{ + avk::sync::sync_hint { + {{ // DESTINATION dependencies for previous commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eInputAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // SOURCE dependencies for subsequent commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, // no resource-specific sync hints + [ + lParametersBufferHandle = aParametersBuffer.handle(), aParametersOffset, aParametersStride, + lDrawCountBufferHandle = aDrawCountBuffer.handle(), aDrawCountOffset, aMaxNumberOfDraws + ](avk::command_buffer_t& cb) { + cb.handle().drawIndirectCount(lParametersBufferHandle, aParametersOffset, lDrawCountBufferHandle, aDrawCountOffset, aMaxNumberOfDraws, aParametersStride); + } + }; + } + else { + std::array handles; + std::array offsets; + bind_vertex_buffer(&handles[0], &offsets[0], aFurtherBuffers...); + + return action_type_command{ + avk::sync::sync_hint { + {{ // DESTINATION dependencies for previous commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eInputAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // SOURCE dependencies for subsequent commands: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, // no resource-specific sync hints + [ + lBindingCount = static_cast(N), + lParametersBufferHandle = aParametersBuffer.handle(), aParametersOffset, aParametersStride, + lDrawCountBufferHandle = aDrawCountBuffer.handle(), aDrawCountOffset, aMaxNumberOfDraws, + handles, offsets + ](avk::command_buffer_t& cb) { + cb.handle().bindVertexBuffers( + 0u, // TODO: Should the first binding really always be 0? + static_cast(N), handles.data(), offsets.data() + ); + cb.handle().drawIndirectCount(lParametersBufferHandle, aParametersOffset, lDrawCountBufferHandle, aDrawCountOffset, aMaxNumberOfDraws, aParametersStride); + } + }; + } + } + /** Draw vertices with vertex buffer bindings starting at BUFFER-BINDING #0 top to the number of total buffers passed -1. * "BUFFER-BINDING" means that it corresponds to the binding specified in `input_binding_location_data::from_buffer_at_binding`. * There can be no gaps between buffer bindings. diff --git a/include/avk/cpp_utils.hpp b/include/avk/cpp_utils.hpp index f253c57..5020789 100644 --- a/include/avk/cpp_utils.hpp +++ b/include/avk/cpp_utils.hpp @@ -69,39 +69,28 @@ namespace avk } /** Load a binary file into memory. - * Adapted from: http://www.cplusplus.com/reference/istream/istream/read/ + * Adapted from: https://coniferproductions.com/posts/2022/10/25/reading-binary-files-cpp/ */ static std::vector load_binary_file(std::string path) { - std::vector buffer; - std::ifstream is(path.c_str(), std::ifstream::binary); - if (!is) { - throw avk::runtime_error("Couldn't load file '" + path + "'"); + try { + std::filesystem::path inputFilePath{path}; + auto length = std::filesystem::file_size(inputFilePath); + if (length == 0) { + throw avk::runtime_error("Couldn't load file '" + path + "'. It appears to be empty."); + } + std::vector buffer(((length + 3) / 4) * 4); + std::ifstream inputFile(path, std::ios_base::binary); + inputFile.read(reinterpret_cast(buffer.data()), length); + inputFile.close(); + return buffer; } - - // get length of file: - is.seekg(0, is.end); - size_t length = is.tellg(); - is.seekg(0, is.beg); - - buffer.resize(length); - - // read data as a block: - is.read(buffer.data(), length); - - if (!is) { - is.close(); - throw avk::runtime_error( - "Couldn't read file '" + path + "' into buffer. " + - "load_binary_file could only read " + std::to_string(is.gcount()) + " bytes instead of " + std::to_string(length) - ); + catch (std::filesystem::filesystem_error& e) + { + throw avk::runtime_error("Couldn't load file '" + path + "'. Reason: " + e.what()); } - - is.close(); - return buffer; } - static std::string trim_spaces(std::string_view s) { if (s.empty()) { diff --git a/src/avk.cpp b/src/avk.cpp index 1e65838..9f8a942 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -2901,12 +2901,15 @@ namespace avk void command_buffer_t::prepare_for_reuse() { if (mPostExecutionHandler.has_value()) { - // Clear post-execution handler + // If there is a post-execution handler => call it now: + invoke_post_execution_handler(); + // Clear post-execution handler: mPostExecutionHandler.reset(); } if (mCustomDeleter.has_value() && *mCustomDeleter) { - // If there is a custom deleter => call it now + // If there is a custom deleter => call it now: (*mCustomDeleter)(); + // Clear custom deleter: mCustomDeleter.reset(); } mLifetimeHandledResources.clear();