@@ -135,6 +135,84 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vkDebugCallback(VkDebugUtilsMessageSeverit
135135 return VK_FALSE;
136136}
137137
138+ static std::pair<VkPhysicalDevice, uint32_t > resolveAdapter (const axstd::pod_vector<VkPhysicalDevice>& devices,
139+ VkInstance instance,
140+ PowerPreference pref)
141+ {
142+ VkPhysicalDevice bestDevice = VK_NULL_HANDLE;
143+ uint32_t graphicsQueueFamily = UINT32_MAX;
144+ int bestScore = -1 ;
145+
146+ for (auto pd : devices)
147+ {
148+ VkPhysicalDeviceProperties props{};
149+ vkGetPhysicalDeviceProperties (pd, &props);
150+
151+ uint32_t qCount = 0 ;
152+ vkGetPhysicalDeviceQueueFamilyProperties (pd, &qCount, nullptr );
153+ std::vector<VkQueueFamilyProperties> qprops (qCount);
154+ vkGetPhysicalDeviceQueueFamilyProperties (pd, &qCount, qprops.data ());
155+
156+ bool hasGraphicsQueue = false ;
157+ for (uint32_t i = 0 ; i < qCount; ++i)
158+ {
159+ if (qprops[i].queueCount > 0 && (qprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
160+ {
161+ hasGraphicsQueue = true ;
162+ graphicsQueueFamily = i;
163+ break ;
164+ }
165+ }
166+ if (!hasGraphicsQueue)
167+ continue ; // skip devices without graphics queue
168+
169+ // --- Score device ---
170+ int score = 0 ;
171+
172+ // Power preference
173+ switch (pref)
174+ {
175+ case PowerPreference::HighPerformance:
176+ if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
177+ score += 100 ;
178+ break ;
179+ case PowerPreference::LowPower:
180+ if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
181+ score += 100 ;
182+ break ;
183+ case PowerPreference::Auto:
184+ if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
185+ score += 50 ;
186+ else if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
187+ score += 25 ;
188+ break ;
189+ }
190+
191+ // Prefer newer Vulkan versions
192+ score += static_cast <int >(props.apiVersion );
193+
194+ // Prefer larger VRAM (optional)
195+ VkPhysicalDeviceMemoryProperties memProps{};
196+ vkGetPhysicalDeviceMemoryProperties (pd, &memProps);
197+ VkDeviceSize vram = 0 ;
198+ for (uint32_t i = 0 ; i < memProps.memoryHeapCount ; ++i)
199+ {
200+ if (memProps.memoryHeaps [i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
201+ vram += memProps.memoryHeaps [i].size ;
202+ }
203+ score += static_cast <int >(vram / (1024 * 1024 * 256 )); // add points per 256MB
204+
205+ // --- Select best ---
206+ if (score > bestScore)
207+ {
208+ bestScore = score;
209+ bestDevice = pd;
210+ }
211+ }
212+
213+ return {bestDevice, graphicsQueueFamily};
214+ }
215+
138216} // namespace
139217
140218DriverImpl::DriverImpl () {}
@@ -147,29 +225,29 @@ DriverImpl::~DriverImpl()
147225 }
148226
149227 if (_surface)
150- vkDestroySurfaceKHR (_vkInstance , _surface, nullptr );
228+ vkDestroySurfaceKHR (_factory , _surface, nullptr );
151229 if (_debugMessenger)
152- vkDestroyDebugUtilsMessengerEXT (_vkInstance , _debugMessenger, nullptr );
230+ vkDestroyDebugUtilsMessengerEXT (_factory , _debugMessenger, nullptr );
153231 if (_device)
154232 vkDestroyDevice (_device, nullptr );
155- if (_vkInstance )
156- vkDestroyInstance (_vkInstance , nullptr );
233+ if (_factory )
234+ vkDestroyInstance (_factory , nullptr );
157235}
158236
159237void DriverImpl::init ()
160238{
161239 // Load basic Vulkan functions without instance/device
162240 gladLoaderLoadVulkan (nullptr , nullptr , nullptr );
163241
164- initializeInstance ();
242+ initializeFactory ();
165243 initializeDevice ();
166244
167245 // Load remaining Vulkan functions with instance/device
168- gladLoaderLoadVulkan (_vkInstance , _physical, _device);
246+ gladLoaderLoadVulkan (_factory , _physical, _device);
169247
170248 if (_debugCreateInfo.sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT)
171249 {
172- if (vkCreateDebugUtilsMessengerEXT (_vkInstance , &_debugCreateInfo, nullptr , &_debugMessenger) != VK_SUCCESS)
250+ if (vkCreateDebugUtilsMessengerEXT (_factory , &_debugCreateInfo, nullptr , &_debugMessenger) != VK_SUCCESS)
173251 {
174252 AXLOGW (" Vulkan validation layer not available!" );
175253 }
@@ -191,7 +269,7 @@ void DriverImpl::init()
191269 _caps.maxSamplesAllowed = static_cast <int32_t >(props.limits .framebufferColorSampleCounts );
192270}
193271
194- void DriverImpl::initializeInstance ()
272+ void DriverImpl::initializeFactory ()
195273{
196274 auto & contextAttrs = Application::getContextAttrs ();
197275
@@ -254,55 +332,26 @@ void DriverImpl::initializeInstance()
254332 }
255333
256334 // Instance layers/extensions are platform-dependent; keep minimal for core init
257- VkResult vr = vkCreateInstance (&createInfo, nullptr , &_vkInstance);
258- AXASSERT (vr == VK_SUCCESS && _vkInstance != VK_NULL_HANDLE, " vkCreateInstance failed" );
259-
260- // Select a physical device
261- uint32_t count = 0 ;
262- vkEnumeratePhysicalDevices (_vkInstance, &count, nullptr );
263- AXASSERT (count > 0 , " No Vulkan physical devices found" );
264-
265- std::vector<VkPhysicalDevice> devices (count);
266- vkEnumeratePhysicalDevices (_vkInstance, &count, devices.data ());
267-
268- // Simple selection: first device with graphics queue
269- _physical = VK_NULL_HANDLE;
270- for (auto pd : devices)
271- {
272- uint32_t qCount = 0 ;
273- vkGetPhysicalDeviceQueueFamilyProperties (pd, &qCount, nullptr );
274- std::vector<VkQueueFamilyProperties> qprops (qCount);
275- vkGetPhysicalDeviceQueueFamilyProperties (pd, &qCount, qprops.data ());
276- if (std::any_of (qprops.begin (), qprops.end (),
277- [](const VkQueueFamilyProperties& p) { return (p.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 ; }))
278- {
279- _physical = pd;
280- break ;
281- }
282- }
283- if (_physical == VK_NULL_HANDLE)
284- _physical = devices[0 ];
335+ VkResult vr = vkCreateInstance (&createInfo, nullptr , &_factory);
336+ AXASSERT (vr == VK_SUCCESS && _factory != VK_NULL_HANDLE, " vkCreateInstance failed" );
285337}
286338
287339void DriverImpl::initializeDevice ()
288340{
289- // find graphics queue family
290- uint32_t queueCount = 0 ;
291- vkGetPhysicalDeviceQueueFamilyProperties (_physical, &queueCount, nullptr );
292- std::vector<VkQueueFamilyProperties> qprops (queueCount);
293- vkGetPhysicalDeviceQueueFamilyProperties (_physical, &queueCount, qprops.data ());
341+ auto & contextAttrs = Application::getContextAttrs ();
294342
295- _graphicsQueueFamily = UINT32_MAX;
296- for (uint32_t i = 0 ; i < queueCount; ++i)
297- {
298- if (qprops[i].queueCount > 0 && (qprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
299- {
300- _graphicsQueueFamily = i;
301- break ;
302- }
303- }
343+ // Select a physical device
344+ uint32_t count = 0 ;
345+ vkEnumeratePhysicalDevices (_factory, &count, nullptr );
346+ AXASSERT (count > 0 , " No Vulkan physical devices found" );
347+
348+ axstd::pod_vector<VkPhysicalDevice> devices (count);
349+ vkEnumeratePhysicalDevices (_factory, &count, devices.data ());
304350
305- AXASSERT (_graphicsQueueFamily != UINT32_MAX, " No graphics queue family found" );
351+ auto [physical, graphicsQueueFamily] = resolveAdapter (devices, _factory, contextAttrs.powerPreference );
352+ AXASSERT (physical != VK_NULL_HANDLE && graphicsQueueFamily != UINT32_MAX, " No available GPU" );
353+ _physical = physical;
354+ _graphicsQueueFamily = graphicsQueueFamily;
306355
307356 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extDynState{};
308357 extDynState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
@@ -345,7 +394,7 @@ void DriverImpl::initializeDevice()
345394
346395bool DriverImpl::setupSurface (void * window, CreateSurfaceFunc func)
347396{
348- auto result = func (_vkInstance , window, &_surface);
397+ auto result = func (_factory , window, &_surface);
349398 if (result != VK_SUCCESS)
350399 return false ;
351400
0 commit comments