From 1594a20b943703fb7c9ec3d8ab420248dcb1af04 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 11 Dec 2018 15:48:57 +0100 Subject: [PATCH] [dxgi] Add new functions to change the display mode of a monitor --- src/dxgi/dxgi_monitor.cpp | 84 +++++++++++++++++++++++++++++++++++++++ src/dxgi/dxgi_monitor.h | 35 ++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/dxgi/dxgi_monitor.cpp b/src/dxgi/dxgi_monitor.cpp index 0547a4b8..9af164ad 100644 --- a/src/dxgi/dxgi_monitor.cpp +++ b/src/dxgi/dxgi_monitor.cpp @@ -6,6 +6,27 @@ namespace dxvk { std::unordered_map g_monitorData; + uint32_t GetMonitorFormatBpp(DXGI_FORMAT Format) { + switch (Format) { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R10G10B10A2_UNORM: + return 32; + + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return 64; + + default: + Logger::warn(str::format( + "GetMonitorFormatBpp: Unknown format: ", + Format)); + return 32; + } + } + + HRESULT InitMonitorData( HMONITOR hMonitor, const DXGI_VK_MONITOR_DATA* pData) { @@ -44,4 +65,67 @@ namespace dxvk { g_monitorMutex.unlock(); } + + HRESULT GetMonitorDisplayMode( + HMONITOR hMonitor, + DWORD ModeNum, + DXGI_MODE_DESC* pMode) { + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("DXGI: Failed to query monitor info"); + return E_FAIL; + } + + DEVMODEW devMode = { }; + devMode.dmSize = sizeof(devMode); + + if (!::EnumDisplaySettingsW(monInfo.szDevice, ModeNum, &devMode)) + return DXGI_ERROR_NOT_FOUND; + + pMode->Width = devMode.dmPelsWidth; + pMode->Height = devMode.dmPelsHeight; + pMode->RefreshRate = { devMode.dmDisplayFrequency, 1 }; + pMode->Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; // FIXME + pMode->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; + pMode->Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + return S_OK; + } + + + HRESULT SetMonitorDisplayMode( + HMONITOR hMonitor, + const DXGI_MODE_DESC* pMode) { + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("DXGI: Failed to query monitor info"); + return E_FAIL; + } + + DEVMODEW devMode = { }; + devMode.dmSize = sizeof(devMode); + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + devMode.dmPelsWidth = pMode->Width; + devMode.dmPelsHeight = pMode->Height; + devMode.dmBitsPerPel = GetMonitorFormatBpp(pMode->Format); + + if (pMode->RefreshRate.Numerator != 0) { + devMode.dmFields |= DM_DISPLAYFREQUENCY; + devMode.dmDisplayFrequency = pMode->RefreshRate.Numerator + / pMode->RefreshRate.Denominator; + } + + Logger::info(str::format("DXGI: Setting display mode: ", + devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@", + devMode.dmDisplayFrequency)); + + LONG status = ::ChangeDisplaySettingsExW( + monInfo.szDevice, &devMode, nullptr, CDS_FULLSCREEN, nullptr); + + return status == DISP_CHANGE_SUCCESSFUL ? S_OK : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;; + } + } \ No newline at end of file diff --git a/src/dxgi/dxgi_monitor.h b/src/dxgi/dxgi_monitor.h index 2fab08c2..281d960c 100644 --- a/src/dxgi/dxgi_monitor.h +++ b/src/dxgi/dxgi_monitor.h @@ -19,6 +19,16 @@ namespace dxvk { }; + /** + * \brief Queries bits per pixel for a format + * + * The format must be a valid swap chain format. + * \param [in] Format The DXGI format to query + * \returns Bits per pixel for this format + */ + uint32_t GetMonitorFormatBpp( + DXGI_FORMAT Format); + /** * \brief Initializes monitor data * @@ -51,4 +61,29 @@ namespace dxvk { */ void ReleaseMonitorData(); + + /** + * \brief Retrieves monitor display mode + * + * \param [in] hMonitor Monitor handle + * \param [in] ModeNum Mode number + * \param [out] Display mode properties + * \returns S_OK on success + */ + HRESULT GetMonitorDisplayMode( + HMONITOR hMonitor, + DWORD ModeNum, + DXGI_MODE_DESC* pMode); + + /** + * \brief Sets monitor display mode + * + * \param [in] hMonitor Monitor handle + * \param [in] pMode Display mode properties + * \returns S_OK on success + */ + HRESULT SetMonitorDisplayMode( + HMONITOR hMonitor, + const DXGI_MODE_DESC* pMode); + } \ No newline at end of file