MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VKDevice.cpp
Go to the documentation of this file.
1#include "VKDevice.hpp"
4
5#include "set"
6
7namespace MayaFlux::Core {
8
13
15 : m_physical_device(other.m_physical_device)
16 , m_logical_device(other.m_logical_device)
17 , m_graphics_queue(other.m_graphics_queue)
18 , m_compute_queue(other.m_compute_queue)
19 , m_transfer_queue(other.m_transfer_queue)
20 , m_queue_families(other.m_queue_families)
21{
22 other.m_physical_device = VK_NULL_HANDLE;
23 other.m_logical_device = VK_NULL_HANDLE;
24 other.m_graphics_queue = VK_NULL_HANDLE;
25 other.m_compute_queue = VK_NULL_HANDLE;
26 other.m_transfer_queue = VK_NULL_HANDLE;
27}
28
30{
31 if (this != &other) {
32 cleanup();
33 m_physical_device = other.m_physical_device;
34 m_logical_device = other.m_logical_device;
35 m_graphics_queue = other.m_graphics_queue;
36 m_compute_queue = other.m_compute_queue;
37 m_transfer_queue = other.m_transfer_queue;
38 m_queue_families = other.m_queue_families;
39
40 other.m_physical_device = VK_NULL_HANDLE;
41 other.m_logical_device = VK_NULL_HANDLE;
42 other.m_graphics_queue = VK_NULL_HANDLE;
43 other.m_compute_queue = VK_NULL_HANDLE;
44 other.m_transfer_queue = VK_NULL_HANDLE;
45 }
46 return *this;
47}
48
49bool VKDevice::initialize(vk::Instance instance, vk::SurfaceKHR /*temp_surface*/, const GraphicsBackendInfo& backend_info)
50{
51 if (!pick_physical_device(instance, nullptr)) {
52 return false;
53 }
54
55 return create_logical_device(instance, backend_info);
56}
57
59{
60 if (m_logical_device) {
61 m_logical_device.destroy();
62 m_logical_device = nullptr;
63 MF_INFO(Journal::Component::Core, Journal::Context::GraphicsBackend, "Vulkan logical device destroyed.");
64 }
65 m_physical_device = nullptr;
66 m_graphics_queue = nullptr;
67 m_compute_queue = nullptr;
68 m_transfer_queue = nullptr;
70}
71
72bool VKDevice::pick_physical_device(vk::Instance instance, vk::SurfaceKHR /*temp_surface*/)
73{
74 vk::Instance vk_instance(instance);
75 auto devices = vk_instance.enumeratePhysicalDevices();
76
77 if (devices.empty()) {
79 std::source_location::current(),
80 "Failed to find GPUs with Vulkan support!");
81 }
82
83 for (const auto& device : devices) {
84 QueueFamilyIndices indices = find_queue_families(device, nullptr);
85
86 if (indices.graphics_family.has_value()) {
87 m_physical_device = device;
88 m_queue_families = indices;
89
90 vk::PhysicalDeviceProperties props = device.getProperties();
92 "Selected GPU: {}", props.deviceName.data());
93 return true;
94 }
95 }
96
98 std::source_location::current(),
99 "Failed to find a suitable GPU!");
100 return false;
101}
102
103QueueFamilyIndices VKDevice::find_queue_families(vk::PhysicalDevice device, vk::SurfaceKHR surface)
104{
105 QueueFamilyIndices indices;
106 auto queue_families = device.getQueueFamilyProperties();
107
108 int i = 0;
109 for (const auto& queue_family : queue_families) {
110 if (queue_family.queueCount > 0 && queue_family.queueFlags & vk::QueueFlagBits::eGraphics) {
111 indices.graphics_family = i;
112 }
113
114 if (queue_family.queueCount > 0 && queue_family.queueFlags & vk::QueueFlagBits::eCompute && !(queue_family.queueFlags & vk::QueueFlagBits::eGraphics)) {
115 indices.compute_family = i;
116 }
117
118 if (queue_family.queueCount > 0 && queue_family.queueFlags & vk::QueueFlagBits::eTransfer && !(queue_family.queueFlags & vk::QueueFlagBits::eGraphics) && !(queue_family.queueFlags & vk::QueueFlagBits::eCompute)) {
119 indices.transfer_family = i;
120 }
121
122 if (surface && queue_family.queueCount > 0) {
123 vk::Bool32 presentSupport = device.getSurfaceSupportKHR(i, surface);
124 if (presentSupport) {
125 indices.present_family = i;
127 "Found presentation support in queue family {}", i);
128 }
129 }
130
131 i++;
132 }
133
134 if (indices.graphics_family.has_value()) {
135 if (!indices.compute_family.has_value()) {
136 indices.compute_family = indices.graphics_family;
137 }
138 if (!indices.transfer_family.has_value()) {
139 indices.transfer_family = indices.graphics_family;
140 }
141 }
142
143 return indices;
144}
145
146bool VKDevice::update_presentation_queue(vk::SurfaceKHR surface)
147{
148 if (!surface) {
150 "No surface provided for presentation support check");
151 return false;
152 }
153
154 auto queue_families = m_physical_device.getQueueFamilyProperties();
155
156 for (uint32_t i = 0; i < queue_families.size(); i++) {
157 if (queue_families[i].queueCount > 0) {
158 vk::Bool32 presentSupport = m_physical_device.getSurfaceSupportKHR(i, surface);
159 if (presentSupport) {
160 if (i == m_queue_families.graphics_family.value()) {
164 "Graphics queue family {} supports presentation", i);
165 return true;
166 }
167 }
168 }
169 }
170
171 for (uint32_t i = 0; i < queue_families.size(); i++) {
172 if (queue_families[i].queueCount > 0) {
173 vk::Bool32 presentSupport = m_physical_device.getSurfaceSupportKHR(i, surface);
174 if (presentSupport) {
178 "Found presentation support in queue family {}", i);
179 return true;
180 }
181 }
182 }
183
185 "No queue family with presentation support found!");
186 return false;
187}
188
190{
191 std::vector<vk::ExtensionProperties> availableExtensions = m_physical_device.enumerateDeviceExtensionProperties();
192
193 MF_PRINT(Journal::Component::Core, Journal::Context::GraphicsBackend, "Available physical device extensions:");
194 for (const auto& extension : availableExtensions) {
195 std::cout << "\t- " << extension.extensionName << " (Version: " << extension.specVersion << ")\n";
196 }
198}
199
200bool VKDevice::create_logical_device(vk::Instance /*instance*/, const GraphicsBackendInfo& backend_info)
201{
202 if (!m_queue_families.graphics_family.has_value()) {
204 std::source_location::current(),
205 "No graphics queue family found!");
206 }
207
208 std::set<uint32_t> unique_queue_families;
209 unique_queue_families.insert(m_queue_families.graphics_family.value());
210
211 if (m_queue_families.compute_family.has_value()) {
212 unique_queue_families.insert(m_queue_families.compute_family.value());
213 }
214
216 unique_queue_families.insert(m_queue_families.transfer_family.value());
217 }
218
219 std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
220 float queue_priority = 1.0F;
221
222 for (uint32_t queue_family : unique_queue_families) {
223 vk::DeviceQueueCreateInfo queue_create_info {};
224 queue_create_info.queueFamilyIndex = queue_family;
225 queue_create_info.queueCount = 1;
226 queue_create_info.pQueuePriorities = &queue_priority;
227 queue_create_infos.push_back(queue_create_info);
228 }
229
230 vk::PhysicalDeviceFeatures device_features {};
231 device_features.samplerAnisotropy = backend_info.required_features.sampler_anisotropy;
232 device_features.geometryShader = backend_info.required_features.geometry_shaders;
233 device_features.tessellationShader = backend_info.required_features.tessellation_shaders;
234 device_features.multiViewport = backend_info.required_features.multi_viewport;
235 device_features.fillModeNonSolid = backend_info.required_features.fill_mode_non_solid;
236
237 std::vector<const char*> device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
238
239 for (const auto& ext : backend_info.required_extensions) {
240 device_extensions.push_back(ext.c_str());
241 }
242
243 vk::DeviceCreateInfo create_info {};
244 create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_create_infos.size());
245 create_info.pQueueCreateInfos = queue_create_infos.data();
246 create_info.pEnabledFeatures = &device_features;
247 create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
248 create_info.ppEnabledExtensionNames = device_extensions.data();
249 // create_info.enabledLayerCount = 0;
250
251 try {
252 m_logical_device = m_physical_device.createDevice(create_info);
253 } catch (const std::exception& e) {
255 std::source_location::current(),
256 "Failed to create logical device: {}", e.what());
257 }
258
260
261 if (backend_info.enable_compute_queue && m_queue_families.compute_family.has_value()) {
263 } else {
265 }
266
267 if (backend_info.enable_transfer_queue && m_queue_families.transfer_family.has_value()) {
269 } else {
271 }
272
273 return true;
274}
275
276}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_PRINT(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
void query_supported_extensions()
Query and log supported device extensions.
Definition VKDevice.cpp:189
bool pick_physical_device(vk::Instance instance, vk::SurfaceKHR temp_surface)
Pick a suitable physical device (GPU)
Definition VKDevice.cpp:72
void cleanup()
Cleanup device resources.
Definition VKDevice.cpp:58
VKDevice & operator=(const VKDevice &)=delete
vk::PhysicalDevice m_physical_device
Selected physical device (GPU)
Definition VKDevice.hpp:109
vk::Queue m_compute_queue
Compute queue handle.
Definition VKDevice.hpp:113
bool create_logical_device(vk::Instance instance, const GraphicsBackendInfo &backend_info)
Create the logical device and retrieve queue handles.
Definition VKDevice.cpp:200
vk::Queue m_transfer_queue
Transfer queue handle.
Definition VKDevice.hpp:114
vk::Device m_logical_device
Logical device handle.
Definition VKDevice.hpp:110
QueueFamilyIndices find_queue_families(vk::PhysicalDevice device, vk::SurfaceKHR surface=nullptr)
Find queue families on the given physical device.
Definition VKDevice.cpp:103
bool update_presentation_queue(vk::SurfaceKHR surface)
Update presentation queue family for a specific surface.
Definition VKDevice.cpp:146
vk::Queue m_graphics_queue
Graphics queue handle.
Definition VKDevice.hpp:112
bool initialize(vk::Instance instance, vk::SurfaceKHR temp_surface, const GraphicsBackendInfo &backend_info)
Initialize device (pick physical device and create logical device)
Definition VKDevice.cpp:49
QueueFamilyIndices m_queue_families
Indices of required queue families.
Definition VKDevice.hpp:116
Manages Vulkan physical device selection and logical device creation.
Definition VKDevice.hpp:32
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
bool enable_compute_queue
Enable compute queue (separate from graphics)
std::vector< std::string > required_extensions
Backend-specific extensions to request.
bool enable_transfer_queue
Enable transfer queue (separate from graphics)
struct MayaFlux::Core::GraphicsBackendInfo::@0 required_features
Required device features (Vulkan-specific)
Configuration for graphics API backend (Vulkan/OpenGL/etc.)
std::optional< uint32_t > transfer_family
Definition VKDevice.hpp:16
std::optional< uint32_t > graphics_family
Definition VKDevice.hpp:14
std::optional< uint32_t > present_family
Definition VKDevice.hpp:17
std::optional< uint32_t > compute_family
Definition VKDevice.hpp:15
Stores indices of queue families we need.
Definition VKDevice.hpp:13