mirror of
https://github.com/stenzek/duckstation.git
synced 2024-11-23 05:49:43 +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 New Issue
Block a user