diff --git a/src/dxgi/dxgi_output.cpp b/src/dxgi/dxgi_output.cpp index f8908217..07ac6f13 100644 --- a/src/dxgi/dxgi_output.cpp +++ b/src/dxgi/dxgi_output.cpp @@ -19,21 +19,19 @@ namespace dxvk { HMONITOR monitor) : m_adapter(adapter), m_monitor(monitor) { - // Init output data if necessary - if (FAILED(m_adapter->GetOutputData(m_monitor, nullptr))) { - DXGI_VK_OUTPUT_DATA outputData; - outputData.FrameStats = DXGI_FRAME_STATISTICS(); - outputData.GammaCurve.Scale = { 1.0f, 1.0f, 1.0f }; - outputData.GammaCurve.Offset = { 0.0f, 0.0f, 0.0f }; - - for (uint32_t i = 0; i < DXGI_VK_GAMMA_CP_COUNT; i++) { - const float value = GammaControlPointLocation(i); - outputData.GammaCurve.GammaCurve[i] = { value, value, value }; - } - - outputData.GammaDirty = FALSE; - m_adapter->SetOutputData(m_monitor, &outputData); + // Init monitor info if necessary + DXGI_VK_MONITOR_DATA monitorData; + monitorData.pSwapChain = nullptr; + monitorData.FrameStats = DXGI_FRAME_STATISTICS(); + monitorData.GammaCurve.Scale = { 1.0f, 1.0f, 1.0f }; + monitorData.GammaCurve.Offset = { 0.0f, 0.0f, 0.0f }; + + for (uint32_t i = 0; i < DXGI_VK_GAMMA_CP_COUNT; i++) { + const float value = GammaControlPointLocation(i); + monitorData.GammaCurve.GammaCurve[i] = { value, value, value }; } + + InitMonitorData(monitor, &monitorData); } @@ -330,27 +328,27 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) { - DXGI_VK_OUTPUT_DATA outputData; + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + HRESULT hr = AcquireMonitorData(m_monitor, &monitorInfo); + + if (FAILED(hr)) + return hr; - if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) { - Logger::err("DXGI: Failed to query output data"); - return E_FAIL; - } - - *pStats = outputData.FrameStats; + *pStats = monitorInfo->FrameStats; + ReleaseMonitorData(); return S_OK; } HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL* pArray) { - DXGI_VK_OUTPUT_DATA outputData; + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + HRESULT hr = AcquireMonitorData(m_monitor, &monitorInfo); + + if (FAILED(hr)) + return hr; - if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) { - Logger::err("DXGI: Failed to query output data"); - return E_FAIL; - } - - *pArray = outputData.GammaCurve; + *pArray = monitorInfo->GammaCurve; + ReleaseMonitorData(); return S_OK; } @@ -385,20 +383,21 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL* pArray) { - DXGI_VK_OUTPUT_DATA outputData; + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + HRESULT hr = AcquireMonitorData(m_monitor, &monitorInfo); + + if (FAILED(hr)) + return hr; - if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) { - Logger::err("DXGI: Failed to query output data"); - return E_FAIL; + monitorInfo->GammaCurve = *pArray; + + if (monitorInfo->pSwapChain) { + hr = monitorInfo->pSwapChain->SetGammaControl( + DXGI_VK_GAMMA_CP_COUNT, pArray->GammaCurve); } - - outputData.GammaCurve = *pArray; - outputData.GammaDirty = TRUE; - - if (FAILED(m_adapter->SetOutputData(m_monitor, &outputData))) { - Logger::err("DXGI: Failed to update output data"); - return E_FAIL; - } return S_OK; + + ReleaseMonitorData(); + return hr; } diff --git a/src/dxgi/dxgi_output.h b/src/dxgi/dxgi_output.h index bb9d5d97..e94fa3ed 100644 --- a/src/dxgi/dxgi_output.h +++ b/src/dxgi/dxgi_output.h @@ -1,5 +1,6 @@ #pragma once +#include "dxgi_monitor.h" #include "dxgi_object.h" namespace dxvk { diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 6495711b..aebecf2e 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -47,6 +47,16 @@ namespace dxvk { if (SUCCEEDED(GetOutputFromMonitor(m_monitor, &output))) RestoreDisplayMode(output.ptr()); + + // Decouple swap chain from monitor if necessary + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (monitorInfo->pSwapChain == this) + monitorInfo->pSwapChain = nullptr; + + ReleaseMonitorData(); + } } @@ -263,17 +273,6 @@ namespace dxvk { SyncInterval = std::min(SyncInterval, 4); try { - // If in fullscreen mode, apply any updated gamma curve - // if it has been changed since the last present call. - DXGI_VK_OUTPUT_DATA outputData; - - if (SUCCEEDED(m_adapter->GetOutputData(m_monitor, &outputData)) && outputData.GammaDirty) { - m_presenter->SetGammaControl(DXGI_VK_GAMMA_CP_COUNT, outputData.GammaCurve.GammaCurve); - - outputData.GammaDirty = FALSE; - m_adapter->SetOutputData(m_monitor, &outputData); - } - return m_presenter->Present(SyncInterval, PresentFlags, nullptr); } catch (const DxvkError& err) { Logger::err(err.message()); @@ -481,10 +480,18 @@ namespace dxvk { } - HRESULT DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) { + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) { Logger::err("DxgiSwapChain::SetColorSpace1: Not implemented"); return E_NOTIMPL; } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetGammaControl( + UINT NumPoints, + const DXGI_RGB* pGammaCurve) { + std::lock_guard lockBuf(m_lockBuffer); + return m_presenter->SetGammaControl(NumPoints, pGammaCurve); + } VkExtent2D DxgiSwapChain::GetWindowSize() const { @@ -560,6 +567,18 @@ namespace dxvk { SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); m_monitor = desc.Monitor; + + // Apply current gamma curve of the output + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (!monitorInfo->pSwapChain) + monitorInfo->pSwapChain = this; + + SetGammaControl(DXGI_VK_GAMMA_CP_COUNT, monitorInfo->GammaCurve.GammaCurve); + ReleaseMonitorData(); + } + return S_OK; } @@ -574,6 +593,17 @@ namespace dxvk { || FAILED(RestoreDisplayMode(output.ptr()))) Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode"); + // Reset gamma control and decouple swap chain from monitor + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (monitorInfo->pSwapChain == this) + monitorInfo->pSwapChain = nullptr; + + SetGammaControl(0, nullptr); + ReleaseMonitorData(); + } + // Restore internal state m_descFs.Windowed = TRUE; m_monitor = nullptr; @@ -596,7 +626,7 @@ namespace dxvk { rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); - return m_presenter->SetGammaControl(0, nullptr); + return S_OK; } diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index e6e5e77f..4b56f3ac 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -155,6 +155,10 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE SetColorSpace1( DXGI_COLOR_SPACE_TYPE ColorSpace) final; + HRESULT STDMETHODCALLTYPE SetGammaControl( + UINT NumPoints, + const DXGI_RGB* pGammaCurve); + private: struct WindowState { @@ -167,7 +171,7 @@ namespace dxvk { std::mutex m_lockBuffer; Com m_factory; - Com m_adapter; + Com m_adapter; HWND m_window; DXGI_SWAP_CHAIN_DESC1 m_desc;