diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index aa34ad3b0d..6768602852 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -886,6 +886,187 @@ VkResult VulkanContext::ReinitSurface() { case WINDOWSYSTEM_DISPLAY: { VkDisplaySurfaceCreateInfoKHR display{ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR }; +#if !defined(__LIBRETRO__) + /* + And when not to use libretro need VkDisplaySurfaceCreateInfoKHR this extension, + then you need to use dlopen to read vulkan loader in VulkanLoader.cpp. + huangzihan China + */ + + if(!vkGetPhysicalDeviceDisplayPropertiesKHR || + !vkGetPhysicalDeviceDisplayPlanePropertiesKHR || + !vkGetDisplayModePropertiesKHR || + !vkGetDisplayPlaneSupportedDisplaysKHR || + !vkGetDisplayPlaneCapabilitiesKHR ) { + _assert_msg_(false, "DISPLAY Vulkan cannot find any vulkan function symbols."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + //The following code is for reference: + // https://github.com/vanfanel/ppsspp + // When using the VK_KHR_display extension and not using LIBRETRO, a complete + // VkDisplaySurfaceCreateInfoKHR is needed. + + uint32_t display_count; + uint32_t plane_count; + + VkDisplayPropertiesKHR *display_props = NULL; + VkDisplayPlanePropertiesKHR *plane_props = NULL; + VkDisplayModePropertiesKHR* mode_props = NULL; + + VkExtent2D image_size; + // This is the chosen physical_device, it has been chosen elsewhere. + VkPhysicalDevice phys_device = physical_devices_[physical_device_]; + VkDisplayModeKHR display_mode = VK_NULL_HANDLE; + VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + uint32_t plane = UINT32_MAX; + + // For now, use the first available (connected) display. + int display_index = 0; + + VkResult result; + bool ret = false; + bool mode_found = false; + + int i, j; + + // 1 physical device can have N displays connected. + // Vulkan only counts the connected displays. + + // Get a list of displays on the physical device. + display_count = 0; + vkGetPhysicalDeviceDisplayPropertiesKHR(phys_device, &display_count, NULL); + if (display_count == 0) { + _assert_msg_(false, "DISPLAY Vulkan couldn't find any displays."); + return VK_ERROR_INITIALIZATION_FAILED; + } + display_props = new VkDisplayPropertiesKHR[display_count]; + vkGetPhysicalDeviceDisplayPropertiesKHR(phys_device, &display_count, display_props); + + // Get a list of display planes on the physical device. + plane_count = 0; + vkGetPhysicalDeviceDisplayPlanePropertiesKHR(phys_device, &plane_count, NULL); + if (plane_count == 0) { + _assert_msg_(false, "DISPLAY Vulkan couldn't find any planes on the physical device"); + return VK_ERROR_INITIALIZATION_FAILED; + + } + plane_props = new VkDisplayPlanePropertiesKHR[plane_count]; + vkGetPhysicalDeviceDisplayPlanePropertiesKHR(phys_device, &plane_count, plane_props); + + // Get the Vulkan display we are going to use. + VkDisplayKHR myDisplay = display_props[display_index].display; + + // Get the list of display modes of the display + uint32_t mode_count = 0; + vkGetDisplayModePropertiesKHR(phys_device, myDisplay, &mode_count, NULL); + if (mode_count == 0) { + _assert_msg_(false, "DISPLAY Vulkan couldn't find any video modes on the display"); + return VK_ERROR_INITIALIZATION_FAILED; + } + mode_props = new VkDisplayModePropertiesKHR[mode_count]; + vkGetDisplayModePropertiesKHR(phys_device, myDisplay, &mode_count, mode_props); + + // See if there's an appropiate mode available on the display + display_mode = VK_NULL_HANDLE; + for (i = 0; i < mode_count; ++i) + { + const VkDisplayModePropertiesKHR* mode = &mode_props[i]; + + if (mode->parameters.visibleRegion.width == pixel_xres && + mode->parameters.visibleRegion.height == pixel_yres) + { + display_mode = mode->displayMode; + mode_found = true; + break; + } + } + + // Free the mode list now. + delete [] mode_props; + + // If there are no useable modes found on the display, error out + if (display_mode == VK_NULL_HANDLE) + { + _assert_msg_(false, "DISPLAY Vulkan couldn't find any video modes on the display"); + return VK_ERROR_INITIALIZATION_FAILED; + } + + /* Iterate on the list of planes of the physical device + to find a plane that matches these criteria: + -It must be compatible with the chosen display + mode. + -It isn't currently bound to another display. + -It supports per-pixel alpha, if possible. */ + for (i = 0; i < plane_count; i++) { + uint32_t supported_displays_count = 0; + VkDisplayKHR* supported_displays; + VkDisplayPlaneCapabilitiesKHR plane_caps; + + /* See if the plane is compatible with the current display. */ + vkGetDisplayPlaneSupportedDisplaysKHR(phys_device, i, &supported_displays_count, NULL); + if (supported_displays_count == 0) { + /* This plane doesn't support any displays. Continue to the next plane. */ + continue; + } + + /* Get the list of displays supported by this plane. */ + supported_displays = new VkDisplayKHR[supported_displays_count]; + vkGetDisplayPlaneSupportedDisplaysKHR(phys_device, i, + &supported_displays_count, supported_displays); + + /* The plane must be bound to the chosen display, or not in use. + If none of these is true, iterate to another plane. */ + if ( !( (plane_props[i].currentDisplay == myDisplay) || + (plane_props[i].currentDisplay == VK_NULL_HANDLE))) + continue; + + /* Iterate the list of displays supported by this plane + in order to find out if the chosen display is among them. */ + bool plane_supports_display = false; + for (j = 0; j < supported_displays_count; j++) { + if (supported_displays[j] == myDisplay) { + plane_supports_display = true; + break; + } + } + + /* Free the list of displays supported by this plane. */ + delete [] supported_displays; + + /* If the display is not supported by this plane, iterate to the next plane. */ + if (!plane_supports_display) + continue; + + /* Want a plane that supports the alpha mode we have chosen. */ + vkGetDisplayPlaneCapabilitiesKHR(phys_device, display_mode, i, &plane_caps); + if (plane_caps.supportedAlpha & alpha_mode) { + /* Yep, this plane is alright. */ + plane = i; + break; + } + } + + /* If we couldn't find an appropiate plane, error out. */ + if (plane == UINT32_MAX) { + _assert_msg_(false, "DISPLAY Vulkan couldn't find an appropiate plane"); + return VK_ERROR_INITIALIZATION_FAILED; + } + + // Finally, create the vulkan surface. + image_size.width = pixel_xres; + image_size.height = pixel_yres; + + display.displayMode = display_mode; + display.imageExtent = image_size; + display.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + display.alphaMode = alpha_mode; + display.globalAlpha = 1.0f; + display.planeIndex = plane; + display.planeStackIndex = plane_props[plane].currentStackIndex; + display.pNext = nullptr; + delete [] display_props; + delete [] plane_props; +#endif display.flags = 0; retval = vkCreateDisplayPlaneSurfaceKHR(instance_, &display, nullptr, &surface_); break; diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index 94092b2166..2a00ed9622 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -195,6 +195,11 @@ PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; #endif #if defined(VK_USE_PLATFORM_DISPLAY_KHR) PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; #endif PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; @@ -564,6 +569,11 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en #endif #if defined(VK_USE_PLATFORM_DISPLAY_KHR) LOAD_INSTANCE_FUNC(instance, vkCreateDisplayPlaneSurfaceKHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceDisplayPropertiesKHR); + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceDisplayPlanePropertiesKHR); + LOAD_INSTANCE_FUNC(instance, vkGetDisplayModePropertiesKHR); + LOAD_INSTANCE_FUNC(instance, vkGetDisplayPlaneSupportedDisplaysKHR); + LOAD_INSTANCE_FUNC(instance, vkGetDisplayPlaneCapabilitiesKHR); #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h index caaef0d597..85b4bb5510 100644 --- a/Common/GPU/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -194,6 +194,11 @@ extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; #endif #if defined(VK_USE_PLATFORM_DISPLAY_KHR) extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; #endif extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index dea43f64f0..406f303a73 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -768,7 +768,7 @@ int main(int argc, char *argv[]) { #if !PPSSPP_PLATFORM(SWITCH) } else if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); - if (!ctx->Init(window, x, y, mode, &error_message)) { + if (!ctx->Init(window, x, y, mode | SDL_WINDOW_VULKAN, &error_message)) { printf("Vulkan init error '%s' - falling back to GL\n", error_message.c_str()); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; SetGPUBackend((GPUBackend)g_Config.iGPUBackend); diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index 624d3b497f..b01571b626 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -110,6 +110,15 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.uikit.window), nullptr); break; #endif +#endif +#if defined(VK_USE_PLATFORM_DISPLAY_KHR) + case WINDOWSYSTEM_DISPLAY: + /* + There is no problem passing null for the next two arguments, and reinit will be called later + huangzihan china + */ + vulkan_->InitSurface(WINDOWSYSTEM_DISPLAY, nullptr, nullptr); + break; #endif default: fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem);