diff --git a/src/dxgi/dxgi_output.cpp b/src/dxgi/dxgi_output.cpp index c1559936..9fa91065 100644 --- a/src/dxgi/dxgi_output.cpp +++ b/src/dxgi/dxgi_output.cpp @@ -6,6 +6,7 @@ #include "dxgi_adapter.h" #include "dxgi_output.h" +#include "dxgi_swapchain.h" #include "../dxvk/dxvk_format.h" @@ -229,20 +230,32 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) { - Logger::err("DxgiOutput::GetFrameStatistics: Not implemented"); - return E_NOTIMPL; + Com swapChain = GetFullscreenSwapChain(); + + return swapChain != nullptr + ? swapChain->GetFrameStatistics(pStats) + : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; } HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL *pArray) { - Logger::err("DxgiOutput::GetGammaControl: Not implemented"); - return E_NOTIMPL; + Com swapChain = GetFullscreenSwapChain(); + + return swapChain != nullptr + ? swapChain->GetGammaControl(pArray) + : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; } HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) { - Logger::err("DxgiOutput::GetGammaControlCapabilities: Not implemented"); - return E_NOTIMPL; + pGammaCaps->ScaleAndOffsetSupported = TRUE; + pGammaCaps->MaxConvertedValue = 1.0f; + pGammaCaps->MinConvertedValue = 0.0f; + pGammaCaps->NumGammaControlPoints = DxgiPresenterGammaRamp::CpCount; + + for (uint32_t i = 0; i < pGammaCaps->NumGammaControlPoints; i++) + pGammaCaps->ControlPointPositions[i] = DxgiPresenterGammaRamp::cpLocation(i); + return S_OK; } @@ -258,8 +271,12 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL *pArray) { - Logger::err("DxgiOutput::SetGammaControl: Not implemented"); - return E_NOTIMPL; + Com swapChain = GetFullscreenSwapChain(); + + Logger::err(str::format("DxgiOutput::SetGammaControl ", swapChain.ptr())); + return swapChain != nullptr + ? swapChain->SetGammaControl(pArray) + : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; } @@ -277,6 +294,23 @@ namespace dxvk { } + BOOL DxgiOutput::SetSwapChain(DxgiSwapChain* pExpected, DxgiSwapChain* pDesired) { + std::lock_guard lock(m_mutex); + + if (m_fullscreenSwapChain == pExpected) { + Logger::err(str::format("SetSwapChain: ", pDesired)); + m_fullscreenSwapChain = pDesired; + return TRUE; + } return FALSE; + } + + + Com DxgiOutput::GetFullscreenSwapChain() { + std::lock_guard lock(m_mutex); + return Com(m_fullscreenSwapChain); + } + + uint32_t DxgiOutput::GetFormatBpp(DXGI_FORMAT Format) const { DxgiFormatInfo formatInfo = m_adapter->LookupFormat(Format, DxgiFormatMode::Any); return imageFormatInfo(formatInfo.format)->elementSize * 8; diff --git a/src/dxgi/dxgi_output.h b/src/dxgi/dxgi_output.h index ce86047c..6b2f35cc 100644 --- a/src/dxgi/dxgi_output.h +++ b/src/dxgi/dxgi_output.h @@ -1,10 +1,13 @@ #pragma once +#include + #include "dxgi_object.h" namespace dxvk { class DxgiAdapter; + class DxgiSwapChain; class DxgiOutput : public DxgiObject { @@ -64,11 +67,20 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE WaitForVBlank() final; + BOOL SetSwapChain( + DxgiSwapChain* pExpected, + DxgiSwapChain* pDesired); + private: - Com m_adapter = nullptr; + DxgiAdapter* m_adapter = nullptr; HMONITOR m_monitor = nullptr; + std::mutex m_mutex; + DxgiSwapChain* m_fullscreenSwapChain = nullptr; + + Com GetFullscreenSwapChain(); + uint32_t GetFormatBpp(DXGI_FORMAT Format) const; }; diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 5cb1a563..6d09fc06 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -1,5 +1,6 @@ #include "dxgi_device.h" #include "dxgi_factory.h" +#include "dxgi_output.h" #include "dxgi_swapchain.h" namespace dxvk { @@ -52,13 +53,14 @@ namespace dxvk { if (FAILED(CreatePresenter()) || FAILED(CreateBackBuffer())) throw DxvkError("DxgiSwapChain: Failed to create presenter or back buffer"); - if (FAILED(SetDefaultGammaRamp())) + if (FAILED(SetDefaultGammaControl())) throw DxvkError("DxgiSwapChain: Failed to set up gamma ramp"); } DxgiSwapChain::~DxgiSwapChain() { - + if (m_output != nullptr) + m_output->SetSwapChain(this, nullptr); } @@ -268,7 +270,52 @@ namespace dxvk { } - HRESULT DxgiSwapChain::SetDefaultGammaRamp() { + HRESULT DxgiSwapChain::GetGammaControl(DXGI_GAMMA_CONTROL* pGammaControl) { + std::lock_guard lock(m_mutex); + + pGammaControl->Scale = { + m_gammaControl.in_factor[0], + m_gammaControl.in_factor[1], + m_gammaControl.in_factor[2] }; + + pGammaControl->Offset = { + m_gammaControl.in_offset[0], + m_gammaControl.in_offset[1], + m_gammaControl.in_offset[2] }; + + for (uint32_t i = 0; i < DxgiPresenterGammaRamp::CpCount; i++) { + pGammaControl->GammaCurve[i] = { + m_gammaControl.cp_values[4 * i + 0], + m_gammaControl.cp_values[4 * i + 1], + m_gammaControl.cp_values[4 * i + 2] }; + } + + return S_OK; + } + + + HRESULT DxgiSwapChain::SetGammaControl(const DXGI_GAMMA_CONTROL* pGammaControl) { + std::lock_guard lock(m_mutex); + m_gammaControl.in_factor[0] = pGammaControl->Scale.Red; + m_gammaControl.in_factor[1] = pGammaControl->Scale.Green; + m_gammaControl.in_factor[2] = pGammaControl->Scale.Blue; + + m_gammaControl.in_offset[0] = pGammaControl->Offset.Red; + m_gammaControl.in_offset[1] = pGammaControl->Offset.Green; + m_gammaControl.in_offset[2] = pGammaControl->Offset.Blue; + + for (uint32_t i = 0; i < DxgiPresenterGammaRamp::CpCount; i++) { + m_gammaControl.cp_values[4 * i + 0] = pGammaControl->GammaCurve[i].Red; + m_gammaControl.cp_values[4 * i + 1] = pGammaControl->GammaCurve[i].Green; + m_gammaControl.cp_values[4 * i + 2] = pGammaControl->GammaCurve[i].Blue; + } + + m_presenter->setGammaRamp(m_gammaControl); + return S_OK; + } + + + HRESULT DxgiSwapChain::SetDefaultGammaControl() { std::lock_guard lock(m_mutex); for (uint32_t i = 0; i < 4; i++) { @@ -342,10 +389,10 @@ namespace dxvk { HRESULT DxgiSwapChain::EnterFullscreenMode(IDXGIOutput *pTarget) { - Com output = pTarget; + m_output = static_cast(pTarget); - if (output == nullptr) { - if (FAILED(GetContainingOutput(&output))) { + if (m_output == nullptr) { + if (FAILED(GetContainingOutput(reinterpret_cast(&m_output)))) { Logger::err("DxgiSwapChain: Failed to enter fullscreen mode: Cannot query containing output"); return E_FAIL; } @@ -372,7 +419,7 @@ namespace dxvk { // Move the window so that it covers the entire output DXGI_OUTPUT_DESC desc; - output->GetDesc(&desc); + m_output->GetDesc(&desc); const RECT rect = desc.DesktopCoordinates; @@ -380,6 +427,8 @@ namespace dxvk { rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); + // Assign this swap chain to the output + m_output->SetSwapChain(nullptr, this); return S_OK; } @@ -387,6 +436,12 @@ namespace dxvk { HRESULT DxgiSwapChain::LeaveFullscreenMode() { m_desc.Windowed = TRUE; + // Remove this swap chain from the output + if (m_output != nullptr) { + m_output->SetSwapChain(this, nullptr); + m_output = nullptr; + } + // FIXME wine only restores window flags if the application // has not modified them in the meantime. Some applications // may rely on that behaviour. diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index e2804ccd..e1222643 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -18,6 +18,7 @@ namespace dxvk { class DxgiDevice; class DxgiFactory; + class DxgiOutput; class DxgiSwapChain : public DxgiObject { @@ -80,7 +81,13 @@ namespace dxvk { BOOL Fullscreen, IDXGIOutput *pTarget) final; - HRESULT SetDefaultGammaRamp(); + HRESULT GetGammaControl( + DXGI_GAMMA_CONTROL* pGammaControl); + + HRESULT SetGammaControl( + const DXGI_GAMMA_CONTROL* pGammaControl); + + HRESULT SetDefaultGammaControl(); private: @@ -95,6 +102,7 @@ namespace dxvk { Com m_factory; Com m_adapter; Com m_device; + Com m_output; Com m_presentDevice; DXGI_SWAP_CHAIN_DESC m_desc;