MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ pick_physical_device()

bool MayaFlux::Core::VKDevice::pick_physical_device ( vk::Instance  instance,
const GraphicsBackendInfo backend_info 
)
private

Select a physical device by config selector or score.

Parameters
instanceVulkan instance
backend_infoGraphics backend configuration
Returns
true if a suitable device was found

Definition at line 285 of file VKDevice.cpp.

286{
287 auto devices = instance.enumeratePhysicalDevices();
288
289 if (devices.empty()) {
291 std::source_location::current(),
292 "Failed to find GPUs with Vulkan support!");
293 }
294
295 const PresentationProbe probe(instance);
296
297 if (backend_info.require_presentation && !probe.available) {
299 "Presentation support cannot be verified on this platform; "
300 "device selection will not filter on it");
301 }
302
303 std::vector<DeviceCandidate> candidates;
304 candidates.reserve(devices.size());
305
306 for (uint32_t i = 0; i < devices.size(); ++i) {
307 const auto& device = devices[i];
308
309 DeviceCandidate cand;
310 cand.device = device;
311 cand.index = i;
312
313 auto available_extensions = device.enumerateDeviceExtensionProperties();
314 bool has_pci_ext = false;
315
316 for (const auto& ext : available_extensions) {
317 if (strcmp(ext.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
318 cand.has_swapchain = true;
319 if (strcmp(ext.extensionName, VK_EXT_MESH_SHADER_EXTENSION_NAME) == 0)
320 cand.has_mesh_shader = true;
321 if (strcmp(ext.extensionName, VK_EXT_PCI_BUS_INFO_EXTENSION_NAME) == 0)
322 has_pci_ext = true;
323 }
324
325 auto prop_chain = vk::StructureChain {
326 vk::PhysicalDeviceProperties2 {},
327 vk::PhysicalDeviceVulkan11Properties {},
328 vk::PhysicalDeviceVulkan12Properties {},
329 vk::PhysicalDevicePCIBusInfoPropertiesEXT {}
330 };
331
332 if (!has_pci_ext) {
333 prop_chain.unlink<vk::PhysicalDevicePCIBusInfoPropertiesEXT>();
334 }
335
336 device.getProperties2(&prop_chain.get<vk::PhysicalDeviceProperties2>());
337
338 const auto& props = prop_chain.get<vk::PhysicalDeviceProperties2>().properties;
339 const auto& props11 = prop_chain.get<vk::PhysicalDeviceVulkan11Properties>();
340 const auto& props12 = prop_chain.get<vk::PhysicalDeviceVulkan12Properties>();
341
342 cand.name = props.deviceName.data();
343 cand.type = props.deviceType;
344 cand.api_version = props.apiVersion;
345 cand.driver_id = props12.driverID;
346 cand.driver_name = props12.driverName.data();
347 std::copy_n(props11.deviceUUID.data(), VK_UUID_SIZE, cand.uuid.begin());
348 cand.uuid_hex = uuid_to_hex(cand.uuid.data());
349
350 if (has_pci_ext) {
351 cand.has_pci_info = true;
352 cand.pci_bus = prop_chain.get<vk::PhysicalDevicePCIBusInfoPropertiesEXT>().pciBus;
353 }
354
355 auto memory_props = device.getMemoryProperties();
356 for (uint32_t h = 0; h < memory_props.memoryHeapCount; ++h) {
357 if (memory_props.memoryHeaps[h].flags & vk::MemoryHeapFlagBits::eDeviceLocal) {
358 cand.device_local_bytes = std::max(cand.device_local_bytes,
359 static_cast<uint64_t>(memory_props.memoryHeaps[h].size));
360 }
361 }
362
363 cand.families = find_queue_families(device);
364
365 if (cand.has_mesh_shader) {
366 vk::PhysicalDeviceMeshShaderFeaturesEXT mesh_features;
367 vk::PhysicalDeviceFeatures2 features;
368 features.pNext = &mesh_features;
369 device.getFeatures2(&features);
370
371 cand.has_mesh_shader = mesh_features.meshShader == VK_TRUE
372 && mesh_features.taskShader == VK_TRUE;
373 }
374
375 {
376 auto family_props = device.getQueueFamilyProperties();
377 const uint32_t probe_count = std::min<uint32_t>(static_cast<uint32_t>(family_props.size()), QueueFamilyIndices::MAX_TRACKED_FAMILIES);
378
379 for (uint32_t f = 0; f < probe_count; ++f) {
380 if (probe.supports(device, f))
381 cand.present_family_mask |= (1U << f);
382 }
383
384 cand.families.present_family_mask = cand.present_family_mask;
385
386 if (cand.families.graphics_family.has_value())
387 cand.graphics_presents = cand.families.can_present(cand.families.graphics_family.value());
388 }
389
390 if (!cand.families.graphics_family.has_value()) {
391 cand.reject_reason = "no graphics queue family";
392 } else if (cand.api_version < VK_API_VERSION_1_3) {
393 cand.reject_reason = "device API version below 1.3";
394 } else if (!cand.has_swapchain) {
395 cand.reject_reason = "no VK_KHR_swapchain";
396 } else if (backend_info.require_presentation && !cand.graphics_presents) {
397 cand.reject_reason = "graphics family cannot present";
398 }
399
400 cand.score = type_base_score(cand.type);
401
402 switch (backend_info.device_preference) {
404 if (cand.type == vk::PhysicalDeviceType::eDiscreteGpu)
405 cand.score += 10000;
406 break;
408 if (cand.type == vk::PhysicalDeviceType::eIntegratedGpu)
409 cand.score += 10000;
410 break;
412 if (cand.type == vk::PhysicalDeviceType::eVirtualGpu)
413 cand.score += 10000;
414 break;
416 if (cand.type == vk::PhysicalDeviceType::eDiscreteGpu) {
417 cand.score += 10000;
418 if (cand.has_pci_info)
419 cand.score += static_cast<int64_t>(cand.pci_bus) * 4;
420 }
421 break;
423 default:
424 break;
425 }
426
427 if (cand.graphics_presents)
428 cand.score += 500;
429 if (cand.has_mesh_shader)
430 cand.score += 100;
431
432 cand.score += static_cast<int64_t>(cand.device_local_bytes >> 30U);
433
434 candidates.push_back(std::move(cand));
435 }
436
437 for (const auto& cand : candidates) {
439 "GPU [{}] {} | type={} driver={} ({}) api={}.{}.{} | uuid={} | "
440 "gfx={} compute={} transfer={} | present=gfx:{} mask:{:#x} mesh={} vram={}MB pci_bus={} | score={}{}{}",
441 cand.index, cand.name, vk::to_string(cand.type),
442 vk::to_string(cand.driver_id), cand.driver_name,
443 VK_API_VERSION_MAJOR(cand.api_version),
444 VK_API_VERSION_MINOR(cand.api_version),
445 VK_API_VERSION_PATCH(cand.api_version),
446 cand.uuid_hex,
447 cand.families.graphics_family.has_value() ? std::to_string(cand.families.graphics_family.value()) : "none",
448 cand.families.compute_family.has_value() ? std::to_string(cand.families.compute_family.value()) : "none",
449 cand.families.transfer_family.has_value() ? std::to_string(cand.families.transfer_family.value()) : "none",
450 cand.graphics_presents ? "yes" : "no",
452 cand.has_mesh_shader ? "yes" : "no",
453 cand.device_local_bytes >> 20U,
454 cand.has_pci_info ? std::to_string(cand.pci_bus) : "n/a",
455 cand.score,
456 cand.viable() ? "" : " | REJECTED: ",
457 cand.reject_reason ? cand.reject_reason : "");
458 }
459
461 "Presentation probe mechanism: {}, require_presentation={}, device_preference={}",
462 probe.mechanism, backend_info.require_presentation ? "true" : "false",
463 Reflect::enum_to_string(backend_info.device_preference));
464
465 int32_t want_index = backend_info.device_index;
466 std::string want_name = backend_info.device_name;
467 std::string want_uuid = backend_info.device_uuid;
468
469 if (int32_t env_index = -1; read_gpu_env(env_index, want_name)) {
470 want_index = env_index;
471 want_uuid.clear();
473 "MAYAFLUX_GPU override active (index={}, name='{}')", want_index, want_name);
474 }
475
476 const DeviceCandidate* selected = nullptr;
477 const char* selection_basis = "score";
478
479 if (want_index >= 0) {
480 for (const auto& cand : candidates) {
481 if (static_cast<int32_t>(cand.index) == want_index && cand.viable()) {
482 selected = &cand;
483 selection_basis = "device_index";
484 break;
485 }
486 }
487 }
488
489 if (!selected && !want_uuid.empty()) {
490 for (const auto& cand : candidates) {
491 if (cand.uuid_hex == want_uuid && cand.viable()) {
492 selected = &cand;
493 selection_basis = "device_uuid";
494 break;
495 }
496 }
497 }
498
499 if (!selected && !want_name.empty()) {
500 for (const auto& cand : candidates) {
501 if (!cand.viable() || !contains_nocase(cand.name, want_name))
502 continue;
503 if (!selected || cand.score > selected->score) {
504 selected = &cand;
505 selection_basis = "device_name";
506 }
507 }
508 }
509
510 const bool selector_requested = want_index >= 0 || !want_uuid.empty() || !want_name.empty();
511
512 if (selector_requested && !selected) {
513 if (backend_info.strict_device_selection) {
515 std::source_location::current(),
516 "No viable physical device matched the requested selector "
517 "(index={}, uuid='{}', name='{}') and strict_device_selection is set",
518 want_index, want_uuid, want_name);
519 }
520
522 "No viable physical device matched the requested selector "
523 "(index={}, uuid='{}', name='{}'); falling back to score",
524 want_index, want_uuid, want_name);
525 }
526
527 if (!selected) {
528 for (const auto& cand : candidates) {
529 if (!cand.viable())
530 continue;
531 if (!selected || cand.score > selected->score)
532 selected = &cand;
533 }
534 }
535
536 if (!selected) {
538 std::source_location::current(),
539 "No suitable GPU found among {} enumerated device(s); "
540 "see the candidate list above for rejection reasons",
541 candidates.size());
542 }
543
544 m_physical_device = selected->device;
545 m_queue_families = selected->families;
546 m_supports_mesh_shaders = selected->has_mesh_shader;
547 m_graphics_presents = selected->graphics_presents;
548 m_device_name = selected->name;
549 m_device_uuid = selected->uuid;
550
552 "Selected GPU [{}] {} by {} (uuid={}, score={})",
553 selected->index, selected->name, selection_basis, selected->uuid_hex, selected->score);
554
555 return true;
556}
#define MF_INFO(comp, ctx,...)
#define MF_LOG(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
uint32_t h
Definition InkPress.cpp:28
bool has_mesh_shader
Definition VKDevice.cpp:152
bool graphics_presents
Definition VKDevice.cpp:154
vk::PhysicalDevice device
Definition VKDevice.cpp:141
const char * reject_reason
Definition VKDevice.cpp:159
vk::Instance instance
Definition VKDevice.cpp:50
uint64_t device_local_bytes
Definition VKDevice.cpp:157
QueueFamilyIndices families
Definition VKDevice.cpp:150
bool has_pci_info
Definition VKDevice.cpp:155
uint32_t pci_bus
Definition VKDevice.cpp:156
int64_t score
Definition VKDevice.cpp:158
uint32_t present_family_mask
Definition VKDevice.cpp:153
float value
static QueueFamilyIndices find_queue_families(vk::PhysicalDevice device)
Find queue families on the given physical device.
Definition VKDevice.cpp:558
std::array< uint8_t, VK_UUID_SIZE > m_device_uuid
Selected device UUID.
Definition VKDevice.hpp:208
bool m_supports_mesh_shaders
Whether the device supports mesh shaders.
Definition VKDevice.hpp:209
vk::PhysicalDevice m_physical_device
Selected physical device (GPU)
Definition VKDevice.hpp:172
bool m_graphics_presents
Graphics family passed the surfaceless presentation probe.
Definition VKDevice.hpp:205
std::string m_device_name
Selected device name, cached for logging.
Definition VKDevice.hpp:207
QueueFamilyIndices m_queue_families
Indices of required queue families.
Definition VKDevice.hpp:179
constexpr std::string_view to_string(EventType type)
Converts an EventType to its string representation.
Definition EventBus.hpp:28
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
static constexpr uint32_t MAX_TRACKED_FAMILIES
Width of present_family_mask.
Definition VKDevice.hpp:18

References MayaFlux::Core::GraphicsBackendInfo::AUTO, MayaFlux::Journal::Core, device, MayaFlux::Core::GraphicsBackendInfo::device_index, MayaFlux::Core::GraphicsBackendInfo::device_name, MayaFlux::Core::GraphicsBackendInfo::device_preference, MayaFlux::Core::GraphicsBackendInfo::device_uuid, MayaFlux::Core::GraphicsBackendInfo::DISCRETE, MayaFlux::Reflect::enum_to_string(), MayaFlux::Core::GraphicsBackendInfo::EXTERNAL, find_queue_families(), MayaFlux::Journal::GraphicsBackend, h, instance, MayaFlux::Core::GraphicsBackendInfo::INTEGRATED, m_device_name, m_device_uuid, m_graphics_presents, m_physical_device, m_queue_families, m_supports_mesh_shaders, MayaFlux::Core::QueueFamilyIndices::MAX_TRACKED_FAMILIES, MF_INFO, MF_LOG, MF_WARN, MayaFlux::Core::GraphicsBackendInfo::require_presentation, MayaFlux::Core::GraphicsBackendInfo::strict_device_selection, and MayaFlux::Core::GraphicsBackendInfo::VIRTUAL.

Referenced by initialize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: