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 | ||||
|     "src/loader/*.cpp" | ||||
|     "src/mini/*.cpp" | ||||
|     "src/*.cpp" | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| #ifndef APPLICATION_HPP | ||||
| #define APPLICATION_HPP | ||||
| 
 | ||||
| #include "mini/image.hpp" | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| 
 | ||||
|  | @ -76,7 +77,7 @@ public: | |||
|     Application& operator=(Application&&) = delete; | ||||
| 
 | ||||
|     /// Destructor, cleans up resources.
 | ||||
|     ~Application() = default; // no resources to clean up as of right now.
 | ||||
|     ~Application(); | ||||
| private: | ||||
|     // (non-owned resources)
 | ||||
|     VkDevice device; | ||||
|  | @ -93,7 +94,6 @@ private: | |||
| ///
 | ||||
| class SwapchainContext { | ||||
| public: | ||||
| 
 | ||||
|     ///
 | ||||
|     /// Create the swapchain context.
 | ||||
|     ///
 | ||||
|  | @ -130,20 +130,24 @@ public: | |||
|     /// Get the swapchain 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& operator=(const SwapchainContext&) = delete; | ||||
|     SwapchainContext(SwapchainContext&&) = default; | ||||
|     SwapchainContext& operator=(SwapchainContext&&) = default; | ||||
|     ~SwapchainContext() = default; | ||||
| 
 | ||||
|     /// Destructor, cleans up resources.
 | ||||
|     ~SwapchainContext(); | ||||
| private: | ||||
|     // (non-owned resources)
 | ||||
|     VkSwapchainKHR swapchain{}; | ||||
|     VkFormat format{}; | ||||
|     VkExtent2D extent{}; | ||||
|     VkSwapchainKHR swapchain; | ||||
|     VkFormat format; | ||||
|     VkExtent2D extent; | ||||
|     std::vector<VkImage> images; | ||||
| 
 | ||||
|     // (owned resources)
 | ||||
|     Mini::Image frame_0, frame_1; | ||||
|     int32_t lsfgId; | ||||
| }; | ||||
| 
 | ||||
| #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/instance.hpp" | ||||
| #include "context.hpp" | ||||
| #include "utils.hpp" | ||||
| 
 | ||||
| #include <ctime> | ||||
| #include <optional> | ||||
|  | @ -22,6 +23,8 @@ void LSFG::initialize() { | |||
|     instance.emplace(); | ||||
|     device.emplace(*instance); | ||||
| 
 | ||||
|     Globals::initializeGlobals(*device); | ||||
| 
 | ||||
|     std::srand(static_cast<uint32_t>(std::time(nullptr))); | ||||
| } | ||||
| 
 | ||||
|  | @ -61,6 +64,8 @@ void LSFG::finalize() { | |||
|     if (!instance.has_value() && !device.has_value()) | ||||
|         return; | ||||
| 
 | ||||
|     Globals::uninitializeGlobals(); | ||||
| 
 | ||||
|     instance.reset(); | ||||
|     device.reset(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,13 +1,16 @@ | |||
| #include "application.hpp" | ||||
| #include "log.hpp" | ||||
| #include "mini/image.hpp" | ||||
| 
 | ||||
| #include <lsfg.hpp> | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| Application::Application(VkDevice device, VkPhysicalDevice physicalDevice, | ||||
|         VkQueue graphicsQueue, VkQueue presentQueue) | ||||
|         : device(device), physicalDevice(physicalDevice), | ||||
|           graphicsQueue(graphicsQueue), presentQueue(presentQueue) {} | ||||
|           graphicsQueue(graphicsQueue), presentQueue(presentQueue) { | ||||
|     LSFG::initialize(); | ||||
| } | ||||
| 
 | ||||
| void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2D extent, | ||||
|         const std::vector<VkImage>& images) { | ||||
|  | @ -20,7 +23,23 @@ void Application::addSwapchain(VkSwapchainKHR handle, VkFormat format, VkExtent2 | |||
| 
 | ||||
| SwapchainContext::SwapchainContext(const Application& app, VkSwapchainKHR swapchain, | ||||
|         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, | ||||
|         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"); | ||||
| } | ||||
| 
 | ||||
| SwapchainContext::~SwapchainContext() { | ||||
|     try { | ||||
|         LSFG::deleteContext(this->lsfgId); | ||||
|     } catch (const std::exception&) { | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Application::removeSwapchain(VkSwapchainKHR handle) { | ||||
|     auto it = this->swapchains.find(handle); | ||||
|     if (it == this->swapchains.end()) | ||||
|  | @ -53,3 +80,8 @@ bool Application::removeSwapchain(VkSwapchainKHR handle) { | |||
|     this->swapchains.erase(it); | ||||
|     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
	
	 PancakeTAS
						PancakeTAS