some reshuffling

This commit is contained in:
PancakeTAS 2025-07-01 10:10:53 +02:00
parent 13076e9fe3
commit 83dde594c6
No known key found for this signature in database
3 changed files with 78 additions and 43 deletions

View file

@ -18,11 +18,13 @@ public:
///
/// @param device Vulkan device
/// @param physicalDevice Vulkan physical device
/// @param graphicsQueue Vulkan queue for graphics operations
/// @param presentQueue Vulkan queue for presentation operations
///
/// @throws std::invalid_argument if the device or physicalDevice is null.
/// @throws LSFG::vulkan_error if any Vulkan call fails.
///
Application(VkDevice device, VkPhysicalDevice physicalDevice);
Application(VkDevice device, VkPhysicalDevice physicalDevice,
VkQueue graphicsQueue, VkQueue presentQueue);
///
/// Add a swapchain to the application.
@ -32,7 +34,6 @@ public:
/// @param extent The extent of the images.
/// @param images The swapchain images.
///
/// @throws std::invalid_argument if the handle is already added.
/// @throws LSFG::vulkan_error if any Vulkan call fails.
///
void addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent,
@ -46,28 +47,27 @@ public:
/// @param semaphores The semaphores to wait on before presenting.
/// @param idx The index of the swapchain image to present.
///
/// @throws std::invalid_argument if the handle is not found.
/// @throws LSFG::vulkan_error if any Vulkan call fails.
///
void presentSwapchain(VkSwapchainKHR handle, VkQueue queue,
const std::vector<VkSemaphore>& semaphores, uint32_t idx);
///
/// 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.
[[nodiscard]] VkPhysicalDevice getPhysicalDevice() const { return this->physicalDevice; }
/// Get the Vulkan graphics queue.
[[nodiscard]] VkQueue getGraphicsQueue() const { return this->graphicsQueue; }
/// Get the Vulkan present queue.
[[nodiscard]] VkQueue getPresentQueue() const { return this->presentQueue; }
// Non-copyable and non-movable
Application(const Application&) = delete;
@ -81,6 +81,8 @@ private:
// (non-owned resources)
VkDevice device;
VkPhysicalDevice physicalDevice;
VkQueue graphicsQueue;
VkQueue presentQueue;
// (owned resources)
std::unordered_map<VkSwapchainKHR, SwapchainContext> swapchains;
@ -95,16 +97,29 @@ public:
///
/// Create the swapchain context.
///
/// @param app The application context to use.
/// @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 LSFG::vulkan_error if any Vulkan call fails.
///
SwapchainContext(VkSwapchainKHR swapchain, VkFormat format, VkExtent2D extent,
const std::vector<VkImage>& images);
SwapchainContext(const Application& app, VkSwapchainKHR swapchain,
VkFormat format, VkExtent2D extent, const std::vector<VkImage>& images);
///
/// Present the next frame
///
/// @param app The application context to use
/// @param queue The Vulkan queue to present the frame on.
/// @param semaphores The semaphores to wait on before presenting.
/// @param idx The index of the swapchain image to present.
///
/// @throws LSFG::vulkan_error if any Vulkan call fails.
///
void present(const Application& app, VkQueue queue,
const std::vector<VkSemaphore>& semaphores, uint32_t idx);
/// Get the Vulkan swapchain handle.
[[nodiscard]] VkSwapchainKHR handle() const { return this->swapchain; }

View file

@ -4,62 +4,49 @@
#include <stdexcept>
Application::Application(VkDevice device, VkPhysicalDevice physicalDevice)
: device(device), physicalDevice(physicalDevice) {
if (device == VK_NULL_HANDLE || physicalDevice == VK_NULL_HANDLE)
throw std::invalid_argument("Invalid Vulkan device or physical device");
}
Application::Application(VkDevice device, VkPhysicalDevice physicalDevice,
VkQueue graphicsQueue, VkQueue presentQueue)
: device(device), physicalDevice(physicalDevice),
graphicsQueue(graphicsQueue), presentQueue(presentQueue) {}
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");
return; // already added
// initialize the swapchain context
this->swapchains.emplace(handle, SwapchainContext(handle, format, extent, images));
this->swapchains.emplace(handle, SwapchainContext(*this, handle, format, extent, images));
}
SwapchainContext::SwapchainContext(const Application& app, VkSwapchainKHR swapchain,
VkFormat format, VkExtent2D extent, const std::vector<VkImage>& images)
: swapchain(swapchain), format(format), extent(extent), images(images) {}
void Application::presentSwapchain(VkSwapchainKHR handle, VkQueue queue,
const std::vector<VkSemaphore>& semaphores, uint32_t idx) {
if (handle == VK_NULL_HANDLE)
throw std::invalid_argument("Invalid swapchain handle");
// find the swapchain context
auto it = this->swapchains.find(handle);
if (it == this->swapchains.end())
throw std::logic_error("Swapchain not found");
// TODO: present
it->second.present(*this, queue, semaphores, idx);
}
void SwapchainContext::present(const Application& app, VkQueue queue,
const std::vector<VkSemaphore>& semaphores, uint32_t idx) {
const VkPresentInfoKHR presentInfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = nullptr,
.waitSemaphoreCount = static_cast<uint32_t>(semaphores.size()),
.pWaitSemaphores = semaphores.data(),
.swapchainCount = 1,
.pSwapchains = &handle,
.pImageIndices = &idx,
.pResults = nullptr // can be null if not needed
.pSwapchains = &this->swapchain,
.pImageIndices = &idx
};
auto res = vkQueuePresentKHR(queue, &presentInfo);
if (res != VK_SUCCESS) // do NOT check VK_SUBOPTIMAL_KHR
if (res != VK_SUCCESS) // FIXME: somehow return VK_SUBOPTIMAL_KHR
throw LSFG::vulkan_error(res, "Failed to present swapchain");
}
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

View file

@ -21,6 +21,39 @@ namespace {
VkDevice* pDevice) {
auto res = vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
// extract graphics and present queues
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos(pCreateInfo->queueCreateInfoCount);
std::copy_n(pCreateInfo->pQueueCreateInfos, queueCreateInfos.size(), queueCreateInfos.data());
uint32_t familyCount{};
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount, nullptr);
std::vector<VkQueueFamilyProperties> families(familyCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount, families.data());
std::optional<uint32_t> graphicsFamilyIdx;
std::optional<uint32_t> presentFamilyIdx;
for (uint32_t i = 0; i < families.size(); ++i) {
auto it = std::ranges::find_if(queueCreateInfos,
[i](const VkDeviceQueueCreateInfo& info) {
return info.queueFamilyIndex == i;
}) ;
if (it == queueCreateInfos.end())
continue; // skip if this family is not used by the device
if (families.at(i).queueFlags & VK_QUEUE_GRAPHICS_BIT)
graphicsFamilyIdx.emplace(i);
if (families.at(i).queueFlags & VK_QUEUE_COMPUTE_BIT)
presentFamilyIdx.emplace(i);
}
if (!graphicsFamilyIdx.has_value() || !presentFamilyIdx.has_value()) {
Log::error("No suitable queue family found for graphics or present");
exit(EXIT_FAILURE);
}
VkQueue graphicsQueue{};
vkGetDeviceQueue(*pDevice, *graphicsFamilyIdx, 0, &graphicsQueue);
VkQueue presentQueue{};
vkGetDeviceQueue(*pDevice, *presentFamilyIdx, 0, &presentQueue);
// create the main application
if (application.has_value()) {
Log::error("Application already initialized, are you trying to create a second device?");
@ -28,7 +61,7 @@ namespace {
}
try {
application.emplace(*pDevice, physicalDevice);
application.emplace(*pDevice, physicalDevice, graphicsQueue, presentQueue);
Log::info("lsfg-vk(hooks): Application created successfully");
} catch (const LSFG::vulkan_error& e) {
Log::error("Encountered Vulkan error {:x} while creating application: {}",