mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-22 10:21:43 +00:00
base swapchain context class
This commit is contained in:
parent
b4e00d2d65
commit
59b05ce220
6 changed files with 232 additions and 2 deletions
|
|
@ -29,7 +29,7 @@ add_library(lsfg-vk SHARED ${SOURCES})
|
|||
target_include_directories(lsfg-vk
|
||||
PRIVATE include)
|
||||
target_link_libraries(lsfg-vk
|
||||
PRIVATE lsfg-vk-gen)
|
||||
PRIVATE lsfg-vk-gen vulkan)
|
||||
target_compile_options(lsfg-vk PRIVATE
|
||||
-Weverything
|
||||
# disable compat c++ flags
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
#ifndef APPLICATION_HPP
|
||||
#define APPLICATION_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
class SwapchainContext;
|
||||
|
||||
///
|
||||
/// Main application class, wrapping around the Vulkan device.
|
||||
///
|
||||
class Application {
|
||||
public:
|
||||
|
||||
///
|
||||
/// Create the application.
|
||||
///
|
||||
|
|
@ -20,6 +24,31 @@ public:
|
|||
///
|
||||
Application(VkDevice device, VkPhysicalDevice physicalDevice);
|
||||
|
||||
///
|
||||
/// Add a swapchain to the application.
|
||||
///
|
||||
/// @param handle The Vulkan handle of the swapchain.
|
||||
/// @param format The format of the swapchain.
|
||||
/// @param extent The extent of the images.
|
||||
/// @param images The swapchain images.
|
||||
///
|
||||
/// @throws std::invalid_argument if the handle is already added.
|
||||
/// @throws ls::vulkan_error if any Vulkan call fails.
|
||||
///
|
||||
void addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent,
|
||||
const std::vector<VkImage>& images);
|
||||
|
||||
///
|
||||
/// Remove a swapchain from the application.
|
||||
///
|
||||
/// @param handle The Vulkan handle of the swapchain state to remove.
|
||||
/// @return true if the swapchain was removed, false if it was already retired.
|
||||
///
|
||||
/// @throws std::invalid_argument if the handle is null.
|
||||
///
|
||||
bool removeSwapchain(VkSwapchainKHR handle);
|
||||
|
||||
|
||||
/// Get the Vulkan device.
|
||||
[[nodiscard]] VkDevice getDevice() const { return this->device; }
|
||||
/// Get the Vulkan physical device.
|
||||
|
|
@ -39,7 +68,52 @@ private:
|
|||
VkPhysicalDevice physicalDevice;
|
||||
|
||||
// (owned resources)
|
||||
std::unordered_map<VkSwapchainKHR, SwapchainContext> swapchains;
|
||||
};
|
||||
|
||||
///
|
||||
/// An application's Vulkan swapchain and it's associated resources.
|
||||
///
|
||||
class SwapchainContext {
|
||||
public:
|
||||
|
||||
///
|
||||
/// Create the swapchain context.
|
||||
///
|
||||
/// @param swapchain The Vulkan swapchain handle.
|
||||
/// @param format The format of the swapchain images.
|
||||
/// @param extent The extent of the swapchain images.
|
||||
/// @param images The swapchain images.
|
||||
///
|
||||
/// @throws std::invalid_argument if any parameter is null
|
||||
/// @throws ls::vulkan_error if any Vulkan call fails.
|
||||
///
|
||||
SwapchainContext(VkSwapchainKHR swapchain, VkFormat format, VkExtent2D extent,
|
||||
const std::vector<VkImage>& images);
|
||||
|
||||
/// Get the Vulkan swapchain handle.
|
||||
[[nodiscard]] VkSwapchainKHR handle() const { return this->swapchain; }
|
||||
/// Get the format of the swapchain images.
|
||||
[[nodiscard]] VkFormat getFormat() const { return this->format; }
|
||||
/// Get the extent of the swapchain images.
|
||||
[[nodiscard]] VkExtent2D getExtent() const { return this->extent; }
|
||||
/// Get the swapchain images.
|
||||
[[nodiscard]] const std::vector<VkImage>& getImages() const { return this->images; }
|
||||
|
||||
// Non-copyable, trivially moveable and destructible
|
||||
SwapchainContext(const SwapchainContext&) = delete;
|
||||
SwapchainContext& operator=(const SwapchainContext&) = delete;
|
||||
SwapchainContext(SwapchainContext&&) = default;
|
||||
SwapchainContext& operator=(SwapchainContext&&) = default;
|
||||
~SwapchainContext() = default;
|
||||
private:
|
||||
// (non-owned resources)
|
||||
VkSwapchainKHR swapchain{};
|
||||
VkFormat format{};
|
||||
VkExtent2D extent{};
|
||||
std::vector<VkImage> images;
|
||||
|
||||
// (owned resources)
|
||||
};
|
||||
|
||||
#endif // APPLICATION_HPP
|
||||
|
|
|
|||
|
|
@ -48,6 +48,20 @@ namespace Vulkan::Funcs {
|
|||
VkDevice device,
|
||||
const VkAllocationCallbacks* pAllocator
|
||||
);
|
||||
|
||||
/// Call to the original vkCreateSwapchainKHR function.
|
||||
VkResult ovkCreateSwapchainKHR(
|
||||
VkDevice device,
|
||||
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkSwapchainKHR* pSwapchain
|
||||
);
|
||||
/// Call to the original vkDestroySwapchainKHR function.
|
||||
void ovkDestroySwapchainKHR(
|
||||
VkDevice device,
|
||||
VkSwapchainKHR swapchain,
|
||||
const VkAllocationCallbacks* pAllocator
|
||||
);
|
||||
}
|
||||
|
||||
#endif // FUNCS_HPP
|
||||
|
|
|
|||
|
|
@ -7,3 +7,33 @@ Application::Application(VkDevice device, VkPhysicalDevice physicalDevice)
|
|||
if (device == VK_NULL_HANDLE || physicalDevice == VK_NULL_HANDLE)
|
||||
throw std::invalid_argument("Invalid Vulkan device or physical device");
|
||||
}
|
||||
|
||||
void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent,
|
||||
const std::vector<VkImage>& images) {
|
||||
// add the swapchain handle
|
||||
auto it = this->swapchains.find(handle);
|
||||
if (it != this->swapchains.end())
|
||||
throw std::invalid_argument("Swapchain handle already exists");
|
||||
|
||||
// initialize the swapchain context
|
||||
this->swapchains.emplace(handle, SwapchainContext(handle, format, extent, images));
|
||||
}
|
||||
|
||||
SwapchainContext::SwapchainContext(VkSwapchainKHR swapchain, VkFormat format, VkExtent2D extent,
|
||||
const std::vector<VkImage>& images)
|
||||
: swapchain(swapchain), format(format), extent(extent), images(images) {
|
||||
if (swapchain == VK_NULL_HANDLE || format == VK_FORMAT_UNDEFINED)
|
||||
throw std::invalid_argument("Invalid swapchain or images");
|
||||
}
|
||||
|
||||
bool Application::removeSwapchain(VkSwapchainKHR handle) {
|
||||
if (handle == VK_NULL_HANDLE)
|
||||
throw std::invalid_argument("Invalid swapchain handle");
|
||||
|
||||
// remove the swapchain context
|
||||
auto it = this->swapchains.find(handle);
|
||||
if (it == this->swapchains.end())
|
||||
return false; // already retired... hopefully
|
||||
this->swapchains.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "loader/dl.hpp"
|
||||
#include "loader/vk.hpp"
|
||||
#include "log.hpp"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
using namespace Vulkan;
|
||||
|
||||
|
|
@ -11,6 +12,9 @@ namespace {
|
|||
|
||||
PFN_vkCreateDevice vkCreateDevice_ptr{};
|
||||
PFN_vkDestroyDevice vkDestroyDevice_ptr{};
|
||||
|
||||
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR_ptr{};
|
||||
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR_ptr{};
|
||||
}
|
||||
|
||||
void Funcs::initialize() {
|
||||
|
|
@ -51,6 +55,20 @@ void Funcs::initializeInstance(VkInstance instance) {
|
|||
}
|
||||
|
||||
void Funcs::initializeDevice(VkDevice device) {
|
||||
if (vkCreateSwapchainKHR_ptr || vkDestroySwapchainKHR_ptr) {
|
||||
Log::warn("lsfg-vk(funcs): Device Vulkan functions already initialized, did you call it twice?");
|
||||
return;
|
||||
}
|
||||
|
||||
vkCreateSwapchainKHR_ptr = reinterpret_cast<PFN_vkCreateSwapchainKHR>(
|
||||
Loader::VK::ovkGetDeviceProcAddr(device, "vkCreateSwapchainKHR"));
|
||||
vkDestroySwapchainKHR_ptr = reinterpret_cast<PFN_vkDestroySwapchainKHR>(
|
||||
Loader::VK::ovkGetDeviceProcAddr(device, "vkDestroySwapchainKHR"));
|
||||
if (!vkCreateSwapchainKHR_ptr || !vkDestroySwapchainKHR_ptr) {
|
||||
Log::error("lsfg-vk(funcs): Failed to initialize Vulkan device functions, missing symbols");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Log::debug("lsfg-vk(funcs): Initialized device Vulkan functions with original pointers");
|
||||
}
|
||||
|
||||
|
|
@ -82,3 +100,18 @@ void Funcs::ovkDestroyDevice(
|
|||
const VkAllocationCallbacks* pAllocator) {
|
||||
vkDestroyDevice_ptr(device, pAllocator);
|
||||
}
|
||||
|
||||
VkResult Funcs::ovkCreateSwapchainKHR(
|
||||
VkDevice device,
|
||||
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkSwapchainKHR* pSwapchain) {
|
||||
return vkCreateSwapchainKHR_ptr(device, pCreateInfo, pAllocator, pSwapchain);
|
||||
}
|
||||
|
||||
void Funcs::ovkDestroySwapchainKHR(
|
||||
VkDevice device,
|
||||
VkSwapchainKHR swapchain,
|
||||
const VkAllocationCallbacks* pAllocator) {
|
||||
vkDestroySwapchainKHR_ptr(device, swapchain, pAllocator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,73 @@ namespace {
|
|||
return res;
|
||||
}
|
||||
|
||||
VkResult myvkCreateSwapchainKHR(
|
||||
VkDevice device,
|
||||
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkSwapchainKHR* pSwapchain) {
|
||||
auto res = Funcs::ovkCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
|
||||
|
||||
// add the swapchain to the application
|
||||
if (!application.has_value()) {
|
||||
Log::error("Application not initialized, cannot create swapchain");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
try {
|
||||
if (pCreateInfo->oldSwapchain) {
|
||||
if (!application->removeSwapchain(pCreateInfo->oldSwapchain))
|
||||
throw std::runtime_error("Failed to remove old swapchain");
|
||||
Log::info("lsfg-vk(hooks): Swapchain retired successfully");
|
||||
}
|
||||
|
||||
uint32_t imageCount{};
|
||||
auto res = vkGetSwapchainImagesKHR(device, *pSwapchain, &imageCount, nullptr);
|
||||
if (res != VK_SUCCESS || imageCount == 0)
|
||||
throw LSFG::vulkan_error(res, "Failed to get swapchain images count");
|
||||
|
||||
std::vector<VkImage> swapchainImages(imageCount);
|
||||
res = vkGetSwapchainImagesKHR(device, *pSwapchain, &imageCount, swapchainImages.data());
|
||||
if (res != VK_SUCCESS)
|
||||
throw LSFG::vulkan_error(res, "Failed to get swapchain images");
|
||||
|
||||
application->addSwapchain(*pSwapchain,
|
||||
pCreateInfo->imageFormat, pCreateInfo->imageExtent, swapchainImages);
|
||||
Log::info("lsfg-vk(hooks): Swapchain created successfully with {} images",
|
||||
swapchainImages.size());
|
||||
} catch (const LSFG::vulkan_error& e) {
|
||||
Log::error("Encountered Vulkan error {:x} while creating swapchain: {}",
|
||||
static_cast<uint32_t>(e.error()), e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (const std::exception& e) {
|
||||
Log::error("Encountered error while creating swapchain: {}", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void myvkDestroySwapchainKHR(
|
||||
VkDevice device,
|
||||
VkSwapchainKHR swapchain,
|
||||
const VkAllocationCallbacks* pAllocator) {
|
||||
if (!application.has_value()) {
|
||||
Log::error("Application not initialized, cannot destroy swapchain");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// remove the swapchain from the application
|
||||
try {
|
||||
if (application->removeSwapchain(swapchain))
|
||||
Log::info("lsfg-vk(hooks): Swapchain retired successfully");
|
||||
} catch (const std::exception& e) {
|
||||
Log::error("Encountered error while removing swapchain: {}", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Funcs::ovkDestroySwapchainKHR(device, swapchain, pAllocator);
|
||||
}
|
||||
|
||||
void myvkDestroyDevice(
|
||||
VkDevice device,
|
||||
const VkAllocationCallbacks* pAllocator) {
|
||||
|
|
@ -85,6 +152,10 @@ void Hooks::initialize() {
|
|||
reinterpret_cast<void*>(myvkCreateDevice));
|
||||
Loader::VK::registerSymbol("vkDestroyDevice",
|
||||
reinterpret_cast<void*>(myvkDestroyDevice));
|
||||
Loader::VK::registerSymbol("vkCreateSwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkCreateSwapchainKHR));
|
||||
Loader::VK::registerSymbol("vkDestroySwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkDestroySwapchainKHR));
|
||||
|
||||
// register hooks to dynamic loader under libvulkan.so.1
|
||||
Loader::DL::File vk1("libvulkan.so.1");
|
||||
|
|
@ -94,6 +165,10 @@ void Hooks::initialize() {
|
|||
reinterpret_cast<void*>(myvkCreateDevice));
|
||||
vk1.defineSymbol("vkDestroyDevice",
|
||||
reinterpret_cast<void*>(myvkDestroyDevice));
|
||||
vk1.defineSymbol("vkCreateSwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkCreateSwapchainKHR));
|
||||
vk1.defineSymbol("vkDestroySwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkDestroySwapchainKHR));
|
||||
Loader::DL::registerFile(vk1);
|
||||
|
||||
// register hooks to dynamic loader under libvulkan.so
|
||||
|
|
@ -104,5 +179,9 @@ void Hooks::initialize() {
|
|||
reinterpret_cast<void*>(myvkCreateDevice));
|
||||
vk2.defineSymbol("vkDestroyDevice",
|
||||
reinterpret_cast<void*>(myvkDestroyDevice));
|
||||
vk2.defineSymbol("vkCreateSwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkCreateSwapchainKHR));
|
||||
vk2.defineSymbol("vkDestroySwapchainKHR",
|
||||
reinterpret_cast<void*>(myvkDestroySwapchainKHR));
|
||||
Loader::DL::registerFile(vk2);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue