Vulkan: Support fullscreen resolution enumeration

This commit is contained in:
Connor McLaughlin 2021-02-16 02:57:35 +10:00
parent e84a39245f
commit 65daf1d6a0
5 changed files with 103 additions and 6 deletions

View file

@ -132,7 +132,7 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p
const VkDisplayModePropertiesKHR* matched_mode = nullptr;
for (const VkDisplayModePropertiesKHR& mode : modes)
{
const float refresh_rate = static_cast<float>(mode.parameters.refreshRate) * 1000.0f;
const float refresh_rate = static_cast<float>(mode.parameters.refreshRate) / 1000.0f;
Log_DevPrintf(" Mode %ux%u @ %f", mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
refresh_rate);
@ -225,6 +225,67 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p
return VK_NULL_HANDLE;
}
static std::vector<SwapChain::FullscreenModeInfo> GetDisplayModes(VkInstance instance, VkPhysicalDevice physical_device,
const WindowInfo& wi)
{
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 {};
}
std::vector<SwapChain::FullscreenModeInfo> result;
for (u32 display_index = 0; display_index < num_displays; display_index++)
{
const VkDisplayPropertiesKHR& props = displays[display_index];
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;
}
for (const VkDisplayModePropertiesKHR& mode : modes)
{
const float refresh_rate = static_cast<float>(mode.parameters.refreshRate) / 1000.0f;
if (std::find_if(result.begin(), result.end(), [&mode, refresh_rate](const SwapChain::FullscreenModeInfo& mi) {
return (mi.width == mode.parameters.visibleRegion.width &&
mi.height == mode.parameters.visibleRegion.height && mode.parameters.refreshRate == refresh_rate);
}) != result.end())
{
continue;
}
result.push_back(SwapChain::FullscreenModeInfo{static_cast<u32>(mode.parameters.visibleRegion.width),
static_cast<u32>(mode.parameters.visibleRegion.height),
refresh_rate});
}
}
return result;
}
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi)
{
#if defined(VK_USE_PLATFORM_WIN32_KHR)
@ -367,6 +428,15 @@ void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurf
#endif
}
std::vector<SwapChain::FullscreenModeInfo>
SwapChain::GetSurfaceFullscreenModes(VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi)
{
if (wi.type == WindowInfo::Type::Display)
return GetDisplayModes(instance, physical_device, wi);
return {};
}
std::unique_ptr<SwapChain> SwapChain::Create(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync)
{
std::unique_ptr<SwapChain> swap_chain = std::make_unique<SwapChain>(wi, surface, vsync);

View file

@ -26,6 +26,16 @@ public:
// Destroys a previously-created surface.
static void DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface);
// Enumerates fullscreen modes for window info.
struct FullscreenModeInfo
{
u32 width;
u32 height;
float refresh_rate;
};
static std::vector<FullscreenModeInfo>
GetSurfaceFullscreenModes(VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi);
// Create a new swap chain from a pre-existing surface.
static std::unique_ptr<SwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync);

View file

@ -183,7 +183,7 @@ void DisplaySettingsWidget::populateGPUAdaptersAndResolutions()
#endif
case GPURenderer::HardwareVulkan:
aml = FrontendCommon::VulkanHostDisplay::StaticGetAdapterAndModeList();
aml = FrontendCommon::VulkanHostDisplay::StaticGetAdapterAndModeList(nullptr);
threaded_presentation_supported = true;
break;

View file

@ -9,6 +9,7 @@
#include "common/vulkan/stream_buffer.h"
#include "common/vulkan/swap_chain.h"
#include "common/vulkan/util.h"
#include "common_host_interface.h"
#include "core/shader_cache_version.h"
#include "imgui.h"
#include "imgui_impl_vulkan.h"
@ -141,7 +142,7 @@ bool VulkanHostDisplay::SetFullscreen(bool fullscreen, u32 width, u32 height, fl
HostDisplay::AdapterAndModeList VulkanHostDisplay::GetAdapterAndModeList()
{
return StaticGetAdapterAndModeList();
return StaticGetAdapterAndModeList(m_window_info.type != WindowInfo::Type::Surfaceless ? &m_window_info : nullptr);
}
void VulkanHostDisplay::DestroyRenderSurface()
@ -752,13 +753,19 @@ void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 h
vkCmdDraw(cmdbuffer, 3, 1, 0, 0);
}
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList()
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(const WindowInfo* wi)
{
AdapterAndModeList ret;
std::vector<Vulkan::SwapChain::FullscreenModeInfo> fsmodes;
if (g_vulkan_context)
{
ret.adapter_names = Vulkan::Context::EnumerateGPUNames(g_vulkan_context->GetVulkanInstance());
if (wi)
{
fsmodes = Vulkan::SwapChain::GetSurfaceFullscreenModes(g_vulkan_context->GetVulkanInstance(),
g_vulkan_context->GetPhysicalDevice(), *wi);
}
}
else if (Vulkan::LoadVulkanLibrary())
{
@ -774,7 +781,17 @@ HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList()
}
}
return {};
if (!fsmodes.empty())
{
ret.fullscreen_modes.reserve(fsmodes.size());
for (const Vulkan::SwapChain::FullscreenModeInfo& fmi : fsmodes)
{
ret.fullscreen_modes.push_back(
CommonHostInterface::GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
}
}
return ret;
}
VulkanHostDisplay::PostProcessingStage::PostProcessingStage(PostProcessingStage&& move)

View file

@ -65,7 +65,7 @@ public:
virtual bool Render() override;
static AdapterAndModeList StaticGetAdapterAndModeList();
static AdapterAndModeList StaticGetAdapterAndModeList(const WindowInfo* wi);
protected:
struct PushConstants