general cleanup

This commit is contained in:
PancakeTAS 2025-06-29 20:20:02 +02:00
parent 6261a6ed6e
commit dc11a64c0a
No known key found for this signature in database
26 changed files with 75 additions and 235 deletions

View file

@ -25,7 +25,6 @@ namespace Vulkan::Core {
/// @param data Initial data for the buffer.
/// @param usage Usage flags for the buffer
///
/// @throws std::invalid_argument if the device or buffer size is invalid
/// @throws ls::vulkan_error if object creation fails.
///
Buffer(const Device& device, size_t size, std::vector<uint8_t> data,
@ -36,11 +35,6 @@ namespace Vulkan::Core {
/// Get the size of the buffer.
[[nodiscard]] size_t getSize() const { return this->size; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->buffer); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
Buffer(const Buffer&) noexcept = default;
Buffer& operator=(const Buffer&) noexcept = default;

View file

@ -41,7 +41,6 @@ namespace Vulkan::Core {
/// @param device Vulkan device
/// @param pool Vulkan command pool
///
/// @throws std::invalid_argument if the device or pool are invalid.
/// @throws ls::vulkan_error if object creation fails.
///
CommandBuffer(const Device& device, const CommandPool& pool);
@ -83,7 +82,6 @@ namespace Vulkan::Core {
/// @param signalSemaphores Semaphores to signal after executing the command buffer
/// @param signalSemaphoreValues Values for the semaphores to signal
///
/// @throws std::invalid_argument if the queue is null.
/// @throws std::logic_error if the command buffer is not in Full state.
/// @throws ls::vulkan_error if submission fails.
///
@ -98,11 +96,6 @@ namespace Vulkan::Core {
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->commandBuffer; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->commandBuffer); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
CommandBuffer(const CommandBuffer&) noexcept = default;
CommandBuffer& operator=(const CommandBuffer&) noexcept = default;

View file

@ -21,7 +21,6 @@ namespace Vulkan::Core {
///
/// @param device Vulkan device
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
CommandPool(const Device& device);
@ -29,11 +28,6 @@ namespace Vulkan::Core {
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->commandPool; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->commandPool); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
CommandPool(const CommandPool&) noexcept = default;
CommandPool& operator=(const CommandPool&) noexcept = default;

View file

@ -21,7 +21,6 @@ namespace Vulkan::Core {
///
/// @param device Vulkan device
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
DescriptorPool(const Device& device);
@ -29,11 +28,6 @@ namespace Vulkan::Core {
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->descriptorPool; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->descriptorPool); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
DescriptorPool(const DescriptorPool&) noexcept = default;
DescriptorPool& operator=(const DescriptorPool&) noexcept = default;

View file

@ -31,7 +31,6 @@ namespace Vulkan::Core {
/// @param pool Descriptor pool to allocate from
/// @param shaderModule Shader module to use for the descriptor set
///
/// @throws std::invalid_argument if the device, pool or shader module is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
DescriptorSet(const Device& device,
@ -45,8 +44,6 @@ namespace Vulkan::Core {
/// @param device Vulkan device
/// @param resources Resources to update the descriptor set with
///
/// @throws std::invalid_argument if the device or resources are invalid.
///
void update(const Device& device,
const std::vector<std::vector<ResourcePair>>& resources) const;
@ -56,18 +53,11 @@ namespace Vulkan::Core {
/// @param commandBuffer Command buffer to bind the descriptor set to.
/// @param pipeline Pipeline to bind the descriptor set to.
///
/// @throws std::invalid_argument if the command buffer or pipeline is invalid.
///
void bind(const CommandBuffer& commandBuffer, const Pipeline& pipeline) const;
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->descriptorSet; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->descriptorSet); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
DescriptorSet(const DescriptorSet&) noexcept = default;
DescriptorSet& operator=(const DescriptorSet&) noexcept = default;

View file

@ -21,7 +21,6 @@ namespace Vulkan::Core {
///
/// @param device Vulkan device
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
Fence(const Device& device);
@ -29,28 +28,26 @@ namespace Vulkan::Core {
///
/// Reset the fence to an unsignaled state.
///
/// @param device Vulkan device
///
/// @throws ls::vulkan_error if resetting fails.
///
void reset() const;
void reset(const Device& device) const;
///
/// Wait for the fence
///
/// @param device Vulkan device
/// @param timeout The timeout in nanoseconds, or UINT64_MAX for no timeout.
/// @returns true if the fence signaled, false if it timed out.
///
/// @throws ls::vulkan_error if waiting fails.
///
[[nodiscard]] bool wait(uint64_t timeout = UINT64_MAX) const;
[[nodiscard]] bool wait(const Device& device, uint64_t timeout = UINT64_MAX) const;
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->fence; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->fence); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
// Trivially copyable, moveable and destructible
Fence(const Fence&) noexcept = default;
Fence& operator=(const Fence&) noexcept = default;
@ -59,7 +56,6 @@ namespace Vulkan::Core {
~Fence() = default;
private:
std::shared_ptr<VkFence> fence;
VkDevice device{};
};
}

View file

@ -25,7 +25,6 @@ namespace Vulkan::Core {
/// @param usage Usage flags for the image
/// @param aspectFlags Aspect flags for the image view
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
Image(const Device& device, VkExtent2D extent, VkFormat format,
@ -40,11 +39,6 @@ namespace Vulkan::Core {
/// Get the format of the image.
[[nodiscard]] VkFormat getFormat() const { return this->format; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->image); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
Image(const Image&) noexcept = default;
Image& operator=(const Image&) noexcept = default;

View file

@ -24,7 +24,6 @@ namespace Vulkan::Core {
/// @param device Vulkan device
/// @param shader Shader module to use for the pipeline.
///
/// @throws std::invalid_argument if the device or shader module is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
Pipeline(const Device& device, const ShaderModule& shader);
@ -34,8 +33,6 @@ namespace Vulkan::Core {
///
/// @param commandBuffer Command buffer to bind the pipeline to.
///
/// @throws std::invalid_argument if the command buffer is invalid.
///
void bind(const CommandBuffer& commandBuffer) const;
/// Get the Vulkan handle.
@ -43,11 +40,6 @@ namespace Vulkan::Core {
/// Get the pipeline layout.
[[nodiscard]] auto getLayout() const { return *this->layout; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->pipeline); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
Pipeline(const Pipeline&) noexcept = default;
Pipeline& operator=(const Pipeline&) noexcept = default;

View file

@ -22,7 +22,6 @@ namespace Vulkan::Core {
/// @param device Vulkan device
/// @param mode Address mode for the sampler.
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
Sampler(const Device& device, VkSamplerAddressMode mode);
@ -30,11 +29,6 @@ namespace Vulkan::Core {
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->sampler; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->sampler); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
Sampler(const Sampler&) noexcept = default;
Sampler& operator=(const Sampler&) noexcept = default;

View file

@ -23,7 +23,6 @@ namespace Vulkan::Core {
/// @param device Vulkan device
/// @param initial Optional initial value for creating a timeline semaphore.
///
/// @throws std::invalid_argument if the device is null.
/// @throws ls::vulkan_error if object creation fails.
///
Semaphore(const Device& device, std::optional<uint32_t> initial = std::nullopt);
@ -31,16 +30,18 @@ namespace Vulkan::Core {
///
/// 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 ls::vulkan_error if signaling fails.
///
void signal(uint64_t value) const;
void signal(const 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.
@ -48,16 +49,11 @@ namespace Vulkan::Core {
/// @throws std::logic_error if the semaphore is not a timeline semaphore.
/// @throws ls::vulkan_error if waiting fails.
///
[[nodiscard]] bool wait(uint64_t value, uint64_t timeout = UINT64_MAX) const;
[[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; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->semaphore); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
// Trivially copyable, moveable and destructible
Semaphore(const Semaphore&) noexcept = default;
Semaphore& operator=(const Semaphore&) noexcept = default;
@ -66,7 +62,6 @@ namespace Vulkan::Core {
~Semaphore() = default;
private:
std::shared_ptr<VkSemaphore> semaphore;
VkDevice device{};
bool isTimeline{};
};

View file

@ -26,7 +26,6 @@ namespace Vulkan::Core {
/// @param path Path to the shader file.
/// @param descriptorTypes Descriptor types used in the shader.
///
/// @throws std::invalid_argument if the device is invalid.
/// @throws std::system_error if the shader file cannot be opened or read.
/// @throws ls::vulkan_error if object creation fails.
///
@ -38,11 +37,6 @@ namespace Vulkan::Core {
/// Get the descriptor set layout.
[[nodiscard]] auto getDescriptorSetLayout() const { return *this->descriptorSetLayout; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->shaderModule); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
ShaderModule(const ShaderModule&) noexcept = default;
ShaderModule& operator=(const ShaderModule&) noexcept = default;

View file

@ -21,7 +21,6 @@ namespace Vulkan {
///
/// @param instance Vulkan instance
///
/// @throws std::invalid_argument if the instance is invalid.
/// @throws ls::vulkan_error if object creation fails.
///
Device(const Vulkan::Instance& instance);
@ -35,11 +34,6 @@ namespace Vulkan {
/// Get the compute queue.
[[nodiscard]] VkQueue getComputeQueue() const { return this->computeQueue; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->device); }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
// Trivially copyable, moveable and destructible
Device(const Device&) noexcept = default;
Device& operator=(const Device&) noexcept = default;

View file

@ -24,11 +24,6 @@ namespace Vulkan {
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return this->instance ? *this->instance : VK_NULL_HANDLE; }
/// Check whether the object is valid.
[[nodiscard]] bool isValid() const { return this->handle() != VK_NULL_HANDLE; }
/// if (obj) operator. Checks if the object is valid.
explicit operator bool() const { return this->isValid(); }
/// Trivially copyable, moveable and destructible
Instance(const Instance&) noexcept = default;
Instance& operator=(const Instance&) noexcept = default;

View file

@ -8,11 +8,6 @@ using namespace Vulkan::Core;
Buffer::Buffer(const Device& device, size_t size, std::vector<uint8_t> data,
VkBufferUsageFlags usage) : size(size) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
if (size < data.size())
throw std::invalid_argument("Invalid buffer size");
// create buffer
const VkBufferCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
@ -62,6 +57,14 @@ Buffer::Buffer(const Device& device, size_t size, std::vector<uint8_t> data,
if (res != VK_SUCCESS)
throw ls::vulkan_error(res, "Failed to bind memory to Vulkan buffer");
// upload data to buffer
uint8_t* buf{};
res = vkMapMemory(device.handle(), memoryHandle, 0, size, 0, reinterpret_cast<void**>(&buf));
if (res != VK_SUCCESS || buf == nullptr)
throw ls::vulkan_error(res, "Failed to map memory for Vulkan buffer");
std::copy_n(data.data(), std::min(size, data.size()), buf);
vkUnmapMemory(device.handle(), memoryHandle);
// store buffer and memory in shared ptr
this->buffer = std::shared_ptr<VkBuffer>(
new VkBuffer(bufferHandle),
@ -75,12 +78,4 @@ Buffer::Buffer(const Device& device, size_t size, std::vector<uint8_t> data,
vkFreeMemory(dev, *mem, nullptr);
}
);
// upload data to buffer
uint8_t* buf{};
res = vkMapMemory(device.handle(), memoryHandle, 0, size, 0, reinterpret_cast<void**>(&buf));
if (res != VK_SUCCESS || buf == nullptr)
throw ls::vulkan_error(res, "Failed to map memory for Vulkan buffer");
std::copy_n(data.data(), size, buf);
vkUnmapMemory(device.handle(), memoryHandle);
}

View file

@ -4,11 +4,8 @@
using namespace Vulkan::Core;
CommandBuffer::CommandBuffer(const Device& device, const CommandPool& pool) {
if (!device || !pool)
throw std::invalid_argument("Invalid Vulkan device or command pool");
// create command buffer
const VkCommandBufferAllocateInfo desc = {
const VkCommandBufferAllocateInfo desc{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = pool.handle(),
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
@ -67,14 +64,12 @@ void CommandBuffer::submit(VkQueue queue, std::optional<Fence> fence,
std::optional<std::vector<uint64_t>> waitSemaphoreValues,
const std::vector<Semaphore>& signalSemaphores,
std::optional<std::vector<uint64_t>> signalSemaphoreValues) {
if (!queue)
throw std::invalid_argument("Invalid Vulkan queue");
if (*this->state != CommandBufferState::Full)
throw std::logic_error("Command buffer is not in Full state");
const std::vector<VkPipelineStageFlags> waitStages(waitSemaphores.size(),
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
VkTimelineSemaphoreSubmitInfo timelineInfo = {
VkTimelineSemaphoreSubmitInfo timelineInfo{
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
};
if (waitSemaphoreValues.has_value()) {
@ -88,20 +83,14 @@ void CommandBuffer::submit(VkQueue queue, std::optional<Fence> fence,
timelineInfo.pSignalSemaphoreValues = signalSemaphoreValues->data();
}
std::vector<VkSemaphore> waitSemaphoresHandles;
for (const auto& semaphore : waitSemaphores) {
if (!semaphore)
throw std::invalid_argument("Invalid Vulkan semaphore in waitSemaphores");
std::vector<VkSemaphore> waitSemaphoresHandles(waitSemaphores.size());
for (const auto& semaphore : waitSemaphores)
waitSemaphoresHandles.push_back(semaphore.handle());
}
std::vector<VkSemaphore> signalSemaphoresHandles;
for (const auto& semaphore : signalSemaphores) {
if (!semaphore)
throw std::invalid_argument("Invalid Vulkan semaphore in signalSemaphores");
std::vector<VkSemaphore> signalSemaphoresHandles(signalSemaphores.size());
for (const auto& semaphore : signalSemaphores)
signalSemaphoresHandles.push_back(semaphore.handle());
}
const VkSubmitInfo submitInfo = {
const VkSubmitInfo submitInfo{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = (waitSemaphoreValues.has_value() || signalSemaphoreValues.has_value())
? &timelineInfo : nullptr,

View file

@ -4,11 +4,8 @@
using namespace Vulkan::Core;
CommandPool::CommandPool(const Device& device) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// create command pool
const VkCommandPoolCreateInfo desc = {
const VkCommandPoolCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.queueFamilyIndex = device.getComputeFamilyIdx()
};
@ -17,7 +14,7 @@ CommandPool::CommandPool(const Device& device) {
if (res != VK_SUCCESS || commandPoolHandle == VK_NULL_HANDLE)
throw ls::vulkan_error(res, "Unable to create command pool");
// store the command pool in a shared pointer
// store command pool in shared ptr
this->commandPool = std::shared_ptr<VkCommandPool>(
new VkCommandPool(commandPoolHandle),
[dev = device.handle()](VkCommandPool* commandPoolHandle) {

View file

@ -6,9 +6,6 @@
using namespace Vulkan::Core;
DescriptorPool::DescriptorPool(const Device& device) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// create descriptor pool
const std::array<VkDescriptorPoolSize, 4> pools{{ // arbitrary limits
{ .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 },
@ -18,7 +15,7 @@ DescriptorPool::DescriptorPool(const Device& device) {
}};
const VkDescriptorPoolCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = 16384, // arbitrary limit
.maxSets = 16384,
.poolSizeCount = static_cast<uint32_t>(pools.size()),
.pPoolSizes = pools.data()
};
@ -27,7 +24,7 @@ DescriptorPool::DescriptorPool(const Device& device) {
if (res != VK_SUCCESS || poolHandle == VK_NULL_HANDLE)
throw ls::vulkan_error(res, "Unable to create descriptor pool");
/// store pool in shared ptr
// store pool in shared ptr
this->descriptorPool = std::shared_ptr<VkDescriptorPool>(
new VkDescriptorPool(poolHandle),
[dev = device.handle()](VkDescriptorPool* poolHandle) {

View file

@ -5,9 +5,6 @@ using namespace Vulkan::Core;
DescriptorSet::DescriptorSet(const Device& device,
DescriptorPool pool, const ShaderModule& shaderModule) {
if (!device || !pool)
throw std::invalid_argument("Invalid Vulkan device");
// create descriptor set
VkDescriptorSetLayout layout = shaderModule.getDescriptorSetLayout();
const VkDescriptorSetAllocateInfo desc{
@ -21,7 +18,7 @@ DescriptorSet::DescriptorSet(const Device& device,
if (res != VK_SUCCESS || descriptorSetHandle == VK_NULL_HANDLE)
throw ls::vulkan_error(res, "Unable to allocate descriptor set");
/// store descriptor set in shared ptr
/// store set in shared ptr
this->descriptorSet = std::shared_ptr<VkDescriptorSet>(
new VkDescriptorSet(descriptorSetHandle),
[dev = device.handle(), pool = std::move(pool)](VkDescriptorSet* setHandle) {
@ -32,9 +29,6 @@ DescriptorSet::DescriptorSet(const Device& device,
void DescriptorSet::update(const Device& device,
const std::vector<std::vector<ResourcePair>>& resources) const {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
uint32_t bindingIndex = 0;
for (const auto& list : resources) {
@ -48,36 +42,23 @@ void DescriptorSet::update(const Device& device,
};
if (std::holds_alternative<Image>(resource)) {
const auto& image = std::get<Image>(resource);
if (!image)
throw std::invalid_argument("Invalid image resource");
const VkDescriptorImageInfo imageInfo{
.imageView = image.getView(),
.imageView = std::get<Image>(resource).getView(),
.imageLayout = VK_IMAGE_LAYOUT_GENERAL
};
writeDesc.pImageInfo = &imageInfo;
} else if (std::holds_alternative<Sampler>(resource)) {
const auto& sampler = std::get<Sampler>(resource);
if (!sampler)
throw std::invalid_argument("Invalid sampler resource");
const VkDescriptorImageInfo imageInfo{
.sampler = sampler.handle()
.sampler = std::get<Sampler>(resource).handle()
};
writeDesc.pImageInfo = &imageInfo;
} else if (std::holds_alternative<Buffer>(resource)) {
const auto& buffer = std::get<Buffer>(resource);
if (!buffer)
throw std::invalid_argument("Invalid buffer resource");
const VkDescriptorBufferInfo bufferInfo{
.buffer = buffer.handle(),
.range = buffer.getSize()
};
writeDesc.pBufferInfo = &bufferInfo;
} else {
throw std::invalid_argument("Unsupported resource type");
}
writeDescriptorSets.push_back(writeDesc);
@ -86,18 +67,12 @@ void DescriptorSet::update(const Device& device,
vkUpdateDescriptorSets(device.handle(),
static_cast<uint32_t>(writeDescriptorSets.size()),
writeDescriptorSets.data(),
0, nullptr);
writeDescriptorSets.data(), 0, nullptr);
}
void DescriptorSet::bind(const CommandBuffer& commandBuffer, const Pipeline& pipeline) const {
if (!commandBuffer)
throw std::invalid_argument("Invalid command buffer");
// bind descriptor set
VkDescriptorSet descriptorSetHandle = this->handle();
vkCmdBindDescriptorSets(commandBuffer.handle(),
VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.getLayout(),
0, 1, &descriptorSetHandle,
0, nullptr);
0, 1, &descriptorSetHandle, 0, nullptr);
}

View file

@ -4,11 +4,8 @@
using namespace Vulkan::Core;
Fence::Fence(const Device& device) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// create fence
const VkFenceCreateInfo desc = {
// create fence
const VkFenceCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
};
VkFence fenceHandle{};
@ -17,7 +14,6 @@ Fence::Fence(const Device& device) {
throw ls::vulkan_error(res, "Unable to create fence");
// store fence in shared ptr
this->device = device.handle();
this->fence = std::shared_ptr<VkFence>(
new VkFence(fenceHandle),
[dev = device.handle()](VkFence* fenceHandle) {
@ -26,16 +22,16 @@ Fence::Fence(const Device& device) {
);
}
void Fence::reset() const {
void Fence::reset(const Device& device) const {
VkFence fenceHandle = this->handle();
auto res = vkResetFences(this->device, 1, &fenceHandle);
auto res = vkResetFences(device.handle(), 1, &fenceHandle);
if (res != VK_SUCCESS)
throw ls::vulkan_error(res, "Unable to reset fence");
}
bool Fence::wait(uint64_t timeout) const {
bool Fence::wait(const Device& device, uint64_t timeout) const {
VkFence fenceHandle = this->handle();
auto res = vkWaitForFences(this->device, 1, &fenceHandle, VK_TRUE, timeout);
auto res = vkWaitForFences(device.handle(), 1, &fenceHandle, VK_TRUE, timeout);
if (res != VK_SUCCESS && res != VK_TIMEOUT)
throw ls::vulkan_error(res, "Unable to wait for fence");

View file

@ -8,9 +8,6 @@ using namespace Vulkan::Core;
Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags)
: extent(extent), format(format) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// create image
const VkImageCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@ -68,24 +65,10 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
if (res != VK_SUCCESS)
throw ls::vulkan_error(res, "Failed to bind memory to Vulkan image");
// store image and memory in shared ptr
this->image = std::shared_ptr<VkImage>(
new VkImage(imageHandle),
[dev = device.handle()](VkImage* img) {
vkDestroyImage(dev, *img, nullptr);
}
);
this->memory = std::shared_ptr<VkDeviceMemory>(
new VkDeviceMemory(memoryHandle),
[dev = device.handle()](VkDeviceMemory* mem) {
vkFreeMemory(dev, *mem, nullptr);
}
);
// create image view
const VkImageViewCreateInfo viewDesc{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = *this->image,
.image = imageHandle,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {
@ -106,7 +89,19 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
throw ls::vulkan_error(res, "Failed to create image view");
// store image view in shared ptr
// store objects in shared ptr
this->image = std::shared_ptr<VkImage>(
new VkImage(imageHandle),
[dev = device.handle()](VkImage* img) {
vkDestroyImage(dev, *img, nullptr);
}
);
this->memory = std::shared_ptr<VkDeviceMemory>(
new VkDeviceMemory(memoryHandle),
[dev = device.handle()](VkDeviceMemory* mem) {
vkFreeMemory(dev, *mem, nullptr);
}
);
this->view = std::shared_ptr<VkImageView>(
new VkImageView(viewHandle),
[dev = device.handle()](VkImageView* imgView) {

View file

@ -4,9 +4,6 @@
using namespace Vulkan::Core;
Pipeline::Pipeline(const Device& device, const ShaderModule& shader) {
if (!device || !shader)
throw std::invalid_argument("Invalid Vulkan device or shader module");
// create pipeline layout
VkDescriptorSetLayout shaderLayout = shader.getDescriptorSetLayout();
const VkPipelineLayoutCreateInfo layoutDesc{
@ -19,14 +16,6 @@ Pipeline::Pipeline(const Device& device, const ShaderModule& shader) {
if (res != VK_SUCCESS || !layoutHandle)
throw ls::vulkan_error(res, "Failed to create pipeline layout");
// store layout in shared ptr
this->layout = std::shared_ptr<VkPipelineLayout>(
new VkPipelineLayout(layoutHandle),
[dev = device.handle()](VkPipelineLayout* layout) {
vkDestroyPipelineLayout(dev, *layout, nullptr);
}
);
// create pipeline
const VkPipelineShaderStageCreateInfo shaderStageInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@ -45,7 +34,13 @@ Pipeline::Pipeline(const Device& device, const ShaderModule& shader) {
if (res != VK_SUCCESS || !pipelineHandle)
throw ls::vulkan_error(res, "Failed to create compute pipeline");
// store pipeline in shared ptr
// store layout and pipeline in shared ptr
this->layout = std::shared_ptr<VkPipelineLayout>(
new VkPipelineLayout(layoutHandle),
[dev = device.handle()](VkPipelineLayout* layout) {
vkDestroyPipelineLayout(dev, *layout, nullptr);
}
);
this->pipeline = std::shared_ptr<VkPipeline>(
new VkPipeline(pipelineHandle),
[dev = device.handle()](VkPipeline* pipeline) {
@ -55,8 +50,5 @@ Pipeline::Pipeline(const Device& device, const ShaderModule& shader) {
}
void Pipeline::bind(const CommandBuffer& commandBuffer) const {
if (!commandBuffer)
throw std::invalid_argument("Invalid command buffer");
vkCmdBindPipeline(commandBuffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, *this->pipeline);
vkCmdBindPipeline(commandBuffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, *this->pipeline);
}

View file

@ -4,9 +4,6 @@
using namespace Vulkan::Core;
Sampler::Sampler(const Device& device, VkSamplerAddressMode mode) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// create sampler
const VkSamplerCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
@ -23,7 +20,7 @@ Sampler::Sampler(const Device& device, VkSamplerAddressMode mode) {
if (res != VK_SUCCESS || samplerHandle == VK_NULL_HANDLE)
throw ls::vulkan_error(res, "Unable to create sampler");
// store the sampler in a shared pointer
// store sampler in shared ptr
this->sampler = std::shared_ptr<VkSampler>(
new VkSampler(samplerHandle),
[dev = device.handle()](VkSampler* samplerHandle) {

View file

@ -4,16 +4,13 @@
using namespace Vulkan::Core;
Semaphore::Semaphore(const Device& device, std::optional<uint32_t> initial) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// 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 = {
const VkSemaphoreCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = initial.has_value() ? &typeInfo : nullptr,
};
@ -24,7 +21,6 @@ Semaphore::Semaphore(const Device& device, std::optional<uint32_t> initial) {
// store semaphore in shared ptr
this->isTimeline = initial.has_value();
this->device = device.handle();
this->semaphore = std::shared_ptr<VkSemaphore>(
new VkSemaphore(semaphoreHandle),
[dev = device.handle()](VkSemaphore* semaphoreHandle) {
@ -33,7 +29,7 @@ Semaphore::Semaphore(const Device& device, std::optional<uint32_t> initial) {
);
}
void Semaphore::signal(uint64_t value) const {
void Semaphore::signal(const Device& device, uint64_t value) const {
if (!this->isTimeline)
throw std::logic_error("Invalid timeline semaphore");
@ -42,12 +38,12 @@ void Semaphore::signal(uint64_t value) const {
.semaphore = this->handle(),
.value = value
};
auto res = vkSignalSemaphore(this->device, &signalInfo);
auto res = vkSignalSemaphore(device.handle(), &signalInfo);
if (res != VK_SUCCESS)
throw ls::vulkan_error(res, "Unable to signal semaphore");
}
bool Semaphore::wait(uint64_t value, uint64_t timeout) const {
bool Semaphore::wait(const Device& device, uint64_t value, uint64_t timeout) const {
if (!this->isTimeline)
throw std::logic_error("Invalid timeline semaphore");
@ -58,7 +54,7 @@ bool Semaphore::wait(uint64_t value, uint64_t timeout) const {
.pSemaphores = &semaphore,
.pValues = &value
};
auto res = vkWaitSemaphores(this->device, &waitInfo, timeout);
auto res = vkWaitSemaphores(device.handle(), &waitInfo, timeout);
if (res != VK_SUCCESS && res != VK_TIMEOUT)
throw ls::vulkan_error(res, "Unable to wait for semaphore");

View file

@ -7,9 +7,6 @@ using namespace Vulkan::Core;
ShaderModule::ShaderModule(const Device& device, const std::string& path,
const std::vector<std::pair<size_t, VkDescriptorType>>& descriptorTypes) {
if (!device)
throw std::invalid_argument("Invalid Vulkan device");
// read shader bytecode
std::ifstream file(path, std::ios::ate | std::ios::binary);
if (!file)
@ -36,14 +33,6 @@ ShaderModule::ShaderModule(const Device& device, const std::string& path,
if (res != VK_SUCCESS || !shaderModuleHandle)
throw ls::vulkan_error(res, "Failed to create shader module");
// store shader module in shared ptr
this->shaderModule = std::shared_ptr<VkShaderModule>(
new VkShaderModule(shaderModuleHandle),
[dev = device.handle()](VkShaderModule* shaderModuleHandle) {
vkDestroyShaderModule(dev, *shaderModuleHandle, nullptr);
}
);
// create descriptor set layout
std::vector<VkDescriptorSetLayoutBinding> layoutBindings;
size_t bindIdx = 0;
@ -66,7 +55,13 @@ ShaderModule::ShaderModule(const Device& device, const std::string& path,
if (res != VK_SUCCESS || !descriptorSetLayout)
throw ls::vulkan_error(res, "Failed to create descriptor set layout");
// store layout in shared ptr
// store module and layout in shared ptr
this->shaderModule = std::shared_ptr<VkShaderModule>(
new VkShaderModule(shaderModuleHandle),
[dev = device.handle()](VkShaderModule* shaderModuleHandle) {
vkDestroyShaderModule(dev, *shaderModuleHandle, nullptr);
}
);
this->descriptorSetLayout = std::shared_ptr<VkDescriptorSetLayout>(
new VkDescriptorSetLayout(descriptorSetLayout),
[dev = device.handle()](VkDescriptorSetLayout* layout) {

View file

@ -7,9 +7,6 @@
using namespace Vulkan;
Device::Device(const Instance& instance) {
if (!instance)
throw std::invalid_argument("Invalid Vulkan instance");
// get all physical devices
uint32_t deviceCount{};
auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr);

View file

@ -145,7 +145,7 @@ int main() {
commandBuffer.end();
commandBuffer.submit(device.getComputeQueue(), fence);
assert(fence.wait() && "Synchronization fence timed out");
assert(fence.wait(device) && "Synchronization fence timed out");
std::cerr << "Application finished" << '\n';
return 0;