mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	Vulkan: Support VK_KHR_display
This commit is contained in:
		
							parent
							
								
									469010868e
								
							
						
					
					
						commit
						8f9bbb0bba
					
				|  | @ -72,6 +72,14 @@ VULKAN_INSTANCE_ENTRY_POINT(vkDebugReportMessageEXT, false) | |||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceProperties2, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilities2KHR, false) | ||||
| 
 | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceDisplayPropertiesKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceDisplayPlanePropertiesKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetDisplayPlaneSupportedDisplaysKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetDisplayModePropertiesKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkCreateDisplayModeKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkGetDisplayPlaneCapabilitiesKHR, false) | ||||
| VULKAN_INSTANCE_ENTRY_POINT(vkCreateDisplayPlaneSurfaceKHR, false) | ||||
| 
 | ||||
| #endif  // VULKAN_INSTANCE_ENTRY_POINT | ||||
| 
 | ||||
| #ifdef VULKAN_DEVICE_ENTRY_POINT | ||||
|  |  | |||
|  | @ -97,10 +97,10 @@ bool Context::CheckValidationLayerAvailablility() | |||
|           }) != layer_list.end()); | ||||
| } | ||||
| 
 | ||||
| VkInstance Context::CreateVulkanInstance(bool enable_surface, bool enable_debug_report, bool enable_validation_layer) | ||||
| VkInstance Context::CreateVulkanInstance(const WindowInfo* wi, bool enable_debug_report, bool enable_validation_layer) | ||||
| { | ||||
|   ExtensionList enabled_extensions; | ||||
|   if (!SelectInstanceExtensions(&enabled_extensions, enable_surface, enable_debug_report)) | ||||
|   if (!SelectInstanceExtensions(&enabled_extensions, wi, enable_debug_report)) | ||||
|     return VK_NULL_HANDLE; | ||||
| 
 | ||||
|   VkApplicationInfo app_info = {}; | ||||
|  | @ -141,7 +141,7 @@ VkInstance Context::CreateVulkanInstance(bool enable_surface, bool enable_debug_ | |||
|   return instance; | ||||
| } | ||||
| 
 | ||||
| bool Context::SelectInstanceExtensions(ExtensionList* extension_list, bool enable_surface, bool enable_debug_report) | ||||
| bool Context::SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo* wi, bool enable_debug_report) | ||||
| { | ||||
|   u32 extension_count = 0; | ||||
|   VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); | ||||
|  | @ -182,31 +182,31 @@ bool Context::SelectInstanceExtensions(ExtensionList* extension_list, bool enabl | |||
|   }; | ||||
| 
 | ||||
|   // Common extensions
 | ||||
|   if (enable_surface && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type != WindowInfo::Type::Surfaceless && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| 
 | ||||
| #if defined(VK_USE_PLATFORM_WIN32_KHR) | ||||
|   if (enable_surface && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type == WindowInfo::Type::Win32 && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #if defined(VK_USE_PLATFORM_XLIB_KHR) | ||||
|   if (enable_surface && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type == WindowInfo::Type::X11 && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #if defined(VK_USE_PLATFORM_WAYLAND_KHR) | ||||
|   if (enable_surface && !SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type == WindowInfo::Type::Wayland && !SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #if defined(VK_USE_PLATFORM_ANDROID_KHR) | ||||
|   if (enable_surface && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #if defined(VK_USE_PLATFORM_MACOS_MVK) | ||||
|   if (enable_surface && !SupportsExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type == WindowInfo::Type::Android && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #if defined(VK_USE_PLATFORM_METAL_EXT) | ||||
|   if (enable_surface && !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true)) | ||||
|   if (wi && wi->type == WindowInfo::Type::MacOS && !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| #ifndef _WIN32 | ||||
|   if (wi && wi->type == WindowInfo::Type::DRM && !SupportsExtension(VK_KHR_DISPLAY_EXTENSION_NAME, true)) | ||||
|     return false; | ||||
| #endif | ||||
| 
 | ||||
|  | @ -302,7 +302,7 @@ bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::uniqu | |||
|   } | ||||
| 
 | ||||
|   const bool enable_surface = (wi && wi->type != WindowInfo::Type::Surfaceless); | ||||
|   VkInstance instance = CreateVulkanInstance(enable_surface, enable_debug_reports, enable_validation_layer); | ||||
|   VkInstance instance = CreateVulkanInstance(wi, enable_debug_reports, enable_validation_layer); | ||||
|   if (instance == VK_NULL_HANDLE) | ||||
|   { | ||||
|     Vulkan::UnloadVulkanLibrary(); | ||||
|  | @ -349,8 +349,12 @@ bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::uniqu | |||
|   } | ||||
| 
 | ||||
|   VkSurfaceKHR surface = VK_NULL_HANDLE; | ||||
|   WindowInfo wi_copy(*wi); | ||||
|   if (enable_surface && (surface = SwapChain::CreateVulkanSurface(instance, wi_copy)) == VK_NULL_HANDLE) | ||||
|   WindowInfo wi_copy; | ||||
|   if (wi) | ||||
|     wi_copy = *wi; | ||||
| 
 | ||||
|   if (enable_surface && | ||||
|       (surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], wi_copy)) == VK_NULL_HANDLE) | ||||
|   { | ||||
|     vkDestroyInstance(instance, nullptr); | ||||
|     Vulkan::UnloadVulkanLibrary(); | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ public: | |||
|   static bool CheckValidationLayerAvailablility(); | ||||
| 
 | ||||
|   // Helper method to create a Vulkan instance.
 | ||||
|   static VkInstance CreateVulkanInstance(bool enable_surface, bool enable_debug_report, bool enable_validation_layer); | ||||
|   static VkInstance CreateVulkanInstance(const WindowInfo* wi, bool enable_debug_report, bool enable_validation_layer); | ||||
| 
 | ||||
|   // Returns a list of Vulkan-compatible GPUs.
 | ||||
|   using GPUList = std::vector<VkPhysicalDevice>; | ||||
|  | @ -180,7 +180,7 @@ private: | |||
|   Context(VkInstance instance, VkPhysicalDevice physical_device, bool owns_device); | ||||
| 
 | ||||
|   using ExtensionList = std::vector<const char*>; | ||||
|   static bool SelectInstanceExtensions(ExtensionList* extension_list, bool enable_surface, bool enable_debug_report); | ||||
|   static bool SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo* wi, bool enable_debug_report); | ||||
|   bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface); | ||||
|   bool SelectDeviceFeatures(const VkPhysicalDeviceFeatures* required_features); | ||||
|   bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, const char** required_device_extensions, | ||||
|  |  | |||
|  | @ -87,7 +87,142 @@ SwapChain::~SwapChain() | |||
|   DestroySurface(); | ||||
| } | ||||
| 
 | ||||
| VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, WindowInfo& wi) | ||||
| #ifndef _WIN32 | ||||
| 
 | ||||
| static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi) | ||||
| { | ||||
|   Log_InfoPrintf("Trying to create a VK_KHR_display surface of %ux%u", wi.surface_width, wi.surface_height); | ||||
| 
 | ||||
|   u32 num_displays; | ||||
|   VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr); | ||||
|   if (res != VK_SUCCESS || num_displays == 0) | ||||
|   { | ||||
|     LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:"); | ||||
|     return {}; | ||||
|   } | ||||
| 
 | ||||
|   std::vector<VkDisplayPropertiesKHR> displays(num_displays); | ||||
|   res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, displays.data()); | ||||
|   if (res != VK_SUCCESS || num_displays != displays.size()) | ||||
|   { | ||||
|     LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:"); | ||||
|     return {}; | ||||
|   } | ||||
| 
 | ||||
|   for (u32 display_index = 0; display_index < num_displays; display_index++) | ||||
|   { | ||||
|     const VkDisplayPropertiesKHR& props = displays[display_index]; | ||||
|     Log_DevPrintf("Testing display '%s'", props.displayName); | ||||
| 
 | ||||
|     u32 num_modes; | ||||
|     res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, nullptr); | ||||
|     if (res != VK_SUCCESS || num_modes == 0) | ||||
|     { | ||||
|       LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:"); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<VkDisplayModePropertiesKHR> modes(num_modes); | ||||
|     res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, modes.data()); | ||||
|     if (res != VK_SUCCESS || num_modes != modes.size()) | ||||
|     { | ||||
|       LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:"); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     const VkDisplayModePropertiesKHR* matched_mode = nullptr; | ||||
|     for (const VkDisplayModePropertiesKHR& mode : modes) | ||||
|     { | ||||
|       Log_DevPrintf("  Mode %ux%u @ %u", mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height, | ||||
|                     mode.parameters.refreshRate); | ||||
|       if (!matched_mode && mode.parameters.visibleRegion.width == wi.surface_width && | ||||
|           mode.parameters.visibleRegion.height) | ||||
|       { | ||||
|         matched_mode = &mode; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (!matched_mode) | ||||
|     { | ||||
|       Log_DevPrintf("No modes matched on '%s'", props.displayName); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     u32 num_planes; | ||||
|     res = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &num_planes, nullptr); | ||||
|     if (res != VK_SUCCESS || num_planes == 0) | ||||
|     { | ||||
|       LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:"); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<VkDisplayPlanePropertiesKHR> planes(num_planes); | ||||
|     res = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &num_planes, planes.data()); | ||||
|     if (res != VK_SUCCESS || num_planes != planes.size()) | ||||
|     { | ||||
|       LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:"); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     u32 plane_index = 0; | ||||
|     for (; plane_index < num_planes; plane_index++) | ||||
|     { | ||||
|       u32 supported_display_count; | ||||
|       res = vkGetDisplayPlaneSupportedDisplaysKHR(physical_device, plane_index, &supported_display_count, nullptr); | ||||
|       if (res != VK_SUCCESS || supported_display_count == 0) | ||||
|       { | ||||
|         LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:"); | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       std::vector<VkDisplayKHR> supported_displays(supported_display_count); | ||||
|       res = vkGetDisplayPlaneSupportedDisplaysKHR(physical_device, plane_index, &supported_display_count, | ||||
|                                                   supported_displays.data()); | ||||
|       if (res != VK_SUCCESS || supported_display_count == 0) | ||||
|       { | ||||
|         LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:"); | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       const bool is_supported = | ||||
|         std::find(supported_displays.begin(), supported_displays.end(), props.display) != supported_displays.end(); | ||||
|       if (!is_supported) | ||||
|         continue; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|     if (plane_index == num_planes) | ||||
|     { | ||||
|       Log_DevPrintf("No planes matched on '%s'", props.displayName); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     VkDisplaySurfaceCreateInfoKHR info = {}; | ||||
|     info.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; | ||||
|     info.displayMode = matched_mode->displayMode; | ||||
|     info.planeIndex = plane_index; | ||||
|     info.planeStackIndex = planes[plane_index].currentStackIndex; | ||||
|     info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; | ||||
|     info.globalAlpha = 1.0f; | ||||
|     info.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; | ||||
|     info.imageExtent = matched_mode->parameters.visibleRegion; | ||||
| 
 | ||||
|     VkSurfaceKHR surface; | ||||
|     res = vkCreateDisplayPlaneSurfaceKHR(instance, &info, nullptr, &surface); | ||||
|     if (res != VK_SUCCESS) | ||||
|     { | ||||
|       LOG_VULKAN_ERROR(res, "vkCreateDisplayPlaneSurfaceKHR() failed: "); | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     return surface; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi) | ||||
| { | ||||
| #if defined(VK_USE_PLATFORM_WIN32_KHR) | ||||
|   if (wi.type == WindowInfo::Type::Win32) | ||||
|  | @ -213,6 +348,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, WindowInfo& wi) | |||
|   } | ||||
| #endif | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
|   if (wi.type == WindowInfo::Type::DRM) | ||||
|     return CreateDisplaySurface(instance, physical_device, wi); | ||||
| #endif | ||||
| 
 | ||||
|   return VK_NULL_HANDLE; | ||||
| } | ||||
| 
 | ||||
|  | @ -559,7 +699,7 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi) | |||
| 
 | ||||
|   // Re-create the surface with the new native handle
 | ||||
|   m_wi = new_wi; | ||||
|   m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_wi); | ||||
|   m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), m_wi); | ||||
|   if (m_surface == VK_NULL_HANDLE) | ||||
|     return false; | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ public: | |||
|   ~SwapChain(); | ||||
| 
 | ||||
|   // Creates a vulkan-renderable surface for the specified window handle.
 | ||||
|   static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, WindowInfo& wi); | ||||
|   static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi); | ||||
| 
 | ||||
|   // Destroys a previously-created surface.
 | ||||
|   static void DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface); | ||||
|  |  | |||
|  | @ -10,10 +10,10 @@ | |||
| #include "common/vulkan/swap_chain.h" | ||||
| #include "common/vulkan/util.h" | ||||
| #include "core/shader_cache_version.h" | ||||
| #include "postprocessing_shadergen.h" | ||||
| #include <array> | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_vulkan.h" | ||||
| #include "postprocessing_shadergen.h" | ||||
| #include <array> | ||||
| Log_SetChannel(VulkanHostDisplay); | ||||
| 
 | ||||
| namespace FrontendCommon { | ||||
|  | @ -79,7 +79,8 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) | |||
|   } | ||||
| 
 | ||||
|   WindowInfo wi_copy(new_wi); | ||||
|   VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), wi_copy); | ||||
|   VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), | ||||
|                                                                 g_vulkan_context->GetPhysicalDevice(), wi_copy); | ||||
|   if (surface == VK_NULL_HANDLE) | ||||
|   { | ||||
|     Log_ErrorPrintf("Failed to create new surface for swap chain"); | ||||
|  | @ -755,7 +756,7 @@ std::vector<std::string> VulkanHostDisplay::EnumerateAdapterNames() | |||
|   { | ||||
|     Common::ScopeGuard lib_guard([]() { Vulkan::UnloadVulkanLibrary(); }); | ||||
| 
 | ||||
|     VkInstance instance = Vulkan::Context::CreateVulkanInstance(false, false, false); | ||||
|     VkInstance instance = Vulkan::Context::CreateVulkanInstance(nullptr, false, false); | ||||
|     if (instance != VK_NULL_HANDLE) | ||||
|     { | ||||
|       Common::ScopeGuard instance_guard([&instance]() { vkDestroyInstance(instance, nullptr); }); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Connor McLaughlin
						Connor McLaughlin