From f5e59b1c848c071e005dd95d37ba6b6d0476752c Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Thu, 12 Feb 2026 11:43:34 +0800 Subject: [PATCH] [Feat] (MG_Backend/DirectVulkan): inspect SwapchainCapabilities --- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 56 ++++++++++++++++--- .../DirectVulkan/Renderer/VulkanRenderer.h | 25 ++++++++- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index b80b4887..53520fc5 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -212,7 +212,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Vector devices(deviceCount); vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data()); for (Int i = 0; i < deviceCount; i++) { - if (GetMoreCapablePhysicalDevice(devices[i], m_physicalDevice, m_physicalDevice)) + if (GetMoreCapablePhysicalDevice(devices[i], m_surface, m_physicalDevice, m_physicalDevice)) MGLOG_I("Picked physical device %d.", i); } @@ -225,7 +225,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } Bool VulkanRenderer::GetMoreCapablePhysicalDevice( - VkPhysicalDevice newVkDevice, const PhysicalDevice& otherDevice, PhysicalDevice& outBetterDevice) { + VkPhysicalDevice newVkDevice, VkSurfaceKHR surface, const PhysicalDevice& otherDevice, PhysicalDevice& outBetterDevice) { const auto deviceTypeToStr = [](VkPhysicalDeviceType type) { switch (type) { case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: @@ -254,6 +254,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion), VK_VERSION_PATCH(apiVersion), deviceTypeToStr(deviceProperties.deviceType)); + // Check device extensions (including swapchain extension) Bool deviceExtSupported = IsNecessaryDeviceExtensionSupported(newVkDevice); if (!deviceExtSupported) { outBetterDevice = otherDevice; @@ -261,6 +262,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { return false; } + // Check swapchain capabilities + newDevice.swapchainCapabilities = GetSwapchainCapabilities(newVkDevice, surface); + if (!newDevice.swapchainCapabilities.IsComplete()) { + outBetterDevice = otherDevice; + MGLOG_I(" Ignored physical device: Swapchain capabilities not met."); + return false; + } + + // Check queue families Vector queueFamilies = GetQueueFamilyFromPhysicalDevice(newVkDevice); newDevice.queueFamilies.graphicsFamily = GetQueueFamilyIndex(queueFamilies, VK_QUEUE_GRAPHICS_BIT); if (newDevice.queueFamilies.graphicsFamily == -1) { @@ -270,7 +280,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } newDevice.queueFamilies.presentFamily = - GetPresentQueueFamilyIndex(newDevice, queueFamilies, newDevice.queueFamilies.graphicsFamily); + GetPresentQueueFamilyIndex(newDevice, surface, queueFamilies, newDevice.queueFamilies.graphicsFamily); if (newDevice.queueFamilies.presentFamily == -1) { outBetterDevice = otherDevice; MGLOG_I(" Ignored physical device: No present queue family."); @@ -289,7 +299,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (newDevice.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && otherDevice.properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { outBetterDevice = newDevice; - MGLOG_I(" Picked physical device: Integrated GPU and the other is not discrete."); + MGLOG_I(" Picked physical device: Integrated GPU and no discrete one found yet."); return true; } @@ -320,17 +330,43 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool found = false; for (const auto& extension : availableExtensions) { if (strcmp(extension.extensionName, s_deviceExtensionNames[i]) == 0) { + MGLOG_I("Required extension found: %s", s_deviceExtensionNames[i]); found = true; break; } } - if (!found) + if (!found) { + MGLOG_I("Required extension not found: %s", s_deviceExtensionNames[i]); return false; + } } return true; } + VulkanRenderer::SwapchainCapabilities VulkanRenderer::GetSwapchainCapabilities(VkPhysicalDevice device, VkSurfaceKHR surface) { + SwapchainCapabilities swapchainCapabilities; + + VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &swapchainCapabilities.capabilities)); + Uint32 formatCount; + VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr)); + + if (formatCount != 0) { + swapchainCapabilities.surfaceFormats.resize(formatCount); + VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, swapchainCapabilities.surfaceFormats.data())); + } + + Uint32 presentModeCount; + VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr)); + + if (presentModeCount != 0) { + swapchainCapabilities.presentModes.resize(presentModeCount); + VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, swapchainCapabilities.presentModes.data())); + } + + return swapchainCapabilities; + } + void VulkanRenderer::CreateLogicalDeviceAndQueues() { Float queuePriority = 1.0f; @@ -365,6 +401,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { } else { deviceCreateInfo.enabledLayerCount = 0; } + deviceCreateInfo.enabledExtensionCount = static_cast(std::size(s_deviceExtensionNames)); + deviceCreateInfo.ppEnabledExtensionNames = s_deviceExtensionNames; VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice"); MGLOG_I("Logical device created."); @@ -416,18 +454,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { } Int VulkanRenderer::GetPresentQueueFamilyIndex( - const PhysicalDevice& physicalDevice, - const Vector& queueFamilies, Int preferredFamilyIndex) const { + const PhysicalDevice& physicalDevice, VkSurfaceKHR surface, + const Vector& queueFamilies, Int preferredFamilyIndex) { if (preferredFamilyIndex != -1) { VkBool32 supportsPresent = false; - vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, preferredFamilyIndex, m_surface, &supportsPresent); + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, preferredFamilyIndex, surface, &supportsPresent); if (supportsPresent) return preferredFamilyIndex; } for (Uint32 i = 0; i < queueFamilies.size(); i++) { VkBool32 supportsPresent = false; - vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, i, m_surface, &supportsPresent); + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.handle, i, surface, &supportsPresent); if (supportsPresent) return i; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 69c5ce46..1ecd3a9a 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -49,10 +49,27 @@ namespace MobileGL::MG_Backend::DirectVulkan { Int32 presentFamily = -1; }; + struct SwapchainCapabilities { + VkSurfaceCapabilitiesKHR capabilities; + Vector surfaceFormats; + Vector presentModes; + + Bool IsComplete() const { + return !surfaceFormats.empty() && !presentModes.empty(); + } + }; + struct PhysicalDevice { QueueFamilyIndices queueFamilies; VkPhysicalDeviceProperties properties; + SwapchainCapabilities swapchainCapabilities; VkPhysicalDevice handle = VK_NULL_HANDLE; + + Bool IsComplete() const { + return handle != VK_NULL_HANDLE && + queueFamilies.graphicsFamily != -1 && + queueFamilies.presentFamily != -1; + } }; NativeWindowType m_window = 0; @@ -80,16 +97,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkResult DestroyDebugMessenger(); VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo(); void PickPhysicalDevice(); - Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, const PhysicalDevice& compareWithDevice, PhysicalDevice& outBetterDevice); void CreateLogicalDeviceAndQueues(); void CreateSurface(); - Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, const Vector& queueFamilies, Int preferredFamilyIndex = -1) const; - + static Int GetPresentQueueFamilyIndex( + const PhysicalDevice& physicalDevice, VkSurfaceKHR surface, + const Vector& queueFamilies, Int preferredFamilyIndex = -1); static Vector GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device); static Int GetQueueFamilyIndex(const Vector& queueFamilies, VkQueueFlagBits flag); static Vector EnumerateInstanceExtensions(); static Bool IsNecessaryDeviceExtensionSupported(VkPhysicalDevice device); + static SwapchainCapabilities GetSwapchainCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface); + static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface, const PhysicalDevice& compareWithDevice, PhysicalDevice& outBetterDevice); static constexpr const char* s_validationLayerNames[] = { "VK_LAYER_KHRONOS_validation" };