mirror of
				https://github.com/PancakeTAS/lsfg-vk.git
				synced 2025-10-30 07:01:10 +00:00 
			
		
		
		
	core sampler and buffer objects
This commit is contained in:
		
							parent
							
								
									d3a903524a
								
							
						
					
					
						commit
						d0bd00d412
					
				
					 4 changed files with 228 additions and 0 deletions
				
			
		
							
								
								
									
										59
									
								
								include/core/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								include/core/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| #ifndef BUFFER_HPP | ||||
| #define BUFFER_HPP | ||||
| 
 | ||||
| #include "device.hpp" | ||||
| 
 | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Vulkan::Core { | ||||
| 
 | ||||
|     ///
 | ||||
|     /// C++ wrapper class for a Vulkan buffer.
 | ||||
|     ///
 | ||||
|     /// This class manages the lifetime of a Vulkan buffer.
 | ||||
|     ///
 | ||||
|     class Buffer { | ||||
|     public: | ||||
|         ///
 | ||||
|         /// Create the buffer.
 | ||||
|         ///
 | ||||
|         /// @param device Vulkan device
 | ||||
|         /// @param size Size of the buffer in bytes.
 | ||||
|         /// @param data Initial data for the buffer.
 | ||||
|         /// @param usage Usage flags for the buffer
 | ||||
|         ///
 | ||||
|         /// @throws std::invalid_argument if the device or buffer size is invalid
 | ||||
|         /// @throws ls::vulkan_error if object creation fails.
 | ||||
|         ///
 | ||||
|         Buffer(const Device& device, uint32_t size, std::vector<uint8_t> data, | ||||
|             VkBufferUsageFlags usage); | ||||
| 
 | ||||
|         /// Get the Vulkan handle.
 | ||||
|         [[nodiscard]] auto handle() const { return *this->buffer; } | ||||
|         /// Get the size of the buffer.
 | ||||
|         [[nodiscard]] uint32_t getSize() const { return this->size; } | ||||
| 
 | ||||
|         /// Check whether the object is valid.
 | ||||
|         [[nodiscard]] bool isValid() const { return static_cast<bool>(this->buffer); } | ||||
|         /// if (obj) operator. Checks if the object is valid.
 | ||||
|         explicit operator bool() const { return this->isValid(); } | ||||
| 
 | ||||
|         /// Trivially copyable, moveable and destructible
 | ||||
|         Buffer(const Buffer&) noexcept = default; | ||||
|         Buffer& operator=(const Buffer&) noexcept = default; | ||||
|         Buffer(Buffer&&) noexcept = default; | ||||
|         Buffer& operator=(Buffer&&) noexcept = default; | ||||
|         ~Buffer() = default; | ||||
|     private: | ||||
|         std::shared_ptr<VkBuffer> buffer; | ||||
|         std::shared_ptr<VkDeviceMemory> memory; | ||||
| 
 | ||||
|         uint32_t size; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // BUFFER_HPP
 | ||||
							
								
								
									
										50
									
								
								include/core/sampler.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								include/core/sampler.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| #ifndef SAMPLER_HPP | ||||
| #define SAMPLER_HPP | ||||
| 
 | ||||
| #include "device.hpp" | ||||
| 
 | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Vulkan::Core { | ||||
| 
 | ||||
|     ///
 | ||||
|     /// C++ wrapper class for a Vulkan sampler.
 | ||||
|     ///
 | ||||
|     /// This class manages the lifetime of a Vulkan sampler.
 | ||||
|     ///
 | ||||
|     class Sampler { | ||||
|     public: | ||||
|         ///
 | ||||
|         /// Create the sampler.
 | ||||
|         ///
 | ||||
|         /// @param device Vulkan device
 | ||||
|         /// @param mode Address mode for the sampler.
 | ||||
|         ///
 | ||||
|         /// @throws std::invalid_argument if the device is invalid.
 | ||||
|         /// @throws ls::vulkan_error if object creation fails.
 | ||||
|         ///
 | ||||
|         Sampler(const Device& device, VkSamplerAddressMode mode); | ||||
| 
 | ||||
|         /// Get the Vulkan handle.
 | ||||
|         [[nodiscard]] auto handle() const { return *this->sampler; } | ||||
| 
 | ||||
|         /// Check whether the object is valid.
 | ||||
|         [[nodiscard]] bool isValid() const { return static_cast<bool>(this->sampler); } | ||||
|         /// if (obj) operator. Checks if the object is valid.
 | ||||
|         explicit operator bool() const { return this->isValid(); } | ||||
| 
 | ||||
|         /// Trivially copyable, moveable and destructible
 | ||||
|         Sampler(const Sampler&) noexcept = default; | ||||
|         Sampler& operator=(const Sampler&) noexcept = default; | ||||
|         Sampler(Sampler&&) noexcept = default; | ||||
|         Sampler& operator=(Sampler&&) noexcept = default; | ||||
|         ~Sampler() = default; | ||||
|     private: | ||||
|         std::shared_ptr<VkSampler> sampler; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // SAMPLER_HPP
 | ||||
							
								
								
									
										86
									
								
								src/core/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/core/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| #include "core/buffer.hpp" | ||||
| #include "utils/exceptions.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <optional> | ||||
| 
 | ||||
| using namespace Vulkan::Core; | ||||
| 
 | ||||
| Buffer::Buffer(const Device& device, uint32_t size, std::vector<uint8_t> data, | ||||
|         VkBufferUsageFlags usage) : size(size) { | ||||
|     if (!device) | ||||
|         throw std::invalid_argument("Invalid Vulkan device"); | ||||
|     if (size < data.size()) | ||||
|         throw std::invalid_argument("Invalid buffer size"); | ||||
| 
 | ||||
|     // create buffer
 | ||||
|     const VkBufferCreateInfo desc{ | ||||
|         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||||
|         .size = size, | ||||
|         .usage = usage, | ||||
|         .sharingMode = VK_SHARING_MODE_EXCLUSIVE | ||||
|     }; | ||||
|     VkBuffer bufferHandle{}; | ||||
|     auto res = vkCreateBuffer(device.handle(), &desc, nullptr, &bufferHandle); | ||||
|     if (res != VK_SUCCESS || bufferHandle == VK_NULL_HANDLE) | ||||
|         throw ls::vulkan_error(res, "Failed to create Vulkan buffer"); | ||||
| 
 | ||||
|     // find memory type
 | ||||
|     VkPhysicalDeviceMemoryProperties memProps; | ||||
|     vkGetPhysicalDeviceMemoryProperties(device.getPhysicalDevice(), &memProps); | ||||
| 
 | ||||
|     VkMemoryRequirements memReqs; | ||||
|     vkGetBufferMemoryRequirements(device.handle(), bufferHandle, &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_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))) { | ||||
|             memType.emplace(i); | ||||
|             break; | ||||
|         } // NOLINTEND
 | ||||
|     } | ||||
|     if (!memType.has_value()) | ||||
|         throw ls::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for buffer"); | ||||
| #pragma clang diagnostic pop | ||||
| 
 | ||||
|     // allocate and bind memory
 | ||||
|     const VkMemoryAllocateInfo allocInfo{ | ||||
|         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||||
|         .allocationSize = memReqs.size, | ||||
|         .memoryTypeIndex = memType.value() | ||||
|     }; | ||||
|     VkDeviceMemory memoryHandle{}; | ||||
|     res = vkAllocateMemory(device.handle(), &allocInfo, nullptr, &memoryHandle); | ||||
|     if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) | ||||
|         throw ls::vulkan_error(res, "Failed to allocate memory for Vulkan buffer"); | ||||
| 
 | ||||
|     res = vkBindBufferMemory(device.handle(), bufferHandle, memoryHandle, 0); | ||||
|     if (res != VK_SUCCESS) | ||||
|         throw ls::vulkan_error(res, "Failed to bind memory to Vulkan buffer"); | ||||
| 
 | ||||
|     // store buffer and memory in shared ptr
 | ||||
|     this->buffer = std::shared_ptr<VkBuffer>( | ||||
|         new VkBuffer(bufferHandle), | ||||
|         [dev = device.handle()](VkBuffer* img) { | ||||
|             vkDestroyBuffer(dev, *img, nullptr); | ||||
|         } | ||||
|     ); | ||||
|     this->memory = std::shared_ptr<VkDeviceMemory>( | ||||
|         new VkDeviceMemory(memoryHandle), | ||||
|         [dev = device.handle()](VkDeviceMemory* mem) { | ||||
|             vkFreeMemory(dev, *mem, nullptr); | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     // upload data to buffer
 | ||||
|     uint8_t* buf{}; | ||||
|     res = vkMapMemory(device.handle(), memoryHandle, 0, size, 0, reinterpret_cast<void**>(&buf)); | ||||
|     if (res != VK_SUCCESS || buf == nullptr) | ||||
|         throw ls::vulkan_error(res, "Failed to map memory for Vulkan buffer"); | ||||
|     std::copy_n(data.data(), size, buf); | ||||
|     vkUnmapMemory(device.handle(), memoryHandle); | ||||
| } | ||||
							
								
								
									
										33
									
								
								src/core/sampler.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/sampler.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #include "core/sampler.hpp" | ||||
| #include "utils/exceptions.hpp" | ||||
| 
 | ||||
| using namespace Vulkan::Core; | ||||
| 
 | ||||
| Sampler::Sampler(const Device& device, VkSamplerAddressMode mode) { | ||||
|     if (!device) | ||||
|         throw std::invalid_argument("Invalid Vulkan device"); | ||||
| 
 | ||||
|     // create sampler
 | ||||
|     const VkSamplerCreateInfo desc{ | ||||
|         .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||||
|         .magFilter = VK_FILTER_LINEAR, | ||||
|         .minFilter = VK_FILTER_LINEAR, | ||||
|         .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, | ||||
|         .addressModeU = mode, | ||||
|         .addressModeV = mode, | ||||
|         .addressModeW = mode, | ||||
|         .maxLod = VK_LOD_CLAMP_NONE | ||||
|     }; | ||||
|     VkSampler samplerHandle{}; | ||||
|     auto res = vkCreateSampler(device.handle(), &desc, nullptr, &samplerHandle); | ||||
|     if (res != VK_SUCCESS || samplerHandle == VK_NULL_HANDLE) | ||||
|         throw ls::vulkan_error(res, "Unable to create sampler"); | ||||
| 
 | ||||
|     // store the sampler in a shared pointer
 | ||||
|     this->sampler = std::shared_ptr<VkSampler>( | ||||
|         new VkSampler(samplerHandle), | ||||
|         [dev = device.handle()](VkSampler* samplerHandle) { | ||||
|             vkDestroySampler(dev, *samplerHandle, nullptr); | ||||
|         } | ||||
|     ); | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 PancakeTAS
						PancakeTAS