import semaphore and images

This commit is contained in:
PancakeTAS 2025-07-01 08:57:44 +02:00
parent c42dcf3ed2
commit 2083b6c85e
No known key found for this signature in database
6 changed files with 206 additions and 1 deletions

View file

@ -32,6 +32,21 @@ namespace LSFG::Core {
Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags);
///
/// 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 LSFG::vulkan_error if object creation fails.
///
Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int fd);
/// Get the Vulkan handle.
[[nodiscard]] auto handle() const { return *this->image; }
/// Get the Vulkan device memory handle.

View file

@ -29,6 +29,16 @@ namespace LSFG::Core {
///
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.
///

View file

@ -1,4 +1,5 @@
#include "context.hpp"
#include "core/semaphore.hpp"
#include "lsfg.hpp"
#include <cassert>
@ -7,6 +8,18 @@
using namespace LSFG;
Context::Context(const Core::Device& device, uint32_t width, uint32_t height, int in0, int in1) {
// import images
this->inImg_0 = Core::Image(device, { width, height },
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT,
in0);
this->inImg_1 = Core::Image(device, { width, height },
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT,
in1);
// create pools
this->descPool = Core::DescriptorPool(device);
this->cmdPool = Core::CommandPool(device);
@ -81,6 +94,9 @@ Context::Context(const Core::Device& device, uint32_t width, uint32_t height, in
}
void Context::present(const Core::Device& device, int inSem, int outSem) {
Core::Semaphore inSemaphore(device, inSem);
Core::Semaphore outSemaphore(device, outSem);
Core::CommandBuffer cmdBuffer(device, this->cmdPool);
cmdBuffer.begin();
@ -102,6 +118,10 @@ void Context::present(const Core::Device& device, int inSem, int outSem) {
cmdBuffer.end();
cmdBuffer.submit(device.getComputeQueue(), std::nullopt,
{ inSemaphore }, {},
{ outSemaphore }, {});
fc++;
}

View file

@ -8,6 +8,7 @@ using namespace LSFG::Core;
const std::vector<const char*> requiredExtensions = {
"VK_KHR_external_memory_fd",
"VK_KHR_external_semaphore_fd",
"VK_EXT_robustness2",
};

View file

@ -109,5 +109,128 @@ Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format,
vkDestroyImageView(dev, *imgView, nullptr);
}
);
}
// shared memory constructor
Image::Image(const Core::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,
.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 LSFG::vulkan_error(res, "Failed to create Vulkan image");
// find memory type
VkPhysicalDeviceMemoryProperties memProps;
vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps);
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device.handle(), imageHandle, &memReqs);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
std::optional<uint32_t> memType{};
for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) {
if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN
(memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
memType.emplace(i);
break;
} // NOLINTEND
}
if (!memType.has_value())
throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image");
#pragma clang diagnostic pop
// ~~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 = &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 LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan image");
res = vkBindImageMemory(device.handle(), imageHandle, memoryHandle, 0);
if (res != VK_SUCCESS)
throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image");
// 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 LSFG::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);
}
);
}

View file

@ -29,6 +29,42 @@ Semaphore::Semaphore(const Core::Device& device, std::optional<uint32_t> initial
);
}
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
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");