mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-10-30 07:01:10 +00:00
core sampler and buffer objects
This commit is contained in:
parent
d3a903524a
commit
d0bd00d412
4 changed files with 228 additions and 0 deletions
59
include/core/buffer.hpp
Normal file
59
include/core/buffer.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef BUFFER_HPP
|
||||
#define BUFFER_HPP
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Vulkan::Core {
|
||||
|
||||
///
|
||||
/// C++ wrapper class for a Vulkan buffer.
|
||||
///
|
||||
/// This class manages the lifetime of a Vulkan buffer.
|
||||
///
|
||||
class Buffer {
|
||||
public:
|
||||
///
|
||||
/// Create the buffer.
|
||||
///
|
||||
/// @param device Vulkan device
|
||||
/// @param size Size of the buffer in bytes.
|
||||
/// @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, uint32_t size, std::vector<uint8_t> data,
|
||||
VkBufferUsageFlags usage);
|
||||
|
||||
/// Get the Vulkan handle.
|
||||
[[nodiscard]] auto handle() const { return *this->buffer; }
|
||||
/// Get the size of the buffer.
|
||||
[[nodiscard]] uint32_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;
|
||||
Buffer(Buffer&&) noexcept = default;
|
||||
Buffer& operator=(Buffer&&) noexcept = default;
|
||||
~Buffer() = default;
|
||||
private:
|
||||
std::shared_ptr<VkBuffer> buffer;
|
||||
std::shared_ptr<VkDeviceMemory> memory;
|
||||
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BUFFER_HPP
|
||||
50
include/core/sampler.hpp
Normal file
50
include/core/sampler.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef SAMPLER_HPP
|
||||
#define SAMPLER_HPP
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Vulkan::Core {
|
||||
|
||||
///
|
||||
/// C++ wrapper class for a Vulkan sampler.
|
||||
///
|
||||
/// This class manages the lifetime of a Vulkan sampler.
|
||||
///
|
||||
class Sampler {
|
||||
public:
|
||||
///
|
||||
/// Create the sampler.
|
||||
///
|
||||
/// @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);
|
||||
|
||||
/// 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;
|
||||
Sampler(Sampler&&) noexcept = default;
|
||||
Sampler& operator=(Sampler&&) noexcept = default;
|
||||
~Sampler() = default;
|
||||
private:
|
||||
std::shared_ptr<VkSampler> sampler;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SAMPLER_HPP
|
||||
86
src/core/buffer.cpp
Normal file
86
src/core/buffer.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include "core/buffer.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
using namespace Vulkan::Core;
|
||||
|
||||
Buffer::Buffer(const Device& device, uint32_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,
|
||||
.size = size,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
VkBuffer bufferHandle{};
|
||||
auto res = vkCreateBuffer(device.handle(), &desc, nullptr, &bufferHandle);
|
||||
if (res != VK_SUCCESS || bufferHandle == VK_NULL_HANDLE)
|
||||
throw ls::vulkan_error(res, "Failed to create Vulkan buffer");
|
||||
|
||||
// find memory type
|
||||
VkPhysicalDeviceMemoryProperties memProps;
|
||||
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
vkGetBufferMemoryRequirements(device.handle(), bufferHandle, &memReqs);
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
std::optional<uint32_t> memType{};
|
||||
for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) {
|
||||
if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN
|
||||
(memProps.memoryTypes[i].propertyFlags &
|
||||
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))) {
|
||||
memType.emplace(i);
|
||||
break;
|
||||
} // NOLINTEND
|
||||
}
|
||||
if (!memType.has_value())
|
||||
throw ls::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// allocate and bind memory
|
||||
const VkMemoryAllocateInfo allocInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memReqs.size,
|
||||
.memoryTypeIndex = memType.value()
|
||||
};
|
||||
VkDeviceMemory memoryHandle{};
|
||||
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
|
||||
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
|
||||
throw ls::vulkan_error(res, "Failed to allocate memory for Vulkan buffer");
|
||||
|
||||
res = vkBindBufferMemory(device.handle(), bufferHandle, memoryHandle, 0);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "Failed to bind memory to Vulkan buffer");
|
||||
|
||||
// store buffer and memory in shared ptr
|
||||
this->buffer = std::shared_ptr<VkBuffer>(
|
||||
new VkBuffer(bufferHandle),
|
||||
[dev = device.handle()](VkBuffer* img) {
|
||||
vkDestroyBuffer(dev, *img, nullptr);
|
||||
}
|
||||
);
|
||||
this->memory = std::shared_ptr<VkDeviceMemory>(
|
||||
new VkDeviceMemory(memoryHandle),
|
||||
[dev = device.handle()](VkDeviceMemory* mem) {
|
||||
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);
|
||||
}
|
||||
33
src/core/sampler.cpp
Normal file
33
src/core/sampler.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "core/sampler.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
|
||||
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,
|
||||
.magFilter = VK_FILTER_LINEAR,
|
||||
.minFilter = VK_FILTER_LINEAR,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
||||
.addressModeU = mode,
|
||||
.addressModeV = mode,
|
||||
.addressModeW = mode,
|
||||
.maxLod = VK_LOD_CLAMP_NONE
|
||||
};
|
||||
VkSampler samplerHandle{};
|
||||
auto res = vkCreateSampler(device.handle(), &desc, nullptr, &samplerHandle);
|
||||
if (res != VK_SUCCESS || samplerHandle == VK_NULL_HANDLE)
|
||||
throw ls::vulkan_error(res, "Unable to create sampler");
|
||||
|
||||
// store the sampler in a shared pointer
|
||||
this->sampler = std::shared_ptr<VkSampler>(
|
||||
new VkSampler(samplerHandle),
|
||||
[dev = device.handle()](VkSampler* samplerHandle) {
|
||||
vkDestroySampler(dev, *samplerHandle, nullptr);
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue