diff --git a/.gitmodules b/.gitmodules index e0aaf2d17c340f98ae875f7e0f1238bfe04f7e5d..cfa32fb462987b3e2f4ffec40caaae37b0ed7285 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,9 @@ [submodule "modules/gui/lib/imgui"] path = modules/gui/lib/imgui url = https://github.com/ocornut/imgui.git +[submodule "lib/VulkanMemoryAllocator"] + path = lib/VulkanMemoryAllocator + url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git +[submodule "lib/VulkanMemoryAllocator-Hpp"] + path = lib/VulkanMemoryAllocator-Hpp + url = https://github.com/malte-v/VulkanMemoryAllocator-Hpp.git diff --git a/config/Libraries.cmake b/config/Libraries.cmake index ec014f84c820abf4988b070d5b733be08c377319..b0684091d59b659c712aeacecd91e200351e0117 100644 --- a/config/Libraries.cmake +++ b/config/Libraries.cmake @@ -19,6 +19,7 @@ set(vkcv_config_msg " - Library: ") include(${vkcv_config_lib}/GLFW.cmake) # glfw-x11 / glfw-wayland # libglfw3-dev include(${vkcv_config_lib}/Vulkan.cmake) # vulkan-intel / vulkan-radeon / nvidia # libvulkan-dev include(${vkcv_config_lib}/SPIRV_Cross.cmake) # SPIRV-Cross # libspirv_cross_c_shared +include(${vkcv_config_lib}/VulkanMemoryAllocator.cmake) # VulkanMemoryAllocator # cleanup of compiler flags if (vkcv_flags) diff --git a/config/lib/GLFW.cmake b/config/lib/GLFW.cmake index 1b68d8aa97ba59158a7bd805ab2470f554f705aa..9668694de5b6887c163f74b626c71873e3f611f8 100644 --- a/config/lib/GLFW.cmake +++ b/config/lib/GLFW.cmake @@ -10,6 +10,7 @@ else() add_subdirectory(${vkcv_lib}/glfw) list(APPEND vkcv_libraries glfw) + list(APPEND vkcv_includes ${vkcv_lib_path}/glfw/include) message(${vkcv_config_msg} " GLFW - " ${glfw3_VERSION}) else() diff --git a/config/lib/SPIRV_Cross.cmake b/config/lib/SPIRV_Cross.cmake index 2e705d7d5a006e3851d14d22a57fd667c61c79f5..00ae45527d0f49c5632d71e19509871d437ae691 100644 --- a/config/lib/SPIRV_Cross.cmake +++ b/config/lib/SPIRV_Cross.cmake @@ -25,6 +25,7 @@ else() add_subdirectory(${vkcv_lib}/SPIRV-Cross) list(APPEND vkcv_libraries spirv-cross-cpp) + list(APPEND vkcv_includes ${vkcv_lib_path}/SPIV-Cross/include) message(${vkcv_config_msg} " SPIRV Cross - " ${SPIRV_CROSS_VERSION}) else() diff --git a/config/lib/VulkanMemoryAllocator.cmake b/config/lib/VulkanMemoryAllocator.cmake new file mode 100644 index 0000000000000000000000000000000000000000..5f670ff04633e1747accb8f1598fee028a287168 --- /dev/null +++ b/config/lib/VulkanMemoryAllocator.cmake @@ -0,0 +1,22 @@ + +if (EXISTS "${vkcv_lib_path}/VulkanMemoryAllocator-Hpp") + set(VMA_HPP_PATH "${vkcv_lib_path}/VulkanMemoryAllocator-Hpp" CACHE INTERNAL "") + + set(VMA_RECORDING_ENABLED OFF CACHE INTERNAL "") + set(VMA_USE_STL_CONTAINERS OFF CACHE INTERNAL "") + set(VMA_STATIC_VULKAN_FUNCTIONS ON CACHE INTERNAL "") + set(VMA_DYNAMIC_VULKAN_FUNCTIONS OFF CACHE INTERNAL "") + set(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY OFF CACHE INTERNAL "") + set(VMA_DEBUG_INITIALIZE_ALLOCATIONS OFF CACHE INTERNAL "") + set(VMA_DEBUG_GLOBAL_MUTEX OFF CACHE INTERNAL "") + set(VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT OFF CACHE INTERNAL "") + + add_subdirectory(${vkcv_config_lib}/vma) + + list(APPEND vkcv_libraries VulkanMemoryAllocator) + list(APPEND vkcv_includes ${vkcv_lib_path}/VulkanMemoryAllocator-Hpp) + + message(${vkcv_config_msg} " VMA - ") +else() + message(WARNING "VulkanMemoryAllocator is required..! Update the submodules!") +endif () diff --git a/config/lib/vma/CMakeLists.txt b/config/lib/vma/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2c018f2b4894e5ce8e2851ca10f981e2af36605 --- /dev/null +++ b/config/lib/vma/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.9) + +project(VulkanMemoryAllocator) + +find_package(Vulkan REQUIRED) + +option(VMA_HPP_PATH "Location of C++ headers" "") + +message(STATUS "VMA_BUILD_SAMPLE = ${VMA_BUILD_SAMPLE}") +message(STATUS "VMA_BUILD_SAMPLE_SHADERS = ${VMA_BUILD_SAMPLE_SHADERS}") +message(STATUS "VMA_BUILD_REPLAY = ${VMA_BUILD_REPLAY}") + +option(VMA_RECORDING_ENABLED "Enable VMA memory recording for debugging" OFF) +option(VMA_USE_STL_CONTAINERS "Use C++ STL containers instead of VMA's containers" OFF) +option(VMA_STATIC_VULKAN_FUNCTIONS "Link statically with Vulkan API" OFF) +option(VMA_DYNAMIC_VULKAN_FUNCTIONS "Fetch pointers to Vulkan functions internally (no static linking)" ON) +option(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY "Every allocation will have its own memory block" OFF) +option(VMA_DEBUG_INITIALIZE_ALLOCATIONS "Automatically fill new allocations and destroyed allocations with some bit pattern" OFF) +option(VMA_DEBUG_GLOBAL_MUTEX "Enable single mutex protecting all entry calls to the library" OFF) +option(VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT "Never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount and return error" OFF) + +message(STATUS "VMA_RECORDING_ENABLED = ${VMA_RECORDING_ENABLED}") +message(STATUS "VMA_USE_STL_CONTAINERS = ${VMA_USE_STL_CONTAINERS}") +message(STATUS "VMA_DYNAMIC_VULKAN_FUNCTIONS = ${VMA_DYNAMIC_VULKAN_FUNCTIONS}") +message(STATUS "VMA_DEBUG_ALWAYS_DEDICATED_MEMORY = ${VMA_DEBUG_ALWAYS_DEDICATED_MEMORY}") +message(STATUS "VMA_DEBUG_INITIALIZE_ALLOCATIONS = ${VMA_DEBUG_INITIALIZE_ALLOCATIONS}") +message(STATUS "VMA_DEBUG_GLOBAL_MUTEX = ${VMA_DEBUG_GLOBAL_MUTEX}") +message(STATUS "VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT = ${VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT}") + +add_library(VulkanMemoryAllocator vma.cpp) + +set_target_properties( + VulkanMemoryAllocator PROPERTIES + + CXX_EXTENSIONS OFF + # Use C++14 + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON +) + +target_include_directories(VulkanMemoryAllocator PUBLIC ${VMA_HPP_PATH}) + +# Only link to Vulkan if static linking is used +if (NOT ${VMA_DYNAMIC_VULKAN_FUNCTIONS}) + target_link_libraries(VulkanMemoryAllocator PUBLIC Vulkan::Vulkan) +endif() + +target_compile_definitions( + VulkanMemoryAllocator + + PUBLIC + VMA_USE_STL_CONTAINERS=$<BOOL:${VMA_USE_STL_CONTAINERS}> + VMA_DYNAMIC_VULKAN_FUNCTIONS=$<BOOL:${VMA_DYNAMIC_VULKAN_FUNCTIONS}> + VMA_DEBUG_ALWAYS_DEDICATED_MEMORY=$<BOOL:${VMA_DEBUG_ALWAYS_DEDICATED_MEMORY}> + VMA_DEBUG_INITIALIZE_ALLOCATIONS=$<BOOL:${VMA_DEBUG_INITIALIZE_ALLOCATIONS}> + VMA_DEBUG_GLOBAL_MUTEX=$<BOOL:${VMA_DEBUG_GLOBAL_MUTEX}> + VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT=$<BOOL:${VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT}> + VMA_RECORDING_ENABLED=$<BOOL:${VMA_RECORDING_ENABLED}> +) diff --git a/config/lib/vma/vma.cpp b/config/lib/vma/vma.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0928b552c10e23914054c44b8de43df722aa2cf0 --- /dev/null +++ b/config/lib/vma/vma.cpp @@ -0,0 +1,7 @@ + +#ifndef NDEBUG +#define _DEBUG +#endif + +#define VMA_IMPLEMENTATION +#include "vk_mem_alloc.hpp" diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index 9eb80d70862a79a01593e6fe4c3aabe98d253ac8..c7f32d9f134108bafa87ff493bca4e113d53003a 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -2,6 +2,7 @@ #include <vector> #include <vulkan/vulkan.hpp> +#include <vk_mem_alloc.hpp> #include "Handles.hpp" @@ -30,9 +31,8 @@ namespace vkcv struct Buffer { vk::Buffer m_handle; - vk::DeviceMemory m_memory; + vma::Allocation m_allocation; size_t m_size = 0; - void* m_mapped = nullptr; bool m_mappable = false; }; diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp index 1c01a6134ba1642b3a130a7a4d3d299cc3f7b875..2ecd9203701510837f49d10c1879efd4890145e9 100644 --- a/include/vkcv/Context.hpp +++ b/include/vkcv/Context.hpp @@ -1,6 +1,7 @@ #pragma once #include <vulkan/vulkan.hpp> +#include <vk_mem_alloc.hpp> #include "QueueManager.hpp" @@ -32,6 +33,9 @@ namespace vkcv [[nodiscard]] const QueueManager& getQueueManager() const; + + [[nodiscard]] + const vma::Allocator& getAllocator() const; static Context create(const char *applicationName, uint32_t applicationVersion, @@ -47,11 +51,14 @@ namespace vkcv * @param physicalDevice Vulkan-PhysicalDevice * @param device Vulkan-Device */ - Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, QueueManager&& queueManager) noexcept; + Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, + QueueManager&& queueManager, vma::Allocator&& allocator) noexcept; vk::Instance m_Instance; vk::PhysicalDevice m_PhysicalDevice; vk::Device m_Device; QueueManager m_QueueManager; + vma::Allocator m_Allocator; + }; } diff --git a/lib/VulkanMemoryAllocator-Hpp b/lib/VulkanMemoryAllocator-Hpp new file mode 160000 index 0000000000000000000000000000000000000000..eae6e8d3bd4593e0d7071c85fba2a8f33fbe5dab --- /dev/null +++ b/lib/VulkanMemoryAllocator-Hpp @@ -0,0 +1 @@ +Subproject commit eae6e8d3bd4593e0d7071c85fba2a8f33fbe5dab diff --git a/projects/first_mesh/CMakeLists.txt b/projects/first_mesh/CMakeLists.txt index eb0f028db38707272f9fbcf61662633f2868eedc..6455e75d88eee276fb89b9f7a1b3462fcbc54da2 100644 --- a/projects/first_mesh/CMakeLists.txt +++ b/projects/first_mesh/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) +target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) +target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler) diff --git a/projects/first_mesh/resources/shaders/compile.bat b/projects/first_mesh/resources/shaders/compile.bat deleted file mode 100644 index b4521235c40fe5fb163bab874560c2f219b7517f..0000000000000000000000000000000000000000 --- a/projects/first_mesh/resources/shaders/compile.bat +++ /dev/null @@ -1,3 +0,0 @@ -%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv -%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv -pause \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/frag.spv b/projects/first_mesh/resources/shaders/frag.spv deleted file mode 100644 index 087e4e22fb2fcec27d99b3ff2aa1a705fe755796..0000000000000000000000000000000000000000 Binary files a/projects/first_mesh/resources/shaders/frag.spv and /dev/null differ diff --git a/projects/first_mesh/resources/shaders/vert.spv b/projects/first_mesh/resources/shaders/vert.spv deleted file mode 100644 index 374c023e14b351eb43cbcda5951cbb8b3d6f96a1..0000000000000000000000000000000000000000 Binary files a/projects/first_mesh/resources/shaders/vert.spv and /dev/null differ diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 44a370be228be32f2e9d95685bb5297401605945..731d3e56975ff0cd2d8e6d503a19d56de1b922fe 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -4,6 +4,7 @@ #include <vkcv/camera/CameraManager.hpp> #include <chrono> #include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> int main(int argc, const char** argv) { const char* applicationName = "First Mesh"; @@ -77,10 +78,19 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::ShaderProgram firstMeshProgram{}; - firstMeshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); - firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + vkcv::ShaderProgram firstMeshProgram; + vkcv::shader::GLSLCompiler compiler; + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), + [&firstMeshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + firstMeshProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), + [&firstMeshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + firstMeshProgram.addShader(shaderStage, path); + }); + auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; diff --git a/projects/first_scene/CMakeLists.txt b/projects/first_scene/CMakeLists.txt index 467663dcb916da78d0625a33c6c88a1af3403af7..ba2f7b1a7ae4845a12b9701269361a0a3f8affb7 100644 --- a/projects/first_scene/CMakeLists.txt +++ b/projects/first_scene/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include}) +target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene) +target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene vkcv_shader_compiler) diff --git a/projects/first_scene/resources/shaders/compile.bat b/projects/first_scene/resources/shaders/compile.bat deleted file mode 100644 index b4521235c40fe5fb163bab874560c2f219b7517f..0000000000000000000000000000000000000000 --- a/projects/first_scene/resources/shaders/compile.bat +++ /dev/null @@ -1,3 +0,0 @@ -%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv -%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv -pause \ No newline at end of file diff --git a/projects/first_scene/resources/shaders/frag.spv b/projects/first_scene/resources/shaders/frag.spv deleted file mode 100644 index 087e4e22fb2fcec27d99b3ff2aa1a705fe755796..0000000000000000000000000000000000000000 Binary files a/projects/first_scene/resources/shaders/frag.spv and /dev/null differ diff --git a/projects/first_scene/resources/shaders/vert.spv b/projects/first_scene/resources/shaders/vert.spv deleted file mode 100644 index 374c023e14b351eb43cbcda5951cbb8b3d6f96a1..0000000000000000000000000000000000000000 Binary files a/projects/first_scene/resources/shaders/vert.spv and /dev/null differ diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 486b21343926e1b922b73ba8ffb29428de6ea9a7..527eba8c3a1e020e14d92f5d305e2ddced936333 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -4,11 +4,9 @@ #include <vkcv/camera/CameraManager.hpp> #include <chrono> #include <vkcv/asset/asset_loader.hpp> -#include <vkcv/Logger.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/scene/Scene.hpp> - - int main(int argc, const char** argv) { const char* applicationName = "First Scene"; @@ -64,9 +62,18 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::ShaderProgram sceneShaderProgram{}; - sceneShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); - sceneShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + vkcv::ShaderProgram sceneShaderProgram; + vkcv::shader::GLSLCompiler compiler; + + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), + [&sceneShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + sceneShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), + [&sceneShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + sceneShaderProgram.addShader(shaderStage, path); + }); const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; diff --git a/projects/first_triangle/shaders/comp.spv b/projects/first_triangle/shaders/comp.spv deleted file mode 100644 index b414e36b2bea66dab00746298e536d029091e0fd..0000000000000000000000000000000000000000 Binary files a/projects/first_triangle/shaders/comp.spv and /dev/null differ diff --git a/projects/first_triangle/shaders/compile.bat b/projects/first_triangle/shaders/compile.bat deleted file mode 100644 index 17743a7c49cdfc6e091c43a42a0adb755a731682..0000000000000000000000000000000000000000 --- a/projects/first_triangle/shaders/compile.bat +++ /dev/null @@ -1,4 +0,0 @@ -%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv -%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv -%VULKAN_SDK%\Bin32\glslc.exe shader.comp -o comp.spv -pause \ No newline at end of file diff --git a/projects/first_triangle/shaders/frag.spv b/projects/first_triangle/shaders/frag.spv deleted file mode 100644 index cb13e606fc0041e24ff6a63c0ec7dcca466732aa..0000000000000000000000000000000000000000 Binary files a/projects/first_triangle/shaders/frag.spv and /dev/null differ diff --git a/projects/first_triangle/shaders/shader.comp b/projects/first_triangle/shaders/shader.comp deleted file mode 100644 index fad6cd0815f2f09bf92dcc3171e2e3723f5466df..0000000000000000000000000000000000000000 --- a/projects/first_triangle/shaders/shader.comp +++ /dev/null @@ -1,25 +0,0 @@ -#version 440 - -layout(std430, binding = 0) buffer testBuffer -{ - float test1[10]; - float test2[10]; - float test3[10]; -}; - -layout( push_constant ) uniform constants{ - float pushConstant; -}; - -layout(local_size_x = 5) in; - -void main(){ - - if(gl_GlobalInvocationID.x >= 10){ - return; - } - - test1[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; - test2[gl_GlobalInvocationID.x] = 69; // nice! - test3[gl_GlobalInvocationID.x] = pushConstant; -} \ No newline at end of file diff --git a/projects/first_triangle/shaders/vert.spv b/projects/first_triangle/shaders/vert.spv deleted file mode 100644 index 03af5758ffff1b5b6505fe98b02044849026832d..0000000000000000000000000000000000000000 Binary files a/projects/first_triangle/shaders/vert.spv and /dev/null differ diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index a69f9bc755f9cfa3a75d0a51dd242876aedabf79..253efad491e6e320ba5e5e8b270b187e2e79da82 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -2,10 +2,8 @@ #include <vkcv/Core.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> -#include <chrono> - #include <vkcv/shader/GLSLCompiler.hpp> -#include <vkcv/gui/GUI.hpp> +#include <chrono> int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; @@ -49,7 +47,7 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::ShaderProgram triangleShaderProgram{}; + vkcv::ShaderProgram triangleShaderProgram; vkcv::shader::GLSLCompiler compiler; compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/shader.vert"), diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index aec96411c5d9e07f200b24fbdcf9fa69e2af53d5..cfa233290b89702f196ed97c706254e002a0551b 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -28,32 +28,6 @@ namespace vkcv { } } - /** - * @brief searches memory type index for buffer allocation, combines requirements of buffer and application - * @param physicalMemoryProperties Memory Properties of physical device - * @param typeBits Bit field for suitable memory types - * @param requirements Property flags that are required - * @return memory type index for Buffer - */ - uint32_t searchBufferMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) { - const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount; - for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) { - const uint32_t memoryTypeBits = (1 << memoryIndex); - const bool isRequiredMemoryType = typeBits & memoryTypeBits; - - const vk::MemoryPropertyFlags properties = - physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags; - const bool hasRequiredProperties = - (properties & requirements) == requirements; - - if (isRequiredMemoryType && hasRequiredProperties) - return static_cast<int32_t>(memoryIndex); - } - - // failed to find memory type - return -1; - } - BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) { vk::BufferCreateFlags createFlags; vk::BufferUsageFlags usageFlags; @@ -83,43 +57,48 @@ namespace vkcv { usageFlags |= vk::BufferUsageFlagBits::eTransferDst; } - const vk::Device& device = m_core->getContext().getDevice(); - - vk::Buffer buffer = device.createBuffer( - vk::BufferCreateInfo(createFlags, size, usageFlags) - ); - - const vk::MemoryRequirements requirements = device.getBufferMemoryRequirements(buffer); - const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); vk::MemoryPropertyFlags memoryTypeFlags; + vma::MemoryUsage memoryUsage; bool mappable = false; switch (memoryType) { case BufferMemoryType::DEVICE_LOCAL: memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; + memoryUsage = vma::MemoryUsage::eGpuOnly; + mappable = false; break; case BufferMemoryType::HOST_VISIBLE: memoryTypeFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + memoryUsage = vma::MemoryUsage::eCpuOnly; mappable = true; break; default: - // TODO: maybe an issue + vkcv_log(LogLevel::WARNING, "Unknown buffer memory type"); + memoryUsage = vma::MemoryUsage::eUnknown; + mappable = false; break; } - const uint32_t memoryTypeIndex = searchBufferMemoryType( - physicalDevice.getMemoryProperties(), - requirements.memoryTypeBits, - memoryTypeFlags + auto bufferAllocation = allocator.createBuffer( + vk::BufferCreateInfo(createFlags, size, usageFlags), + vma::AllocationCreateInfo( + vma::AllocationCreateFlags(), + memoryUsage, + memoryTypeFlags, + memoryTypeFlags, + 0, + vma::Pool(), + nullptr + ) ); - vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); - - device.bindBufferMemory(buffer, memory, 0); + vk::Buffer buffer = bufferAllocation.first; + vma::Allocation allocation = bufferAllocation.second; const uint64_t id = m_buffers.size(); - m_buffers.push_back({ buffer, memory, size, nullptr, mappable }); + m_buffers.push_back({ buffer, allocation, size, mappable }); return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); } @@ -130,7 +109,7 @@ namespace vkcv { vk::Buffer buffer; vk::Buffer stagingBuffer; - vk::DeviceMemory stagingMemory; + vma::Allocation stagingAllocation; size_t stagingLimit; size_t stagingPosition; @@ -150,11 +129,11 @@ namespace vkcv { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); - const vk::Device& device = core->getContext().getDevice(); + const vma::Allocator& allocator = core->getContext().getAllocator(); - void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size); + void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size); - device.unmapMemory(info.stagingMemory); + allocator.unmapMemory(info.stagingAllocation); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Transfer; @@ -216,7 +195,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - return buffer.m_memory; + const vma::Allocator& allocator = m_core->getContext().getAllocator(); + + auto info = allocator.getAllocationInfo( + buffer.m_allocation + ); + + return info.deviceMemory; } void BufferManager::fillBuffer(const BufferHandle& handle, const void *data, size_t size, size_t offset) { @@ -232,11 +217,7 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped) { - return; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -245,9 +226,9 @@ namespace vkcv { const size_t max_size = std::min(size, buffer.m_size - offset); if (buffer.m_mappable) { - void* mapped = device.mapMemory(buffer.m_memory, offset, max_size); - memcpy(mapped, data, max_size); - device.unmapMemory(buffer.m_memory); + void* mapped = allocator.mapMemory(buffer.m_allocation); + memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size); + allocator.unmapMemory(buffer.m_allocation); } else { auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; @@ -258,11 +239,9 @@ namespace vkcv { info.buffer = buffer.m_handle; info.stagingBuffer = stagingBuffer.m_handle; - info.stagingMemory = stagingBuffer.m_memory; + info.stagingAllocation = stagingBuffer.m_allocation; - const vk::MemoryRequirements stagingRequirements = device.getBufferMemoryRequirements(stagingBuffer.m_handle); - - info.stagingLimit = stagingRequirements.size; + info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; copyFromStagingBuffer(m_core, info); @@ -282,19 +261,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped) { - return nullptr; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (offset > buffer.m_size) { return nullptr; } - const size_t max_size = std::min(size, buffer.m_size - offset); - buffer.m_mapped = device.mapMemory(buffer.m_memory, offset, max_size); - return buffer.m_mapped; + return reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation)) + offset; } void BufferManager::unmapBuffer(const BufferHandle& handle) { @@ -306,14 +279,9 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped == nullptr) { - return; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); - device.unmapMemory(buffer.m_memory); - buffer.m_mapped = nullptr; + allocator.unmapMemory(buffer.m_allocation); } void BufferManager::destroyBufferById(uint64_t id) { @@ -323,16 +291,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - const vk::Device& device = m_core->getContext().getDevice(); - - if (buffer.m_memory) { - device.freeMemory(buffer.m_memory); - buffer.m_memory = nullptr; - } + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (buffer.m_handle) { - device.destroyBuffer(buffer.m_handle); + allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); + buffer.m_handle = nullptr; + buffer.m_allocation = nullptr; } } diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index e23213b41a3c9a289b679652b66bbe2e75cf0340..5db50869498600fa8e926c0feff2cb5fda1eb22e 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -9,11 +9,13 @@ namespace vkcv m_Instance(other.m_Instance), m_PhysicalDevice(other.m_PhysicalDevice), m_Device(other.m_Device), - m_QueueManager(other.m_QueueManager) + m_QueueManager(other.m_QueueManager), + m_Allocator(other.m_Allocator) { other.m_Instance = nullptr; other.m_PhysicalDevice = nullptr; other.m_Device = nullptr; + other.m_Allocator = nullptr; } Context & Context::operator=(Context &&other) noexcept @@ -22,10 +24,12 @@ namespace vkcv m_PhysicalDevice = other.m_PhysicalDevice; m_Device = other.m_Device; m_QueueManager = other.m_QueueManager; + m_Allocator = other.m_Allocator; other.m_Instance = nullptr; other.m_PhysicalDevice = nullptr; other.m_Device = nullptr; + other.m_Allocator = nullptr; return *this; } @@ -33,15 +37,18 @@ namespace vkcv Context::Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, - QueueManager&& queueManager) noexcept : - m_Instance{instance}, - m_PhysicalDevice{physicalDevice}, - m_Device{device}, - m_QueueManager{queueManager} + QueueManager&& queueManager, + vma::Allocator&& allocator) noexcept : + m_Instance(instance), + m_PhysicalDevice(physicalDevice), + m_Device(device), + m_QueueManager(queueManager), + m_Allocator(allocator) {} Context::~Context() noexcept { + m_Allocator.destroy(); m_Device.destroy(); m_Instance.destroy(); } @@ -64,6 +71,10 @@ namespace vkcv const QueueManager& Context::getQueueManager() const { return m_QueueManager; } + + const vma::Allocator& Context::getAllocator() const { + return m_Allocator; + } /** * @brief The physical device is evaluated by three categories: @@ -290,9 +301,44 @@ namespace vkcv vk::Device device = physicalDevice.createDevice(deviceCreateInfo); - QueueManager queueManager = QueueManager::create(device, queuePairsGraphics, queuePairsCompute, queuePairsTransfer); + QueueManager queueManager = QueueManager::create( + device, + queuePairsGraphics, + queuePairsCompute, + queuePairsTransfer + ); + + const vma::AllocatorCreateInfo allocatorCreateInfo ( + vma::AllocatorCreateFlags(), + physicalDevice, + device, + 0, + nullptr, + nullptr, + 0, + nullptr, + nullptr, + nullptr, + instance, + + /* Uses default version when set to 0 (currently VK_VERSION_1_0): + * + * The reason for this is that the allocator restricts the allowed version + * to be at maximum VK_VERSION_1_1 which is already less than + * VK_HEADER_VERSION_COMPLETE at most platforms. + * */ + 0 + ); + + vma::Allocator allocator = vma::createAllocator(allocatorCreateInfo); - return Context(instance, physicalDevice, device, std::move(queueManager)); + return Context( + instance, + physicalDevice, + device, + std::move(queueManager), + std::move(allocator) + ); } } diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index ba96cf8ff1be1988dbaf3f9cb01bdaa96c84ac0b..1cb6ad3a1187c08cf1aa014ae4ae259591f5c786 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -12,26 +12,6 @@ namespace vkcv { - ImageManager::Image::Image( - vk::Image handle, - vk::DeviceMemory memory, - std::vector<vk::ImageView> views, - uint32_t width, - uint32_t height, - uint32_t depth, - vk::Format format, - uint32_t layers) - : - m_handle(handle), - m_memory(memory), - m_viewPerMip(views), - m_width(width), - m_height(height), - m_depth(depth), - m_format(format), - m_layers(layers) - {} - /** * @brief searches memory type index for image allocation, combines requirements of image and application * @param physicalMemoryProperties Memory Properties of physical device @@ -124,7 +104,7 @@ namespace vkcv { imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); vk::ImageType imageType = vk::ImageType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D; @@ -158,7 +138,7 @@ namespace vkcv { vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa); - const vk::ImageCreateInfo imageCreateInfo( + const vk::ImageCreateInfo imageCreateInfo ( createFlags, imageType, format, @@ -172,21 +152,22 @@ namespace vkcv { {}, vk::ImageLayout::eUndefined ); - - vk::Image image = device.createImage(imageCreateInfo); - const vk::MemoryRequirements requirements = device.getImageMemoryRequirements(image); - - vk::MemoryPropertyFlags memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; - - const uint32_t memoryTypeIndex = searchImageMemoryType( - physicalDevice.getMemoryProperties(), - requirements.memoryTypeBits, - memoryTypeFlags + auto imageAllocation = allocator.createImage( + imageCreateInfo, + vma::AllocationCreateInfo( + vma::AllocationCreateFlags(), + vma::MemoryUsage::eGpuOnly, + vk::MemoryPropertyFlagBits::eDeviceLocal, + vk::MemoryPropertyFlagBits::eDeviceLocal, + 0, + vma::Pool(), + nullptr + ) ); - vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); - device.bindImageMemory(image, memory, 0); + vk::Image image = imageAllocation.first; + vma::Allocation allocation = imageAllocation.second; vk::ImageAspectFlags aspectFlags; @@ -196,6 +177,8 @@ namespace vkcv { aspectFlags = vk::ImageAspectFlagBits::eColor; } + const vk::Device& device = m_core->getContext().getDevice(); + std::vector<vk::ImageView> views; for (uint32_t mip = 0; mip < mipCount; mip++) { const vk::ImageViewCreateInfo imageViewCreateInfo( @@ -222,11 +205,11 @@ namespace vkcv { } const uint64_t id = m_images.size(); - m_images.push_back(Image(image, memory, views, width, height, depth, format, arrayLayers)); + m_images.push_back({ image, allocation, views, width, height, depth, format, arrayLayers, vk::ImageLayout::eUndefined }); return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); } - ImageHandle ImageManager::createSwapchainImage() { + ImageHandle ImageManager::createSwapchainImage() const { return ImageHandle::createSwapchainImageHandle(); } @@ -262,10 +245,16 @@ namespace vkcv { auto& image = m_images[id]; - return image.m_memory; + const vma::Allocator& allocator = m_core->getContext().getAllocator(); + + auto info = allocator.getAllocationInfo( + image.m_allocation + ); + + return info.deviceMemory; } - vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, const size_t mipLevel) const { + vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel) const { if (handle.isSwapchainImage()) { return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0]; @@ -626,15 +615,14 @@ namespace vkcv { view = nullptr; } } - - if (image.m_memory) { - device.freeMemory(image.m_memory); - image.m_memory = nullptr; - } + + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (image.m_handle) { - device.destroyImage(image.m_handle); + allocator.destroyImage(image.m_handle, image.m_allocation); + image.m_handle = nullptr; + image.m_allocation = nullptr; } } @@ -670,11 +658,11 @@ namespace vkcv { m_currentSwapchainInputImage = index; } - void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, + void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, uint32_t width, uint32_t height, vk::Format format) { // destroy old views - for (auto image : m_swapchainImages) { + for (const auto& image : m_swapchainImages) { for (const auto& view : image.m_viewPerMip) { m_core->getContext().getDevice().destroyImageView(view); } @@ -683,7 +671,17 @@ namespace vkcv { assert(images.size() == views.size()); m_swapchainImages.clear(); for (size_t i = 0; i < images.size(); i++) { - m_swapchainImages.push_back(Image(images[i], nullptr, { views[i] }, width, height, 1, format, 1)); + m_swapchainImages.push_back({ + images[i], + nullptr, + { views[i] }, + width, + height, + 1, + format, + 1, + vk::ImageLayout::eUndefined + }); } } diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 9edd747141305a8a795a2ec8ada04f46e96c9852..646b3211f761f0c71596fc088b39b784d5f39a5c 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -6,6 +6,7 @@ */ #include <vector> #include <vulkan/vulkan.hpp> +#include <vk_mem_alloc.hpp> #include "vkcv/BufferManager.hpp" #include "vkcv/Handles.hpp" @@ -20,28 +21,16 @@ namespace vkcv { struct Image { vk::Image m_handle; - vk::DeviceMemory m_memory; + vma::Allocation m_allocation; std::vector<vk::ImageView> m_viewPerMip; - uint32_t m_width = 0; - uint32_t m_height = 0; - uint32_t m_depth = 0; + uint32_t m_width; + uint32_t m_height; + uint32_t m_depth; vk::Format m_format; - uint32_t m_layers = 1; - vk::ImageLayout m_layout = vk::ImageLayout::eUndefined; + uint32_t m_layers; + vk::ImageLayout m_layout; private: - // struct is public so utility functions can access members, but only ImageManager can create Image friend ImageManager; - Image( - vk::Image handle, - vk::DeviceMemory memory, - std::vector<vk::ImageView> views, - uint32_t width, - uint32_t height, - uint32_t depth, - vk::Format format, - uint32_t layers); - - Image(); }; private: @@ -52,7 +41,7 @@ namespace vkcv { std::vector<Image> m_swapchainImages; int m_currentSwapchainInputImage; - ImageManager(BufferManager& bufferManager) noexcept; + explicit ImageManager(BufferManager& bufferManager) noexcept; /** * Destroys and deallocates image represented by a given @@ -82,7 +71,8 @@ namespace vkcv { bool supportColorAttachment, Multisampling msaa); - ImageHandle createSwapchainImage(); + [[nodiscard]] + ImageHandle createSwapchainImage() const; [[nodiscard]] vk::Image getVulkanImage(const ImageHandle& handle) const; @@ -91,7 +81,7 @@ namespace vkcv { vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const; [[nodiscard]] - vk::ImageView getVulkanImageView(const ImageHandle& handle, const size_t mipLevel = 0) const; + vk::ImageView getVulkanImageView(const ImageHandle& handle, size_t mipLevel = 0) const; void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); void recordImageLayoutTransition( @@ -124,8 +114,9 @@ namespace vkcv { uint32_t getImageMipCount(const ImageHandle& handle) const; void setCurrentSwapchainImageIndex(int index); - void setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, - uint32_t width, uint32_t height, vk::Format format); + + void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, + uint32_t width, uint32_t height, vk::Format format); }; } \ No newline at end of file