This commit is contained in:
TheLastRar 2025-12-14 21:15:40 +07:00 committed by GitHub
commit a71fb8a9fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 265 additions and 71 deletions

View File

@ -133,7 +133,7 @@ void DisplaySurface::handleCloseEvent(QCloseEvent* event)
// In the latter case, it's going to destroy us, so don't let Qt do it first.
// Treat a close event while fullscreen as an exit, that way ALT+F4 closes PCSX2,
// rather than just the game.
if (QtHost::IsVMValid() && !isActuallyFullscreen())
if (QtHost::IsVMValid() && !isFullScreen())
{
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true),
Q_ARG(bool, true), Q_ARG(bool, false));
@ -147,10 +147,44 @@ void DisplaySurface::handleCloseEvent(QCloseEvent* event)
event->ignore();
}
bool DisplaySurface::isActuallyFullscreen() const
bool DisplaySurface::isFullScreen() const
{
// DisplaySurface is always in a container, so we need to check parent window
return parent()->windowState() & Qt::WindowFullScreen;
// DisplaySurface may be in a container
return (parent() ? parent()->windowState() : windowState()) & Qt::WindowFullScreen;
}
void DisplaySurface::setFocus()
{
if (m_container)
m_container->setFocus();
else
requestActivate();
}
QByteArray DisplaySurface::saveGeometry() const
{
if (m_container)
return m_container->saveGeometry();
else
{
// QWindow lacks saveGeometry, so create a dummy widget and copy geometry across.
QWidget dummy = QWidget();
dummy.setGeometry(geometry());
return dummy.saveGeometry();
}
}
void DisplaySurface::restoreGeometry(const QByteArray& geometry)
{
if (m_container)
m_container->restoreGeometry(geometry);
else
{
// QWindow lacks restoreGeometry, so create a dummy widget and copy geometry across.
QWidget dummy = QWidget();
dummy.restoreGeometry(geometry);
setGeometry(dummy.geometry());
}
}
void DisplaySurface::updateCenterPos()
@ -393,10 +427,18 @@ bool DisplaySurface::event(QEvent* event)
return event->isAccepted();
case QEvent::Move:
{
updateCenterPos();
return true;
}
// These events only work on the top level control.
// Which is this container when render to seperate or fullscreen is active (Windows).
case QEvent::Close:
handleCloseEvent(static_cast<QCloseEvent*>(event));
return true;
case QEvent::WindowStateChange:
if (static_cast<QWindowStateChangeEvent*>(event)->oldState() & Qt::WindowMinimized)
emit windowRestoredEvent();
return false;
default:
return QWindow::event(event);
@ -418,7 +460,7 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
return true;
// These events only work on the top level control.
// Which is this container when render to seperate or fullscreen is active.
// Which is this container when render to seperate or fullscreen is active (Non-Windows).
case QEvent::Close:
handleCloseEvent(static_cast<QCloseEvent*>(event));
return true;
@ -427,8 +469,8 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
emit windowRestoredEvent();
return false;
case QEvent::ChildRemoved:
if (static_cast<QChildEvent*>(event)->child() == m_container)
case QEvent::ChildWindowRemoved:
if (static_cast<QChildWindowEvent*>(event)->child() == this)
{
object->removeEventFilter(this);
m_container = nullptr;

View File

@ -30,6 +30,12 @@ public:
void updateRelativeMode(bool enabled);
void updateCursor(bool hidden);
bool isFullScreen() const;
void setFocus();
QByteArray saveGeometry() const;
void restoreGeometry(const QByteArray& geometry);
Q_SIGNALS:
void windowResizedEvent(int width, int height, float scale);
void windowRestoredEvent();
@ -47,7 +53,6 @@ private Q_SLOTS:
void onResizeDebounceTimer();
private:
bool isActuallyFullscreen() const;
void updateCenterPos();
QPoint m_relative_mouse_start_pos{};

View File

@ -100,6 +100,13 @@ static quint32 s_current_running_crc;
static bool s_record_on_start = false;
static QString s_path_to_recording_for_record_on_start;
// DX cannot fullscreen when the display surface is in a container.
// QWindow, however, seems to lack CSD under wayland, so needs the container.
// MAC is unknown
#ifdef _WIN32
#define DISPLAY_SURFACE_WINDOW
#endif
MainWindow::MainWindow()
{
pxAssert(!g_main_window);
@ -1008,10 +1015,15 @@ void MainWindow::updateWindowTitle()
if (windowTitle() != main_title)
setWindowTitle(main_title);
if (m_display_container && !isRenderingToMain())
if (m_display_surface && !isRenderingToMain())
{
#ifdef DISPLAY_SURFACE_WINDOW
if (m_display_surface->title() != display_title)
m_display_surface->setTitle(display_title);
#else
if (m_display_container->windowTitle() != display_title)
m_display_container->setWindowTitle(display_title);
#endif
}
if (g_log_window)
@ -1040,7 +1052,13 @@ void MainWindow::updateWindowState(bool force_visible)
// Update the display widget too if rendering separately.
if (m_display_surface && !isRenderingToMain())
{
#ifdef DISPLAY_SURFACE_WINDOW
QtUtils::SetWindowResizeable(m_display_surface, resizeable);
#else
QtUtils::SetWindowResizeable(m_display_container, resizeable);
#endif
}
}
void MainWindow::setProgressBar(int current, int total)
@ -1075,12 +1093,12 @@ bool MainWindow::isRenderingFullscreen() const
if (!MTGS::IsOpen() || !m_display_surface)
return false;
return m_display_container->isFullScreen();
return m_display_surface->isFullScreen();
}
bool MainWindow::isRenderingToMain() const
{
return (m_display_surface && m_ui.mainContainer->indexOf(m_display_container) == 1);
return (m_display_container && m_ui.mainContainer->indexOf(m_display_container) == 1);
}
bool MainWindow::shouldHideMouseCursor() const
@ -1108,16 +1126,25 @@ bool MainWindow::shouldMouseLock() const
if (m_display_created == false || m_display_surface == nullptr)
return false;
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
(!m_settings_window || m_settings_window->isHidden());
const bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
(!m_settings_window || m_settings_window->isHidden());
auto* displayWindow = isRenderingToMain() ? window() : m_display_container->window();
if (displayWindow == nullptr)
if (!windowsHidden)
return false;
return windowsHidden && (displayWindow->isActiveWindow() || displayWindow->isFullScreen());
#ifdef DISPLAY_SURFACE_WINDOW
if (isRenderingToMain())
{
const auto* displayWindow = window();
return displayWindow ? (displayWindow->isActiveWindow() || displayWindow->isFullScreen()) : false;
}
else
return m_display_surface->isActive() || m_display_surface->isFullScreen();
#else
const auto* displayWindow = isRenderingToMain() ? window() : m_display_container->window();
return displayWindow ? (displayWindow->isActiveWindow() || displayWindow->isFullScreen()) : false;
#endif
}
bool MainWindow::shouldAbortForMemcardBusy(const VMLock& lock)
@ -1180,7 +1207,7 @@ void MainWindow::switchToEmulationView()
g_emu_thread->setVMPaused(false);
if (m_display_surface)
m_display_container->setFocus();
m_display_surface->setFocus();
}
void MainWindow::refreshGameList(bool invalidate_cache, bool popup_on_error)
@ -2129,7 +2156,7 @@ void MainWindow::onVMResumed()
if (m_display_surface)
{
updateDisplayWidgetCursor();
m_display_container->setFocus();
m_display_surface->setFocus();
}
}
@ -2449,21 +2476,25 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
if (!is_fullscreen && !is_rendering_to_main)
saveDisplayWindowGeometryToConfig();
#ifdef DISPLAY_SURFACE_WINDOW
auto* displayWindow = m_display_surface;
#else
auto* displayWindow = m_display_container;
#endif
if (fullscreen)
{
m_display_container->showFullScreen();
}
displayWindow->showFullScreen();
else
{
// Needs to exit fullscreen before resizing
displayWindow->showNormal();
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
m_display_container->setGeometry(geometry());
displayWindow->setGeometry(geometry());
else
restoreDisplayWindowGeometryFromConfig();
m_display_container->showNormal();
}
updateDisplayWidgetCursor();
m_display_container->setFocus();
m_display_surface->setFocus();
updateWindowState();
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
@ -2500,7 +2531,7 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
updateWindowState();
updateDisplayWidgetCursor();
m_display_container->setFocus();
m_display_surface->setFocus();
return wi;
}
@ -2517,31 +2548,62 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
m_display_surface = new DisplaySurface();
if (fullscreen || !render_to_main)
{
#ifdef DISPLAY_SURFACE_WINDOW
m_display_surface->setTitle(windowTitle());
m_display_surface->setIcon(windowIcon());
#else
m_display_container = m_display_surface->createWindowContainer();
m_display_container->setWindowTitle(windowTitle());
m_display_container->setWindowIcon(windowIcon());
#endif
}
else
{
m_display_container = m_display_surface->createWindowContainer(getContentParent());
}
if (fullscreen)
if (fullscreen || g_emu_thread->isExclusiveFullscreen())
{
// On Wayland, while move/restoreGeometry can't position the window, it can influence which screen they show up on
// On Wayland, while move/restoreGeometry can't position the window, it can influence which screen they show up on.
// Other platforms can position windows fine, but the only thing that matters here is the screen.
#ifdef DISPLAY_SURFACE_WINDOW
if (isVisible() && g_emu_thread->shouldRenderToMain())
m_display_surface->setFramePosition(pos());
else
restoreDisplayWindowGeometryFromConfig();
if (fullscreen)
m_display_surface->showFullScreen();
else
m_display_surface->showNormal();
#else
if (isVisible() && g_emu_thread->shouldRenderToMain())
m_display_container->move(pos());
else
restoreDisplayWindowGeometryFromConfig();
m_display_container->showFullScreen();
if (fullscreen)
m_display_container->showFullScreen();
else
m_display_container->showNormal();
#endif
}
else if (!render_to_main)
{
#ifdef DISPLAY_SURFACE_WINDOW
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
m_display_surface->setGeometry(geometry());
else
restoreDisplayWindowGeometryFromConfig();
m_display_surface->showNormal();
#else
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
m_display_container->setGeometry(geometry());
else
restoreDisplayWindowGeometryFromConfig();
m_display_container->showNormal();
#endif
}
else
{
@ -2570,12 +2632,21 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height)
width = static_cast<qint32>(std::max(static_cast<int>(std::lroundf(static_cast<float>(width) / dpr)), 1));
height = static_cast<qint32>(std::max(static_cast<int>(std::lroundf(static_cast<float>(height) / dpr)), 1));
#ifdef DISPLAY_SURFACE_WINDOW
if (!m_display_container)
{
// no parent - rendering to separate window. easy.
QtUtils::ResizePotentiallyFixedSizeWindow(m_display_surface, width, height);
return;
}
#else
if (!m_display_container->parent())
{
// no parent - rendering to separate window. easy.
QtUtils::ResizePotentiallyFixedSizeWindow(m_display_container, width, height);
return;
}
#endif
// we are rendering to the main window. we have to add in the extra height from the toolbar/status bar.
const s32 extra_height = this->height() - m_display_container->height();
@ -2608,7 +2679,7 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
if (!m_display_surface)
return;
if (!isRenderingFullscreen() && !isRenderingToMain())
if (!m_display_surface->isFullScreen() && !isRenderingToMain())
saveDisplayWindowGeometryToConfig();
if (isRenderingToMain())
@ -2622,12 +2693,18 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
}
}
// displau surface is always in a container
pxAssert(m_display_container != nullptr);
m_display_container->deleteLater();
m_display_container = nullptr;
// m_display_surface will be destroyed by the container's dtor
m_display_surface = nullptr;
if (m_display_container)
{
m_display_container->deleteLater();
m_display_container = nullptr;
// m_display_surface will be destroyed by the container's dtor
m_display_surface = nullptr;
}
else
{
m_display_surface->deleteLater();
m_display_surface = nullptr;
}
updateDisplayRelatedActions(false, false, false);
}
@ -2639,14 +2716,6 @@ void MainWindow::updateDisplayWidgetCursor()
m_display_surface->updateCursor(s_vm_valid && !s_vm_paused && shouldHideMouseCursor());
}
void MainWindow::focusDisplayWidget()
{
if (!m_display_surface || centralWidget() != m_display_container)
return;
m_display_container->setFocus();
}
void MainWindow::setupMouseMoveHandler()
{
auto mouse_cb_fn = [](int x, int y) {
@ -2677,7 +2746,11 @@ void MainWindow::checkMousePosition(int x, int y)
// logical (DIP) frame rect
const QSize logicalSize = displayWindow->size();
#ifdef DISPLAY_SURFACE_WINDOW
const QPoint logicalPosition = isRenderingToMain() ? (displayWindow->position() + displayWindow->parent()->position()) : displayWindow->position();
#else
const QPoint logicalPosition = displayWindow->position() + displayWindow->parent()->position();
#endif
// The offset to the origin of the current screen is in device-independent pixels while the origin itself is native!
// The logicalPosition is the sum of these two values, so we need to separate them and only scale the offset
@ -2708,13 +2781,13 @@ void MainWindow::checkMousePosition(int x, int y)
void MainWindow::saveDisplayWindowGeometryToConfig()
{
if (m_display_container->windowState() & Qt::WindowFullScreen)
if (m_display_surface->isFullScreen())
{
// if we somehow ended up here, don't save the fullscreen state to the config
return;
}
const QByteArray geometry = m_display_container->saveGeometry();
const QByteArray geometry = m_display_surface->saveGeometry();
const QByteArray geometry_b64 = geometry.toBase64();
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "DisplayWindowGeometry");
if (old_geometry_b64 != geometry_b64.constData())
@ -2730,15 +2803,23 @@ void MainWindow::restoreDisplayWindowGeometryFromConfig()
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
if (!geometry.isEmpty())
{
m_display_container->restoreGeometry(geometry);
m_display_surface->restoreGeometry(geometry);
// make sure we're not loading a dodgy config which had fullscreen set...
#ifdef DISPLAY_SURFACE_WINDOW
m_display_surface->setWindowStates(m_display_surface->windowStates() & ~(Qt::WindowFullScreen | Qt::WindowActive));
#else
m_display_container->setWindowState(m_display_container->windowState() & ~(Qt::WindowFullScreen | Qt::WindowActive));
#endif
}
else
{
// default size
#ifdef DISPLAY_SURFACE_WINDOW
m_display_surface->resize(640, 480);
#else
m_display_container->resize(640, 480);
#endif
}
}
@ -3308,7 +3389,7 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
g_emu_thread->setFullscreen(false, false);
// Process events untill both EmuThread and Qt have finished exiting fullscreen
while (QtHost::IsVMValid() && (g_emu_thread->isFullscreen() || m_display_container->isFullScreen()))
while (QtHost::IsVMValid() && (g_emu_thread->isFullscreen() || m_display_surface->isFullScreen()))
{
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
@ -3320,7 +3401,27 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
g_main_window->raise();
g_main_window->activateWindow();
return VMLock(m_display_container, was_paused, was_fullscreen);
#ifdef DISPLAY_SURFACE_WINDOW
if (!m_display_container)
{
// Create a temporary parent for the dialog.
QWidget* dialog_parent = new QWidget();
dialog_parent->setAttribute(Qt::WA_NativeWindow);
QWindow* window_handle = dialog_parent->windowHandle();
// Set the transient parent to the display surface.
// This will position the dialog_parent over the display surface (and thus so will any dialogs)
// and also enforces the focus lock of modal dialogs against the display surface.
// This works even without showing the dialog_parent window.
window_handle->setTransientParent(m_display_surface);
return VMLock(dialog_parent, was_paused, was_fullscreen, true);
}
else
return VMLock(m_display_container, was_paused, was_fullscreen, false);
#else
return VMLock(m_display_container, was_paused, was_fullscreen, false);
#endif
}
void MainWindow::rescanFile(const std::string& path)
@ -3328,11 +3429,12 @@ void MainWindow::rescanFile(const std::string& path)
m_game_list_widget->rescanFile(path);
}
MainWindow::VMLock::VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen)
MainWindow::VMLock::VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen, bool owns_parent)
: m_dialog_parent(dialog_parent)
, m_has_lock(true)
, m_was_paused(was_paused)
, m_was_fullscreen(was_fullscreen)
, m_owns_dialog_parent(owns_parent)
{
QtHost::LockVMWithDialog();
}
@ -3342,11 +3444,13 @@ MainWindow::VMLock::VMLock(VMLock&& lock)
, m_has_lock(lock.m_has_lock)
, m_was_paused(lock.m_was_paused)
, m_was_fullscreen(lock.m_was_fullscreen)
, m_owns_dialog_parent(lock.m_owns_dialog_parent)
{
lock.m_dialog_parent = nullptr;
lock.m_has_lock = false;
lock.m_was_paused = true;
lock.m_was_fullscreen = false;
lock.m_owns_dialog_parent = false;
}
MainWindow::VMLock::~VMLock()
@ -3354,6 +3458,12 @@ MainWindow::VMLock::~VMLock()
if (m_has_lock)
QtHost::UnlockVMWithDialog();
if (m_owns_dialog_parent && m_dialog_parent)
{
m_dialog_parent->deleteLater();
m_dialog_parent = nullptr;
}
if (m_was_fullscreen)
{
g_main_window->m_is_temporarily_windowed = false;

View File

@ -65,13 +65,14 @@ public:
void cancelResume();
private:
VMLock(QWidget* dialog_parent, bool was_paused, bool was_exclusive_fullscreen);
VMLock(QWidget* dialog_parent, bool was_paused, bool was_exclusive_fullscreen, bool owns_parent);
friend MainWindow;
QWidget* m_dialog_parent;
bool m_has_lock;
bool m_was_paused;
bool m_was_fullscreen;
bool m_owns_dialog_parent;
};
/// Default filter for opening a file.
@ -138,7 +139,6 @@ private Q_SLOTS:
void displayResizeRequested(qint32 width, qint32 height);
void mouseModeRequested(bool relative_mode, bool hide_cursor);
void releaseRenderWindow();
void focusDisplayWidget();
void setupMouseMoveHandler();
void onGameListRefreshComplete();
void onGameListRefreshProgress(const QString& status, int current, int total);

View File

@ -366,6 +366,25 @@ namespace QtUtils
}
}
void SetWindowResizeable(QWindow* window, bool resizeable)
{
if (resizeable)
{
// Min/max numbers come from uic.
window->setMinimumWidth(1);
window->setMinimumHeight(1);
window->setMaximumWidth(16777215);
window->setMaximumHeight(16777215);
}
else
{
window->setMinimumWidth(window->width());
window->setMinimumHeight(window->height());
window->setMaximumWidth(window->width());
window->setMaximumHeight(window->height());
}
}
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height)
{
width = std::max(width, 1);
@ -376,6 +395,22 @@ namespace QtUtils
widget->resize(width, height);
}
void ResizePotentiallyFixedSizeWindow(QWindow* window, int width, int height)
{
width = std::max(width, 1);
height = std::max(height, 1);
if (window->minimumHeight() == window->maximumHeight())
{
window->setMinimumWidth(width);
window->setMinimumHeight(height);
window->setMaximumWidth(width);
window->setMaximumHeight(height);
}
window->resize(width, height);
}
QString AbstractItemModelToCSV(QAbstractItemModel* model, int role, bool useQuotes)
{
QString csv;

View File

@ -102,9 +102,11 @@ namespace QtUtils
/// Changes whether a window is resizable.
void SetWindowResizeable(QWidget* widget, bool resizeable);
void SetWindowResizeable(QWindow* window, bool resizeable);
/// Adjusts the fixed size for a window if it's not resizeable.
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height);
void ResizePotentiallyFixedSizeWindow(QWindow* window, int width, int height);
/// Returns the common window info structure for a Qt Window/Widget.
template <class T>

View File

@ -123,17 +123,18 @@ std::vector<GSAdapterInfo> D3D::GetAdapterInfo(IDXGIFactory5* factory)
return adapters;
}
bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width,
bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, HWND window_hwnd, u32 width,
u32 height, float refresh_rate, DXGI_FORMAT format, DXGI_MODE_DESC* fullscreen_mode, IDXGIOutput** output)
{
// We need to find which monitor the window is located on.
const GSVector4i client_rc_vec = GSVector4i::load<false>(&window_rect);
// DXGI seems to use the nearest monitor if the window is out of bounds.
const HMONITOR const monitor = MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST);
// The window might be on a different adapter to which we are rendering.. so we have to enumerate them all.
// The monitor might be on a different adapter to which we are rendering.. so we have to enumerate them all.
HRESULT hr;
wil::com_ptr_nothrow<IDXGIOutput> first_output, intersecting_output;
wil::com_ptr_nothrow<IDXGIOutput> first_output, monitor_output;
for (u32 adapter_index = 0; !intersecting_output; adapter_index++)
for (u32 adapter_index = 0; !monitor_output; adapter_index++)
{
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
hr = factory->EnumAdapters1(adapter_index, adapter.put());
@ -152,10 +153,9 @@ bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const
else if (FAILED(hr) || FAILED(this_output->GetDesc(&output_desc)))
continue;
const GSVector4i output_rc = GSVector4i::load<false>(&output_desc.DesktopCoordinates);
if (!client_rc_vec.rintersect(output_rc).rempty())
if (output_desc.Monitor == monitor)
{
intersecting_output = std::move(this_output);
monitor_output = std::move(this_output);
break;
}
@ -165,7 +165,7 @@ bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const
}
}
if (!intersecting_output)
if (!monitor_output)
{
if (!first_output)
{
@ -174,7 +174,7 @@ bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const
}
Console.Warning("No DXGI output found for window, using first.");
intersecting_output = std::move(first_output);
monitor_output = std::move(first_output);
}
DXGI_MODE_DESC request_mode = {};
@ -184,15 +184,15 @@ bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const
request_mode.RefreshRate.Numerator = static_cast<UINT>(std::floor(refresh_rate * 1000.0f));
request_mode.RefreshRate.Denominator = 1000u;
if (FAILED(hr = intersecting_output->FindClosestMatchingMode(&request_mode, fullscreen_mode, nullptr)) ||
if (FAILED(hr = monitor_output->FindClosestMatchingMode(&request_mode, fullscreen_mode, nullptr)) ||
request_mode.Format != format)
{
ERROR_LOG("Failed to find closest matching mode, hr={:08X}", static_cast<unsigned>(hr));
return false;
}
*output = intersecting_output.get();
intersecting_output->AddRef();
*output = monitor_output.get();
monitor_output->AddRef();
return true;
}

View File

@ -24,7 +24,7 @@ namespace D3D
std::vector<GSAdapterInfo> GetAdapterInfo(IDXGIFactory5* factory);
// returns the fullscreen mode to use for the specified dimensions
bool GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width, u32 height,
bool GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, HWND window_hwnd, u32 width, u32 height,
float refresh_rate, DXGI_FORMAT format, DXGI_MODE_DESC* fullscreen_mode, IDXGIOutput** output);
// get an adapter based on name

View File

@ -659,7 +659,7 @@ bool GSDevice11::CreateSwapChain()
float fullscreen_refresh_rate;
m_is_exclusive_fullscreen =
GetRequestedExclusiveFullscreenMode(&fullscreen_width, &fullscreen_height, &fullscreen_refresh_rate) &&
D3D::GetRequestedExclusiveFullscreenModeDesc(m_dxgi_factory.get(), client_rc, fullscreen_width,
D3D::GetRequestedExclusiveFullscreenModeDesc(m_dxgi_factory.get(), window_hwnd, fullscreen_width,
fullscreen_height, fullscreen_refresh_rate, swap_chain_format, &fullscreen_mode,
fullscreen_output.put());

View File

@ -817,7 +817,7 @@ bool GSDevice12::CreateSwapChain()
float fullscreen_refresh_rate;
m_is_exclusive_fullscreen =
GetRequestedExclusiveFullscreenMode(&fullscreen_width, &fullscreen_height, &fullscreen_refresh_rate) &&
D3D::GetRequestedExclusiveFullscreenModeDesc(m_dxgi_factory.get(), client_rc, fullscreen_width,
D3D::GetRequestedExclusiveFullscreenModeDesc(m_dxgi_factory.get(), window_hwnd, fullscreen_width,
fullscreen_height, fullscreen_refresh_rate, swap_chain_format, &fullscreen_mode,
fullscreen_output.put());