mirror of
				https://github.com/PancakeTAS/lsfg-vk.git
				synced 2025-10-30 07:01:10 +00:00 
			
		
		
		
	base vulkan classes
This commit is contained in:
		
							parent
							
								
									bf2b683264
								
							
						
					
					
						commit
						fe5a8520e5
					
				
					 5 changed files with 247 additions and 0 deletions
				
			
		
							
								
								
									
										60
									
								
								include/device.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								include/device.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| #ifndef DEVICE_HPP | ||||
| #define DEVICE_HPP | ||||
| 
 | ||||
| #include "instance.hpp" | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Vulkan { | ||||
| 
 | ||||
|     ///
 | ||||
|     /// C++ wrapper class for a Vulkan device.
 | ||||
|     ///
 | ||||
|     /// This class manages the lifetime of a Vulkan device.
 | ||||
|     ///
 | ||||
|     class Device { | ||||
|     public: | ||||
|         ///
 | ||||
|         /// Create the device.
 | ||||
|         ///
 | ||||
|         /// @param instance Vulkan instance
 | ||||
|         ///
 | ||||
|         /// @throws std::invalid_argument if the instance is invalid.
 | ||||
|         /// @throws ls::vulkan_error if object creation fails.
 | ||||
|         ///
 | ||||
|         Device(const Vulkan::Instance& instance); | ||||
| 
 | ||||
|         /// Get the Vulkan handle.
 | ||||
|         [[nodiscard]] auto handle() const { return *this->device; } | ||||
|         /// Get the physical device associated with this logical device.
 | ||||
|         [[nodiscard]] VkPhysicalDevice getPhysicalDevice() const { return this->physicalDevice; } | ||||
|         /// Get the compute queue family index.
 | ||||
|         [[nodiscard]] uint32_t getComputeFamilyIdx() const { return this->computeFamilyIdx; } | ||||
|         /// Get the compute queue.
 | ||||
|         [[nodiscard]] VkQueue getComputeQueue() const { return this->computeQueue; } | ||||
| 
 | ||||
|         /// Check whether the object is valid.
 | ||||
|         [[nodiscard]] bool isValid() const { return static_cast<bool>(this->device); } | ||||
|         /// if (obj) operator. Checks if the object is valid.
 | ||||
|         explicit operator bool() const { return this->isValid(); } | ||||
| 
 | ||||
|         // Trivially copyable, moveable and destructible
 | ||||
|         Device(const Device&) noexcept = default; | ||||
|         Device& operator=(const Device&) noexcept = default; | ||||
|         Device(Device&&) noexcept = default; | ||||
|         Device& operator=(Device&&) noexcept = default; | ||||
|         ~Device() = default; | ||||
|     private: | ||||
|         std::shared_ptr<VkDevice> device; | ||||
|         VkPhysicalDevice physicalDevice{}; | ||||
| 
 | ||||
|         uint32_t computeFamilyIdx{0}; | ||||
| 
 | ||||
|         VkQueue computeQueue{}; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // DEVICE_HPP
 | ||||
							
								
								
									
										44
									
								
								include/instance.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								include/instance.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| #ifndef INSTANCE_HPP | ||||
| #define INSTANCE_HPP | ||||
| 
 | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Vulkan { | ||||
| 
 | ||||
|     ///
 | ||||
|     /// C++ wrapper class for a Vulkan instance.
 | ||||
|     ///
 | ||||
|     /// This class manages the lifetime of a Vulkan instance.
 | ||||
|     ///
 | ||||
|     class Instance { | ||||
|     public: | ||||
|         ///
 | ||||
|         /// Create the instance.
 | ||||
|         ///
 | ||||
|         /// @throws ls::vulkan_error if object creation fails.
 | ||||
|         ///
 | ||||
|         Instance(); | ||||
| 
 | ||||
|         /// Get the Vulkan handle.
 | ||||
|         [[nodiscard]] auto handle() const { return this->instance ? *this->instance : VK_NULL_HANDLE; } | ||||
| 
 | ||||
|         /// Check whether the object is valid.
 | ||||
|         [[nodiscard]] bool isValid() const { return this->handle() != VK_NULL_HANDLE; } | ||||
|         /// if (obj) operator. Checks if the object is valid.
 | ||||
|         explicit operator bool() const { return this->isValid(); } | ||||
| 
 | ||||
|         /// Trivially copyable, moveable and destructible
 | ||||
|         Instance(const Instance&) noexcept = default; | ||||
|         Instance& operator=(const Instance&) noexcept = default; | ||||
|         Instance(Instance&&) noexcept = default; | ||||
|         Instance& operator=(Instance&&) noexcept = default; | ||||
|         ~Instance() = default; | ||||
|     private: | ||||
|         std::shared_ptr<VkInstance> instance; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // INSTANCE_HPP
 | ||||
							
								
								
									
										85
									
								
								src/device.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/device.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| #include "device.hpp" | ||||
| #include "utils/exceptions.hpp" | ||||
| 
 | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| 
 | ||||
| using namespace Vulkan; | ||||
| 
 | ||||
| Device::Device(const Instance& instance) { | ||||
|     if (!instance) | ||||
|         throw std::invalid_argument("Invalid Vulkan instance"); | ||||
| 
 | ||||
|     // get all physical devices
 | ||||
|     uint32_t deviceCount{}; | ||||
|     auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr); | ||||
|     if (res != VK_SUCCESS || deviceCount == 0) | ||||
|         throw ls::vulkan_error(res, "Failed to enumerate physical devices"); | ||||
| 
 | ||||
|     std::vector<VkPhysicalDevice> devices(deviceCount); | ||||
|     res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, devices.data()); | ||||
|     if (res != VK_SUCCESS) | ||||
|         throw ls::vulkan_error(res, "Failed to get physical devices"); | ||||
| 
 | ||||
|     // find first discrete GPU
 | ||||
|     std::optional<VkPhysicalDevice> physicalDevice; | ||||
|     for (const auto& device : devices) { | ||||
|         VkPhysicalDeviceProperties properties; | ||||
|         vkGetPhysicalDeviceProperties(device, &properties); | ||||
| 
 | ||||
|         if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { | ||||
|             physicalDevice = device; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if (!physicalDevice) | ||||
|         throw ls::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No discrete GPU found"); | ||||
| 
 | ||||
|     // find queue family indices
 | ||||
|     uint32_t familyCount{}; | ||||
|     vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, nullptr); | ||||
| 
 | ||||
|     std::vector<VkQueueFamilyProperties> queueFamilies(familyCount); | ||||
|     vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data()); | ||||
| 
 | ||||
|     std::optional<uint32_t> computeFamilyIdx; | ||||
|     for (uint32_t i = 0; i < familyCount; ++i) { | ||||
|         if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) | ||||
|             computeFamilyIdx = i; | ||||
|     } | ||||
|     if (!computeFamilyIdx) | ||||
|         throw ls::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No compute queue family found"); | ||||
| 
 | ||||
|     // create logical device
 | ||||
|     const float queuePriority{1.0F}; // highest priority
 | ||||
|     const VkDeviceQueueCreateInfo computeQueueDesc{ | ||||
|         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | ||||
|         .queueFamilyIndex = *computeFamilyIdx, | ||||
|         .queueCount = 1, | ||||
|         .pQueuePriorities = &queuePriority | ||||
|     }; | ||||
|     const VkDeviceCreateInfo deviceCreateInfo{ | ||||
|         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | ||||
|         .queueCreateInfoCount = 1, | ||||
|         .pQueueCreateInfos = &computeQueueDesc | ||||
|     }; | ||||
|     VkDevice deviceHandle{}; | ||||
|     res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle); | ||||
|     if (res != VK_SUCCESS | deviceHandle == VK_NULL_HANDLE) | ||||
|         throw ls::vulkan_error(res, "Failed to create logical device"); | ||||
| 
 | ||||
|     // get compute queue
 | ||||
|     VkQueue queueHandle{}; | ||||
|     vkGetDeviceQueue(deviceHandle, *computeFamilyIdx, 0, &queueHandle); | ||||
| 
 | ||||
|     // store in shared ptr
 | ||||
|     this->computeQueue = queueHandle; | ||||
|     this->computeFamilyIdx = *computeFamilyIdx; | ||||
|     this->physicalDevice = *physicalDevice; | ||||
|     this->device = std::shared_ptr<VkDevice>( | ||||
|         new VkDevice(deviceHandle), | ||||
|         [](VkDevice* device) { | ||||
|             vkDestroyDevice(*device, nullptr); | ||||
|         } | ||||
|     ); | ||||
| } | ||||
							
								
								
									
										46
									
								
								src/instance.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/instance.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| #include "instance.hpp" | ||||
| #include "utils/exceptions.hpp" | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| using namespace Vulkan; | ||||
| 
 | ||||
| const std::vector<const char*> requiredExtensions = { | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| const std::vector<const char*> requiredLayers = { | ||||
|     "VK_LAYER_KHRONOS_validation" | ||||
| }; | ||||
| 
 | ||||
| Instance::Instance() { | ||||
|     // create Vulkan instance
 | ||||
|     const VkApplicationInfo appInfo{ | ||||
|         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | ||||
|         .pApplicationName = "lsfg-vk-base", | ||||
|         .applicationVersion = VK_MAKE_VERSION(0, 0, 1), | ||||
|         .pEngineName = "lsfg-vk-base", | ||||
|         .engineVersion = VK_MAKE_VERSION(0, 0, 1), | ||||
|         .apiVersion = VK_API_VERSION_1_4 | ||||
|     }; | ||||
|     const VkInstanceCreateInfo createInfo{ | ||||
|         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | ||||
|         .pApplicationInfo = &appInfo, | ||||
|         .enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()), | ||||
|         .ppEnabledLayerNames = requiredLayers.data(), | ||||
|         .enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()), | ||||
|         .ppEnabledExtensionNames = requiredExtensions.data() | ||||
|     }; | ||||
|     VkInstance instanceHandle{}; | ||||
|     auto res = vkCreateInstance(&createInfo, nullptr, &instanceHandle); | ||||
|     if (res != VK_SUCCESS) | ||||
|         throw ls::vulkan_error(res, "Failed to create Vulkan instance"); | ||||
| 
 | ||||
|     // store in shared ptr
 | ||||
|     this->instance = std::shared_ptr<VkInstance>( | ||||
|         new VkInstance(instanceHandle), | ||||
|         [](VkInstance* instance) { | ||||
|             vkDestroyInstance(*instance, nullptr); | ||||
|         } | ||||
|     ); | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include "device.hpp" | ||||
| #include "instance.hpp" | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| int main() { | ||||
|     const Vulkan::Instance instance; | ||||
|     const Vulkan::Device device(instance); | ||||
| 
 | ||||
|     std::cerr << "Application finished" << '\n'; | ||||
|     return 0; | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 PancakeTAS
						PancakeTAS