From b86291b9510aecdbaed0b6e12fd7716d172d65a8 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Mon, 1 Sep 2025 16:47:55 +0200 Subject: [PATCH] refactor: start refactoring core Vulkan abstractions --- .../core => .old/include}/descriptorset.hpp | 0 .../{ => .old}/include/pool/resourcepool.hpp | 0 .../{ => .old}/include/pool/shaderpool.hpp | 0 .../common => .old/include}/utils.hpp | 0 framegen/{ => .old}/public/lsfg_3_1.hpp | 0 framegen/{ => .old}/public/lsfg_3_1p.hpp | 0 framegen/{ => .old}/src/common/utils.cpp | 0 .../{ => .old}/src/core/descriptorset.cpp | 0 framegen/{ => .old}/src/pool/resourcepool.cpp | 0 framegen/{ => .old}/src/pool/shaderpool.cpp | 0 framegen/{ => .old2}/v3.1_src/context.cpp | 0 framegen/{ => .old2}/v3.1_src/lsfg.cpp | 0 .../{ => .old2}/v3.1_src/shaders/alpha.cpp | 0 .../{ => .old2}/v3.1_src/shaders/beta.cpp | 0 .../{ => .old2}/v3.1_src/shaders/delta.cpp | 0 .../{ => .old2}/v3.1_src/shaders/gamma.cpp | 0 .../{ => .old2}/v3.1_src/shaders/generate.cpp | 0 .../{ => .old2}/v3.1_src/shaders/mipmaps.cpp | 0 framegen/{ => .old2}/v3.1p_src/context.cpp | 0 framegen/{ => .old2}/v3.1p_src/lsfg.cpp | 0 .../{ => .old2}/v3.1p_src/shaders/alpha.cpp | 0 .../{ => .old2}/v3.1p_src/shaders/beta.cpp | 0 .../{ => .old2}/v3.1p_src/shaders/delta.cpp | 0 .../{ => .old2}/v3.1p_src/shaders/gamma.cpp | 0 .../v3.1p_src/shaders/generate.cpp | 0 .../{ => .old2}/v3.1p_src/shaders/mipmaps.cpp | 0 .../{v3.1_include => .old2}/v3_1/context.hpp | 0 .../v3_1/shaders/alpha.hpp | 0 .../v3_1/shaders/beta.hpp | 0 .../v3_1/shaders/delta.hpp | 0 .../v3_1/shaders/gamma.hpp | 0 .../v3_1/shaders/generate.hpp | 0 .../v3_1/shaders/mipmaps.hpp | 0 .../v3_1p/context.hpp | 0 .../v3_1p/shaders/alpha.hpp | 0 .../v3_1p/shaders/beta.hpp | 0 .../v3_1p/shaders/delta.hpp | 0 .../v3_1p/shaders/gamma.hpp | 0 .../v3_1p/shaders/generate.hpp | 0 .../v3_1p/shaders/mipmaps.hpp | 0 framegen/CMakeLists.txt | 22 +-- framegen/include/core/device.hpp | 57 ------ framegen/include/core/semaphore.hpp | 80 --------- framegen/include/{ => vk}/core/buffer.hpp | 24 ++- .../include/{ => vk}/core/commandbuffer.hpp | 45 +++-- .../include/{ => vk}/core/commandpool.hpp | 8 +- .../include/{ => vk}/core/descriptorpool.hpp | 8 +- framegen/include/vk/core/device.hpp | 75 ++++++++ framegen/include/{ => vk}/core/fence.hpp | 16 +- framegen/include/{ => vk}/core/image.hpp | 24 +-- framegen/include/{ => vk}/core/instance.hpp | 6 +- framegen/include/{ => vk}/core/pipeline.hpp | 18 +- framegen/include/{ => vk}/core/sampler.hpp | 12 +- framegen/include/vk/core/semaphore.hpp | 44 +++++ .../include/{ => vk}/core/shadermodule.hpp | 8 +- .../include/vk/core/timeline_semaphore.hpp | 67 +++++++ framegen/include/{common => vk}/exception.hpp | 2 +- framegen/src/core/device.cpp | 134 -------------- framegen/src/core/semaphore.cpp | 110 ------------ framegen/src/{ => vk}/core/buffer.cpp | 46 ++--- framegen/src/{ => vk}/core/commandbuffer.cpp | 36 ++-- framegen/src/{ => vk}/core/commandpool.cpp | 12 +- framegen/src/{ => vk}/core/descriptorpool.cpp | 14 +- framegen/src/vk/core/device.cpp | 169 ++++++++++++++++++ framegen/src/{ => vk}/core/fence.cpp | 24 +-- framegen/src/{ => vk}/core/image.cpp | 95 +++------- framegen/src/{ => vk}/core/instance.cpp | 12 +- framegen/src/{ => vk}/core/pipeline.cpp | 21 +-- framegen/src/{ => vk}/core/sampler.cpp | 16 +- framegen/src/vk/core/semaphore.cpp | 51 ++++++ framegen/src/{ => vk}/core/shadermodule.cpp | 20 +-- framegen/src/vk/core/timeline_semaphore.cpp | 62 +++++++ framegen/src/{common => vk}/exception.cpp | 4 +- 73 files changed, 686 insertions(+), 656 deletions(-) rename framegen/{include/core => .old/include}/descriptorset.hpp (100%) rename framegen/{ => .old}/include/pool/resourcepool.hpp (100%) rename framegen/{ => .old}/include/pool/shaderpool.hpp (100%) rename framegen/{include/common => .old/include}/utils.hpp (100%) rename framegen/{ => .old}/public/lsfg_3_1.hpp (100%) rename framegen/{ => .old}/public/lsfg_3_1p.hpp (100%) rename framegen/{ => .old}/src/common/utils.cpp (100%) rename framegen/{ => .old}/src/core/descriptorset.cpp (100%) rename framegen/{ => .old}/src/pool/resourcepool.cpp (100%) rename framegen/{ => .old}/src/pool/shaderpool.cpp (100%) rename framegen/{ => .old2}/v3.1_src/context.cpp (100%) rename framegen/{ => .old2}/v3.1_src/lsfg.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/alpha.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/beta.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/delta.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/gamma.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/generate.cpp (100%) rename framegen/{ => .old2}/v3.1_src/shaders/mipmaps.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/context.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/lsfg.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/alpha.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/beta.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/delta.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/gamma.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/generate.cpp (100%) rename framegen/{ => .old2}/v3.1p_src/shaders/mipmaps.cpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/context.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/alpha.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/beta.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/delta.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/gamma.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/generate.hpp (100%) rename framegen/{v3.1_include => .old2}/v3_1/shaders/mipmaps.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/context.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/alpha.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/beta.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/delta.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/gamma.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/generate.hpp (100%) rename framegen/{v3.1p_include => .old2}/v3_1p/shaders/mipmaps.hpp (100%) delete mode 100644 framegen/include/core/device.hpp delete mode 100644 framegen/include/core/semaphore.hpp rename framegen/include/{ => vk}/core/buffer.hpp (66%) rename framegen/include/{ => vk}/core/commandbuffer.hpp (71%) rename framegen/include/{ => vk}/core/commandpool.hpp (85%) rename framegen/include/{ => vk}/core/descriptorpool.hpp (85%) create mode 100644 framegen/include/vk/core/device.hpp rename framegen/include/{ => vk}/core/fence.hpp (74%) rename framegen/include/{ => vk}/core/image.hpp (81%) rename framegen/include/{ => vk}/core/instance.hpp (79%) rename framegen/include/{ => vk}/core/pipeline.hpp (70%) rename framegen/include/{ => vk}/core/sampler.hpp (80%) create mode 100644 framegen/include/vk/core/semaphore.hpp rename framegen/include/{ => vk}/core/shadermodule.hpp (87%) create mode 100644 framegen/include/vk/core/timeline_semaphore.hpp rename framegen/include/{common => vk}/exception.hpp (99%) delete mode 100644 framegen/src/core/device.cpp delete mode 100644 framegen/src/core/semaphore.cpp rename framegen/src/{ => vk}/core/buffer.cpp (54%) rename framegen/src/{ => vk}/core/commandbuffer.cpp (83%) rename framegen/src/{ => vk}/core/commandpool.cpp (75%) rename framegen/src/{ => vk}/core/descriptorpool.cpp (83%) create mode 100644 framegen/src/vk/core/device.cpp rename framegen/src/{ => vk}/core/fence.cpp (65%) rename framegen/src/{ => vk}/core/image.cpp (76%) rename framegen/src/{ => vk}/core/instance.cpp (83%) rename framegen/src/{ => vk}/core/pipeline.cpp (74%) rename framegen/src/{ => vk}/core/sampler.cpp (77%) create mode 100644 framegen/src/vk/core/semaphore.cpp rename framegen/src/{ => vk}/core/shadermodule.cpp (86%) create mode 100644 framegen/src/vk/core/timeline_semaphore.cpp rename framegen/src/{common => vk}/exception.cpp (92%) diff --git a/framegen/include/core/descriptorset.hpp b/framegen/.old/include/descriptorset.hpp similarity index 100% rename from framegen/include/core/descriptorset.hpp rename to framegen/.old/include/descriptorset.hpp diff --git a/framegen/include/pool/resourcepool.hpp b/framegen/.old/include/pool/resourcepool.hpp similarity index 100% rename from framegen/include/pool/resourcepool.hpp rename to framegen/.old/include/pool/resourcepool.hpp diff --git a/framegen/include/pool/shaderpool.hpp b/framegen/.old/include/pool/shaderpool.hpp similarity index 100% rename from framegen/include/pool/shaderpool.hpp rename to framegen/.old/include/pool/shaderpool.hpp diff --git a/framegen/include/common/utils.hpp b/framegen/.old/include/utils.hpp similarity index 100% rename from framegen/include/common/utils.hpp rename to framegen/.old/include/utils.hpp diff --git a/framegen/public/lsfg_3_1.hpp b/framegen/.old/public/lsfg_3_1.hpp similarity index 100% rename from framegen/public/lsfg_3_1.hpp rename to framegen/.old/public/lsfg_3_1.hpp diff --git a/framegen/public/lsfg_3_1p.hpp b/framegen/.old/public/lsfg_3_1p.hpp similarity index 100% rename from framegen/public/lsfg_3_1p.hpp rename to framegen/.old/public/lsfg_3_1p.hpp diff --git a/framegen/src/common/utils.cpp b/framegen/.old/src/common/utils.cpp similarity index 100% rename from framegen/src/common/utils.cpp rename to framegen/.old/src/common/utils.cpp diff --git a/framegen/src/core/descriptorset.cpp b/framegen/.old/src/core/descriptorset.cpp similarity index 100% rename from framegen/src/core/descriptorset.cpp rename to framegen/.old/src/core/descriptorset.cpp diff --git a/framegen/src/pool/resourcepool.cpp b/framegen/.old/src/pool/resourcepool.cpp similarity index 100% rename from framegen/src/pool/resourcepool.cpp rename to framegen/.old/src/pool/resourcepool.cpp diff --git a/framegen/src/pool/shaderpool.cpp b/framegen/.old/src/pool/shaderpool.cpp similarity index 100% rename from framegen/src/pool/shaderpool.cpp rename to framegen/.old/src/pool/shaderpool.cpp diff --git a/framegen/v3.1_src/context.cpp b/framegen/.old2/v3.1_src/context.cpp similarity index 100% rename from framegen/v3.1_src/context.cpp rename to framegen/.old2/v3.1_src/context.cpp diff --git a/framegen/v3.1_src/lsfg.cpp b/framegen/.old2/v3.1_src/lsfg.cpp similarity index 100% rename from framegen/v3.1_src/lsfg.cpp rename to framegen/.old2/v3.1_src/lsfg.cpp diff --git a/framegen/v3.1_src/shaders/alpha.cpp b/framegen/.old2/v3.1_src/shaders/alpha.cpp similarity index 100% rename from framegen/v3.1_src/shaders/alpha.cpp rename to framegen/.old2/v3.1_src/shaders/alpha.cpp diff --git a/framegen/v3.1_src/shaders/beta.cpp b/framegen/.old2/v3.1_src/shaders/beta.cpp similarity index 100% rename from framegen/v3.1_src/shaders/beta.cpp rename to framegen/.old2/v3.1_src/shaders/beta.cpp diff --git a/framegen/v3.1_src/shaders/delta.cpp b/framegen/.old2/v3.1_src/shaders/delta.cpp similarity index 100% rename from framegen/v3.1_src/shaders/delta.cpp rename to framegen/.old2/v3.1_src/shaders/delta.cpp diff --git a/framegen/v3.1_src/shaders/gamma.cpp b/framegen/.old2/v3.1_src/shaders/gamma.cpp similarity index 100% rename from framegen/v3.1_src/shaders/gamma.cpp rename to framegen/.old2/v3.1_src/shaders/gamma.cpp diff --git a/framegen/v3.1_src/shaders/generate.cpp b/framegen/.old2/v3.1_src/shaders/generate.cpp similarity index 100% rename from framegen/v3.1_src/shaders/generate.cpp rename to framegen/.old2/v3.1_src/shaders/generate.cpp diff --git a/framegen/v3.1_src/shaders/mipmaps.cpp b/framegen/.old2/v3.1_src/shaders/mipmaps.cpp similarity index 100% rename from framegen/v3.1_src/shaders/mipmaps.cpp rename to framegen/.old2/v3.1_src/shaders/mipmaps.cpp diff --git a/framegen/v3.1p_src/context.cpp b/framegen/.old2/v3.1p_src/context.cpp similarity index 100% rename from framegen/v3.1p_src/context.cpp rename to framegen/.old2/v3.1p_src/context.cpp diff --git a/framegen/v3.1p_src/lsfg.cpp b/framegen/.old2/v3.1p_src/lsfg.cpp similarity index 100% rename from framegen/v3.1p_src/lsfg.cpp rename to framegen/.old2/v3.1p_src/lsfg.cpp diff --git a/framegen/v3.1p_src/shaders/alpha.cpp b/framegen/.old2/v3.1p_src/shaders/alpha.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/alpha.cpp rename to framegen/.old2/v3.1p_src/shaders/alpha.cpp diff --git a/framegen/v3.1p_src/shaders/beta.cpp b/framegen/.old2/v3.1p_src/shaders/beta.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/beta.cpp rename to framegen/.old2/v3.1p_src/shaders/beta.cpp diff --git a/framegen/v3.1p_src/shaders/delta.cpp b/framegen/.old2/v3.1p_src/shaders/delta.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/delta.cpp rename to framegen/.old2/v3.1p_src/shaders/delta.cpp diff --git a/framegen/v3.1p_src/shaders/gamma.cpp b/framegen/.old2/v3.1p_src/shaders/gamma.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/gamma.cpp rename to framegen/.old2/v3.1p_src/shaders/gamma.cpp diff --git a/framegen/v3.1p_src/shaders/generate.cpp b/framegen/.old2/v3.1p_src/shaders/generate.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/generate.cpp rename to framegen/.old2/v3.1p_src/shaders/generate.cpp diff --git a/framegen/v3.1p_src/shaders/mipmaps.cpp b/framegen/.old2/v3.1p_src/shaders/mipmaps.cpp similarity index 100% rename from framegen/v3.1p_src/shaders/mipmaps.cpp rename to framegen/.old2/v3.1p_src/shaders/mipmaps.cpp diff --git a/framegen/v3.1_include/v3_1/context.hpp b/framegen/.old2/v3_1/context.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/context.hpp rename to framegen/.old2/v3_1/context.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/alpha.hpp b/framegen/.old2/v3_1/shaders/alpha.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/alpha.hpp rename to framegen/.old2/v3_1/shaders/alpha.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/beta.hpp b/framegen/.old2/v3_1/shaders/beta.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/beta.hpp rename to framegen/.old2/v3_1/shaders/beta.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/delta.hpp b/framegen/.old2/v3_1/shaders/delta.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/delta.hpp rename to framegen/.old2/v3_1/shaders/delta.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/gamma.hpp b/framegen/.old2/v3_1/shaders/gamma.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/gamma.hpp rename to framegen/.old2/v3_1/shaders/gamma.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/generate.hpp b/framegen/.old2/v3_1/shaders/generate.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/generate.hpp rename to framegen/.old2/v3_1/shaders/generate.hpp diff --git a/framegen/v3.1_include/v3_1/shaders/mipmaps.hpp b/framegen/.old2/v3_1/shaders/mipmaps.hpp similarity index 100% rename from framegen/v3.1_include/v3_1/shaders/mipmaps.hpp rename to framegen/.old2/v3_1/shaders/mipmaps.hpp diff --git a/framegen/v3.1p_include/v3_1p/context.hpp b/framegen/.old2/v3_1p/context.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/context.hpp rename to framegen/.old2/v3_1p/context.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/alpha.hpp b/framegen/.old2/v3_1p/shaders/alpha.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/alpha.hpp rename to framegen/.old2/v3_1p/shaders/alpha.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/beta.hpp b/framegen/.old2/v3_1p/shaders/beta.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/beta.hpp rename to framegen/.old2/v3_1p/shaders/beta.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/delta.hpp b/framegen/.old2/v3_1p/shaders/delta.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/delta.hpp rename to framegen/.old2/v3_1p/shaders/delta.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/gamma.hpp b/framegen/.old2/v3_1p/shaders/gamma.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/gamma.hpp rename to framegen/.old2/v3_1p/shaders/gamma.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/generate.hpp b/framegen/.old2/v3_1p/shaders/generate.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/generate.hpp rename to framegen/.old2/v3_1p/shaders/generate.hpp diff --git a/framegen/v3.1p_include/v3_1p/shaders/mipmaps.hpp b/framegen/.old2/v3_1p/shaders/mipmaps.hpp similarity index 100% rename from framegen/v3.1p_include/v3_1p/shaders/mipmaps.hpp rename to framegen/.old2/v3_1p/shaders/mipmaps.hpp diff --git a/framegen/CMakeLists.txt b/framegen/CMakeLists.txt index 9ac0787..f795a6d 100644 --- a/framegen/CMakeLists.txt +++ b/framegen/CMakeLists.txt @@ -14,22 +14,9 @@ project(lsfg-vk-framegen LANGUAGES C CXX) file(GLOB SOURCES - "src/common/*.cpp" - "src/config/*.cpp" - "src/core/*.cpp" - "src/pool/*.cpp" + "src/vk/core/*.cpp" + "src/vk/*.cpp" "src/*.cpp" - "v3.1_src/core/*.cpp" - "v3.1_src/pool/*.cpp" - "v3.1_src/shaders/*.cpp" - "v3.1_src/utils/*.cpp" - "v3.1_src/*.cpp" - "v3.1p_src/core/*.cpp" - "v3.1p_src/pool/*.cpp" - "v3.1p_src/shaders/*.cpp" - "v3.1p_src/utils/*.cpp" - "v3.1p_src/*.cpp" - "src/thirdparty/*.c" ) add_library(lsfg-vk-framegen STATIC ${SOURCES}) @@ -41,10 +28,7 @@ set_target_properties(lsfg-vk-framegen PROPERTIES target_include_directories(lsfg-vk-framegen SYSTEM PUBLIC include/thirdparty) target_include_directories(lsfg-vk-framegen - PUBLIC include - PUBLIC public - PRIVATE v3.1_include - PRIVATE v3.1p_include) + PUBLIC include) # diagnostics if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/framegen/include/core/device.hpp b/framegen/include/core/device.hpp deleted file mode 100644 index a913a42..0000000 --- a/framegen/include/core/device.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "core/instance.hpp" - -#include - -#include -#include - -namespace LSFG::Core { - - /// - /// C++ wrapper class for a Vulkan device. - /// - /// This class manages the lifetime of a Vulkan device. - /// - class Device { - public: - /// - /// Create the device. - /// - /// @param instance Vulkan instance - /// @param deviceUUID The UUID of the Vulkan device to use. - /// @param forceDisableFp16 Force-disable FP16 shaders. - /// - /// @throws LSFG::vulkan_error if object creation fails. - /// - Device(const Instance& instance, uint64_t deviceUUID, bool forceDisableFp16); - - /// Get the Vulkan handle. - [[nodiscard]] auto handle() const { return *this->device; } - /// Get the physical device associated with this logical device. - [[nodiscard]] VkPhysicalDevice getPhysicalDevice() const { return this->physicalDevice; } - /// Get the compute queue family index. - [[nodiscard]] uint32_t getComputeFamilyIdx() const { return this->computeFamilyIdx; } - /// Get the compute queue. - [[nodiscard]] VkQueue getComputeQueue() const { return this->computeQueue; } - /// Check if the device supports FP16. - [[nodiscard]] bool getFP16Support() const { return this->supportsFP16; } - - // Trivially copyable, moveable and destructible - Device(const Core::Device&) noexcept = default; - Device& operator=(const Core::Device&) noexcept = default; - Device(Device&&) noexcept = default; - Device& operator=(Device&&) noexcept = default; - ~Device() = default; - private: - std::shared_ptr device; - VkPhysicalDevice physicalDevice{}; - - uint32_t computeFamilyIdx{0}; - bool supportsFP16{false}; - - VkQueue computeQueue{}; - }; - -} diff --git a/framegen/include/core/semaphore.hpp b/framegen/include/core/semaphore.hpp deleted file mode 100644 index 773ca0c..0000000 --- a/framegen/include/core/semaphore.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include "core/device.hpp" - -#include - -#include -#include -#include - -namespace LSFG::Core { - - /// - /// C++ wrapper class for a Vulkan semaphore. - /// - /// This class manages the lifetime of a Vulkan semaphore. - /// - class Semaphore { - public: - Semaphore() noexcept = default; - - /// - /// Create the semaphore. - /// - /// @param device Vulkan device - /// @param initial Optional initial value for creating a timeline semaphore. - /// - /// @throws LSFG::vulkan_error if object creation fails. - /// - Semaphore(const Core::Device& device, std::optional initial = std::nullopt); - - /// - /// Import a semaphore. - /// - /// @param device Vulkan device - /// @param fd File descriptor to import the semaphore from. - /// - /// @throws LSFG::vulkan_error if object creation fails. - /// - Semaphore(const Core::Device& device, int fd); - - /// - /// Signal the semaphore to a specific value. - /// - /// @param device Vulkan device - /// @param value The value to signal the semaphore to. - /// - /// @throws std::logic_error if the semaphore is not a timeline semaphore. - /// @throws LSFG::vulkan_error if signaling fails. - /// - void signal(const Core::Device& device, uint64_t value) const; - - /// - /// Wait for the semaphore to reach a specific value. - /// - /// @param device Vulkan device - /// @param value The value to wait for. - /// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout. - /// @returns true if the semaphore reached the value, false if it timed out. - /// - /// @throws std::logic_error if the semaphore is not a timeline semaphore. - /// @throws LSFG::vulkan_error if waiting fails. - /// - [[nodiscard]] bool wait(const Core::Device& device, uint64_t value, uint64_t timeout = UINT64_MAX) const; - - /// Get the Vulkan handle. - [[nodiscard]] auto handle() const { return *this->semaphore; } - - // Trivially copyable, moveable and destructible - Semaphore(const Semaphore&) noexcept = default; - Semaphore& operator=(const Semaphore&) noexcept = default; - Semaphore(Semaphore&&) noexcept = default; - Semaphore& operator=(Semaphore&&) noexcept = default; - ~Semaphore() = default; - private: - std::shared_ptr semaphore; - bool isTimeline{}; - }; - -} diff --git a/framegen/include/core/buffer.hpp b/framegen/include/vk/core/buffer.hpp similarity index 66% rename from framegen/include/core/buffer.hpp rename to framegen/include/vk/core/buffer.hpp index 1aa1b49..a35b000 100644 --- a/framegen/include/core/buffer.hpp +++ b/framegen/include/vk/core/buffer.hpp @@ -1,13 +1,13 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan buffer. @@ -25,13 +25,11 @@ namespace LSFG::Core { /// @param data Initial data for the buffer, also specifies the size of the buffer. /// @param usage Usage flags for the buffer /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// template - Buffer(const Core::Device& device, const T& data, VkBufferUsageFlags usage) - : size(sizeof(T)) { - construct(device, reinterpret_cast(&data), usage); - } + Buffer(const Device& device, const T& data, VkBufferUsageFlags usage) + : Buffer(device, reinterpret_cast(&data), sizeof(T), usage) {} /// /// Create the buffer. @@ -41,17 +39,16 @@ namespace LSFG::Core { /// @param size Size of the buffer in bytes /// @param usage Usage flags for the buffer /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Buffer(const Core::Device& device, const void* data, size_t size, VkBufferUsageFlags usage) - : size(size) { - construct(device, data, usage); - } + Buffer(const Device& device, const void* data, size_t size, VkBufferUsageFlags usage); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->buffer; } + /// Get the Vulkan device memory handle. + [[nodiscard]] auto getMemory() const { return *this->memory; } /// Get the size of the buffer. - [[nodiscard]] size_t getSize() const { return this->size; } + [[nodiscard]] auto getSize() const { return this->size; } /// Trivially copyable, moveable and destructible Buffer(const Buffer&) noexcept = default; @@ -60,7 +57,6 @@ namespace LSFG::Core { Buffer& operator=(Buffer&&) noexcept = default; ~Buffer() = default; private: - void construct(const Core::Device& device, const void* data, VkBufferUsageFlags usage); std::shared_ptr buffer; std::shared_ptr memory; diff --git a/framegen/include/core/commandbuffer.hpp b/framegen/include/vk/core/commandbuffer.hpp similarity index 71% rename from framegen/include/core/commandbuffer.hpp rename to framegen/include/vk/core/commandbuffer.hpp index 35eeb57..49c25aa 100644 --- a/framegen/include/core/commandbuffer.hpp +++ b/framegen/include/vk/core/commandbuffer.hpp @@ -1,18 +1,19 @@ #pragma once -#include "core/commandpool.hpp" -#include "core/fence.hpp" -#include "core/semaphore.hpp" -#include "core/device.hpp" +#include "vk/core/commandpool.hpp" +#include "vk/core/semaphore.hpp" +#include "vk/core/pipeline.hpp" +#include "vk/core/device.hpp" +#include "vk/core/fence.hpp" #include -#include #include +#include #include #include -namespace LSFG::Core { +namespace VK::Core { /// State of the command buffer. enum class CommandBufferState { @@ -43,18 +44,34 @@ namespace LSFG::Core { /// @param device Vulkan device /// @param pool Vulkan command pool /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - CommandBuffer(const Core::Device& device, const CommandPool& pool); + CommandBuffer(const Device& device, const CommandPool& pool); /// /// Begin recording commands in the command buffer. /// - /// @throws std::logic_error if the command buffer is in Empty state - /// @throws LSFG::vulkan_error if beginning the command buffer fails. + /// @throws std::logic_error if the command buffer is not in Empty state + /// @throws VK::vulkan_error if beginning the command buffer fails. /// void begin(); + /// + /// Bind a compute pipeline to the command buffer. + /// + /// @param pipeline Vulkan compute pipeline + /// + /// @throws std::logic_error if the command buffer is not in Recording state + /// + void bindPipeline(const Pipeline& pipeline) const; + + // TODO: Method for binding a descriptor set. + // TODO: Rework abstraction for descriptor sets. + // TODO: Method for inserting a pipeline barrier. + // TODO: Rework abstraction for barriers. + // TODO: Method for copying a buffer to an image + // TODO: Method for clearing an image to a color + /// /// Dispatch a compute command. /// @@ -70,10 +87,12 @@ namespace LSFG::Core { /// End recording commands in the command buffer. /// /// @throws std::logic_error if the command buffer is not in Recording state - /// @throws LSFG::vulkan_error if ending the command buffer fails. + /// @throws VK::vulkan_error if ending the command buffer fails. /// void end(); + // FIXME: Submit logic is kind of janky. + /// /// Submit the command buffer to a queue. /// @@ -85,7 +104,7 @@ namespace LSFG::Core { /// @param signalSemaphoreValues Values for the semaphores to signal /// /// @throws std::logic_error if the command buffer is not in Full state. - /// @throws LSFG::vulkan_error if submission fails. + /// @throws VK::vulkan_error if submission fails. /// void submit(VkQueue queue, std::optional fence, const std::vector& waitSemaphores = {}, @@ -94,7 +113,7 @@ namespace LSFG::Core { std::optional> signalSemaphoreValues = std::nullopt); /// Get the state of the command buffer. - [[nodiscard]] CommandBufferState getState() const { return *this->state; } + [[nodiscard]] auto getState() const { return *this->state; } /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->commandBuffer; } diff --git a/framegen/include/core/commandpool.hpp b/framegen/include/vk/core/commandpool.hpp similarity index 85% rename from framegen/include/core/commandpool.hpp rename to framegen/include/vk/core/commandpool.hpp index 7f4539d..883e06a 100644 --- a/framegen/include/core/commandpool.hpp +++ b/framegen/include/vk/core/commandpool.hpp @@ -1,12 +1,12 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan command pool. @@ -22,9 +22,9 @@ namespace LSFG::Core { /// /// @param device Vulkan device /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - CommandPool(const Core::Device& device); + CommandPool(const Device& device); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->commandPool; } diff --git a/framegen/include/core/descriptorpool.hpp b/framegen/include/vk/core/descriptorpool.hpp similarity index 85% rename from framegen/include/core/descriptorpool.hpp rename to framegen/include/vk/core/descriptorpool.hpp index 792f843..0c160e7 100644 --- a/framegen/include/core/descriptorpool.hpp +++ b/framegen/include/vk/core/descriptorpool.hpp @@ -1,12 +1,12 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan descriptor pool. @@ -22,9 +22,9 @@ namespace LSFG::Core { /// /// @param device Vulkan device /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - DescriptorPool(const Core::Device& device); + DescriptorPool(const Device& device); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->descriptorPool; } diff --git a/framegen/include/vk/core/device.hpp b/framegen/include/vk/core/device.hpp new file mode 100644 index 0000000..bf2d85d --- /dev/null +++ b/framegen/include/vk/core/device.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "vk/core/instance.hpp" + +#include + +#include +#include +#include +#include + +namespace VK::Core { + + // FIXME: More intelligent device choosing method. See #200. + + /// + /// C++ wrapper class for a Vulkan device. + /// + /// This class manages the lifetime of a Vulkan device. + /// + class Device { + public: + /// + /// Create the device. + /// + /// @param instance Vulkan instance + /// @param uuid The UUID of the Vulkan device to use. + /// @param enforceFP32 Whether to enforce FP32 support even if FP16 is available. + /// + /// @throws VK::vulkan_error if object creation fails. + /// + Device(const Instance& instance, uint64_t uuid, bool enforceFP32); + + /// + /// Find a suitable memory type. + /// + /// @param validTypes A bitset representing the valid memory types. + /// @param hostVisible Whether the memory should be host visible. + /// + /// @return The index of a suitable memory type, or std::nullopt if none found. + /// + [[nodiscard]] std::optional findMemoryType( + std::bitset<32> validTypes, bool hostVisible = false) const; + + /// Get the Vulkan handle. + [[nodiscard]] auto handle() const { return *this->device; } + + /// Get the physical device associated with this logical device. + [[nodiscard]] auto getPhysicalDevice() const { return this->physicalDevice; } + /// Get the compute queue. + [[nodiscard]] auto getComputeQueue() const { return this->computeQueue; } + + /// Get the compute queue family index. + [[nodiscard]] auto getComputeFamilyIdx() const { return this->computeFamilyIdx; } + /// Check if the device supports FP16. + [[nodiscard]] auto supportsFP16() const { return this->fp16; } + + // Trivially copyable, moveable and destructible + Device(const Device&) noexcept = default; + Device& operator=(const Device&) noexcept = default; + Device(Device&&) noexcept = default; + Device& operator=(Device&&) noexcept = default; + ~Device() = default; + private: + std::shared_ptr device; + + VkPhysicalDevice physicalDevice{}; + VkQueue computeQueue{}; + + uint32_t computeFamilyIdx{0}; + bool fp16{false}; + + }; + +} diff --git a/framegen/include/core/fence.hpp b/framegen/include/vk/core/fence.hpp similarity index 74% rename from framegen/include/core/fence.hpp rename to framegen/include/vk/core/fence.hpp index 1739220..33b9e89 100644 --- a/framegen/include/core/fence.hpp +++ b/framegen/include/vk/core/fence.hpp @@ -1,13 +1,13 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan fence. @@ -23,18 +23,18 @@ namespace LSFG::Core { /// /// @param device Vulkan device /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Fence(const Core::Device& device); + Fence(const Device& device); /// /// Reset the fence to an unsignaled state. /// /// @param device Vulkan device /// - /// @throws LSFG::vulkan_error if resetting fails. + /// @throws VK::vulkan_error if resetting fails. /// - void reset(const Core::Device& device) const; + void reset(const Device& device) const; /// /// Wait for the fence @@ -43,9 +43,9 @@ namespace LSFG::Core { /// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout. /// @returns true if the fence signaled, false if it timed out. /// - /// @throws LSFG::vulkan_error if waiting fails. + /// @throws VK::vulkan_error if waiting fails. /// - [[nodiscard]] bool wait(const Core::Device& device, uint64_t timeout = UINT64_MAX) const; + [[nodiscard]] bool wait(const Device& device, uint64_t timeout = UINT64_MAX) const; /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->fence; } diff --git a/framegen/include/core/image.hpp b/framegen/include/vk/core/image.hpp similarity index 81% rename from framegen/include/core/image.hpp rename to framegen/include/vk/core/image.hpp index b89fea5..190a36c 100644 --- a/framegen/include/core/image.hpp +++ b/framegen/include/vk/core/image.hpp @@ -1,12 +1,14 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include -namespace LSFG::Core { +namespace VK::Core { + + // TODO: Refactoring /// /// C++ wrapper class for a Vulkan image. @@ -26,9 +28,9 @@ namespace LSFG::Core { /// @param usage Usage flags for the image /// @param aspectFlags Aspect flags for the image view /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Image(const Core::Device& device, VkExtent2D extent, + Image(const Device& device, VkExtent2D extent, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT); @@ -43,9 +45,9 @@ namespace LSFG::Core { /// @param aspectFlags Aspect flags for the image view /// @param fd File descriptor for shared memory. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Image(const Core::Device& device, VkExtent2D extent, VkFormat format, + Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd); /// @@ -58,9 +60,9 @@ namespace LSFG::Core { /// @param aspectFlags Aspect flags for the image view /// @param fd Pointer to an integer where the file descriptor will be stored. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Image(const Core::Device& device, VkExtent2D extent, VkFormat format, + Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd); /// Get the Vulkan handle. @@ -70,11 +72,11 @@ namespace LSFG::Core { /// Get the Vulkan image view handle. [[nodiscard]] auto getView() const { return *this->view; } /// Get the extent of the image. - [[nodiscard]] VkExtent2D getExtent() const { return this->extent; } + [[nodiscard]] auto getExtent() const { return this->extent; } /// Get the format of the image. - [[nodiscard]] VkFormat getFormat() const { return this->format; } + [[nodiscard]] auto getFormat() const { return this->format; } /// Get the aspect flags of the image. - [[nodiscard]] VkImageAspectFlags getAspectFlags() const { return this->aspectFlags; } + [[nodiscard]] auto getAspectFlags() const { return this->aspectFlags; } /// Set the layout of the image. void setLayout(VkImageLayout layout) { *this->layout = layout; } diff --git a/framegen/include/core/instance.hpp b/framegen/include/vk/core/instance.hpp similarity index 79% rename from framegen/include/core/instance.hpp rename to framegen/include/vk/core/instance.hpp index 24cba8a..594a0ab 100644 --- a/framegen/include/core/instance.hpp +++ b/framegen/include/vk/core/instance.hpp @@ -4,7 +4,7 @@ #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan instance. @@ -16,12 +16,12 @@ namespace LSFG::Core { /// /// Create the instance. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// Instance(); /// Get the Vulkan handle. - [[nodiscard]] auto handle() const { return this->instance ? *this->instance : VK_NULL_HANDLE; } + [[nodiscard]] auto handle() const { return *this->instance; } /// Trivially copyable, moveable and destructible Instance(const Instance&) noexcept = default; diff --git a/framegen/include/core/pipeline.hpp b/framegen/include/vk/core/pipeline.hpp similarity index 70% rename from framegen/include/core/pipeline.hpp rename to framegen/include/vk/core/pipeline.hpp index 6eddb5a..cbb3d25 100644 --- a/framegen/include/core/pipeline.hpp +++ b/framegen/include/vk/core/pipeline.hpp @@ -1,14 +1,13 @@ #pragma once -#include "core/commandbuffer.hpp" -#include "core/shadermodule.hpp" -#include "core/device.hpp" +#include "vk/core/shadermodule.hpp" +#include "vk/core/device.hpp" #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan pipeline. @@ -25,16 +24,9 @@ namespace LSFG::Core { /// @param device Vulkan device /// @param shader Shader module to use for the pipeline. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Pipeline(const Core::Device& device, const ShaderModule& shader); - - /// - /// Bind the pipeline to a command buffer. - /// - /// @param commandBuffer Command buffer to bind the pipeline to. - /// - void bind(const CommandBuffer& commandBuffer) const; + Pipeline(const Device& device, const ShaderModule& shader); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->pipeline; } diff --git a/framegen/include/core/sampler.hpp b/framegen/include/vk/core/sampler.hpp similarity index 80% rename from framegen/include/core/sampler.hpp rename to framegen/include/vk/core/sampler.hpp index 981077c..bc91a12 100644 --- a/framegen/include/core/sampler.hpp +++ b/framegen/include/vk/core/sampler.hpp @@ -1,12 +1,12 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan sampler. @@ -25,12 +25,10 @@ namespace LSFG::Core { /// @param compare Compare operation for the sampler. /// @param isWhite Whether the border color is white. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - Sampler(const Core::Device& device, - VkSamplerAddressMode mode, - VkCompareOp compare, - bool isWhite); + Sampler(const Device& device, + VkSamplerAddressMode mode, VkCompareOp compare, bool isWhite); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->sampler; } diff --git a/framegen/include/vk/core/semaphore.hpp b/framegen/include/vk/core/semaphore.hpp new file mode 100644 index 0000000..c0fa37f --- /dev/null +++ b/framegen/include/vk/core/semaphore.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "vk/core/device.hpp" + +#include + +#include +#include + +namespace VK::Core { + + /// + /// C++ wrapper class for a Vulkan semaphore. + /// + /// This class manages the lifetime of a Vulkan semaphore. + /// + class Semaphore { + public: + Semaphore() noexcept = default; + + /// + /// Create/Import a semaphore. + /// + /// @param device Vulkan device + /// @param fd Optional file descriptor to import the semaphore from. + /// + /// @throws VK::vulkan_error if object creation fails. + /// + Semaphore(const Device& device, std::optional fd = std::nullopt); + + /// Get the Vulkan handle. + [[nodiscard]] auto handle() const { return *this->semaphore; } + + // Trivially copyable, moveable and destructible + Semaphore(const Semaphore&) noexcept = default; + Semaphore& operator=(const Semaphore&) noexcept = default; + Semaphore(Semaphore&&) noexcept = default; + Semaphore& operator=(Semaphore&&) noexcept = default; + ~Semaphore() = default; + private: + std::shared_ptr semaphore; + }; + +} diff --git a/framegen/include/core/shadermodule.hpp b/framegen/include/vk/core/shadermodule.hpp similarity index 87% rename from framegen/include/core/shadermodule.hpp rename to framegen/include/vk/core/shadermodule.hpp index ac38234..43fffde 100644 --- a/framegen/include/core/shadermodule.hpp +++ b/framegen/include/vk/core/shadermodule.hpp @@ -1,6 +1,6 @@ #pragma once -#include "core/device.hpp" +#include "vk/core/device.hpp" #include @@ -10,7 +10,7 @@ #include #include -namespace LSFG::Core { +namespace VK::Core { /// /// C++ wrapper class for a Vulkan shader module. @@ -28,9 +28,9 @@ namespace LSFG::Core { /// @param code SPIR-V bytecode for the shader. /// @param descriptorTypes Descriptor types used in the shader. /// - /// @throws LSFG::vulkan_error if object creation fails. + /// @throws VK::vulkan_error if object creation fails. /// - ShaderModule(const Core::Device& device, const std::vector& code, + ShaderModule(const Device& device, const std::vector& code, const std::vector>& descriptorTypes); /// Get the Vulkan handle. diff --git a/framegen/include/vk/core/timeline_semaphore.hpp b/framegen/include/vk/core/timeline_semaphore.hpp new file mode 100644 index 0000000..51d249f --- /dev/null +++ b/framegen/include/vk/core/timeline_semaphore.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "vk/core/device.hpp" + +#include + +#include +#include + +namespace VK::Core { + + /// + /// C++ wrapper class for a Vulkan timeline semaphore. + /// + /// This class manages the lifetime of a Vulkan timeline semaphore. + /// + class TimelineSemaphore { + public: + TimelineSemaphore() noexcept = default; + + /// + /// Create the timeline semaphore. + /// + /// @param device Vulkan device + /// @param initial Initial value of the timeline semaphore. + /// + /// @throws VK::vulkan_error if object creation fails. + /// + TimelineSemaphore(const Device& device, uint32_t initial); + + /// + /// Signal the timeline semaphore to a specific value. + /// + /// @param device Vulkan device + /// @param value The value to signal the semaphore to. + /// + /// @throws VK::vulkan_error if signaling fails. + /// + void signal(const Device& device, uint64_t value) const; + + /// + /// Wait for the timeline semaphore to reach a specific value. + /// + /// @param device Vulkan device + /// @param value The value to wait for. + /// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout. + /// @returns true if the semaphore reached the value, false if it timed out. + /// + /// @throws VK::vulkan_error if waiting fails. + /// + [[nodiscard]] bool wait(const Device& device, + uint64_t value, uint64_t timeout = UINT64_MAX) const; + + /// Get the Vulkan handle. + [[nodiscard]] auto handle() const { return *this->semaphore; } + + // Trivially copyable, moveable and destructible + TimelineSemaphore(const TimelineSemaphore&) noexcept = default; + TimelineSemaphore& operator=(const TimelineSemaphore&) noexcept = default; + TimelineSemaphore(TimelineSemaphore&&) noexcept = default; + TimelineSemaphore& operator=(TimelineSemaphore&&) noexcept = default; + ~TimelineSemaphore() = default; + private: + std::shared_ptr semaphore; + }; + +} diff --git a/framegen/include/common/exception.hpp b/framegen/include/vk/exception.hpp similarity index 99% rename from framegen/include/common/exception.hpp rename to framegen/include/vk/exception.hpp index a0e6a35..c07d5ce 100644 --- a/framegen/include/common/exception.hpp +++ b/framegen/include/vk/exception.hpp @@ -6,7 +6,7 @@ #include #include -namespace LSFG { +namespace VK { /// Simple exception class for Vulkan errors. class vulkan_error : public std::runtime_error { diff --git a/framegen/src/core/device.cpp b/framegen/src/core/device.cpp deleted file mode 100644 index acb802b..0000000 --- a/framegen/src/core/device.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include - -#include "core/device.hpp" -#include "core/instance.hpp" -#include "common/exception.hpp" - -#include -#include -#include -#include - -using namespace LSFG::Core; - -const std::vector requiredExtensions = { - "VK_KHR_external_memory_fd", - "VK_KHR_external_semaphore_fd", - "VK_EXT_robustness2" -}; - -Device::Device(const Instance& instance, uint64_t deviceUUID, bool forceDisableFp16) { - // get all physical devices - uint32_t deviceCount{}; - auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr); - if (res != VK_SUCCESS || deviceCount == 0) - throw LSFG::vulkan_error(res, "Failed to enumerate physical devices"); - - std::vector devices(deviceCount); - res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, devices.data()); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to get physical devices"); - - // get device by uuid - std::optional physicalDevice; - for (const auto& device : devices) { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - - const uint64_t uuid = - static_cast(properties.vendorID) << 32 | properties.deviceID; - if (deviceUUID == uuid || deviceUUID == 0x1463ABAC) { - physicalDevice = device; - break; - } - } - if (!physicalDevice) - throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, - "Could not find physical device with UUID"); - - // find queue family indices - uint32_t familyCount{}; - vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, nullptr); - - std::vector queueFamilies(familyCount); - vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data()); - - std::optional computeFamilyIdx; - for (uint32_t i = 0; i < familyCount; ++i) { - if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) - computeFamilyIdx = i; - } - if (!computeFamilyIdx) - throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No compute queue family found"); - - // check if physical device supports float16 - VkPhysicalDeviceVulkan12Features supported12Features{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES - }; - VkPhysicalDeviceFeatures2 supportedFeatures{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - .pNext = &supported12Features - }; - vkGetPhysicalDeviceFeatures2(*physicalDevice, &supportedFeatures); - this->supportsFP16 = !forceDisableFp16 && supported12Features.shaderFloat16; - if (this->supportsFP16) - std::cerr << "lsfg-vk: Using FP16 acceleration" << '\n'; - else if (!forceDisableFp16) - std::cerr << "lsfg-vk: FP16 acceleration not supported, using FP32" << '\n'; - - // create logical device - const float queuePriority{1.0F}; // highest priority - VkPhysicalDeviceRobustness2FeaturesEXT robustness2{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT, - .nullDescriptor = VK_TRUE - }; - VkPhysicalDeviceVulkan13Features features13{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, - .pNext = &robustness2, - .synchronization2 = VK_TRUE - }; - const VkPhysicalDeviceVulkan12Features features12{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, - .pNext = &features13, - .shaderFloat16 = this->supportsFP16, - .timelineSemaphore = VK_TRUE, - .vulkanMemoryModel = VK_TRUE - }; - const VkDeviceQueueCreateInfo computeQueueDesc{ - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = *computeFamilyIdx, - .queueCount = 1, - .pQueuePriorities = &queuePriority - }; - const VkDeviceCreateInfo deviceCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = &features12, - .queueCreateInfoCount = 1, - .pQueueCreateInfos = &computeQueueDesc, - .enabledExtensionCount = static_cast(requiredExtensions.size()), - .ppEnabledExtensionNames = requiredExtensions.data() - }; - VkDevice deviceHandle{}; - res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle); - if (res != VK_SUCCESS | deviceHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create logical device"); - - volkLoadDevice(deviceHandle); - - // get compute queue - VkQueue queueHandle{}; - vkGetDeviceQueue(deviceHandle, *computeFamilyIdx, 0, &queueHandle); - - // store in shared ptr - this->computeQueue = queueHandle; - this->computeFamilyIdx = *computeFamilyIdx; - this->physicalDevice = *physicalDevice; - this->device = std::shared_ptr( - new VkDevice(deviceHandle), - [](VkDevice* device) { - vkDestroyDevice(*device, nullptr); - } - ); -} diff --git a/framegen/src/core/semaphore.cpp b/framegen/src/core/semaphore.cpp deleted file mode 100644 index 102898a..0000000 --- a/framegen/src/core/semaphore.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -#include "core/semaphore.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" - -#include -#include -#include -#include - -using namespace LSFG::Core; - -Semaphore::Semaphore(const Core::Device& device, std::optional initial) { - // create semaphore - const VkSemaphoreTypeCreateInfo typeInfo{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, - .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, - .initialValue = initial.value_or(0) - }; - const VkSemaphoreCreateInfo desc{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .pNext = initial.has_value() ? &typeInfo : nullptr, - }; - VkSemaphore semaphoreHandle{}; - auto res = vkCreateSemaphore(device.handle(), &desc, nullptr, &semaphoreHandle); - if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create semaphore"); - - // store semaphore in shared ptr - this->isTimeline = initial.has_value(); - this->semaphore = std::shared_ptr( - new VkSemaphore(semaphoreHandle), - [dev = device.handle()](VkSemaphore* semaphoreHandle) { - vkDestroySemaphore(dev, *semaphoreHandle, nullptr); - } - ); -} - -Semaphore::Semaphore(const Core::Device& device, int fd) { - // create semaphore - const VkExportSemaphoreCreateInfo exportInfo{ - .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, - .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT - }; - const VkSemaphoreCreateInfo desc{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .pNext = &exportInfo - }; - VkSemaphore semaphoreHandle{}; - auto res = vkCreateSemaphore(device.handle(), &desc, nullptr, &semaphoreHandle); - if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create semaphore"); - - // import semaphore from fd - auto vkImportSemaphoreFdKHR = reinterpret_cast( - vkGetDeviceProcAddr(device.handle(), "vkImportSemaphoreFdKHR")); - - const VkImportSemaphoreFdInfoKHR importInfo{ - .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, - .semaphore = semaphoreHandle, - .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, - .fd = fd // closes the fd - }; - res = vkImportSemaphoreFdKHR(device.handle(), &importInfo); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to import semaphore from fd"); - - // store semaphore in shared ptr - this->isTimeline = false; - this->semaphore = std::shared_ptr( - new VkSemaphore(semaphoreHandle), - [dev = device.handle()](VkSemaphore* semaphoreHandle) { - vkDestroySemaphore(dev, *semaphoreHandle, nullptr); - } - ); -} - -void Semaphore::signal(const Core::Device& device, uint64_t value) const { - if (!this->isTimeline) - throw std::logic_error("Invalid timeline semaphore"); - - const VkSemaphoreSignalInfo signalInfo{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, - .semaphore = this->handle(), - .value = value - }; - auto res = vkSignalSemaphore(device.handle(), &signalInfo); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to signal semaphore"); -} - -bool Semaphore::wait(const Core::Device& device, uint64_t value, uint64_t timeout) const { - if (!this->isTimeline) - throw std::logic_error("Invalid timeline semaphore"); - - VkSemaphore semaphore = this->handle(); - const VkSemaphoreWaitInfo waitInfo{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, - .semaphoreCount = 1, - .pSemaphores = &semaphore, - .pValues = &value - }; - auto res = vkWaitSemaphores(device.handle(), &waitInfo, timeout); - if (res != VK_SUCCESS && res != VK_TIMEOUT) - throw LSFG::vulkan_error(res, "Unable to wait for semaphore"); - - return res == VK_SUCCESS; -} diff --git a/framegen/src/core/buffer.cpp b/framegen/src/vk/core/buffer.cpp similarity index 54% rename from framegen/src/core/buffer.cpp rename to framegen/src/vk/core/buffer.cpp index 319c829..2c43ac3 100644 --- a/framegen/src/core/buffer.cpp +++ b/framegen/src/vk/core/buffer.cpp @@ -1,51 +1,38 @@ #include #include -#include "core/buffer.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/buffer.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" #include +#include +#include #include #include -#include -using namespace LSFG::Core; +using namespace VK::Core; -void Buffer::construct(const Core::Device& device, const void* data, VkBufferUsageFlags usage) { +Buffer::Buffer(const Device& device, const void* data, size_t size, VkBufferUsageFlags usage) { // create buffer const VkBufferCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = this->size, + .size = size, .usage = usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE }; VkBuffer bufferHandle{}; auto res = vkCreateBuffer(device.handle(), &desc, nullptr, &bufferHandle); if (res != VK_SUCCESS || bufferHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create Vulkan buffer"); + throw VK::vulkan_error(res, "Failed to create Vulkan buffer"); // find memory type - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps); - VkMemoryRequirements memReqs; vkGetBufferMemoryRequirements(device.handle(), bufferHandle, &memReqs); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" - std::optional memType{}; - for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { - if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN - (memProps.memoryTypes[i].propertyFlags & - (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))) { - memType.emplace(i); - break; - } // NOLINTEND - } + std::optional memType = device.findMemoryType(memReqs.memoryTypeBits, true); if (!memType.has_value()) - throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); -#pragma clang diagnostic pop + throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); // allocate and bind memory const VkMemoryAllocateInfo allocInfo{ @@ -56,21 +43,22 @@ void Buffer::construct(const Core::Device& device, const void* data, VkBufferUsa VkDeviceMemory memoryHandle{}; res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle); if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan buffer"); + throw VK::vulkan_error(res, "Failed to allocate memory for Vulkan buffer"); res = vkBindBufferMemory(device.handle(), bufferHandle, memoryHandle, 0); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan buffer"); + throw VK::vulkan_error(res, "Failed to bind memory to Vulkan buffer"); // upload data to buffer uint8_t* buf{}; - res = vkMapMemory(device.handle(), memoryHandle, 0, this->size, 0, reinterpret_cast(&buf)); + res = vkMapMemory(device.handle(), memoryHandle, 0, size, 0, reinterpret_cast(&buf)); if (res != VK_SUCCESS || buf == nullptr) - throw LSFG::vulkan_error(res, "Failed to map memory for Vulkan buffer"); - std::copy_n(reinterpret_cast(data), this->size, buf); + throw VK::vulkan_error(res, "Failed to map memory for Vulkan buffer"); + std::copy_n(reinterpret_cast(data), size, buf); vkUnmapMemory(device.handle(), memoryHandle); // store buffer and memory in shared ptr + this->size = size; this->buffer = std::shared_ptr( new VkBuffer(bufferHandle), [dev = device.handle()](VkBuffer* img) { diff --git a/framegen/src/core/commandbuffer.cpp b/framegen/src/vk/core/commandbuffer.cpp similarity index 83% rename from framegen/src/core/commandbuffer.cpp rename to framegen/src/vk/core/commandbuffer.cpp index 7deea63..34c7e13 100644 --- a/framegen/src/core/commandbuffer.cpp +++ b/framegen/src/vk/core/commandbuffer.cpp @@ -1,22 +1,23 @@ #include #include -#include "core/commandbuffer.hpp" -#include "core/device.hpp" -#include "core/commandpool.hpp" -#include "core/fence.hpp" -#include "core/semaphore.hpp" -#include "common/exception.hpp" +#include "vk/core/commandbuffer.hpp" +#include "vk/core/commandpool.hpp" +#include "vk/core/semaphore.hpp" +#include "vk/core/pipeline.hpp" +#include "vk/core/device.hpp" +#include "vk/core/fence.hpp" +#include "vk/exception.hpp" -#include #include -#include #include +#include +#include #include -using namespace LSFG::Core; +using namespace VK::Core; -CommandBuffer::CommandBuffer(const Core::Device& device, const CommandPool& pool) { +CommandBuffer::CommandBuffer(const Device& device, const CommandPool& pool) { // create command buffer const VkCommandBufferAllocateInfo desc{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, @@ -27,7 +28,7 @@ CommandBuffer::CommandBuffer(const Core::Device& device, const CommandPool& pool VkCommandBuffer commandBufferHandle{}; auto res = vkAllocateCommandBuffers(device.handle(), &desc, &commandBufferHandle); if (res != VK_SUCCESS || commandBufferHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to allocate command buffer"); + throw VK::vulkan_error(res, "Unable to allocate command buffer"); // store command buffer in shared ptr this->state = std::make_shared(CommandBufferState::Empty); @@ -49,11 +50,18 @@ void CommandBuffer::begin() { }; auto res = vkBeginCommandBuffer(*this->commandBuffer, &beginInfo); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to begin command buffer"); + throw VK::vulkan_error(res, "Unable to begin command buffer"); *this->state = CommandBufferState::Recording; } +void CommandBuffer::bindPipeline(const Pipeline& pipeline) const { + if (*this->state != CommandBufferState::Recording) + throw std::logic_error("Command buffer is not in Recording state"); + + vkCmdBindPipeline(*this->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.handle()); +} + void CommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) const { if (*this->state != CommandBufferState::Recording) throw std::logic_error("Command buffer is not in Recording state"); @@ -67,7 +75,7 @@ void CommandBuffer::end() { auto res = vkEndCommandBuffer(*this->commandBuffer); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to end command buffer"); + throw VK::vulkan_error(res, "Unable to end command buffer"); *this->state = CommandBufferState::Full; } @@ -119,7 +127,7 @@ void CommandBuffer::submit(VkQueue queue, std::optional fence, }; auto res = vkQueueSubmit(queue, 1, &submitInfo, fence ? fence->handle() : VK_NULL_HANDLE); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to submit command buffer"); + throw VK::vulkan_error(res, "Unable to submit command buffer"); *this->state = CommandBufferState::Submitted; } diff --git a/framegen/src/core/commandpool.cpp b/framegen/src/vk/core/commandpool.cpp similarity index 75% rename from framegen/src/core/commandpool.cpp rename to framegen/src/vk/core/commandpool.cpp index 2ff457f..3232a94 100644 --- a/framegen/src/core/commandpool.cpp +++ b/framegen/src/vk/core/commandpool.cpp @@ -1,15 +1,15 @@ #include #include -#include "core/commandpool.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/commandpool.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" #include -using namespace LSFG::Core; +using namespace VK::Core; -CommandPool::CommandPool(const Core::Device& device) { +CommandPool::CommandPool(const Device& device) { // create command pool const VkCommandPoolCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -18,7 +18,7 @@ CommandPool::CommandPool(const Core::Device& device) { VkCommandPool commandPoolHandle{}; auto res = vkCreateCommandPool(device.handle(), &desc, nullptr, &commandPoolHandle); if (res != VK_SUCCESS || commandPoolHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create command pool"); + throw VK::vulkan_error(res, "Unable to create command pool"); // store command pool in shared ptr this->commandPool = std::shared_ptr( diff --git a/framegen/src/core/descriptorpool.cpp b/framegen/src/vk/core/descriptorpool.cpp similarity index 83% rename from framegen/src/core/descriptorpool.cpp rename to framegen/src/vk/core/descriptorpool.cpp index eea5bb2..1a8b995 100644 --- a/framegen/src/core/descriptorpool.cpp +++ b/framegen/src/vk/core/descriptorpool.cpp @@ -1,17 +1,17 @@ #include #include -#include "core/descriptorpool.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/descriptorpool.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" -#include #include #include +#include -using namespace LSFG::Core; +using namespace VK::Core; -DescriptorPool::DescriptorPool(const Core::Device& device) { +DescriptorPool::DescriptorPool(const Device& device) { // create descriptor pool const std::array pools{{ // arbitrary limits { .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 }, @@ -29,7 +29,7 @@ DescriptorPool::DescriptorPool(const Core::Device& device) { VkDescriptorPool poolHandle{}; auto res = vkCreateDescriptorPool(device.handle(), &desc, nullptr, &poolHandle); if (res != VK_SUCCESS || poolHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create descriptor pool"); + throw VK::vulkan_error(res, "Unable to create descriptor pool"); // store pool in shared ptr this->descriptorPool = std::shared_ptr( diff --git a/framegen/src/vk/core/device.cpp b/framegen/src/vk/core/device.cpp new file mode 100644 index 0000000..bbde125 --- /dev/null +++ b/framegen/src/vk/core/device.cpp @@ -0,0 +1,169 @@ +#include +#include + +#include "vk/core/instance.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace VK::Core; + +const std::vector requiredExtensions = { + "VK_KHR_external_memory_fd", + "VK_KHR_external_semaphore_fd", + "VK_EXT_robustness2" +}; + +namespace { + /// Find a physical device by its UUID. + std::optional findDeviceByUUID(const Instance& instance, uint64_t uuid) { + uint32_t deviceCount{}; + auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr); + if (res != VK_SUCCESS || deviceCount == 0) + throw VK::vulkan_error(res, "Failed to enumerate physical devices"); + + std::vector devices(deviceCount); + res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, devices.data()); + if (res != VK_SUCCESS) + throw VK::vulkan_error(res, "Failed to get physical devices"); + + for (const auto& device : devices) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + + const uint64_t gpuid = + static_cast(properties.vendorID) << 32 | properties.deviceID; + if (uuid == gpuid || uuid == 0x1463ABAC) + return device; + } + return std::nullopt; + } + + /// Find the compute queue family index. + std::optional findComputeQueueFamily(VkPhysicalDevice device) { + uint32_t familyCount{}; + vkGetPhysicalDeviceQueueFamilyProperties(device, &familyCount, nullptr); + + std::vector queueFamilies(familyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &familyCount, queueFamilies.data()); + + for (uint32_t i = 0; i < familyCount; ++i) { + if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) + return i; + } + return std::nullopt; + } + + /// Query the physical device for FP16 support. + bool checkFP16Support(VkPhysicalDevice device) { + VkPhysicalDeviceVulkan12Features features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES + }; + VkPhysicalDeviceFeatures2 features2{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &features + }; + vkGetPhysicalDeviceFeatures2(device, &features2); + return features.shaderFloat16; + } +} + +Device::Device(const Instance& instance, uint64_t uuid, bool enforceFP32) { + // get device by uuid + std::optional physicalDevice = findDeviceByUUID(instance, uuid); + if (!physicalDevice) + throw VK::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, + "Could not find physical device with UUID"); + + // find queue family indices + std::optional computeFamilyIdx = findComputeQueueFamily(*physicalDevice); + if (!computeFamilyIdx) + throw VK::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No compute queue family found"); + + // print fp16 debug info + const bool fp16 = !enforceFP32 && checkFP16Support(*physicalDevice); + if (fp16) + std::cerr << "lsfg-vk: Using FP16 acceleration" << '\n'; + else if (!enforceFP32) + std::cerr << "lsfg-vk: FP16 acceleration not supported, using FP32" << '\n'; + + // create logical device + const float queuePriority{1.0F}; // highest priority + VkPhysicalDeviceRobustness2FeaturesEXT robustness2{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT, + .nullDescriptor = VK_TRUE + }; + VkPhysicalDeviceVulkan13Features features13{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &robustness2, + .synchronization2 = VK_TRUE + }; + const VkPhysicalDeviceVulkan12Features features12{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = &features13, + .shaderFloat16 = fp16, + .timelineSemaphore = VK_TRUE, + .vulkanMemoryModel = VK_TRUE + }; + const VkDeviceQueueCreateInfo computeQueueDesc{ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = *computeFamilyIdx, + .queueCount = 1, + .pQueuePriorities = &queuePriority + }; + const VkDeviceCreateInfo deviceCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &features12, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &computeQueueDesc, + .enabledExtensionCount = static_cast(requiredExtensions.size()), + .ppEnabledExtensionNames = requiredExtensions.data() + }; + VkDevice deviceHandle{}; + auto res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle); + if (res != VK_SUCCESS | deviceHandle == VK_NULL_HANDLE) + throw VK::vulkan_error(res, "Failed to create logical device"); + + // get queue + volkLoadDevice(deviceHandle); + + VkQueue queueHandle{}; + vkGetDeviceQueue(deviceHandle, *computeFamilyIdx, 0, &queueHandle); + if (!queueHandle) + throw VK::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "Failed to get compute queue"); + + // store in shared ptr + this->fp16 = fp16; + this->computeFamilyIdx = *computeFamilyIdx; + this->computeQueue = queueHandle; + this->physicalDevice = *physicalDevice; + this->device = std::shared_ptr( + new VkDevice(deviceHandle), + [](VkDevice* device) { + vkDestroyDevice(*device, nullptr); + } + ); +} + +std::optional Device::findMemoryType(std::bitset<32> validTypes, bool hostVisible) const { + const VkMemoryPropertyFlags desiredProps = hostVisible ? + (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) : + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + VkPhysicalDeviceMemoryProperties memProps; + vkGetPhysicalDeviceMemoryProperties(this->physicalDevice, &memProps); + + std::array memTypes = std::to_array(memProps.memoryTypes); + for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) + if (validTypes.test(i) && (memTypes.at(i).propertyFlags & desiredProps) == desiredProps) + return i; + + return std::nullopt; +} diff --git a/framegen/src/core/fence.cpp b/framegen/src/vk/core/fence.cpp similarity index 65% rename from framegen/src/core/fence.cpp rename to framegen/src/vk/core/fence.cpp index 0284f08..4ad8fd1 100644 --- a/framegen/src/core/fence.cpp +++ b/framegen/src/vk/core/fence.cpp @@ -1,24 +1,24 @@ #include #include -#include "core/fence.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/device.hpp" +#include "vk/core/fence.hpp" +#include "vk/exception.hpp" -#include #include +#include -using namespace LSFG::Core; +using namespace VK::Core; -Fence::Fence(const Core::Device& device) { - // create fence +Fence::Fence(const Device& device) { + // create fence const VkFenceCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; VkFence fenceHandle{}; auto res = vkCreateFence(device.handle(), &desc, nullptr, &fenceHandle); if (res != VK_SUCCESS || fenceHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create fence"); + throw VK::vulkan_error(res, "Unable to create fence"); // store fence in shared ptr this->fence = std::shared_ptr( @@ -29,18 +29,18 @@ Fence::Fence(const Core::Device& device) { ); } -void Fence::reset(const Core::Device& device) const { +void Fence::reset(const Device& device) const { VkFence fenceHandle = this->handle(); auto res = vkResetFences(device.handle(), 1, &fenceHandle); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to reset fence"); + throw VK::vulkan_error(res, "Unable to reset fence"); } -bool Fence::wait(const Core::Device& device, uint64_t timeout) const { +bool Fence::wait(const Device& device, uint64_t timeout) const { VkFence fenceHandle = this->handle(); auto res = vkWaitForFences(device.handle(), 1, &fenceHandle, VK_TRUE, timeout); if (res != VK_SUCCESS && res != VK_TIMEOUT) - throw LSFG::vulkan_error(res, "Unable to wait for fence"); + throw VK::vulkan_error(res, "Unable to wait for fence"); return res == VK_SUCCESS; } diff --git a/framegen/src/core/image.cpp b/framegen/src/vk/core/image.cpp similarity index 76% rename from framegen/src/core/image.cpp rename to framegen/src/vk/core/image.cpp index b9c4f17..b74fdb1 100644 --- a/framegen/src/core/image.cpp +++ b/framegen/src/vk/core/image.cpp @@ -1,17 +1,17 @@ #include #include -#include "core/image.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/device.hpp" +#include "vk/core/image.hpp" +#include "vk/exception.hpp" +#include #include #include -#include -using namespace LSFG::Core; +using namespace VK::Core; -Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, +Image::Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags) : extent(extent), format(format), aspectFlags(aspectFlags) { // create image @@ -33,28 +33,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImage imageHandle{}; auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle); if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create Vulkan image"); + throw VK::vulkan_error(res, "Failed to create Vulkan image"); // find memory type - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps); - VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" - std::optional memType{}; - for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { - if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN - (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - memType.emplace(i); - break; - } // NOLINTEND - } + std::optional memType = device.findMemoryType(memReqs.memoryTypeBits, false); if (!memType.has_value()) - throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image"); -#pragma clang diagnostic pop + throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); // allocate and bind memory const VkMemoryAllocateInfo allocInfo{ @@ -65,11 +52,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkDeviceMemory memoryHandle{}; res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle); if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan image"); + throw VK::vulkan_error(res, "Failed to allocate memory for Vulkan image"); res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image"); + throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image"); // create image view const VkImageViewCreateInfo viewDesc{ @@ -93,7 +80,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImageView viewHandle{}; res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle); if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create image view"); + throw VK::vulkan_error(res, "Failed to create image view"); // store objects in shared ptr this->layout = std::make_shared(VK_IMAGE_LAYOUT_UNDEFINED); @@ -119,7 +106,9 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, // shared memory constructor -Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, +// FIXME: Less constructors... jesus. + +Image::Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd) : extent(extent), format(format), aspectFlags(aspectFlags) { // create image @@ -146,28 +135,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImage imageHandle{}; auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle); if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create Vulkan image"); + throw VK::vulkan_error(res, "Failed to create Vulkan image"); // find memory type - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps); - VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" - std::optional memType{}; - for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { - if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN - (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - memType.emplace(i); - break; - } // NOLINTEND - } + std::optional memType = device.findMemoryType(memReqs.memoryTypeBits, false); if (!memType.has_value()) - throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image"); -#pragma clang diagnostic pop + throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); // ~~allocate~~ and bind memory const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo2{ @@ -189,11 +165,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkDeviceMemory memoryHandle{}; res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle); if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan image"); + throw VK::vulkan_error(res, "Failed to allocate memory for Vulkan image"); res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image"); + throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image"); // create image view const VkImageViewCreateInfo viewDesc{ @@ -217,7 +193,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImageView viewHandle{}; res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle); if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create image view"); + throw VK::vulkan_error(res, "Failed to create image view"); // store objects in shared ptr this->layout = std::make_shared(VK_IMAGE_LAYOUT_UNDEFINED); @@ -243,7 +219,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, // second shared memory constructors -Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, +Image::Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd) : extent(extent), format(format), aspectFlags(aspectFlags) { // create image @@ -270,28 +246,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImage imageHandle{}; auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle); if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create Vulkan image"); + throw VK::vulkan_error(res, "Failed to create Vulkan image"); // find memory type - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps); - VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" - std::optional memType{}; - for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { - if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN - (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - memType.emplace(i); - break; - } // NOLINTEND - } + std::optional memType = device.findMemoryType(memReqs.memoryTypeBits); if (!memType.has_value()) - throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image"); -#pragma clang diagnostic pop + throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); // allocate and bind memory const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo{ @@ -312,11 +275,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkDeviceMemory memoryHandle{}; res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle); if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan image"); + throw VK::vulkan_error(res, "Failed to allocate memory for Vulkan image"); res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image"); + throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image"); // obtain the sharing fd const VkMemoryGetFdInfoKHR fdInfo{ @@ -326,7 +289,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, }; res = vkGetMemoryFdKHR(device.handle(), &fdInfo, fd); if (res != VK_SUCCESS || *fd < 0) - throw LSFG::vulkan_error(res, "Failed to obtain sharing fd for Vulkan image"); + throw VK::vulkan_error(res, "Failed to obtain sharing fd for Vulkan image"); // create image view const VkImageViewCreateInfo viewDesc{ @@ -350,7 +313,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImageView viewHandle{}; res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle); if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Failed to create image view"); + throw VK::vulkan_error(res, "Failed to create image view"); // store objects in shared ptr this->layout = std::make_shared(VK_IMAGE_LAYOUT_UNDEFINED); diff --git a/framegen/src/core/instance.cpp b/framegen/src/vk/core/instance.cpp similarity index 83% rename from framegen/src/core/instance.cpp rename to framegen/src/vk/core/instance.cpp index 981e634..039b413 100644 --- a/framegen/src/core/instance.cpp +++ b/framegen/src/vk/core/instance.cpp @@ -1,21 +1,21 @@ #include #include -#include "core/instance.hpp" -#include "common/exception.hpp" +#include "vk/core/instance.hpp" +#include "vk/exception.hpp" #include #include #include -using namespace LSFG::Core; +using namespace VK::Core; const std::vector requiredExtensions = { - + // empty, for now :3 }; Instance::Instance() { - volkInitialize(); + volkInitialize(); // FIXME: get rid of volk dependency fully // create Vulkan instance const VkApplicationInfo appInfo{ @@ -35,7 +35,7 @@ Instance::Instance() { VkInstance instanceHandle{}; auto res = vkCreateInstance(&createInfo, nullptr, &instanceHandle); if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to create Vulkan instance"); + throw VK::vulkan_error(res, "Failed to create Vulkan instance"); volkLoadInstance(instanceHandle); diff --git a/framegen/src/core/pipeline.cpp b/framegen/src/vk/core/pipeline.cpp similarity index 74% rename from framegen/src/core/pipeline.cpp rename to framegen/src/vk/core/pipeline.cpp index c2a6375..e955f07 100644 --- a/framegen/src/core/pipeline.cpp +++ b/framegen/src/vk/core/pipeline.cpp @@ -1,17 +1,16 @@ #include #include -#include "core/pipeline.hpp" -#include "core/device.hpp" -#include "core/shadermodule.hpp" -#include "core/commandbuffer.hpp" -#include "common/exception.hpp" +#include "vk/core/shadermodule.hpp" +#include "vk/core/pipeline.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" #include -using namespace LSFG::Core; +using namespace VK::Core; -Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) { +Pipeline::Pipeline(const Device& device, const ShaderModule& shader) { // create pipeline layout VkDescriptorSetLayout shaderLayout = shader.getLayout(); const VkPipelineLayoutCreateInfo layoutDesc{ @@ -22,7 +21,7 @@ Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) { VkPipelineLayout layoutHandle{}; auto res = vkCreatePipelineLayout(device.handle(), &layoutDesc, nullptr, &layoutHandle); if (res != VK_SUCCESS || !layoutHandle) - throw LSFG::vulkan_error(res, "Failed to create pipeline layout"); + throw VK::vulkan_error(res, "Failed to create pipeline layout"); // create pipeline const VkPipelineShaderStageCreateInfo shaderStageInfo{ @@ -40,7 +39,7 @@ Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) { res = vkCreateComputePipelines(device.handle(), VK_NULL_HANDLE, 1, &pipelineDesc, nullptr, &pipelineHandle); if (res != VK_SUCCESS || !pipelineHandle) - throw LSFG::vulkan_error(res, "Failed to create compute pipeline"); + throw VK::vulkan_error(res, "Failed to create compute pipeline"); // store layout and pipeline in shared ptr this->layout = std::shared_ptr( @@ -56,7 +55,3 @@ Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) { } ); } - -void Pipeline::bind(const CommandBuffer& commandBuffer) const { - vkCmdBindPipeline(commandBuffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, *this->pipeline); -} diff --git a/framegen/src/core/sampler.cpp b/framegen/src/vk/core/sampler.cpp similarity index 77% rename from framegen/src/core/sampler.cpp rename to framegen/src/vk/core/sampler.cpp index 2e8f4eb..24a66de 100644 --- a/framegen/src/core/sampler.cpp +++ b/framegen/src/vk/core/sampler.cpp @@ -1,18 +1,16 @@ #include #include -#include "core/sampler.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/sampler.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" #include -using namespace LSFG::Core; +using namespace VK::Core; -Sampler::Sampler(const Core::Device& device, - VkSamplerAddressMode mode, - VkCompareOp compare, - bool isWhite) { +Sampler::Sampler(const Device& device, + VkSamplerAddressMode mode, VkCompareOp compare, bool isWhite) { // create sampler const VkSamplerCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, @@ -31,7 +29,7 @@ Sampler::Sampler(const Core::Device& device, VkSampler samplerHandle{}; auto res = vkCreateSampler(device.handle(), &desc, nullptr, &samplerHandle); if (res != VK_SUCCESS || samplerHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create sampler"); + throw VK::vulkan_error(res, "Unable to create sampler"); // store sampler in shared ptr this->sampler = std::shared_ptr( diff --git a/framegen/src/vk/core/semaphore.cpp b/framegen/src/vk/core/semaphore.cpp new file mode 100644 index 0000000..9136bdc --- /dev/null +++ b/framegen/src/vk/core/semaphore.cpp @@ -0,0 +1,51 @@ +#include +#include + +#include "vk/core/semaphore.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" + +#include +#include + +using namespace VK::Core; + +Semaphore::Semaphore(const Device& device, std::optional fd) { + // create semaphore + const VkExportSemaphoreCreateInfo exportInfo{ + .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT + }; + const VkSemaphoreCreateInfo desc{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = fd.has_value() ? &exportInfo : nullptr + }; + VkSemaphore semaphoreHandle{}; + auto res = vkCreateSemaphore(device.handle(), &desc, nullptr, &semaphoreHandle); + if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) + throw VK::vulkan_error(res, "Unable to create semaphore"); + + if (fd.has_value()) { + // import semaphore from fd + auto vkImportSemaphoreFdKHR = reinterpret_cast( + vkGetDeviceProcAddr(device.handle(), "vkImportSemaphoreFdKHR")); + + const VkImportSemaphoreFdInfoKHR importInfo{ + .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, + .semaphore = semaphoreHandle, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + .fd = *fd // closes the fd + }; + res = vkImportSemaphoreFdKHR(device.handle(), &importInfo); + if (res != VK_SUCCESS) + throw VK::vulkan_error(res, "Unable to import semaphore from fd"); + } + + // store semaphore in shared ptr + this->semaphore = std::shared_ptr( + new VkSemaphore(semaphoreHandle), + [dev = device.handle()](VkSemaphore* semaphoreHandle) { + vkDestroySemaphore(dev, *semaphoreHandle, nullptr); + } + ); +} diff --git a/framegen/src/core/shadermodule.cpp b/framegen/src/vk/core/shadermodule.cpp similarity index 86% rename from framegen/src/core/shadermodule.cpp rename to framegen/src/vk/core/shadermodule.cpp index e2135e9..7409f32 100644 --- a/framegen/src/core/shadermodule.cpp +++ b/framegen/src/vk/core/shadermodule.cpp @@ -1,19 +1,19 @@ #include #include -#include "core/shadermodule.hpp" -#include "core/device.hpp" -#include "common/exception.hpp" +#include "vk/core/shadermodule.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" -#include +#include #include #include -#include +#include #include -using namespace LSFG::Core; +using namespace VK::Core; -ShaderModule::ShaderModule(const Core::Device& device, const std::vector& code, +ShaderModule::ShaderModule(const Device& device, const std::vector& code, const std::vector>& descriptorTypes) { // create shader module const uint8_t* data_ptr = code.data(); @@ -25,7 +25,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector layoutBindings; @@ -50,7 +50,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vectorshaderModule = std::shared_ptr( diff --git a/framegen/src/vk/core/timeline_semaphore.cpp b/framegen/src/vk/core/timeline_semaphore.cpp new file mode 100644 index 0000000..7316ef6 --- /dev/null +++ b/framegen/src/vk/core/timeline_semaphore.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include "vk/core/timeline_semaphore.hpp" +#include "vk/core/device.hpp" +#include "vk/exception.hpp" + +#include +#include + +using namespace VK::Core; + +TimelineSemaphore::TimelineSemaphore(const Device& device, uint32_t initial) { + // create semaphore + const VkSemaphoreTypeCreateInfo typeInfo{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + .initialValue = initial + }; + const VkSemaphoreCreateInfo desc{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &typeInfo, + }; + VkSemaphore semaphoreHandle{}; + auto res = vkCreateSemaphore(device.handle(), &desc, nullptr, &semaphoreHandle); + if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) + throw VK::vulkan_error(res, "Unable to create semaphore"); + + // store semaphore in shared ptr + this->semaphore = std::shared_ptr( + new VkSemaphore(semaphoreHandle), + [dev = device.handle()](VkSemaphore* semaphoreHandle) { + vkDestroySemaphore(dev, *semaphoreHandle, nullptr); + } + ); +} + +void TimelineSemaphore::signal(const Device& device, uint64_t value) const { + const VkSemaphoreSignalInfo signalInfo{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + .semaphore = this->handle(), + .value = value + }; + auto res = vkSignalSemaphore(device.handle(), &signalInfo); + if (res != VK_SUCCESS) + throw VK::vulkan_error(res, "Unable to signal semaphore"); +} + +bool TimelineSemaphore::wait(const Device& device, uint64_t value, uint64_t timeout) const { + VkSemaphore semaphore = this->handle(); + const VkSemaphoreWaitInfo waitInfo{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .semaphoreCount = 1, + .pSemaphores = &semaphore, + .pValues = &value + }; + auto res = vkWaitSemaphores(device.handle(), &waitInfo, timeout); + if (res != VK_SUCCESS && res != VK_TIMEOUT) + throw VK::vulkan_error(res, "Unable to wait for semaphore"); + + return res == VK_SUCCESS; +} diff --git a/framegen/src/common/exception.cpp b/framegen/src/vk/exception.cpp similarity index 92% rename from framegen/src/common/exception.cpp rename to framegen/src/vk/exception.cpp index 5ea7b0d..e1670c9 100644 --- a/framegen/src/common/exception.cpp +++ b/framegen/src/vk/exception.cpp @@ -1,4 +1,4 @@ -#include "common/exception.hpp" +#include "vk/exception.hpp" #include @@ -8,7 +8,7 @@ #include #include -using namespace LSFG; +using namespace VK; vulkan_error::vulkan_error(VkResult result, const std::string& message) : std::runtime_error(std::format("{} (error {})", message, static_cast(result))),