mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 19:45:33 +00:00
GPUThread: Switch to borderless if exclusive fullscreen fails
Better than ending up windowed.
This commit is contained in:
parent
e36dbaf255
commit
231ba050a2
@ -716,7 +716,7 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
|
|||||||
"GameDBCompatibility", ICON_EMOJI_INFORMATION,
|
"GameDBCompatibility", ICON_EMOJI_INFORMATION,
|
||||||
fmt::format("{}{}", TRANSLATE_SV("GameDatabase", "Compatibility settings for this game have been applied."),
|
fmt::format("{}{}", TRANSLATE_SV("GameDatabase", "Compatibility settings for this game have been applied."),
|
||||||
messages.view()),
|
messages.view()),
|
||||||
Host::OSD_WARNING_DURATION);
|
Host::OSD_INFO_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef APPEND_MESSAGE_FMT
|
#undef APPEND_MESSAGE_FMT
|
||||||
|
@ -74,8 +74,9 @@ static bool SleepGPUThread(bool allow_sleep);
|
|||||||
static bool CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_fsui_state_on_failure, Error* error);
|
static bool CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_fsui_state_on_failure, Error* error);
|
||||||
static void DestroyDeviceOnThread(bool clear_fsui_state);
|
static void DestroyDeviceOnThread(bool clear_fsui_state);
|
||||||
static void ResizeDisplayWindowOnThread(u32 width, u32 height, float scale);
|
static void ResizeDisplayWindowOnThread(u32 width, u32 height, float scale);
|
||||||
static void UpdateDisplayWindowOnThread(bool fullscreen);
|
static void UpdateDisplayWindowOnThread(bool fullscreen, bool allow_exclusive_fullscreen);
|
||||||
static void DisplayWindowResizedOnThread();
|
static void DisplayWindowResizedOnThread();
|
||||||
|
static bool CheckExclusiveFullscreenOnThread();
|
||||||
|
|
||||||
static void ReconfigureOnThread(GPUThreadReconfigureCommand* cmd);
|
static void ReconfigureOnThread(GPUThreadReconfigureCommand* cmd);
|
||||||
static bool CreateGPUBackendOnThread(GPURenderer renderer, bool upload_vram, Error* error);
|
static bool CreateGPUBackendOnThread(GPURenderer renderer, bool upload_vram, Error* error);
|
||||||
@ -725,6 +726,11 @@ bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_
|
|||||||
|
|
||||||
std::atomic_thread_fence(std::memory_order_release);
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
UpdateRunIdle();
|
UpdateRunIdle();
|
||||||
|
|
||||||
|
// Switch to borderless if exclusive failed.
|
||||||
|
if (fullscreen_mode.has_value() && !CheckExclusiveFullscreenOnThread())
|
||||||
|
UpdateDisplayWindowOnThread(true, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,7 +1151,7 @@ void GPUThread::ResizeDisplayWindowOnThread(u32 width, u32 height, float scale)
|
|||||||
if (!g_gpu_device->GetMainSwapChain()->ResizeBuffers(width, height, scale, &error))
|
if (!g_gpu_device->GetMainSwapChain()->ResizeBuffers(width, height, scale, &error))
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to resize main swap chain: {}", error.GetDescription());
|
ERROR_LOG("Failed to resize main swap chain: {}", error.GetDescription());
|
||||||
UpdateDisplayWindowOnThread(Host::IsFullscreen());
|
UpdateDisplayWindowOnThread(Host::IsFullscreen(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1154,20 +1160,22 @@ void GPUThread::ResizeDisplayWindowOnThread(u32 width, u32 height, float scale)
|
|||||||
|
|
||||||
void GPUThread::UpdateDisplayWindow(bool fullscreen)
|
void GPUThread::UpdateDisplayWindow(bool fullscreen)
|
||||||
{
|
{
|
||||||
RunOnThread([fullscreen]() { UpdateDisplayWindowOnThread(fullscreen); });
|
RunOnThread([fullscreen]() { UpdateDisplayWindowOnThread(fullscreen, true); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUThread::UpdateDisplayWindowOnThread(bool fullscreen)
|
void GPUThread::UpdateDisplayWindowOnThread(bool fullscreen, bool allow_exclusive_fullscreen)
|
||||||
{
|
{
|
||||||
// In case we get the event late.
|
// In case we get the event late.
|
||||||
if (!g_gpu_device)
|
if (!g_gpu_device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool exclusive_fullscreen_requested = false;
|
||||||
std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode;
|
std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode;
|
||||||
if (fullscreen && g_gpu_device->GetFeatures().exclusive_fullscreen)
|
if (allow_exclusive_fullscreen && fullscreen && g_gpu_device->GetFeatures().exclusive_fullscreen)
|
||||||
{
|
{
|
||||||
fullscreen_mode =
|
fullscreen_mode =
|
||||||
GPUDevice::ExclusiveFullscreenMode::Parse(Host::GetTinyStringSettingValue("GPU", "FullscreenMode", ""));
|
GPUDevice::ExclusiveFullscreenMode::Parse(Host::GetTinyStringSettingValue("GPU", "FullscreenMode", ""));
|
||||||
|
exclusive_fullscreen_requested = fullscreen_mode.has_value();
|
||||||
}
|
}
|
||||||
std::optional<bool> exclusive_fullscreen_control;
|
std::optional<bool> exclusive_fullscreen_control;
|
||||||
if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic)
|
if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic)
|
||||||
@ -1180,7 +1188,7 @@ void GPUThread::UpdateDisplayWindowOnThread(bool fullscreen)
|
|||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
std::optional<WindowInfo> wi =
|
std::optional<WindowInfo> wi =
|
||||||
Host::AcquireRenderWindow(g_gpu_device->GetRenderAPI(), fullscreen, fullscreen_mode.has_value(), &error);
|
Host::AcquireRenderWindow(g_gpu_device->GetRenderAPI(), fullscreen, exclusive_fullscreen_requested, &error);
|
||||||
if (!wi.has_value())
|
if (!wi.has_value())
|
||||||
{
|
{
|
||||||
Host::ReportFatalError("Failed to get render window after update", error.GetDescription());
|
Host::ReportFatalError("Failed to get render window after update", error.GetDescription());
|
||||||
@ -1205,9 +1213,28 @@ void GPUThread::UpdateDisplayWindowOnThread(bool fullscreen)
|
|||||||
ERROR_LOG("Failed to switch to surfaceless, rendering commands may fail: {}", error.GetDescription());
|
ERROR_LOG("Failed to switch to surfaceless, rendering commands may fail: {}", error.GetDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If exclusive fullscreen failed, switch to borderless fullscreen.
|
||||||
|
if (exclusive_fullscreen_requested && !CheckExclusiveFullscreenOnThread())
|
||||||
|
{
|
||||||
|
UpdateDisplayWindowOnThread(true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DisplayWindowResizedOnThread();
|
DisplayWindowResizedOnThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUThread::CheckExclusiveFullscreenOnThread()
|
||||||
|
{
|
||||||
|
if (g_gpu_device->HasMainSwapChain() && g_gpu_device->GetMainSwapChain()->IsExclusiveFullscreen())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Host::AddIconOSDWarning(
|
||||||
|
"ExclusiveFullscreenFailed", ICON_EMOJI_WARNING,
|
||||||
|
TRANSLATE_STR("OSDMessage", "Failed to switch to exclusive fullscreen, using borderless instead."),
|
||||||
|
Host::OSD_INFO_DURATION);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void GPUThread::DisplayWindowResizedOnThread()
|
void GPUThread::DisplayWindowResizedOnThread()
|
||||||
{
|
{
|
||||||
const GPUSwapChain* swap_chain = g_gpu_device->GetMainSwapChain();
|
const GPUSwapChain* swap_chain = g_gpu_device->GetMainSwapChain();
|
||||||
|
@ -233,8 +233,23 @@ bool D3D11SwapChain::InitializeExclusiveFullscreenMode(const GPUDevice::Exclusiv
|
|||||||
RECT client_rc{};
|
RECT client_rc{};
|
||||||
GetClientRect(window_hwnd, &client_rc);
|
GetClientRect(window_hwnd, &client_rc);
|
||||||
|
|
||||||
|
// Little bit messy...
|
||||||
|
HRESULT hr;
|
||||||
|
ComPtr<IDXGIDevice> dxgi_dev;
|
||||||
|
if (FAILED((hr = D3D11Device::GetD3DDevice()->QueryInterface(IID_PPV_ARGS(dxgi_dev.GetAddressOf())))))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Failed to get DXGIDevice from D3D device: {:08X}", static_cast<unsigned>(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ComPtr<IDXGIAdapter> dxgi_adapter;
|
||||||
|
if (FAILED((hr = dxgi_dev->GetAdapter(dxgi_adapter.GetAddressOf()))))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Failed to get DXGIAdapter from DXGIDevice: {:08X}", static_cast<unsigned>(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_fullscreen_mode = D3DCommon::GetRequestedExclusiveFullscreenModeDesc(
|
m_fullscreen_mode = D3DCommon::GetRequestedExclusiveFullscreenModeDesc(
|
||||||
D3D11Device::GetDXGIFactory(), client_rc, mode, fm.resource_format, m_fullscreen_output.GetAddressOf());
|
dxgi_adapter.Get(), client_rc, mode, fm.resource_format, m_fullscreen_output.GetAddressOf());
|
||||||
return m_fullscreen_mode.has_value();
|
return m_fullscreen_mode.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,6 +459,11 @@ bool D3D11SwapChain::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle
|
|||||||
return CreateSwapChain(error) && CreateRTV(error);
|
return CreateSwapChain(error) && CreateRTV(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D3D11SwapChain::IsExclusiveFullscreen() const
|
||||||
|
{
|
||||||
|
return m_fullscreen_mode.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUSwapChain> D3D11Device::CreateSwapChain(const WindowInfo& wi, GPUVSyncMode vsync_mode,
|
std::unique_ptr<GPUSwapChain> D3D11Device::CreateSwapChain(const WindowInfo& wi, GPUVSyncMode vsync_mode,
|
||||||
bool allow_present_throttle,
|
bool allow_present_throttle,
|
||||||
const ExclusiveFullscreenMode* exclusive_fullscreen_mode,
|
const ExclusiveFullscreenMode* exclusive_fullscreen_mode,
|
||||||
|
@ -224,10 +224,10 @@ public:
|
|||||||
ALWAYS_INLINE ID3D11RenderTargetView* GetRTV() const { return m_swap_chain_rtv.Get(); }
|
ALWAYS_INLINE ID3D11RenderTargetView* GetRTV() const { return m_swap_chain_rtv.Get(); }
|
||||||
ALWAYS_INLINE ID3D11RenderTargetView* const* GetRTVArray() const { return m_swap_chain_rtv.GetAddressOf(); }
|
ALWAYS_INLINE ID3D11RenderTargetView* const* GetRTVArray() const { return m_swap_chain_rtv.GetAddressOf(); }
|
||||||
ALWAYS_INLINE bool IsUsingAllowTearing() const { return m_using_allow_tearing; }
|
ALWAYS_INLINE bool IsUsingAllowTearing() const { return m_using_allow_tearing; }
|
||||||
ALWAYS_INLINE bool IsExclusiveFullscreen() const { return m_fullscreen_mode.has_value(); }
|
|
||||||
|
|
||||||
bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) override;
|
bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) override;
|
||||||
bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) override;
|
bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) override;
|
||||||
|
bool IsExclusiveFullscreen() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static u32 GetNewBufferCount(GPUVSyncMode vsync_mode);
|
static u32 GetNewBufferCount(GPUVSyncMode vsync_mode);
|
||||||
|
@ -880,9 +880,8 @@ bool D3D12SwapChain::InitializeExclusiveFullscreenMode(const GPUDevice::Exclusiv
|
|||||||
RECT client_rc{};
|
RECT client_rc{};
|
||||||
GetClientRect(window_hwnd, &client_rc);
|
GetClientRect(window_hwnd, &client_rc);
|
||||||
|
|
||||||
m_fullscreen_mode =
|
m_fullscreen_mode = D3DCommon::GetRequestedExclusiveFullscreenModeDesc(
|
||||||
D3DCommon::GetRequestedExclusiveFullscreenModeDesc(D3D12Device::GetInstance().GetDXGIFactory(), client_rc, mode,
|
D3D12Device::GetInstance().GetAdapter(), client_rc, mode, fm.resource_format, m_fullscreen_output.GetAddressOf());
|
||||||
fm.resource_format, m_fullscreen_output.GetAddressOf());
|
|
||||||
return m_fullscreen_mode.has_value();
|
return m_fullscreen_mode.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,6 +1081,11 @@ bool D3D12SwapChain::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle
|
|||||||
return CreateSwapChain(dev, error) && CreateRTV(dev, error);
|
return CreateSwapChain(dev, error) && CreateRTV(dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D3D12SwapChain::IsExclusiveFullscreen() const
|
||||||
|
{
|
||||||
|
return m_fullscreen_mode.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
bool D3D12SwapChain::ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error)
|
bool D3D12SwapChain::ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error)
|
||||||
{
|
{
|
||||||
m_window_info.surface_scale = new_scale;
|
m_window_info.surface_scale = new_scale;
|
||||||
|
@ -381,7 +381,6 @@ public:
|
|||||||
ALWAYS_INLINE IDXGISwapChain1* GetSwapChain() const { return m_swap_chain.Get(); }
|
ALWAYS_INLINE IDXGISwapChain1* GetSwapChain() const { return m_swap_chain.Get(); }
|
||||||
ALWAYS_INLINE const BufferPair& GetCurrentBuffer() const { return m_swap_chain_buffers[m_current_swap_chain_buffer]; }
|
ALWAYS_INLINE const BufferPair& GetCurrentBuffer() const { return m_swap_chain_buffers[m_current_swap_chain_buffer]; }
|
||||||
ALWAYS_INLINE bool IsUsingAllowTearing() const { return m_using_allow_tearing; }
|
ALWAYS_INLINE bool IsUsingAllowTearing() const { return m_using_allow_tearing; }
|
||||||
ALWAYS_INLINE bool IsExclusiveFullscreen() const { return m_fullscreen_mode.has_value(); }
|
|
||||||
|
|
||||||
void AdvanceBuffer()
|
void AdvanceBuffer()
|
||||||
{
|
{
|
||||||
@ -389,6 +388,7 @@ public:
|
|||||||
}
|
}
|
||||||
bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) override;
|
bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) override;
|
||||||
bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) override;
|
bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) override;
|
||||||
|
bool IsExclusiveFullscreen() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static u32 GetNewBufferCount(GPUVSyncMode vsync_mode);
|
static u32 GetNewBufferCount(GPUVSyncMode vsync_mode);
|
||||||
|
@ -225,50 +225,40 @@ GPUDevice::AdapterInfoList D3DCommon::GetAdapterInfoList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DXGI_MODE_DESC>
|
std::optional<DXGI_MODE_DESC>
|
||||||
D3DCommon::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect,
|
D3DCommon::GetRequestedExclusiveFullscreenModeDesc(IDXGIAdapter* adapter, const RECT& window_rect,
|
||||||
const GPUDevice::ExclusiveFullscreenMode* requested_fullscreen_mode,
|
const GPUDevice::ExclusiveFullscreenMode* requested_fullscreen_mode,
|
||||||
DXGI_FORMAT format, IDXGIOutput** output)
|
DXGI_FORMAT format, IDXGIOutput** output)
|
||||||
{
|
{
|
||||||
std::optional<DXGI_MODE_DESC> ret;
|
std::optional<DXGI_MODE_DESC> ret;
|
||||||
|
|
||||||
// We need to find which monitor the window is located on.
|
// We need to find which monitor the window is located on.
|
||||||
|
// The adapter must match, you cannot restrict the output to a monitor that is not connected to the device.
|
||||||
const GSVector4i client_rc_vec(window_rect.left, window_rect.top, window_rect.right, window_rect.bottom);
|
const GSVector4i client_rc_vec(window_rect.left, window_rect.top, window_rect.right, window_rect.bottom);
|
||||||
|
|
||||||
// The window might be on a different adapter to which we are rendering.. so we have to enumerate them all.
|
// The window might be on a different adapter to which we are rendering.. so we have to enumerate them all.
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
Microsoft::WRL::ComPtr<IDXGIOutput> first_output, intersecting_output;
|
Microsoft::WRL::ComPtr<IDXGIOutput> first_output, intersecting_output;
|
||||||
|
for (u32 output_index = 0;; output_index++)
|
||||||
for (u32 adapter_index = 0; !intersecting_output; adapter_index++)
|
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
Microsoft::WRL::ComPtr<IDXGIOutput> this_output;
|
||||||
hr = factory->EnumAdapters1(adapter_index, adapter.GetAddressOf());
|
DXGI_OUTPUT_DESC output_desc;
|
||||||
|
hr = adapter->EnumOutputs(output_index, this_output.GetAddressOf());
|
||||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
if (hr == DXGI_ERROR_NOT_FOUND)
|
||||||
break;
|
break;
|
||||||
else if (FAILED(hr))
|
else if (FAILED(hr) || FAILED(this_output->GetDesc(&output_desc)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (u32 output_index = 0;; output_index++)
|
const GSVector4i output_rc(output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
|
||||||
|
output_desc.DesktopCoordinates.right, output_desc.DesktopCoordinates.bottom);
|
||||||
|
if (!client_rc_vec.rintersects(output_rc))
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IDXGIOutput> this_output;
|
intersecting_output = std::move(this_output);
|
||||||
DXGI_OUTPUT_DESC output_desc;
|
break;
|
||||||
hr = adapter->EnumOutputs(output_index, this_output.GetAddressOf());
|
|
||||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
|
||||||
break;
|
|
||||||
else if (FAILED(hr) || FAILED(this_output->GetDesc(&output_desc)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const GSVector4i output_rc(output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top,
|
|
||||||
output_desc.DesktopCoordinates.right, output_desc.DesktopCoordinates.bottom);
|
|
||||||
if (!client_rc_vec.rintersects(output_rc))
|
|
||||||
{
|
|
||||||
intersecting_output = std::move(this_output);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to the first monitor.
|
|
||||||
if (!first_output)
|
|
||||||
first_output = std::move(this_output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to the first monitor.
|
||||||
|
if (!first_output)
|
||||||
|
first_output = std::move(this_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intersecting_output)
|
if (!intersecting_output)
|
||||||
@ -561,11 +551,7 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShaderWithDXC(u32 shader_m
|
|||||||
DXC_ARG_OPTIMIZATION_LEVEL3,
|
DXC_ARG_OPTIMIZATION_LEVEL3,
|
||||||
};
|
};
|
||||||
static constexpr const wchar_t* debug_arguments[] = {
|
static constexpr const wchar_t* debug_arguments[] = {
|
||||||
L"-Qstrip_reflect",
|
L"-Qstrip_reflect", DXC_ARG_DEBUG, L"-Qembed_debug", DXC_ARG_PACK_MATRIX_ROW_MAJOR, DXC_ARG_SKIP_OPTIMIZATIONS,
|
||||||
DXC_ARG_DEBUG,
|
|
||||||
L"-Qembed_debug",
|
|
||||||
DXC_ARG_PACK_MATRIX_ROW_MAJOR,
|
|
||||||
DXC_ARG_SKIP_OPTIMIZATIONS,
|
|
||||||
};
|
};
|
||||||
const wchar_t* const* arguments = debug_device ? debug_arguments : nondebug_arguments;
|
const wchar_t* const* arguments = debug_device ? debug_arguments : nondebug_arguments;
|
||||||
const size_t arguments_size = debug_device ? std::size(debug_arguments) : std::size(nondebug_arguments);
|
const size_t arguments_size = debug_device ? std::size(debug_arguments) : std::size(nondebug_arguments);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <d3dcommon.h>
|
#include <d3dcommon.h>
|
||||||
#include <dxgiformat.h>
|
#include <dxgiformat.h>
|
||||||
|
#include <dxgitype.h>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -19,9 +20,9 @@
|
|||||||
class Error;
|
class Error;
|
||||||
|
|
||||||
struct IDXGIFactory5;
|
struct IDXGIFactory5;
|
||||||
|
struct IDXGIAdapter;
|
||||||
struct IDXGIAdapter1;
|
struct IDXGIAdapter1;
|
||||||
struct IDXGIOutput;
|
struct IDXGIOutput;
|
||||||
struct DXGI_MODE_DESC;
|
|
||||||
|
|
||||||
namespace D3DCommon {
|
namespace D3DCommon {
|
||||||
// returns string representation of feature level
|
// returns string representation of feature level
|
||||||
@ -42,7 +43,7 @@ GPUDevice::AdapterInfoList GetAdapterInfoList();
|
|||||||
|
|
||||||
// returns the fullscreen mode to use for the specified dimensions
|
// returns the fullscreen mode to use for the specified dimensions
|
||||||
std::optional<DXGI_MODE_DESC>
|
std::optional<DXGI_MODE_DESC>
|
||||||
GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect,
|
GetRequestedExclusiveFullscreenModeDesc(IDXGIAdapter* adapter, const RECT& window_rect,
|
||||||
const GPUDevice::ExclusiveFullscreenMode* requested_fullscreen_mode,
|
const GPUDevice::ExclusiveFullscreenMode* requested_fullscreen_mode,
|
||||||
DXGI_FORMAT format, IDXGIOutput** output);
|
DXGI_FORMAT format, IDXGIOutput** output);
|
||||||
|
|
||||||
|
@ -275,6 +275,11 @@ GSVector4i GPUSwapChain::PreRotateClipRect(WindowInfo::PreRotation prerotation,
|
|||||||
return new_clip;
|
return new_clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUSwapChain::IsExclusiveFullscreen() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUSwapChain::ShouldSkipPresentingFrame()
|
bool GPUSwapChain::ShouldSkipPresentingFrame()
|
||||||
{
|
{
|
||||||
// Only needed with FIFO. But since we're so fast, we allow it always.
|
// Only needed with FIFO. But since we're so fast, we allow it always.
|
||||||
|
@ -528,6 +528,9 @@ public:
|
|||||||
virtual bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) = 0;
|
virtual bool ResizeBuffers(u32 new_width, u32 new_height, float new_scale, Error* error) = 0;
|
||||||
virtual bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) = 0;
|
virtual bool SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle, Error* error) = 0;
|
||||||
|
|
||||||
|
/// Returns true if exclusive fullscreen is currently active on this swap chain.
|
||||||
|
virtual bool IsExclusiveFullscreen() const;
|
||||||
|
|
||||||
bool ShouldSkipPresentingFrame();
|
bool ShouldSkipPresentingFrame();
|
||||||
void ThrottlePresentation();
|
void ThrottlePresentation();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user