mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-26 12:21:43 +00:00
refactor: start refactoring core Vulkan abstractions
This commit is contained in:
parent
0048283a8a
commit
b86291b951
73 changed files with 686 additions and 656 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/instance.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
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<VkDevice> device;
|
||||
VkPhysicalDevice physicalDevice{};
|
||||
|
||||
uint32_t computeFamilyIdx{0};
|
||||
bool supportsFP16{false};
|
||||
|
||||
VkQueue computeQueue{};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
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<uint32_t> 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<VkSemaphore> semaphore;
|
||||
bool isTimeline{};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
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<typename T>
|
||||
Buffer(const Core::Device& device, const T& data, VkBufferUsageFlags usage)
|
||||
: size(sizeof(T)) {
|
||||
construct(device, reinterpret_cast<const void*>(&data), usage);
|
||||
}
|
||||
Buffer(const Device& device, const T& data, VkBufferUsageFlags usage)
|
||||
: Buffer(device, reinterpret_cast<const void*>(&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<VkBuffer> buffer;
|
||||
std::shared_ptr<VkDeviceMemory> memory;
|
||||
|
|
@ -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 <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
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> fence,
|
||||
const std::vector<Semaphore>& waitSemaphores = {},
|
||||
|
|
@ -94,7 +113,7 @@ namespace LSFG::Core {
|
|||
std::optional<std::vector<uint64_t>> 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; }
|
||||
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
75
framegen/include/vk/core/device.hpp
Normal file
75
framegen/include/vk/core/device.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk/core/instance.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
|
||||
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<uint32_t> 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<VkDevice> device;
|
||||
|
||||
VkPhysicalDevice physicalDevice{};
|
||||
VkQueue computeQueue{};
|
||||
|
||||
uint32_t computeFamilyIdx{0};
|
||||
bool fp16{false};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
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;
|
||||
|
|
@ -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 <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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; }
|
||||
44
framegen/include/vk/core/semaphore.hpp
Normal file
44
framegen/include/vk/core/semaphore.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
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<int> 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<VkSemaphore> semaphore;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
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<uint8_t>& code,
|
||||
ShaderModule(const Device& device, const std::vector<uint8_t>& code,
|
||||
const std::vector<std::pair<size_t, VkDescriptorType>>& descriptorTypes);
|
||||
|
||||
/// Get the Vulkan handle.
|
||||
67
framegen/include/vk/core/timeline_semaphore.hpp
Normal file
67
framegen/include/vk/core/timeline_semaphore.hpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk/core/device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
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<VkSemaphore> semaphore;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace LSFG {
|
||||
namespace VK {
|
||||
|
||||
/// Simple exception class for Vulkan errors.
|
||||
class vulkan_error : public std::runtime_error {
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "core/device.hpp"
|
||||
#include "core/instance.hpp"
|
||||
#include "common/exception.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
using namespace LSFG::Core;
|
||||
|
||||
const std::vector<const char*> 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<VkPhysicalDevice> 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<VkPhysicalDevice> physicalDevice;
|
||||
for (const auto& device : devices) {
|
||||
VkPhysicalDeviceProperties properties;
|
||||
vkGetPhysicalDeviceProperties(device, &properties);
|
||||
|
||||
const uint64_t uuid =
|
||||
static_cast<uint64_t>(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<VkQueueFamilyProperties> queueFamilies(familyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data());
|
||||
|
||||
std::optional<uint32_t> 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<uint32_t>(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<VkDevice>(
|
||||
new VkDevice(deviceHandle),
|
||||
[](VkDevice* device) {
|
||||
vkDestroyDevice(*device, nullptr);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "core/semaphore.hpp"
|
||||
#include "core/device.hpp"
|
||||
#include "common/exception.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace LSFG::Core;
|
||||
|
||||
Semaphore::Semaphore(const Core::Device& device, std::optional<uint32_t> 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<VkSemaphore>(
|
||||
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<PFN_vkImportSemaphoreFdKHR>(
|
||||
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<VkSemaphore>(
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,51 +1,38 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <algorithm>
|
||||
#include <optional>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
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<uint32_t> 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<uint32_t> 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<void**>(&buf));
|
||||
res = vkMapMemory(device.handle(), memoryHandle, 0, size, 0, reinterpret_cast<void**>(&buf));
|
||||
if (res != VK_SUCCESS || buf == nullptr)
|
||||
throw LSFG::vulkan_error(res, "Failed to map memory for Vulkan buffer");
|
||||
std::copy_n(reinterpret_cast<const uint8_t*>(data), this->size, buf);
|
||||
throw VK::vulkan_error(res, "Failed to map memory for Vulkan buffer");
|
||||
std::copy_n(reinterpret_cast<const uint8_t*>(data), size, buf);
|
||||
vkUnmapMemory(device.handle(), memoryHandle);
|
||||
|
||||
// store buffer and memory in shared ptr
|
||||
this->size = size;
|
||||
this->buffer = std::shared_ptr<VkBuffer>(
|
||||
new VkBuffer(bufferHandle),
|
||||
[dev = device.handle()](VkBuffer* img) {
|
||||
|
|
@ -1,22 +1,23 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <memory>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
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>(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> 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;
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <memory>
|
||||
|
||||
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<VkCommandPool>(
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
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<VkDescriptorPoolSize, 4> 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<VkDescriptorPool>(
|
||||
169
framegen/src/vk/core/device.cpp
Normal file
169
framegen/src/vk/core/device.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "vk/core/instance.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
#include "vk/exception.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
using namespace VK::Core;
|
||||
|
||||
const std::vector<const char*> requiredExtensions = {
|
||||
"VK_KHR_external_memory_fd",
|
||||
"VK_KHR_external_semaphore_fd",
|
||||
"VK_EXT_robustness2"
|
||||
};
|
||||
|
||||
namespace {
|
||||
/// Find a physical device by its UUID.
|
||||
std::optional<VkPhysicalDevice> 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<VkPhysicalDevice> 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<uint64_t>(properties.vendorID) << 32 | properties.deviceID;
|
||||
if (uuid == gpuid || uuid == 0x1463ABAC)
|
||||
return device;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Find the compute queue family index.
|
||||
std::optional<uint32_t> findComputeQueueFamily(VkPhysicalDevice device) {
|
||||
uint32_t familyCount{};
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &familyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> 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<VkPhysicalDevice> 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<uint32_t> 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<uint32_t>(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<VkDevice>(
|
||||
new VkDevice(deviceHandle),
|
||||
[](VkDevice* device) {
|
||||
vkDestroyDevice(*device, nullptr);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<uint32_t> 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<VkMemoryType, 32> 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;
|
||||
}
|
||||
|
|
@ -1,24 +1,24 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <memory>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
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<VkFence>(
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <optional>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
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<uint32_t> 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<uint32_t> 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<VkImageLayout>(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<uint32_t> 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<uint32_t> 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<VkImageLayout>(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<uint32_t> 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<uint32_t> 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<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "core/instance.hpp"
|
||||
#include "common/exception.hpp"
|
||||
#include "vk/core/instance.hpp"
|
||||
#include "vk/exception.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace LSFG::Core;
|
||||
using namespace VK::Core;
|
||||
|
||||
const std::vector<const char*> 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);
|
||||
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <memory>
|
||||
|
||||
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<VkPipelineLayout>(
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <memory>
|
||||
|
||||
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<VkSampler>(
|
||||
51
framegen/src/vk/core/semaphore.cpp
Normal file
51
framegen/src/vk/core/semaphore.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "vk/core/semaphore.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
#include "vk/exception.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
using namespace VK::Core;
|
||||
|
||||
Semaphore::Semaphore(const Device& device, std::optional<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 = 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<PFN_vkImportSemaphoreFdKHR>(
|
||||
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<VkSemaphore>(
|
||||
new VkSemaphore(semaphoreHandle),
|
||||
[dev = device.handle()](VkSemaphore* semaphoreHandle) {
|
||||
vkDestroySemaphore(dev, *semaphoreHandle, nullptr);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#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 <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using namespace LSFG::Core;
|
||||
using namespace VK::Core;
|
||||
|
||||
ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t>& code,
|
||||
ShaderModule::ShaderModule(const Device& device, const std::vector<uint8_t>& code,
|
||||
const std::vector<std::pair<size_t, VkDescriptorType>>& descriptorTypes) {
|
||||
// create shader module
|
||||
const uint8_t* data_ptr = code.data();
|
||||
|
|
@ -25,7 +25,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
|||
VkShaderModule shaderModuleHandle{};
|
||||
auto res = vkCreateShaderModule(device.handle(), &createInfo, nullptr, &shaderModuleHandle);
|
||||
if (res != VK_SUCCESS || !shaderModuleHandle)
|
||||
throw LSFG::vulkan_error(res, "Failed to create shader module");
|
||||
throw VK::vulkan_error(res, "Failed to create shader module");
|
||||
|
||||
// create descriptor set layout
|
||||
std::vector<VkDescriptorSetLayoutBinding> layoutBindings;
|
||||
|
|
@ -50,7 +50,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
|||
bindIdx = &outputIdx;
|
||||
break;
|
||||
default:
|
||||
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unsupported descriptor type");
|
||||
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unsupported descriptor type");
|
||||
}
|
||||
|
||||
layoutBindings.emplace_back(VkDescriptorSetLayoutBinding {
|
||||
|
|
@ -71,7 +71,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
|||
VkDescriptorSetLayout descriptorSetLayout{};
|
||||
res = vkCreateDescriptorSetLayout(device.handle(), &layoutDesc, nullptr, &descriptorSetLayout);
|
||||
if (res != VK_SUCCESS || !descriptorSetLayout)
|
||||
throw LSFG::vulkan_error(res, "Failed to create descriptor set layout");
|
||||
throw VK::vulkan_error(res, "Failed to create descriptor set layout");
|
||||
|
||||
// store module and layout in shared ptr
|
||||
this->shaderModule = std::shared_ptr<VkShaderModule>(
|
||||
62
framegen/src/vk/core/timeline_semaphore.cpp
Normal file
62
framegen/src/vk/core/timeline_semaphore.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <volk.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "vk/core/timeline_semaphore.hpp"
|
||||
#include "vk/core/device.hpp"
|
||||
#include "vk/exception.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
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<VkSemaphore>(
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "common/exception.hpp"
|
||||
#include "vk/exception.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
#include <format>
|
||||
#include <string>
|
||||
|
||||
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<int32_t>(result))),
|
||||
Loading…
Add table
Reference in a new issue