[Feat] (MG_Test/Backend/DirectVulkan): pick and compare physical device

This commit is contained in:
2026-02-12 00:07:52 +08:00
parent 341749706d
commit 99bc2e121b
2 changed files with 104 additions and 52 deletions
@@ -207,69 +207,112 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_I("Found %d physical device(s).", deviceCount); MGLOG_I("Found %d physical device(s).", deviceCount);
} }
auto deviceTypeToStr = [](VkPhysicalDeviceType type) { MOBILEGL_ASSERT(deviceCount > 0, "No physical devices found.");
switch (type) {
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
return "INTEGRATED_GPU";
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
return "DISCRETE_GPU";
case VK_PHYSICAL_DEVICE_TYPE_CPU:
return "CPU";
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
return "VIRTUAL_GPU";
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
return "OTHER";
default:
return "UNKNOWN";
}
};
Vector<VkPhysicalDevice> devices(deviceCount); Vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data()); vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data());
for (const auto& device : devices) { for (Int i = 0; i < deviceCount; i++) {
VkPhysicalDeviceProperties deviceProperties; if (CheckPhysicalDeviceEligibilityAndCompare(devices[i], m_physicalDevice, m_physicalDevice))
vkGetPhysicalDeviceProperties(device, &deviceProperties); MGLOG_I("Picked physical device %d.", i);
auto apiVersion = deviceProperties.apiVersion;
MGLOG_I(" %s (Vulkan %d.%d.%d, %s)",
deviceProperties.deviceName,
VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion), VK_VERSION_PATCH(apiVersion),
deviceTypeToStr(deviceProperties.deviceType));
// TODO: Properly check device eligibility
m_queueFamilies = GetQueueFamilyFromPhysicalDevice(device);
auto gfxQueueFamily = GetQueueFamilyIndex(m_queueFamilies, VK_QUEUE_GRAPHICS_BIT);
if (m_physicalDevice == VK_NULL_HANDLE && gfxQueueFamily != -1) {
m_physicalDevice = device;
m_queueFamilyIndices.graphicsFamily = gfxQueueFamily;
MGLOG_I("Physical device picked.");
}
} }
MOBILEGL_ASSERT(!devices.empty(), "No physical devices found."); if (m_physicalDevice.handle == VK_NULL_HANDLE) {
if (m_physicalDevice == VK_NULL_HANDLE) { m_physicalDevice.handle = devices[0];
m_physicalDevice = devices[0]; vkGetPhysicalDeviceProperties(devices[0], &m_physicalDevice.properties);
MGLOG_I("No suitable physical device picked yet, defaulting to device 0."); MGLOG_I("No suitable physical device picked yet, defaulting to device 0.");
MGLOG_W("No graphics queue found on physical device. Picking a device that doesn't do graphics?"); MGLOG_W("No graphics queue found on physical device. Picking a device that doesn't do graphics?");
} }
}
m_queueFamilyIndices.presentFamily = GetPresentQueueFamilyIndex(m_queueFamilies, m_queueFamilyIndices.graphicsFamily); Bool VulkanRenderer::CheckPhysicalDeviceEligibilityAndCompare(
VkPhysicalDevice device, const PhysicalDevice& otherDevice, PhysicalDevice& outDevice) {
const auto deviceTypeToStr = [](VkPhysicalDeviceType type) {
switch (type) {
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
return "INTEGRATED_GPU";
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
return "DISCRETE_GPU";
case VK_PHYSICAL_DEVICE_TYPE_CPU:
return "CPU";
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
return "VIRTUAL_GPU";
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
return "OTHER";
default:
return "UNKNOWN";
}
};
PhysicalDevice newDevice;
newDevice.handle = device;
vkGetPhysicalDeviceProperties(device, &newDevice.properties);
const auto& deviceProperties = newDevice.properties;
auto apiVersion = deviceProperties.apiVersion;
MGLOG_I(" %s (Vulkan %d.%d.%d, %s)",
deviceProperties.deviceName,
VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion), VK_VERSION_PATCH(apiVersion),
deviceTypeToStr(deviceProperties.deviceType));
Vector<VkQueueFamilyProperties> queueFamilies = GetQueueFamilyFromPhysicalDevice(device);
newDevice.queueFamilies.graphicsFamily = GetQueueFamilyIndex(queueFamilies, VK_QUEUE_GRAPHICS_BIT);
if (newDevice.queueFamilies.graphicsFamily == -1) {
outDevice = otherDevice;
MGLOG_I(" Ignored physical device: No graphics queue family.");
return false;
}
newDevice.queueFamilies.presentFamily =
GetPresentQueueFamilyIndex(newDevice, queueFamilies, newDevice.queueFamilies.graphicsFamily);
if (newDevice.queueFamilies.presentFamily == -1) {
outDevice = otherDevice;
MGLOG_I(" Ignored physical device: No present queue family.");
return false;
}
// Pick discrete GPU
if (newDevice.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
otherDevice.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
outDevice = newDevice;
MGLOG_I(" Picked physical device: Discrete GPU.");
return true;
}
// Pick integrated GPU if no discrete GPU
if (newDevice.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
otherDevice.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
outDevice = newDevice;
MGLOG_I(" Picked physical device: Integrated GPU and the other is not discrete.");
return true;
}
// Ignore other GPU when discrete GPU found
if (newDevice.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
otherDevice.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
outDevice = newDevice;
MGLOG_I(" Ignored physical device: Already picked discrete GPU.");
return false;
}
return false;
} }
void VulkanRenderer::CreateLogicalDeviceAndQueues() { void VulkanRenderer::CreateLogicalDeviceAndQueues() {
Float queuePriority = 1.0f; Float queuePriority = 1.0f;
Vector<VkDeviceQueueCreateInfo> queueCreateInfos; Vector<VkDeviceQueueCreateInfo> queueCreateInfos;
MOBILEGL_ASSERT(m_queueFamilyIndices.graphicsFamily != -1, "Graphics queue family not found."); MOBILEGL_ASSERT(m_physicalDevice.queueFamilies.graphicsFamily != -1, "Graphics queue family not found.");
VkDeviceQueueCreateInfo& gfxQueueCreateInfo = queueCreateInfos.emplace_back(); VkDeviceQueueCreateInfo& gfxQueueCreateInfo = queueCreateInfos.emplace_back();
gfxQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; gfxQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
gfxQueueCreateInfo.queueFamilyIndex = m_queueFamilyIndices.graphicsFamily; gfxQueueCreateInfo.queueFamilyIndex = m_physicalDevice.queueFamilies.graphicsFamily;
gfxQueueCreateInfo.queueCount = 1; gfxQueueCreateInfo.queueCount = 1;
gfxQueueCreateInfo.pQueuePriorities = &queuePriority; gfxQueueCreateInfo.pQueuePriorities = &queuePriority;
if (m_queueFamilyIndices.graphicsFamily != m_queueFamilyIndices.presentFamily) { if (m_physicalDevice.queueFamilies.graphicsFamily != m_physicalDevice.queueFamilies.presentFamily) {
MOBILEGL_ASSERT(m_queueFamilyIndices.presentFamily != -1, "Present queue family not found."); MOBILEGL_ASSERT(m_physicalDevice.queueFamilies.presentFamily != -1, "Present queue family not found.");
VkDeviceQueueCreateInfo& presentQueueCreateInfo = queueCreateInfos.emplace_back(); VkDeviceQueueCreateInfo& presentQueueCreateInfo = queueCreateInfos.emplace_back();
presentQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; presentQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
presentQueueCreateInfo.queueFamilyIndex = m_queueFamilyIndices.presentFamily; presentQueueCreateInfo.queueFamilyIndex = m_physicalDevice.queueFamilies.presentFamily;
presentQueueCreateInfo.queueCount = 1; presentQueueCreateInfo.queueCount = 1;
presentQueueCreateInfo.pQueuePriorities = &queuePriority; presentQueueCreateInfo.pQueuePriorities = &queuePriority;
} }
@@ -288,12 +331,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} else { } else {
deviceCreateInfo.enabledLayerCount = 0; deviceCreateInfo.enabledLayerCount = 0;
} }
VK_VERIFY(vkCreateDevice(m_physicalDevice, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice"); VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
MGLOG_I("Logical device created."); MGLOG_I("Logical device created.");
// Queues // Queues
vkGetDeviceQueue(m_device, m_queueFamilyIndices.graphicsFamily, 0, &m_graphicsQueue); vkGetDeviceQueue(m_device, m_physicalDevice.queueFamilies.graphicsFamily, 0, &m_graphicsQueue);
vkGetDeviceQueue(m_device, m_queueFamilyIndices.presentFamily, 0, &m_presentQueue); vkGetDeviceQueue(m_device, m_physicalDevice.queueFamilies.presentFamily, 0, &m_presentQueue);
MGLOG_I("Queues got successfully."); MGLOG_I("Queues got successfully.");
} }
@@ -338,18 +381,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return -1; return -1;
} }
Int VulkanRenderer::GetPresentQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, Int VulkanRenderer::GetPresentQueueFamilyIndex(
Int preferredFamilyIndex) const { const PhysicalDevice& physicalDevice,
const Vector<VkQueueFamilyProperties>& queueFamilies, Int preferredFamilyIndex) const {
if (preferredFamilyIndex != -1) { if (preferredFamilyIndex != -1) {
VkBool32 supportsPresent = false; VkBool32 supportsPresent = false;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, preferredFamilyIndex, m_surface, &supportsPresent); vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, preferredFamilyIndex, m_surface, &supportsPresent);
if (supportsPresent) if (supportsPresent)
return preferredFamilyIndex; return preferredFamilyIndex;
} }
for (Uint32 i = 0; i < queueFamilies.size(); i++) { for (Uint32 i = 0; i < queueFamilies.size(); i++) {
VkBool32 supportsPresent = false; VkBool32 supportsPresent = false;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent); vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, i, m_surface, &supportsPresent);
if (supportsPresent) if (supportsPresent)
return i; return i;
} }
@@ -49,6 +49,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Int32 presentFamily = -1; Int32 presentFamily = -1;
}; };
struct PhysicalDevice {
QueueFamilyIndices queueFamilies;
VkPhysicalDeviceProperties properties;
VkPhysicalDevice handle = VK_NULL_HANDLE;
};
NativeWindowType m_window = 0; NativeWindowType m_window = 0;
RendererConfig m_config; RendererConfig m_config;
@@ -57,12 +63,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Vector<VkExtensionProperties> m_extensions; Vector<VkExtensionProperties> m_extensions;
VkInstance m_instance = VK_NULL_HANDLE; VkInstance m_instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; PhysicalDevice m_physicalDevice;
// VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSurfaceKHR m_surface = VK_NULL_HANDLE;
Vector<VkQueueFamilyProperties> m_queueFamilies; // Vector<VkQueueFamilyProperties> m_queueFamilies;
QueueFamilyIndices m_queueFamilyIndices; // QueueFamilyIndices m_queueFamilyIndices;
VkQueue m_graphicsQueue = VK_NULL_HANDLE; VkQueue m_graphicsQueue = VK_NULL_HANDLE;
VkQueue m_presentQueue = VK_NULL_HANDLE; VkQueue m_presentQueue = VK_NULL_HANDLE;
@@ -73,10 +80,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkResult DestroyDebugMessenger(); VkResult DestroyDebugMessenger();
VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo(); VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo();
void PickPhysicalDevice(); void PickPhysicalDevice();
Bool CheckPhysicalDeviceEligibilityAndCompare(VkPhysicalDevice device, const PhysicalDevice& compareWithDevice, PhysicalDevice& outDevice);
void CreateLogicalDeviceAndQueues(); void CreateLogicalDeviceAndQueues();
void CreateSurface(); void CreateSurface();
Int GetPresentQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, Int preferredFamilyIndex = -1) const; Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, const Vector<VkQueueFamilyProperties>& queueFamilies, Int preferredFamilyIndex = -1) const;
static Vector<VkQueueFamilyProperties> GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device); static Vector<VkQueueFamilyProperties> GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device);
static Int GetQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, VkQueueFlagBits flag); static Int GetQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, VkQueueFlagBits flag);