From 6f5f8edbddeeb31c262217314f228506c1b79f03 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Mon, 15 Dec 2025 14:55:28 +0100 Subject: [PATCH] refactor(cleanup): support device loader function in backend --- include/mini/commandbuffer.hpp | 91 ------ include/mini/image.hpp | 60 ---- include/mini/semaphore.hpp | 50 --- include/utils/utils.hpp | 102 ------- .../include/lsfg-vk-common/vulkan/vulkan.hpp | 12 +- lsfg-vk-common/src/vulkan/command_buffer.cpp | 7 + lsfg-vk-common/src/vulkan/vulkan.cpp | 28 +- lsfg-vk-layer/src/entrypoint.cpp | 3 +- src/mini/commandbuffer.cpp | 91 ------ src/mini/image.cpp | 112 ------- src/mini/semaphore.cpp | 62 ---- src/utils/utils.cpp | 285 ------------------ 12 files changed, 40 insertions(+), 863 deletions(-) delete mode 100644 include/mini/commandbuffer.hpp delete mode 100644 include/mini/image.hpp delete mode 100644 include/mini/semaphore.hpp delete mode 100644 include/utils/utils.hpp delete mode 100644 src/mini/commandbuffer.cpp delete mode 100644 src/mini/image.cpp delete mode 100644 src/mini/semaphore.cpp delete mode 100644 src/utils/utils.cpp diff --git a/include/mini/commandbuffer.hpp b/include/mini/commandbuffer.hpp deleted file mode 100644 index 2189596..0000000 --- a/include/mini/commandbuffer.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include "mini/commandpool.hpp" - -#include - -#include -#include - -namespace Mini { - - /// State of the command buffer. - enum class CommandBufferState { - /// Command buffer is not initialized or has been destroyed. - Invalid, - /// Command buffer has been created. - Empty, - /// Command buffer recording has started. - Recording, - /// Command buffer recording has ended. - Full, - /// Command buffer has been submitted to a queue. - Submitted - }; - - /// - /// C++ wrapper class for a Vulkan command buffer. - /// - /// This class manages the lifetime of a Vulkan command buffer. - /// - class CommandBuffer { - public: - CommandBuffer() noexcept = default; - - /// - /// Create the command buffer. - /// - /// @param device Vulkan device - /// @param pool Vulkan command pool - /// - /// @throws LSFG::vulkan_error if object creation fails. - /// - CommandBuffer(VkDevice device, const CommandPool& pool); - - /// - /// Begin recording commands in the command buffer. - /// - /// @throws std::logic_error if the command buffer is in Empty state - /// @throws LSFG::vulkan_error if beginning the command buffer fails. - /// - void begin(); - - /// - /// End recording commands in the command buffer. - /// - /// @throws std::logic_error if the command buffer is not in Recording state - /// @throws LSFG::vulkan_error if ending the command buffer fails. - /// - void end(); - - /// - /// Submit the command buffer to a queue. - /// - /// @param queue Vulkan queue to submit to - /// @param waitSemaphores Semaphores to wait on before executing the command buffer - /// @param signalSemaphores Semaphores to signal after executing the command buffer - /// - /// @throws std::logic_error if the command buffer is not in Full state. - /// @throws LSFG::vulkan_error if submission fails. - /// - void submit(VkQueue queue, - const std::vector& waitSemaphores = {}, - const std::vector& signalSemaphores = {}); - - /// Get the state of the command buffer. - [[nodiscard]] CommandBufferState getState() const { return *this->state; } - /// Get the Vulkan handle. - [[nodiscard]] auto handle() const { return *this->commandBuffer; } - - /// Trivially copyable, moveable and destructible - CommandBuffer(const CommandBuffer&) noexcept = default; - CommandBuffer& operator=(const CommandBuffer&) noexcept = default; - CommandBuffer(CommandBuffer&&) noexcept = default; - CommandBuffer& operator=(CommandBuffer&&) noexcept = default; - ~CommandBuffer() = default; - private: - std::shared_ptr state; - std::shared_ptr commandBuffer; - }; - -} diff --git a/include/mini/image.hpp b/include/mini/image.hpp deleted file mode 100644 index 4c159cd..0000000 --- a/include/mini/image.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#include - -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 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; } - - /// 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 image; - std::shared_ptr memory; - - VkExtent2D extent{}; - VkFormat format{}; - VkImageAspectFlags aspectFlags{}; - }; - -} diff --git a/include/mini/semaphore.hpp b/include/mini/semaphore.hpp deleted file mode 100644 index 03df4d9..0000000 --- a/include/mini/semaphore.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include - -#include - -namespace Mini { - - /// - /// C++ wrapper class for a Vulkan semaphore. - /// - /// This class manages the lifetime of a Vulkan semaphore. - /// - class Semaphore { - public: - Semaphore() noexcept = default; - - /// - /// Create the semaphore. - /// - /// @param device Vulkan device - /// - /// @throws LSFG::vulkan_error if object creation fails. - /// - Semaphore(VkDevice device); - - /// - /// 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(VkDevice device, int* fd); - - /// Get the Vulkan handle. - [[nodiscard]] auto handle() const { return *this->semaphore; } - - // Trivially copyable, moveable and destructible - Semaphore(const Semaphore&) noexcept = default; - Semaphore& operator=(const Semaphore&) noexcept = default; - Semaphore(Semaphore&&) noexcept = default; - Semaphore& operator=(Semaphore&&) noexcept = default; - ~Semaphore() = default; - private: - std::shared_ptr semaphore; - }; - -} diff --git a/include/utils/utils.hpp b/include/utils/utils.hpp deleted file mode 100644 index 0dc8605..0000000 --- a/include/utils/utils.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include - -namespace Utils { - - /// - /// Find a queue in the physical device that supports the given queue flags. - /// - /// @param device The Vulkan device to use for queue retrieval. - /// @param physicalDevice The physical device to search in. - /// @param desc The device creation info, used to determine enabled queue families. - /// @param flags The queue flags to search for (e.g., VK_QUEUE_GRAPHICS_BIT). - /// @return Pair of queue family index and queue handle. - /// - /// @throws LSFG::vulkan_error if no suitable queue is found. - /// - std::pair findQueue(VkDevice device, VkPhysicalDevice physicalDevice, - VkDeviceCreateInfo* desc, VkQueueFlags flags); - - /// - /// Get the UUID of the physical device. - /// - /// @param physicalDevice The physical device to get the UUID from. - /// @return The UUID of the physical device. - /// - uint64_t getDeviceUUID(VkPhysicalDevice physicalDevice); - - /// - /// Get the max image count for a swapchain. - /// - /// @param physicalDevice The physical device to query. - /// @param surface The surface to query the capabilities for. - /// @return The maximum image count for the swapchain. - /// - uint32_t getMaxImageCount(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface); - - /// - /// Ensure a list of extensions is present in the given array. - /// - /// @param extensions The array of extensions to check. - /// @param requiredExtensions The list of required extensions to ensure are present. - /// - std::vector addExtensions(const char* const* extensions, size_t count, - const std::vector& requiredExtensions); - - /// - /// Copy an image from source to destination in a command buffer. - /// - /// @param buf The command buffer to record the copy operation into. - /// @param src The source image to copy from. - /// @param dst The destination image to copy to. - /// @param width The width of the image to copy. - /// @param height The height of the image to copy. - /// @param pre The pipeline stage to wait on. - /// @param post The pipeline stage to provide after the copy. - /// @param makeSrcPresentable If true, the source image will be made presentable after the copy. - /// @param makeDstPresentable If true, the destination image will be made presentable after the copy. - /// - void copyImage(VkCommandBuffer buf, - VkImage src, VkImage dst, - uint32_t width, uint32_t height, - VkPipelineStageFlags pre, VkPipelineStageFlags post, - bool makeSrcPresentable, bool makeDstPresentable); - - /// - /// Log a message at most n times. - /// - /// @param id The identifier for the log message. - /// @param n The maximum number of times to log the message. - /// @param message The message to log. - /// - void logLimitN(const std::string& id, size_t n, const std::string& message); - - /// - /// Reset the log limit for a given identifier. - /// - /// @param id The identifier for the log message. - /// - void resetLimitN(const std::string& id) noexcept; - - /// - /// Get the process name of the current executable. - /// - /// @return The name of the process. - /// - std::pair getProcessName(); - - /// - /// Get the configuration file path. - /// - /// @return The path to the configuration file. - /// - std::string getConfigFile(); - -} diff --git a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp index 5fffb75..9863c37 100644 --- a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp +++ b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp @@ -10,6 +10,7 @@ #include #include +#include namespace vk { @@ -91,7 +92,6 @@ namespace vk { PFN_vkCreateComputePipelines CreateComputePipelines; PFN_vkDestroyPipeline DestroyPipeline; - // extension functions PFN_vkSignalSemaphoreKHR SignalSemaphoreKHR; PFN_vkWaitSemaphoresKHR WaitSemaphoresKHR; @@ -136,7 +136,8 @@ namespace vk { Vulkan(const std::string& appName, version appVersion, const std::string& engineName, version engineVersion, PhysicalDeviceSelector selectPhysicalDevice, - bool isGraphical = false); + bool isGraphical = false, + std::optional setLoaderData = std::nullopt); /// create based on an existing externally managed vulkan instance. /// @param instance vulkan instance handle @@ -150,7 +151,8 @@ namespace vk { VkPhysicalDevice physdev, VulkanInstanceFuncs instanceFuncs, VulkanDeviceFuncs deviceFuncs, - bool isGraphical = true); + bool isGraphical = true, + std::optional setLoaderData = std::nullopt); /// find a memory type index /// @param validTypes bitset of valid memory types @@ -182,6 +184,9 @@ namespace vk { /// get device-level function pointers /// @return the device function pointers [[nodiscard]] const auto& df() const { return this->device_funcs; } + /// get optional setLoaderData function + /// @return the setLoaderData function + [[nodiscard]] const auto& loaderdatafunc() const { return this->setLoaderData; } private: ls::owned_ptr instance; VulkanInstanceFuncs instance_funcs; @@ -191,6 +196,7 @@ namespace vk { bool fp16; ls::owned_ptr device; + std::optional setLoaderData; VulkanDeviceFuncs device_funcs; VkQueue computeQueue; diff --git a/lsfg-vk-common/src/vulkan/command_buffer.cpp b/lsfg-vk-common/src/vulkan/command_buffer.cpp index b9af775..a88ba30 100644 --- a/lsfg-vk-common/src/vulkan/command_buffer.cpp +++ b/lsfg-vk-common/src/vulkan/command_buffer.cpp @@ -32,6 +32,13 @@ namespace { if (res != VK_SUCCESS) throw ls::vulkan_error(res, "vkAllocateCommandBuffers() failed"); + auto setLoaderData = vk.loaderdatafunc(); + if (setLoaderData) { + res = (*setLoaderData)(vk.dev(), handle); + if (res != VK_SUCCESS) + throw ls::vulkan_error(res, "vkSetDeviceLoaderData() failed"); + } + return ls::owned_ptr( new VkCommandBuffer(handle), [dev = vk.dev(), pool = vk.cmdpool(), defunc = vk.df().FreeCommandBuffers]( diff --git a/lsfg-vk-common/src/vulkan/vulkan.cpp b/lsfg-vk-common/src/vulkan/vulkan.cpp index 96ada55..c0980af 100644 --- a/lsfg-vk-common/src/vulkan/vulkan.cpp +++ b/lsfg-vk-common/src/vulkan/vulkan.cpp @@ -10,6 +10,7 @@ #include #include +#include #include using namespace vk; @@ -199,11 +200,18 @@ namespace { } /// get a queue from the logical device - VkQueue getQueue(const VulkanDeviceFuncs& fd, - VkDevice device, uint32_t cfi) { + VkQueue getQueue(const VulkanDeviceFuncs& fd, VkDevice device, + std::optional setLoaderData, + uint32_t cfi) { VkQueue queue{}; fd.GetDeviceQueue(device, cfi, 0, &queue); + + if (setLoaderData) { // optionally set loader data + auto res = (*setLoaderData)(device, queue); + if (res != VK_SUCCESS) + throw ls::vulkan_error(res, "vkSetDeviceLoaderData() failed"); + } return queue; } @@ -353,7 +361,8 @@ VulkanDeviceFuncs vk::initVulkanDeviceFuncs(const VulkanInstanceFuncs& f, VkDevi Vulkan::Vulkan(const std::string& appName, version appVersion, const std::string& engineName, version engineVersion, PhysicalDeviceSelector selectPhysicalDevice, - bool isGraphical) : + bool isGraphical, + std::optional setLoaderData) : instance(createInstance( appName, appVersion, engineName, engineVersion @@ -371,11 +380,14 @@ Vulkan::Vulkan(const std::string& appName, version appVersion, this->queueFamilyIdx, this->fp16 )), + setLoaderData(setLoaderData), device_funcs(initVulkanDeviceFuncs( this->instance_funcs, *this->device )), - computeQueue(getQueue(this->device_funcs, *this->device, this->queueFamilyIdx)), + computeQueue(getQueue(this->device_funcs, *this->device, + this->setLoaderData, + this->queueFamilyIdx)), cmdPool(createCommandPool(this->device_funcs, *this->device, this->queueFamilyIdx @@ -389,7 +401,8 @@ Vulkan::Vulkan(VkInstance instance, VkDevice device, VkPhysicalDevice physdev, VulkanInstanceFuncs instanceFuncs, VulkanDeviceFuncs deviceFuncs, - bool isGraphical) : + bool isGraphical, + std::optional setLoaderData) : instance(new VkInstance(instance)), instance_funcs(instanceFuncs), physdev(physdev), @@ -397,8 +410,11 @@ Vulkan::Vulkan(VkInstance instance, VkDevice device, isGraphical ? VK_QUEUE_GRAPHICS_BIT : VK_QUEUE_COMPUTE_BIT)), fp16(false), device(new VkDevice(device)), + setLoaderData(setLoaderData), device_funcs(deviceFuncs), - computeQueue(getQueue(this->device_funcs, *this->device, this->queueFamilyIdx)), + computeQueue(getQueue(this->device_funcs, *this->device, + this->setLoaderData, + this->queueFamilyIdx)), cmdPool(createCommandPool(this->device_funcs, *this->device, this->queueFamilyIdx diff --git a/lsfg-vk-layer/src/entrypoint.cpp b/lsfg-vk-layer/src/entrypoint.cpp index 96b3b97..d6d77a9 100644 --- a/lsfg-vk-layer/src/entrypoint.cpp +++ b/lsfg-vk-layer/src/entrypoint.cpp @@ -212,7 +212,8 @@ namespace { global->instance, *device, physdev, global->fi, - vk::initVulkanDeviceFuncs(global->fi, *device) + vk::initVulkanDeviceFuncs(global->fi, *device), + setLoaderData ) ) ); diff --git a/src/mini/commandbuffer.cpp b/src/mini/commandbuffer.cpp deleted file mode 100644 index 3b0e49a..0000000 --- a/src/mini/commandbuffer.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "mini/commandbuffer.hpp" -#include "mini/commandpool.hpp" -#include "common/exception.hpp" -#include "layer.hpp" - -#include - -#include -#include -#include -#include - -using namespace Mini; - -CommandBuffer::CommandBuffer(VkDevice device, const CommandPool& pool) { - // create command buffer - const VkCommandBufferAllocateInfo desc{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = pool.handle(), - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1 - }; - VkCommandBuffer commandBufferHandle{}; - auto res = Layer::ovkAllocateCommandBuffers(device, &desc, &commandBufferHandle); - if (res != VK_SUCCESS || commandBufferHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to allocate command buffer"); - res = Layer::ovkSetDeviceLoaderData(device, commandBufferHandle); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to set device loader data for command buffer"); - - // store command buffer in shared ptr - this->state = std::make_shared(CommandBufferState::Empty); - this->commandBuffer = std::shared_ptr( - new VkCommandBuffer(commandBufferHandle), - [dev = device, pool = pool.handle()](VkCommandBuffer* cmdBuffer) { - Layer::ovkFreeCommandBuffers(dev, pool, 1, cmdBuffer); - } - ); -} - -void CommandBuffer::begin() { - if (*this->state != CommandBufferState::Empty) - throw std::logic_error("Command buffer is not in Empty state"); - - const VkCommandBufferBeginInfo beginInfo = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT - }; - auto res = Layer::ovkBeginCommandBuffer(*this->commandBuffer, &beginInfo); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to begin command buffer"); - - *this->state = CommandBufferState::Recording; -} - -void CommandBuffer::end() { - if (*this->state != CommandBufferState::Recording) - throw std::logic_error("Command buffer is not in Recording state"); - - auto res = Layer::ovkEndCommandBuffer(*this->commandBuffer); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to end command buffer"); - - *this->state = CommandBufferState::Full; -} - -void CommandBuffer::submit(VkQueue queue, - const std::vector& waitSemaphores, - const std::vector& signalSemaphores) { - if (*this->state != CommandBufferState::Full) - throw std::logic_error("Command buffer is not in Full state"); - - const std::vector waitStages(waitSemaphores.size(), - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - - const VkSubmitInfo submitInfo{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = static_cast(waitSemaphores.size()), - .pWaitSemaphores = waitSemaphores.data(), - .pWaitDstStageMask = waitStages.data(), - .commandBufferCount = 1, - .pCommandBuffers = &(*this->commandBuffer), - .signalSemaphoreCount = static_cast(signalSemaphores.size()), - .pSignalSemaphores = signalSemaphores.data() - }; - auto res = Layer::ovkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to submit command buffer"); - - *this->state = CommandBufferState::Submitted; -} diff --git a/src/mini/image.cpp b/src/mini/image.cpp deleted file mode 100644 index 978c67c..0000000 --- a/src/mini/image.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "mini/image.hpp" -#include "common/exception.hpp" -#include "layer.hpp" - -#include - -#include -#include -#include - -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 = Layer::ovkCreateImage(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; - Layer::ovkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); - - VkMemoryRequirements memReqs; - Layer::ovkGetImageMemoryRequirements(device, imageHandle, &memReqs); - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" - std::optional 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 = Layer::ovkAllocateMemory(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 = Layer::ovkBindImageMemory(device, imageHandle, memoryHandle, 0); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image"); - - // obtain the sharing fd - 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 = Layer::ovkGetMemoryFdKHR(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->image = std::shared_ptr( - new VkImage(imageHandle), - [dev = device](VkImage* img) { - Layer::ovkDestroyImage(dev, *img, nullptr); - } - ); - this->memory = std::shared_ptr( - new VkDeviceMemory(memoryHandle), - [dev = device](VkDeviceMemory* mem) { - Layer::ovkFreeMemory(dev, *mem, nullptr); - } - ); -} diff --git a/src/mini/semaphore.cpp b/src/mini/semaphore.cpp deleted file mode 100644 index cd03031..0000000 --- a/src/mini/semaphore.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "mini/semaphore.hpp" -#include "common/exception.hpp" -#include "layer.hpp" - -#include - -#include - -using namespace Mini; - -Semaphore::Semaphore(VkDevice device) { - // create semaphore - const VkSemaphoreCreateInfo desc{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO - }; - VkSemaphore semaphoreHandle{}; - auto res = Layer::ovkCreateSemaphore(device, &desc, nullptr, &semaphoreHandle); - if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create semaphore"); - - // store semaphore in shared ptr - this->semaphore = std::shared_ptr( - new VkSemaphore(semaphoreHandle), - [dev = device](VkSemaphore* semaphoreHandle) { - Layer::ovkDestroySemaphore(dev, *semaphoreHandle, nullptr); - } - ); -} - -Semaphore::Semaphore(VkDevice 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 = Layer::ovkCreateSemaphore(device, &desc, nullptr, &semaphoreHandle); - if (res != VK_SUCCESS || semaphoreHandle == VK_NULL_HANDLE) - throw LSFG::vulkan_error(res, "Unable to create semaphore"); - - // export semaphore to fd - const VkSemaphoreGetFdInfoKHR fdInfo{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, - .semaphore = semaphoreHandle, - .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT - }; - res = Layer::ovkGetSemaphoreFdKHR(device, &fdInfo, fd); - if (res != VK_SUCCESS || *fd < 0) - throw LSFG::vulkan_error(res, "Unable to export semaphore to fd"); - - // store semaphore in shared ptr - this->semaphore = std::shared_ptr( - new VkSemaphore(semaphoreHandle), - [dev = device](VkSemaphore* semaphoreHandle) { - Layer::ovkDestroySemaphore(dev, *semaphoreHandle, nullptr); - } - ); -} diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp deleted file mode 100644 index 7ab40a0..0000000 --- a/src/utils/utils.cpp +++ /dev/null @@ -1,285 +0,0 @@ -#include "utils/utils.hpp" -#include "common/exception.hpp" -#include "layer.hpp" - -#include -#include -#include // NOLINT -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Utils; - -std::pair Utils::findQueue(VkDevice device, VkPhysicalDevice physicalDevice, - VkDeviceCreateInfo* desc, VkQueueFlags flags) { - std::vector enabledQueues(desc->queueCreateInfoCount); - std::copy_n(desc->pQueueCreateInfos, enabledQueues.size(), enabledQueues.data()); - - uint32_t familyCount{}; - Layer::ovkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount, nullptr); - std::vector families(familyCount); - Layer::ovkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount, - families.data()); - - std::optional idx; - for (const auto& queueInfo : enabledQueues) { - if ((queueInfo.queueFamilyIndex < families.size()) && - (families[queueInfo.queueFamilyIndex].queueFlags & flags)) { - idx = queueInfo.queueFamilyIndex; - break; - } - } - if (!idx.has_value()) - throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No suitable queue found"); - - VkQueue queue{}; - Layer::ovkGetDeviceQueue(device, *idx, 0, &queue); - - auto res = Layer::ovkSetDeviceLoaderData(device, queue); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Unable to set device loader data for queue"); - - return { *idx, queue }; -} - -uint64_t Utils::getDeviceUUID(VkPhysicalDevice physicalDevice) { - VkPhysicalDeviceProperties properties{}; - Layer::ovkGetPhysicalDeviceProperties(physicalDevice, &properties); - - return static_cast(properties.vendorID) << 32 | properties.deviceID; -} - -uint32_t Utils::getMaxImageCount(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { - VkSurfaceCapabilitiesKHR capabilities{}; - auto res = Layer::ovkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, - surface, &capabilities); - if (res != VK_SUCCESS) - throw LSFG::vulkan_error(res, "Failed to get surface capabilities"); - if (capabilities.maxImageCount == 0) - return 999; // :3 - return capabilities.maxImageCount; -} - -std::vector Utils::addExtensions(const char* const* extensions, size_t count, - const std::vector& requiredExtensions) { - std::vector ext(count); - std::copy_n(extensions, count, ext.data()); - - for (const auto& e : requiredExtensions) { - auto it = std::ranges::find_if(ext, - [e](const char* extName) { - return std::string(extName) == std::string(e); - }); - if (it == ext.end()) - ext.push_back(e); - } - - return ext; -} - -void Utils::copyImage(VkCommandBuffer buf, - VkImage src, VkImage dst, - uint32_t width, uint32_t height, - VkPipelineStageFlags pre, VkPipelineStageFlags post, - bool makeSrcPresentable, bool makeDstPresentable) { - const VkImageMemoryBarrier srcBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - .image = src, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }; - const VkImageMemoryBarrier dstBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .image = dst, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }; - const std::vector barriers = { srcBarrier, dstBarrier }; - Layer::ovkCmdPipelineBarrier(buf, - pre, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, 0, nullptr, - static_cast(barriers.size()), barriers.data()); - - const VkImageBlit imageBlit{ - .srcSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .layerCount = 1 - }, - .srcOffsets = { - { 0, 0, 0 }, - { static_cast(width), static_cast(height), 1 } - }, - .dstSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .layerCount = 1 - }, - .dstOffsets = { - { 0, 0, 0 }, - { static_cast(width), static_cast(height), 1 } - } - }; - Layer::ovkCmdBlitImage( - buf, - src, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &imageBlit, - VK_FILTER_NEAREST - ); - - if (makeSrcPresentable) { - const VkImageMemoryBarrier presentBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - .image = src, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }; - Layer::ovkCmdPipelineBarrier(buf, - VK_PIPELINE_STAGE_TRANSFER_BIT, post, 0, - 0, nullptr, 0, nullptr, - 1, &presentBarrier); - } - - if (makeDstPresentable) { - const VkImageMemoryBarrier presentBarrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - .image = dst, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }; - Layer::ovkCmdPipelineBarrier(buf, - VK_PIPELINE_STAGE_TRANSFER_BIT, post, 0, - 0, nullptr, 0, nullptr, - 1, &presentBarrier); - } -} - -namespace { - auto& logCounts() { - static std::unordered_map map; - return map; - } -} - -void Utils::logLimitN(const std::string& id, size_t n, const std::string& message) { - auto& count = logCounts()[id]; - if (count <= n) - std::cerr << "lsfg-vk: " << message << '\n'; - if (count == n) - std::cerr << "(above message has been repeated " << n << " times, suppressing further)\n"; - count++; -} - -void Utils::resetLimitN(const std::string& id) noexcept { - logCounts().erase(id); -} - -std::pair Utils::getProcessName() { - // check benchmark flag - const char* benchmark_flag = std::getenv("LSFG_BENCHMARK"); - if (benchmark_flag) - return { "benchmark", "benchmark" }; - std::array exe{}; - - // then check override - const char* process_name = std::getenv("LSFG_PROCESS"); - if (process_name && *process_name != '\0') - return { process_name, process_name }; - - // find executed binary - const ssize_t exe_len = readlink("/proc/self/exe", exe.data(), exe.size() - 1); - if (exe_len <= 0) - return { "Unknown Process", "unknown" }; - exe.at(static_cast(exe_len)) = '\0'; - std::string exe_str(exe.data()); - - // find command name as well - std::ifstream comm_file("/proc/self/comm"); - if (!comm_file.is_open()) - return { std::string(exe.data()), "unknown" }; - std::array comm{}; - comm_file.read(comm.data(), 256); - comm.at(static_cast(comm_file.gcount())) = '\0'; - std::string comm_str(comm.data()); - if (comm_str.back() == '\n') - comm_str.pop_back(); - - // replace binary with exe for wine apps - if (exe_str.find("wine") != std::string::npos - || exe_str.find("proton") != std::string::npos) { - - std::ifstream proc_maps("/proc/self/maps"); - if (!proc_maps.is_open()) - return{ exe_str, comm_str }; - - std::string line; - while (std::getline(proc_maps, line)) { - if (!line.ends_with(".exe")) - continue; - - size_t pos = line.find_first_of('/'); - if (pos == std::string::npos) { - pos = line.find_last_of(' '); - if (pos == std::string::npos) - continue; - pos += 1; // skip space - } - - const std::string exe_name = line.substr(pos); - if (exe_name.empty()) - continue; - - exe_str = exe_name; - break; - } - } - - return{ exe_str, comm_str }; -} - -std::string Utils::getConfigFile() { - const char* configFile = std::getenv("LSFG_CONFIG"); - if (configFile && *configFile != '\0') - return{configFile}; - const char* xdgPath = std::getenv("XDG_CONFIG_HOME"); - if (xdgPath && *xdgPath != '\0') - return std::string(xdgPath) + "/lsfg-vk/conf.toml"; - const char* homePath = std::getenv("HOME"); - if (homePath && *homePath != '\0') - return std::string(homePath) + "/.config/lsfg-vk/conf.toml"; - return "/etc/lsfg-vk/conf.toml"; -}