mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-05-10 19:21:42 +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)
|
LANGUAGES C CXX)
|
||||||
|
|
||||||
file(GLOB SOURCES
|
file(GLOB SOURCES
|
||||||
"src/common/*.cpp"
|
"src/vk/core/*.cpp"
|
||||||
"src/config/*.cpp"
|
"src/vk/*.cpp"
|
||||||
"src/core/*.cpp"
|
|
||||||
"src/pool/*.cpp"
|
|
||||||
"src/*.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})
|
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
|
target_include_directories(lsfg-vk-framegen SYSTEM
|
||||||
PUBLIC include/thirdparty)
|
PUBLIC include/thirdparty)
|
||||||
target_include_directories(lsfg-vk-framegen
|
target_include_directories(lsfg-vk-framegen
|
||||||
PUBLIC include
|
PUBLIC include)
|
||||||
PUBLIC public
|
|
||||||
PRIVATE v3.1_include
|
|
||||||
PRIVATE v3.1p_include)
|
|
||||||
|
|
||||||
# diagnostics
|
# diagnostics
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan buffer.
|
/// 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 data Initial data for the buffer, also specifies the size of the buffer.
|
||||||
/// @param usage Usage flags for 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>
|
template<typename T>
|
||||||
Buffer(const Core::Device& device, const T& data, VkBufferUsageFlags usage)
|
Buffer(const Device& device, const T& data, VkBufferUsageFlags usage)
|
||||||
: size(sizeof(T)) {
|
: Buffer(device, reinterpret_cast<const void*>(&data), sizeof(T), usage) {}
|
||||||
construct(device, reinterpret_cast<const void*>(&data), usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Create the buffer.
|
/// Create the buffer.
|
||||||
|
|
@ -41,17 +39,16 @@ namespace LSFG::Core {
|
||||||
/// @param size Size of the buffer in bytes
|
/// @param size Size of the buffer in bytes
|
||||||
/// @param usage Usage flags for 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.
|
||||||
///
|
///
|
||||||
Buffer(const Core::Device& device, const void* data, size_t size, VkBufferUsageFlags usage)
|
Buffer(const Device& device, const void* data, size_t size, VkBufferUsageFlags usage);
|
||||||
: size(size) {
|
|
||||||
construct(device, data, usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->buffer; }
|
[[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.
|
/// 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
|
/// Trivially copyable, moveable and destructible
|
||||||
Buffer(const Buffer&) noexcept = default;
|
Buffer(const Buffer&) noexcept = default;
|
||||||
|
|
@ -60,7 +57,6 @@ namespace LSFG::Core {
|
||||||
Buffer& operator=(Buffer&&) noexcept = default;
|
Buffer& operator=(Buffer&&) noexcept = default;
|
||||||
~Buffer() = default;
|
~Buffer() = default;
|
||||||
private:
|
private:
|
||||||
void construct(const Core::Device& device, const void* data, VkBufferUsageFlags usage);
|
|
||||||
|
|
||||||
std::shared_ptr<VkBuffer> buffer;
|
std::shared_ptr<VkBuffer> buffer;
|
||||||
std::shared_ptr<VkDeviceMemory> memory;
|
std::shared_ptr<VkDeviceMemory> memory;
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/commandpool.hpp"
|
#include "vk/core/commandpool.hpp"
|
||||||
#include "core/fence.hpp"
|
#include "vk/core/semaphore.hpp"
|
||||||
#include "core/semaphore.hpp"
|
#include "vk/core/pipeline.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
#include "vk/core/fence.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
/// State of the command buffer.
|
/// State of the command buffer.
|
||||||
enum class CommandBufferState {
|
enum class CommandBufferState {
|
||||||
|
|
@ -43,18 +44,34 @@ namespace LSFG::Core {
|
||||||
/// @param device Vulkan device
|
/// @param device Vulkan device
|
||||||
/// @param pool Vulkan command pool
|
/// @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.
|
/// Begin recording commands in the command buffer.
|
||||||
///
|
///
|
||||||
/// @throws std::logic_error if the command buffer is in Empty state
|
/// @throws std::logic_error if the command buffer is not in Empty state
|
||||||
/// @throws LSFG::vulkan_error if beginning the command buffer fails.
|
/// @throws VK::vulkan_error if beginning the command buffer fails.
|
||||||
///
|
///
|
||||||
void begin();
|
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.
|
/// Dispatch a compute command.
|
||||||
///
|
///
|
||||||
|
|
@ -70,10 +87,12 @@ namespace LSFG::Core {
|
||||||
/// End recording commands in the command buffer.
|
/// End recording commands in the command buffer.
|
||||||
///
|
///
|
||||||
/// @throws std::logic_error if the command buffer is not in Recording state
|
/// @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();
|
void end();
|
||||||
|
|
||||||
|
// FIXME: Submit logic is kind of janky.
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Submit the command buffer to a queue.
|
/// Submit the command buffer to a queue.
|
||||||
///
|
///
|
||||||
|
|
@ -85,7 +104,7 @@ namespace LSFG::Core {
|
||||||
/// @param signalSemaphoreValues Values for the semaphores to signal
|
/// @param signalSemaphoreValues Values for the semaphores to signal
|
||||||
///
|
///
|
||||||
/// @throws std::logic_error if the command buffer is not in Full state.
|
/// @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,
|
void submit(VkQueue queue, std::optional<Fence> fence,
|
||||||
const std::vector<Semaphore>& waitSemaphores = {},
|
const std::vector<Semaphore>& waitSemaphores = {},
|
||||||
|
|
@ -94,7 +113,7 @@ namespace LSFG::Core {
|
||||||
std::optional<std::vector<uint64_t>> signalSemaphoreValues = std::nullopt);
|
std::optional<std::vector<uint64_t>> signalSemaphoreValues = std::nullopt);
|
||||||
|
|
||||||
/// Get the state of the command buffer.
|
/// 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.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->commandBuffer; }
|
[[nodiscard]] auto handle() const { return *this->commandBuffer; }
|
||||||
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan command pool.
|
/// C++ wrapper class for a Vulkan command pool.
|
||||||
|
|
@ -22,9 +22,9 @@ namespace LSFG::Core {
|
||||||
///
|
///
|
||||||
/// @param device Vulkan device
|
/// @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.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->commandPool; }
|
[[nodiscard]] auto handle() const { return *this->commandPool; }
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan descriptor pool.
|
/// C++ wrapper class for a Vulkan descriptor pool.
|
||||||
|
|
@ -22,9 +22,9 @@ namespace LSFG::Core {
|
||||||
///
|
///
|
||||||
/// @param device Vulkan device
|
/// @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.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->descriptorPool; }
|
[[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
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan fence.
|
/// C++ wrapper class for a Vulkan fence.
|
||||||
|
|
@ -23,18 +23,18 @@ namespace LSFG::Core {
|
||||||
///
|
///
|
||||||
/// @param device Vulkan device
|
/// @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.
|
/// Reset the fence to an unsignaled state.
|
||||||
///
|
///
|
||||||
/// @param device Vulkan device
|
/// @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
|
/// Wait for the fence
|
||||||
|
|
@ -43,9 +43,9 @@ namespace LSFG::Core {
|
||||||
/// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout.
|
/// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout.
|
||||||
/// @returns true if the fence signaled, false if it timed out.
|
/// @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.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->fence; }
|
[[nodiscard]] auto handle() const { return *this->fence; }
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
|
// TODO: Refactoring
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan image.
|
/// C++ wrapper class for a Vulkan image.
|
||||||
|
|
@ -26,9 +28,9 @@ namespace LSFG::Core {
|
||||||
/// @param usage Usage flags for the image
|
/// @param usage Usage flags for the image
|
||||||
/// @param aspectFlags Aspect flags for the image view
|
/// @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,
|
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT);
|
VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
|
@ -43,9 +45,9 @@ namespace LSFG::Core {
|
||||||
/// @param aspectFlags Aspect flags for the image view
|
/// @param aspectFlags Aspect flags for the image view
|
||||||
/// @param fd File descriptor for shared memory.
|
/// @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);
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd);
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
@ -58,9 +60,9 @@ namespace LSFG::Core {
|
||||||
/// @param aspectFlags Aspect flags for the image view
|
/// @param aspectFlags Aspect flags for the image view
|
||||||
/// @param fd Pointer to an integer where the file descriptor will be stored.
|
/// @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);
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd);
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// Get the Vulkan handle.
|
||||||
|
|
@ -70,11 +72,11 @@ namespace LSFG::Core {
|
||||||
/// Get the Vulkan image view handle.
|
/// Get the Vulkan image view handle.
|
||||||
[[nodiscard]] auto getView() const { return *this->view; }
|
[[nodiscard]] auto getView() const { return *this->view; }
|
||||||
/// Get the extent of the image.
|
/// 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.
|
/// 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.
|
/// 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.
|
/// Set the layout of the image.
|
||||||
void setLayout(VkImageLayout layout) { *this->layout = layout; }
|
void setLayout(VkImageLayout layout) { *this->layout = layout; }
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan instance.
|
/// C++ wrapper class for a Vulkan instance.
|
||||||
|
|
@ -16,12 +16,12 @@ namespace LSFG::Core {
|
||||||
///
|
///
|
||||||
/// Create the instance.
|
/// Create the instance.
|
||||||
///
|
///
|
||||||
/// @throws LSFG::vulkan_error if object creation fails.
|
/// @throws VK::vulkan_error if object creation fails.
|
||||||
///
|
///
|
||||||
Instance();
|
Instance();
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// 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
|
/// Trivially copyable, moveable and destructible
|
||||||
Instance(const Instance&) noexcept = default;
|
Instance(const Instance&) noexcept = default;
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/commandbuffer.hpp"
|
#include "vk/core/shadermodule.hpp"
|
||||||
#include "core/shadermodule.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "core/device.hpp"
|
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan pipeline.
|
/// C++ wrapper class for a Vulkan pipeline.
|
||||||
|
|
@ -25,16 +24,9 @@ namespace LSFG::Core {
|
||||||
/// @param device Vulkan device
|
/// @param device Vulkan device
|
||||||
/// @param shader Shader module to use for the pipeline.
|
/// @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);
|
Pipeline(const 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;
|
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->pipeline; }
|
[[nodiscard]] auto handle() const { return *this->pipeline; }
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan sampler.
|
/// C++ wrapper class for a Vulkan sampler.
|
||||||
|
|
@ -25,12 +25,10 @@ namespace LSFG::Core {
|
||||||
/// @param compare Compare operation for the sampler.
|
/// @param compare Compare operation for the sampler.
|
||||||
/// @param isWhite Whether the border color is white.
|
/// @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,
|
Sampler(const Device& device,
|
||||||
VkSamplerAddressMode mode,
|
VkSamplerAddressMode mode, VkCompareOp compare, bool isWhite);
|
||||||
VkCompareOp compare,
|
|
||||||
bool isWhite);
|
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// Get the Vulkan handle.
|
||||||
[[nodiscard]] auto handle() const { return *this->sampler; }
|
[[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
|
#pragma once
|
||||||
|
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace LSFG::Core {
|
namespace VK::Core {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// C++ wrapper class for a Vulkan shader module.
|
/// C++ wrapper class for a Vulkan shader module.
|
||||||
|
|
@ -28,9 +28,9 @@ namespace LSFG::Core {
|
||||||
/// @param code SPIR-V bytecode for the shader.
|
/// @param code SPIR-V bytecode for the shader.
|
||||||
/// @param descriptorTypes Descriptor types used in 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);
|
const std::vector<std::pair<size_t, VkDescriptorType>>& descriptorTypes);
|
||||||
|
|
||||||
/// Get the Vulkan handle.
|
/// 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 <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace LSFG {
|
namespace VK {
|
||||||
|
|
||||||
/// Simple exception class for Vulkan errors.
|
/// Simple exception class for Vulkan errors.
|
||||||
class vulkan_error : public std::runtime_error {
|
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 <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/buffer.hpp"
|
#include "vk/core/buffer.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#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
|
// create buffer
|
||||||
const VkBufferCreateInfo desc{
|
const VkBufferCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
.size = this->size,
|
.size = size,
|
||||||
.usage = usage,
|
.usage = usage,
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||||
};
|
};
|
||||||
VkBuffer bufferHandle{};
|
VkBuffer bufferHandle{};
|
||||||
auto res = vkCreateBuffer(device.handle(), &desc, nullptr, &bufferHandle);
|
auto res = vkCreateBuffer(device.handle(), &desc, nullptr, &bufferHandle);
|
||||||
if (res != VK_SUCCESS || bufferHandle == VK_NULL_HANDLE)
|
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
|
// find memory type
|
||||||
VkPhysicalDeviceMemoryProperties memProps;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
|
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
vkGetBufferMemoryRequirements(device.handle(), bufferHandle, &memReqs);
|
vkGetBufferMemoryRequirements(device.handle(), bufferHandle, &memReqs);
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits, true);
|
||||||
#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
|
|
||||||
}
|
|
||||||
if (!memType.has_value())
|
if (!memType.has_value())
|
||||||
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
// allocate and bind memory
|
// allocate and bind memory
|
||||||
const VkMemoryAllocateInfo allocInfo{
|
const VkMemoryAllocateInfo allocInfo{
|
||||||
|
|
@ -56,21 +43,22 @@ void Buffer::construct(const Core::Device& device, const void* data, VkBufferUsa
|
||||||
VkDeviceMemory memoryHandle{};
|
VkDeviceMemory memoryHandle{};
|
||||||
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
||||||
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
|
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);
|
res = vkBindBufferMemory(device.handle(), bufferHandle, memoryHandle, 0);
|
||||||
if (res != VK_SUCCESS)
|
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
|
// upload data to buffer
|
||||||
uint8_t* buf{};
|
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)
|
if (res != VK_SUCCESS || buf == nullptr)
|
||||||
throw LSFG::vulkan_error(res, "Failed to map memory for Vulkan buffer");
|
throw VK::vulkan_error(res, "Failed to map memory for Vulkan buffer");
|
||||||
std::copy_n(reinterpret_cast<const uint8_t*>(data), this->size, buf);
|
std::copy_n(reinterpret_cast<const uint8_t*>(data), size, buf);
|
||||||
vkUnmapMemory(device.handle(), memoryHandle);
|
vkUnmapMemory(device.handle(), memoryHandle);
|
||||||
|
|
||||||
// store buffer and memory in shared ptr
|
// store buffer and memory in shared ptr
|
||||||
|
this->size = size;
|
||||||
this->buffer = std::shared_ptr<VkBuffer>(
|
this->buffer = std::shared_ptr<VkBuffer>(
|
||||||
new VkBuffer(bufferHandle),
|
new VkBuffer(bufferHandle),
|
||||||
[dev = device.handle()](VkBuffer* img) {
|
[dev = device.handle()](VkBuffer* img) {
|
||||||
|
|
@ -1,22 +1,23 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/commandbuffer.hpp"
|
#include "vk/core/commandbuffer.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/commandpool.hpp"
|
||||||
#include "core/commandpool.hpp"
|
#include "vk/core/semaphore.hpp"
|
||||||
#include "core/fence.hpp"
|
#include "vk/core/pipeline.hpp"
|
||||||
#include "core/semaphore.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/core/fence.hpp"
|
||||||
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstdint>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#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
|
// create command buffer
|
||||||
const VkCommandBufferAllocateInfo desc{
|
const VkCommandBufferAllocateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||||
|
|
@ -27,7 +28,7 @@ CommandBuffer::CommandBuffer(const Core::Device& device, const CommandPool& pool
|
||||||
VkCommandBuffer commandBufferHandle{};
|
VkCommandBuffer commandBufferHandle{};
|
||||||
auto res = vkAllocateCommandBuffers(device.handle(), &desc, &commandBufferHandle);
|
auto res = vkAllocateCommandBuffers(device.handle(), &desc, &commandBufferHandle);
|
||||||
if (res != VK_SUCCESS || commandBufferHandle == VK_NULL_HANDLE)
|
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
|
// store command buffer in shared ptr
|
||||||
this->state = std::make_shared<CommandBufferState>(CommandBufferState::Empty);
|
this->state = std::make_shared<CommandBufferState>(CommandBufferState::Empty);
|
||||||
|
|
@ -49,11 +50,18 @@ void CommandBuffer::begin() {
|
||||||
};
|
};
|
||||||
auto res = vkBeginCommandBuffer(*this->commandBuffer, &beginInfo);
|
auto res = vkBeginCommandBuffer(*this->commandBuffer, &beginInfo);
|
||||||
if (res != VK_SUCCESS)
|
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;
|
*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 {
|
void CommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) const {
|
||||||
if (*this->state != CommandBufferState::Recording)
|
if (*this->state != CommandBufferState::Recording)
|
||||||
throw std::logic_error("Command buffer is not in Recording state");
|
throw std::logic_error("Command buffer is not in Recording state");
|
||||||
|
|
@ -67,7 +75,7 @@ void CommandBuffer::end() {
|
||||||
|
|
||||||
auto res = vkEndCommandBuffer(*this->commandBuffer);
|
auto res = vkEndCommandBuffer(*this->commandBuffer);
|
||||||
if (res != VK_SUCCESS)
|
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;
|
*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);
|
auto res = vkQueueSubmit(queue, 1, &submitInfo, fence ? fence->handle() : VK_NULL_HANDLE);
|
||||||
if (res != VK_SUCCESS)
|
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;
|
*this->state = CommandBufferState::Submitted;
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/commandpool.hpp"
|
#include "vk/core/commandpool.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace LSFG::Core;
|
using namespace VK::Core;
|
||||||
|
|
||||||
CommandPool::CommandPool(const Core::Device& device) {
|
CommandPool::CommandPool(const Device& device) {
|
||||||
// create command pool
|
// create command pool
|
||||||
const VkCommandPoolCreateInfo desc{
|
const VkCommandPoolCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||||
|
|
@ -18,7 +18,7 @@ CommandPool::CommandPool(const Core::Device& device) {
|
||||||
VkCommandPool commandPoolHandle{};
|
VkCommandPool commandPoolHandle{};
|
||||||
auto res = vkCreateCommandPool(device.handle(), &desc, nullptr, &commandPoolHandle);
|
auto res = vkCreateCommandPool(device.handle(), &desc, nullptr, &commandPoolHandle);
|
||||||
if (res != VK_SUCCESS || commandPoolHandle == VK_NULL_HANDLE)
|
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
|
// store command pool in shared ptr
|
||||||
this->commandPool = std::shared_ptr<VkCommandPool>(
|
this->commandPool = std::shared_ptr<VkCommandPool>(
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/descriptorpool.hpp"
|
#include "vk/core/descriptorpool.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#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
|
// create descriptor pool
|
||||||
const std::array<VkDescriptorPoolSize, 4> pools{{ // arbitrary limits
|
const std::array<VkDescriptorPoolSize, 4> pools{{ // arbitrary limits
|
||||||
{ .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 },
|
{ .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 },
|
||||||
|
|
@ -29,7 +29,7 @@ DescriptorPool::DescriptorPool(const Core::Device& device) {
|
||||||
VkDescriptorPool poolHandle{};
|
VkDescriptorPool poolHandle{};
|
||||||
auto res = vkCreateDescriptorPool(device.handle(), &desc, nullptr, &poolHandle);
|
auto res = vkCreateDescriptorPool(device.handle(), &desc, nullptr, &poolHandle);
|
||||||
if (res != VK_SUCCESS || poolHandle == VK_NULL_HANDLE)
|
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
|
// store pool in shared ptr
|
||||||
this->descriptorPool = std::shared_ptr<VkDescriptorPool>(
|
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 <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/fence.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/fence.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace LSFG::Core;
|
using namespace VK::Core;
|
||||||
|
|
||||||
Fence::Fence(const Core::Device& device) {
|
Fence::Fence(const Device& device) {
|
||||||
// create fence
|
// create fence
|
||||||
const VkFenceCreateInfo desc{
|
const VkFenceCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
|
||||||
};
|
};
|
||||||
VkFence fenceHandle{};
|
VkFence fenceHandle{};
|
||||||
auto res = vkCreateFence(device.handle(), &desc, nullptr, &fenceHandle);
|
auto res = vkCreateFence(device.handle(), &desc, nullptr, &fenceHandle);
|
||||||
if (res != VK_SUCCESS || fenceHandle == VK_NULL_HANDLE)
|
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
|
// store fence in shared ptr
|
||||||
this->fence = std::shared_ptr<VkFence>(
|
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();
|
VkFence fenceHandle = this->handle();
|
||||||
auto res = vkResetFences(device.handle(), 1, &fenceHandle);
|
auto res = vkResetFences(device.handle(), 1, &fenceHandle);
|
||||||
if (res != VK_SUCCESS)
|
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();
|
VkFence fenceHandle = this->handle();
|
||||||
auto res = vkWaitForFences(device.handle(), 1, &fenceHandle, VK_TRUE, timeout);
|
auto res = vkWaitForFences(device.handle(), 1, &fenceHandle, VK_TRUE, timeout);
|
||||||
if (res != VK_SUCCESS && res != VK_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;
|
return res == VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/image.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/image.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#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)
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags)
|
||||||
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
||||||
// create image
|
// create image
|
||||||
|
|
@ -33,28 +33,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImage imageHandle{};
|
VkImage imageHandle{};
|
||||||
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
||||||
if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE)
|
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
|
// find memory type
|
||||||
VkPhysicalDeviceMemoryProperties memProps;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
|
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits, false);
|
||||||
#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
|
|
||||||
}
|
|
||||||
if (!memType.has_value())
|
if (!memType.has_value())
|
||||||
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image");
|
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
// allocate and bind memory
|
// allocate and bind memory
|
||||||
const VkMemoryAllocateInfo allocInfo{
|
const VkMemoryAllocateInfo allocInfo{
|
||||||
|
|
@ -65,11 +52,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkDeviceMemory memoryHandle{};
|
VkDeviceMemory memoryHandle{};
|
||||||
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
||||||
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
|
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);
|
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
|
||||||
if (res != VK_SUCCESS)
|
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
|
// create image view
|
||||||
const VkImageViewCreateInfo viewDesc{
|
const VkImageViewCreateInfo viewDesc{
|
||||||
|
|
@ -93,7 +80,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImageView viewHandle{};
|
VkImageView viewHandle{};
|
||||||
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
||||||
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
|
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
|
// store objects in shared ptr
|
||||||
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
|
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
|
// 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)
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd)
|
||||||
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
||||||
// create image
|
// create image
|
||||||
|
|
@ -146,28 +135,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImage imageHandle{};
|
VkImage imageHandle{};
|
||||||
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
||||||
if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE)
|
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
|
// find memory type
|
||||||
VkPhysicalDeviceMemoryProperties memProps;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
|
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits, false);
|
||||||
#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
|
|
||||||
}
|
|
||||||
if (!memType.has_value())
|
if (!memType.has_value())
|
||||||
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image");
|
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
// ~~allocate~~ and bind memory
|
// ~~allocate~~ and bind memory
|
||||||
const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo2{
|
const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo2{
|
||||||
|
|
@ -189,11 +165,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkDeviceMemory memoryHandle{};
|
VkDeviceMemory memoryHandle{};
|
||||||
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
||||||
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
|
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);
|
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
|
||||||
if (res != VK_SUCCESS)
|
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
|
// create image view
|
||||||
const VkImageViewCreateInfo viewDesc{
|
const VkImageViewCreateInfo viewDesc{
|
||||||
|
|
@ -217,7 +193,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImageView viewHandle{};
|
VkImageView viewHandle{};
|
||||||
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
||||||
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
|
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
|
// store objects in shared ptr
|
||||||
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
|
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
|
// 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)
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd)
|
||||||
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
||||||
// create image
|
// create image
|
||||||
|
|
@ -270,28 +246,15 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImage imageHandle{};
|
VkImage imageHandle{};
|
||||||
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
|
||||||
if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE)
|
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
|
// find memory type
|
||||||
VkPhysicalDeviceMemoryProperties memProps;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
|
|
||||||
|
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits);
|
||||||
#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
|
|
||||||
}
|
|
||||||
if (!memType.has_value())
|
if (!memType.has_value())
|
||||||
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image");
|
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
// allocate and bind memory
|
// allocate and bind memory
|
||||||
const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo{
|
const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo{
|
||||||
|
|
@ -312,11 +275,11 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkDeviceMemory memoryHandle{};
|
VkDeviceMemory memoryHandle{};
|
||||||
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
||||||
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
|
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);
|
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
|
||||||
if (res != VK_SUCCESS)
|
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
|
// obtain the sharing fd
|
||||||
const VkMemoryGetFdInfoKHR fdInfo{
|
const VkMemoryGetFdInfoKHR fdInfo{
|
||||||
|
|
@ -326,7 +289,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
};
|
};
|
||||||
res = vkGetMemoryFdKHR(device.handle(), &fdInfo, fd);
|
res = vkGetMemoryFdKHR(device.handle(), &fdInfo, fd);
|
||||||
if (res != VK_SUCCESS || *fd < 0)
|
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
|
// create image view
|
||||||
const VkImageViewCreateInfo viewDesc{
|
const VkImageViewCreateInfo viewDesc{
|
||||||
|
|
@ -350,7 +313,7 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImageView viewHandle{};
|
VkImageView viewHandle{};
|
||||||
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
|
||||||
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
|
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
|
// store objects in shared ptr
|
||||||
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
|
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/instance.hpp"
|
#include "vk/core/instance.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace LSFG::Core;
|
using namespace VK::Core;
|
||||||
|
|
||||||
const std::vector<const char*> requiredExtensions = {
|
const std::vector<const char*> requiredExtensions = {
|
||||||
|
// empty, for now :3
|
||||||
};
|
};
|
||||||
|
|
||||||
Instance::Instance() {
|
Instance::Instance() {
|
||||||
volkInitialize();
|
volkInitialize(); // FIXME: get rid of volk dependency fully
|
||||||
|
|
||||||
// create Vulkan instance
|
// create Vulkan instance
|
||||||
const VkApplicationInfo appInfo{
|
const VkApplicationInfo appInfo{
|
||||||
|
|
@ -35,7 +35,7 @@ Instance::Instance() {
|
||||||
VkInstance instanceHandle{};
|
VkInstance instanceHandle{};
|
||||||
auto res = vkCreateInstance(&createInfo, nullptr, &instanceHandle);
|
auto res = vkCreateInstance(&createInfo, nullptr, &instanceHandle);
|
||||||
if (res != VK_SUCCESS)
|
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);
|
volkLoadInstance(instanceHandle);
|
||||||
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/pipeline.hpp"
|
#include "vk/core/shadermodule.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/pipeline.hpp"
|
||||||
#include "core/shadermodule.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "core/commandbuffer.hpp"
|
#include "vk/exception.hpp"
|
||||||
#include "common/exception.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
#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
|
// create pipeline layout
|
||||||
VkDescriptorSetLayout shaderLayout = shader.getLayout();
|
VkDescriptorSetLayout shaderLayout = shader.getLayout();
|
||||||
const VkPipelineLayoutCreateInfo layoutDesc{
|
const VkPipelineLayoutCreateInfo layoutDesc{
|
||||||
|
|
@ -22,7 +21,7 @@ Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) {
|
||||||
VkPipelineLayout layoutHandle{};
|
VkPipelineLayout layoutHandle{};
|
||||||
auto res = vkCreatePipelineLayout(device.handle(), &layoutDesc, nullptr, &layoutHandle);
|
auto res = vkCreatePipelineLayout(device.handle(), &layoutDesc, nullptr, &layoutHandle);
|
||||||
if (res != VK_SUCCESS || !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
|
// create pipeline
|
||||||
const VkPipelineShaderStageCreateInfo shaderStageInfo{
|
const VkPipelineShaderStageCreateInfo shaderStageInfo{
|
||||||
|
|
@ -40,7 +39,7 @@ Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) {
|
||||||
res = vkCreateComputePipelines(device.handle(),
|
res = vkCreateComputePipelines(device.handle(),
|
||||||
VK_NULL_HANDLE, 1, &pipelineDesc, nullptr, &pipelineHandle);
|
VK_NULL_HANDLE, 1, &pipelineDesc, nullptr, &pipelineHandle);
|
||||||
if (res != VK_SUCCESS || !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
|
// store layout and pipeline in shared ptr
|
||||||
this->layout = std::shared_ptr<VkPipelineLayout>(
|
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 <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/sampler.hpp"
|
#include "vk/core/sampler.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace LSFG::Core;
|
using namespace VK::Core;
|
||||||
|
|
||||||
Sampler::Sampler(const Core::Device& device,
|
Sampler::Sampler(const Device& device,
|
||||||
VkSamplerAddressMode mode,
|
VkSamplerAddressMode mode, VkCompareOp compare, bool isWhite) {
|
||||||
VkCompareOp compare,
|
|
||||||
bool isWhite) {
|
|
||||||
// create sampler
|
// create sampler
|
||||||
const VkSamplerCreateInfo desc{
|
const VkSamplerCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
|
|
@ -31,7 +29,7 @@ Sampler::Sampler(const Core::Device& device,
|
||||||
VkSampler samplerHandle{};
|
VkSampler samplerHandle{};
|
||||||
auto res = vkCreateSampler(device.handle(), &desc, nullptr, &samplerHandle);
|
auto res = vkCreateSampler(device.handle(), &desc, nullptr, &samplerHandle);
|
||||||
if (res != VK_SUCCESS || samplerHandle == VK_NULL_HANDLE)
|
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
|
// store sampler in shared ptr
|
||||||
this->sampler = std::shared_ptr<VkSampler>(
|
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 <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "core/shadermodule.hpp"
|
#include "vk/core/shadermodule.hpp"
|
||||||
#include "core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
#include "common/exception.hpp"
|
#include "vk/exception.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cstddef>
|
#include <vector>
|
||||||
#include <memory>
|
#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) {
|
const std::vector<std::pair<size_t, VkDescriptorType>>& descriptorTypes) {
|
||||||
// create shader module
|
// create shader module
|
||||||
const uint8_t* data_ptr = code.data();
|
const uint8_t* data_ptr = code.data();
|
||||||
|
|
@ -25,7 +25,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
||||||
VkShaderModule shaderModuleHandle{};
|
VkShaderModule shaderModuleHandle{};
|
||||||
auto res = vkCreateShaderModule(device.handle(), &createInfo, nullptr, &shaderModuleHandle);
|
auto res = vkCreateShaderModule(device.handle(), &createInfo, nullptr, &shaderModuleHandle);
|
||||||
if (res != VK_SUCCESS || !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
|
// create descriptor set layout
|
||||||
std::vector<VkDescriptorSetLayoutBinding> layoutBindings;
|
std::vector<VkDescriptorSetLayoutBinding> layoutBindings;
|
||||||
|
|
@ -50,7 +50,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
||||||
bindIdx = &outputIdx;
|
bindIdx = &outputIdx;
|
||||||
break;
|
break;
|
||||||
default:
|
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 {
|
layoutBindings.emplace_back(VkDescriptorSetLayoutBinding {
|
||||||
|
|
@ -71,7 +71,7 @@ ShaderModule::ShaderModule(const Core::Device& device, const std::vector<uint8_t
|
||||||
VkDescriptorSetLayout descriptorSetLayout{};
|
VkDescriptorSetLayout descriptorSetLayout{};
|
||||||
res = vkCreateDescriptorSetLayout(device.handle(), &layoutDesc, nullptr, &descriptorSetLayout);
|
res = vkCreateDescriptorSetLayout(device.handle(), &layoutDesc, nullptr, &descriptorSetLayout);
|
||||||
if (res != VK_SUCCESS || !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
|
// store module and layout in shared ptr
|
||||||
this->shaderModule = std::shared_ptr<VkShaderModule>(
|
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>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace LSFG;
|
using namespace VK;
|
||||||
|
|
||||||
vulkan_error::vulkan_error(VkResult result, const std::string& message)
|
vulkan_error::vulkan_error(VkResult result, const std::string& message)
|
||||||
: std::runtime_error(std::format("{} (error {})", message, static_cast<int32_t>(result))),
|
: std::runtime_error(std::format("{} (error {})", message, static_cast<int32_t>(result))),
|
||||||
Loading…
Add table
Reference in a new issue