mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-10-30 07:01:10 +00:00
implement lsfg base
This commit is contained in:
parent
4e6d3deaac
commit
969fcfadeb
6 changed files with 268 additions and 11 deletions
|
|
@ -20,6 +20,7 @@ add_subdirectory(lsfg-vk-gen)
|
||||||
|
|
||||||
file(GLOB SOURCES
|
file(GLOB SOURCES
|
||||||
"src/loader/*.cpp"
|
"src/loader/*.cpp"
|
||||||
|
"src/mini/*.cpp"
|
||||||
"src/*.cpp"
|
"src/*.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef APPLICATION_HPP
|
#ifndef APPLICATION_HPP
|
||||||
#define APPLICATION_HPP
|
#define APPLICATION_HPP
|
||||||
|
|
||||||
|
#include "mini/image.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -76,7 +77,7 @@ public:
|
||||||
Application& operator=(Application&&) = delete;
|
Application& operator=(Application&&) = delete;
|
||||||
|
|
||||||
/// Destructor, cleans up resources.
|
/// Destructor, cleans up resources.
|
||||||
~Application() = default; // no resources to clean up as of right now.
|
~Application();
|
||||||
private:
|
private:
|
||||||
// (non-owned resources)
|
// (non-owned resources)
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
|
|
@ -93,7 +94,6 @@ private:
|
||||||
///
|
///
|
||||||
class SwapchainContext {
|
class SwapchainContext {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Create the swapchain context.
|
/// Create the swapchain context.
|
||||||
///
|
///
|
||||||
|
|
@ -130,20 +130,24 @@ public:
|
||||||
/// Get the swapchain images.
|
/// Get the swapchain images.
|
||||||
[[nodiscard]] const std::vector<VkImage>& getImages() const { return this->images; }
|
[[nodiscard]] const std::vector<VkImage>& getImages() const { return this->images; }
|
||||||
|
|
||||||
// Non-copyable, trivially moveable and destructible
|
// Non-copyable, trivially moveable
|
||||||
SwapchainContext(const SwapchainContext&) = delete;
|
SwapchainContext(const SwapchainContext&) = delete;
|
||||||
SwapchainContext& operator=(const SwapchainContext&) = delete;
|
SwapchainContext& operator=(const SwapchainContext&) = delete;
|
||||||
SwapchainContext(SwapchainContext&&) = default;
|
SwapchainContext(SwapchainContext&&) = default;
|
||||||
SwapchainContext& operator=(SwapchainContext&&) = default;
|
SwapchainContext& operator=(SwapchainContext&&) = default;
|
||||||
~SwapchainContext() = default;
|
|
||||||
|
/// Destructor, cleans up resources.
|
||||||
|
~SwapchainContext();
|
||||||
private:
|
private:
|
||||||
// (non-owned resources)
|
// (non-owned resources)
|
||||||
VkSwapchainKHR swapchain{};
|
VkSwapchainKHR swapchain;
|
||||||
VkFormat format{};
|
VkFormat format;
|
||||||
VkExtent2D extent{};
|
VkExtent2D extent;
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
|
|
||||||
// (owned resources)
|
// (owned resources)
|
||||||
|
Mini::Image frame_0, frame_1;
|
||||||
|
int32_t lsfgId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APPLICATION_HPP
|
#endif // APPLICATION_HPP
|
||||||
|
|
|
||||||
73
include/mini/image.hpp
Normal file
73
include/mini/image.hpp
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef IMAGE_HPP
|
||||||
|
#define IMAGE_HPP
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Mini {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// C++ wrapper class for a Vulkan image.
|
||||||
|
///
|
||||||
|
/// This class manages the lifetime of a Vulkan image.
|
||||||
|
///
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
Image() noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Create the image and export the backing fd
|
||||||
|
///
|
||||||
|
/// @param device Vulkan device
|
||||||
|
/// @param physicalDevice Vulkan physical 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 LSFG::vulkan_error if object creation fails.
|
||||||
|
///
|
||||||
|
Image(VkDevice device, VkPhysicalDevice physicalDevice, 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.
|
||||||
|
[[nodiscard]] auto getMemory() const { return *this->memory; }
|
||||||
|
/// Get the Vulkan image view handle.
|
||||||
|
[[nodiscard]] auto getView() const { return *this->view; }
|
||||||
|
/// Get the extent of the image.
|
||||||
|
[[nodiscard]] VkExtent2D getExtent() const { return this->extent; }
|
||||||
|
/// Get the format of the image.
|
||||||
|
[[nodiscard]] VkFormat getFormat() const { return this->format; }
|
||||||
|
/// Get the aspect flags of the image.
|
||||||
|
[[nodiscard]] VkImageAspectFlags 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; }
|
||||||
|
|
||||||
|
/// Trivially copyable, moveable and destructible
|
||||||
|
Image(const Image&) noexcept = default;
|
||||||
|
Image& operator=(const Image&) noexcept = default;
|
||||||
|
Image(Image&&) noexcept = default;
|
||||||
|
Image& operator=(Image&&) noexcept = default;
|
||||||
|
~Image() = default;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<VkImage> image;
|
||||||
|
std::shared_ptr<VkDeviceMemory> memory;
|
||||||
|
std::shared_ptr<VkImageView> view;
|
||||||
|
|
||||||
|
std::shared_ptr<VkImageLayout> layout;
|
||||||
|
|
||||||
|
VkExtent2D extent{};
|
||||||
|
VkFormat format{};
|
||||||
|
VkImageAspectFlags aspectFlags{};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IMAGE_HPP
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "core/device.hpp"
|
#include "core/device.hpp"
|
||||||
#include "core/instance.hpp"
|
#include "core/instance.hpp"
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
@ -22,6 +23,8 @@ void LSFG::initialize() {
|
||||||
instance.emplace();
|
instance.emplace();
|
||||||
device.emplace(*instance);
|
device.emplace(*instance);
|
||||||
|
|
||||||
|
Globals::initializeGlobals(*device);
|
||||||
|
|
||||||
std::srand(static_cast<uint32_t>(std::time(nullptr)));
|
std::srand(static_cast<uint32_t>(std::time(nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +64,8 @@ void LSFG::finalize() {
|
||||||
if (!instance.has_value() && !device.has_value())
|
if (!instance.has_value() && !device.has_value())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Globals::uninitializeGlobals();
|
||||||
|
|
||||||
instance.reset();
|
instance.reset();
|
||||||
device.reset();
|
device.reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
#include "application.hpp"
|
#include "application.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "mini/image.hpp"
|
||||||
|
|
||||||
#include <lsfg.hpp>
|
#include <lsfg.hpp>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
Application::Application(VkDevice device, VkPhysicalDevice physicalDevice,
|
Application::Application(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||||
VkQueue graphicsQueue, VkQueue presentQueue)
|
VkQueue graphicsQueue, VkQueue presentQueue)
|
||||||
: device(device), physicalDevice(physicalDevice),
|
: device(device), physicalDevice(physicalDevice),
|
||||||
graphicsQueue(graphicsQueue), presentQueue(presentQueue) {}
|
graphicsQueue(graphicsQueue), presentQueue(presentQueue) {
|
||||||
|
LSFG::initialize();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent,
|
void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent,
|
||||||
const std::vector<VkImage>& images) {
|
const std::vector<VkImage>& images) {
|
||||||
|
|
@ -20,7 +23,23 @@ void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2
|
||||||
|
|
||||||
SwapchainContext::SwapchainContext(const Application& app, VkSwapchainKHR swapchain,
|
SwapchainContext::SwapchainContext(const Application& app, VkSwapchainKHR swapchain,
|
||||||
VkFormat format, VkExtent2D extent, const std::vector<VkImage>& images)
|
VkFormat format, VkExtent2D extent, const std::vector<VkImage>& images)
|
||||||
: swapchain(swapchain), format(format), extent(extent), images(images) {}
|
: swapchain(swapchain), format(format), extent(extent), images(images) {
|
||||||
|
int frame0fd{};
|
||||||
|
this->frame_0 = Mini::Image(
|
||||||
|
app.getDevice(), app.getPhysicalDevice(),
|
||||||
|
extent, VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT, &frame0fd
|
||||||
|
);
|
||||||
|
int frame1fd{};
|
||||||
|
this->frame_1 = Mini::Image(
|
||||||
|
app.getDevice(), app.getPhysicalDevice(),
|
||||||
|
extent, VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT, &frame1fd
|
||||||
|
);
|
||||||
|
this->lsfgId = LSFG::createContext(extent.width, extent.height, frame0fd, frame1fd);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::presentSwapchain(VkSwapchainKHR handle, VkQueue queue,
|
void Application::presentSwapchain(VkSwapchainKHR handle, VkQueue queue,
|
||||||
const std::vector<VkSemaphore>& semaphores, uint32_t idx) {
|
const std::vector<VkSemaphore>& semaphores, uint32_t idx) {
|
||||||
|
|
@ -46,6 +65,14 @@ void SwapchainContext::present(const Application& app, VkQueue queue,
|
||||||
throw LSFG::vulkan_error(res, "Failed to present swapchain");
|
throw LSFG::vulkan_error(res, "Failed to present swapchain");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwapchainContext::~SwapchainContext() {
|
||||||
|
try {
|
||||||
|
LSFG::deleteContext(this->lsfgId);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Application::removeSwapchain(VkSwapchainKHR handle) {
|
bool Application::removeSwapchain(VkSwapchainKHR handle) {
|
||||||
auto it = this->swapchains.find(handle);
|
auto it = this->swapchains.find(handle);
|
||||||
if (it == this->swapchains.end())
|
if (it == this->swapchains.end())
|
||||||
|
|
@ -53,3 +80,8 @@ bool Application::removeSwapchain(VkSwapchainKHR handle) {
|
||||||
this->swapchains.erase(it);
|
this->swapchains.erase(it);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Application::~Application() {
|
||||||
|
this->swapchains.clear();
|
||||||
|
LSFG::finalize();
|
||||||
|
}
|
||||||
|
|
|
||||||
142
src/mini/image.cpp
Normal file
142
src/mini/image.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include "mini/image.hpp"
|
||||||
|
#include "lsfg.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
using namespace Mini;
|
||||||
|
|
||||||
|
Image::Image(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||||
|
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, &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(physicalDevice, &memProps);
|
||||||
|
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
vkGetImageMemoryRequirements(device, 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 dedicatedInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
|
||||||
|
.image = imageHandle,
|
||||||
|
};
|
||||||
|
const VkExportMemoryAllocateInfo exportInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
|
||||||
|
.pNext = &dedicatedInfo,
|
||||||
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
|
||||||
|
};
|
||||||
|
const VkMemoryAllocateInfo allocInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.pNext = &exportInfo,
|
||||||
|
.allocationSize = memReqs.size,
|
||||||
|
.memoryTypeIndex = memType.value()
|
||||||
|
};
|
||||||
|
VkDeviceMemory memoryHandle{};
|
||||||
|
res = vkAllocateMemory(device, &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, 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, &viewDesc, nullptr, &viewHandle);
|
||||||
|
if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE)
|
||||||
|
throw LSFG::vulkan_error(res, "Failed to create image view");
|
||||||
|
|
||||||
|
// obtain the sharing fd
|
||||||
|
auto vkGetMemoryFdKHR =
|
||||||
|
reinterpret_cast<PFN_vkGetMemoryFdKHR>(vkGetDeviceProcAddr(device, "vkGetMemoryFdKHR"));
|
||||||
|
|
||||||
|
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, &fdInfo, fd);
|
||||||
|
if (res != VK_SUCCESS || *fd < 0)
|
||||||
|
throw LSFG::vulkan_error(res, "Failed to obtain sharing fd for Vulkan image");
|
||||||
|
|
||||||
|
// 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](VkImage* img) {
|
||||||
|
vkDestroyImage(dev, *img, nullptr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this->memory = std::shared_ptr<VkDeviceMemory>(
|
||||||
|
new VkDeviceMemory(memoryHandle),
|
||||||
|
[dev = device](VkDeviceMemory* mem) {
|
||||||
|
vkFreeMemory(dev, *mem, nullptr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this->view = std::shared_ptr<VkImageView>(
|
||||||
|
new VkImageView(viewHandle),
|
||||||
|
[dev = device](VkImageView* imgView) {
|
||||||
|
vkDestroyImageView(dev, *imgView, nullptr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue