mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-25 20:02:13 +00:00
import semaphore and images
This commit is contained in:
parent
c42dcf3ed2
commit
2083b6c85e
6 changed files with 206 additions and 1 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue