refactor: refactor image class

This commit is contained in:
PancakeTAS 2025-09-01 18:14:26 +02:00
parent 5d9660c1eb
commit 4c85e45485
No known key found for this signature in database
3 changed files with 36 additions and 269 deletions

View file

@ -2,14 +2,13 @@
#include "vk/core/device.hpp" #include "vk/core/device.hpp"
#include <optional>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <memory> #include <memory>
namespace VK::Core { namespace VK::Core {
// TODO: Refactoring
/// ///
/// C++ wrapper class for a Vulkan image. /// C++ wrapper class for a Vulkan image.
/// ///
@ -26,44 +25,16 @@ namespace VK::Core {
/// @param extent Extent of the image in pixels. /// @param extent Extent of the image in pixels.
/// @param format Vulkan format of the image /// @param format Vulkan format of the image
/// @param usage Usage flags for the image /// @param usage Usage flags for the image
/// @param aspectFlags Aspect flags for the image view /// @param importFd Optional file descriptor for shared memory.
/// @param exportFd Optional pointer to an integer where the file descriptor will be stored.
/// ///
/// @throws VK::vulkan_error if object creation fails. /// @throws VK::vulkan_error if object creation fails.
/// ///
Image(const 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); // TODO: get rid std::optional<int> importFd = std::nullopt,
std::optional<int*> exportFd = std::nullopt);
///
/// Create the image with shared backing memory.
///
/// @param device Vulkan device
/// @param extent Extent of the image in pixels.
/// @param format Vulkan format of the image
/// @param usage Usage flags for the image
/// @param aspectFlags Aspect flags for the image view
/// @param fd File descriptor for shared memory.
///
/// @throws VK::vulkan_error if object creation fails.
///
Image(const Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd);
///
/// Create the image and export the backing fd
///
/// @param device Vulkan device
/// @param extent Extent of the image in pixels.
/// @param format Vulkan format of the image
/// @param usage Usage flags for the image
/// @param aspectFlags Aspect flags for the image view
/// @param fd Pointer to an integer where the file descriptor will be stored.
///
/// @throws VK::vulkan_error if object creation fails.
///
Image(const Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd);
/// Get the Vulkan handle. /// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->image; } [[nodiscard]] auto handle() const { return *this->image; }
@ -75,23 +46,13 @@ namespace VK::Core {
[[nodiscard]] auto 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]] auto getFormat() const { return this->format; } [[nodiscard]] auto getFormat() const { return this->format; }
/// Get the aspect flags of the image.
[[nodiscard]] auto getAspectFlags() const { return this->aspectFlags; }
/// Set the layout of the image.
void setLayout(VkImageLayout layout) { *this->layout = layout; }
/// Get the current layout of the image.
[[nodiscard]] VkImageLayout getLayout() const { return *this->layout; }
private: private:
std::shared_ptr<VkImage> image; std::shared_ptr<VkImage> image;
std::shared_ptr<VkDeviceMemory> memory; std::shared_ptr<VkDeviceMemory> memory;
std::shared_ptr<VkImageView> view; std::shared_ptr<VkImageView> view;
std::shared_ptr<VkImageLayout> layout;
VkExtent2D extent{}; VkExtent2D extent{};
VkFormat format{}; VkFormat format{};
VkImageAspectFlags aspectFlags{};
}; };
} }

View file

@ -12,6 +12,7 @@
#include <stdexcept> #include <stdexcept>
#include <optional> #include <optional>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <vector> #include <vector>

View file

@ -11,106 +11,10 @@
using namespace VK::Core; using namespace VK::Core;
Image::Image(const Device& device, VkExtent2D extent, VkFormat format, Image::Image(const Device& device, VkExtent2D extent,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags) VkFormat format, VkImageUsageFlags usage,
: extent(extent), format(format), aspectFlags(aspectFlags) { std::optional<int> importFd, std::optional<int*> exportFd)
// create image : extent(extent), format(format) {
const VkImageCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = format,
.extent = {
.width = extent.width,
.height = extent.height,
.depth = 1
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.usage = usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
};
VkImage imageHandle{};
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to create Vulkan image");
// find memory type
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits, false);
if (!memType.has_value())
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
// 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 VK::vulkan_error(res, "Failed to allocate memory for Vulkan image");
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
if (res != VK_SUCCESS)
throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image");
// create image view
const VkImageViewCreateInfo viewDesc{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = imageHandle,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY
},
.subresourceRange = {
.aspectMask = aspectFlags,
.levelCount = 1,
.layerCount = 1
}
};
VkImageView viewHandle{};
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to create image view");
// store objects in shared ptr
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
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) {
vkDestroyImageView(dev, *imgView, nullptr);
}
);
}
// shared memory constructor
// FIXME: Less constructors... jesus.
Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd)
: extent(extent), format(format), aspectFlags(aspectFlags) {
// create image // create image
const VkExternalMemoryImageCreateInfo externalInfo{ const VkExternalMemoryImageCreateInfo externalInfo{
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
@ -118,118 +22,7 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
}; };
const VkImageCreateInfo desc{ const VkImageCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &externalInfo, .pNext = (importFd.has_value() || exportFd.has_value()) ? &externalInfo : nullptr,
.imageType = VK_IMAGE_TYPE_2D,
.format = format,
.extent = {
.width = extent.width,
.height = extent.height,
.depth = 1
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.usage = usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
};
VkImage imageHandle{};
auto res = vkCreateImage(device.handle(), &desc, nullptr, &imageHandle);
if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to create Vulkan image");
// find memory type
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
std::optional<uint32_t> memType = device.findMemoryType(memReqs.memoryTypeBits, false);
if (!memType.has_value())
throw VK::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer");
// ~~allocate~~ and bind memory
const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo2{
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
.image = imageHandle,
};
const VkImportMemoryFdInfoKHR importInfo{
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
.pNext = &dedicatedInfo2,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
.fd = fd // closes the fd
};
const VkMemoryAllocateInfo allocInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = fd == -1 ? nullptr : &importInfo,
.allocationSize = memReqs.size,
.memoryTypeIndex = memType.value()
};
VkDeviceMemory memoryHandle{};
res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle);
if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to allocate memory for Vulkan image");
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
if (res != VK_SUCCESS)
throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image");
// create image view
const VkImageViewCreateInfo viewDesc{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = imageHandle,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY
},
.subresourceRange = {
.aspectMask = aspectFlags,
.levelCount = 1,
.layerCount = 1
}
};
VkImageView viewHandle{};
res = vkCreateImageView(device.handle(), &viewDesc, nullptr, &viewHandle);
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to create image view");
// store objects in shared ptr
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
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) {
vkDestroyImageView(dev, *imgView, nullptr);
}
);
}
// second shared memory constructors
Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd)
: extent(extent), format(format), aspectFlags(aspectFlags) {
// create image
const VkExternalMemoryImageCreateInfo externalInfo{
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
};
const VkImageCreateInfo desc{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &externalInfo,
.imageType = VK_IMAGE_TYPE_2D, .imageType = VK_IMAGE_TYPE_2D,
.format = format, .format = format,
.extent = { .extent = {
@ -261,14 +54,25 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
.image = imageHandle, .image = imageHandle,
}; };
const VkImportMemoryFdInfoKHR importInfo{
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
.pNext = &dedicatedInfo,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
.fd = importFd.value_or(-1)
};
const VkExportMemoryAllocateInfo exportInfo{ const VkExportMemoryAllocateInfo exportInfo{
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
.pNext = &dedicatedInfo, .pNext = &dedicatedInfo,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
}; };
const void* pNextAlloc{};
if (importFd.has_value())
pNextAlloc = &importInfo;
else if (exportFd.has_value())
pNextAlloc = &exportInfo;
const VkMemoryAllocateInfo allocInfo{ const VkMemoryAllocateInfo allocInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &exportInfo, .pNext = pNextAlloc,
.allocationSize = memReqs.size, .allocationSize = memReqs.size,
.memoryTypeIndex = memType.value() .memoryTypeIndex = memType.value()
}; };
@ -281,16 +85,6 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image"); throw VK::vulkan_error(res, "Failed to bind memory to Vulkan image");
// obtain the sharing fd
const VkMemoryGetFdInfoKHR fdInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
.memory = memoryHandle,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
};
res = vkGetMemoryFdKHR(device.handle(), &fdInfo, fd);
if (res != VK_SUCCESS || *fd < 0)
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{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -304,7 +98,7 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
.a = VK_COMPONENT_SWIZZLE_IDENTITY .a = VK_COMPONENT_SWIZZLE_IDENTITY
}, },
.subresourceRange = { .subresourceRange = {
.aspectMask = aspectFlags, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1, .levelCount = 1,
.layerCount = 1 .layerCount = 1
} }
@ -315,8 +109,19 @@ Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE) if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
throw VK::vulkan_error(res, "Failed to create image view"); throw VK::vulkan_error(res, "Failed to create image view");
// obtain the sharing fd
if (exportFd.has_value()) {
const VkMemoryGetFdInfoKHR fdInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
.memory = memoryHandle,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
};
res = vkGetMemoryFdKHR(device.handle(), &fdInfo, exportFd.value());
if (res != VK_SUCCESS || *exportFd.value() < 0)
throw VK::vulkan_error(res, "Failed to obtain sharing fd for Vulkan image");
}
// store objects in shared ptr // store objects in shared ptr
this->layout = std::make_shared<VkImageLayout>(VK_IMAGE_LAYOUT_UNDEFINED);
this->image = std::shared_ptr<VkImage>( this->image = std::shared_ptr<VkImage>(
new VkImage(imageHandle), new VkImage(imageHandle),
[dev = device.handle()](VkImage* img) { [dev = device.handle()](VkImage* img) {