[dxgi] Implicitly set HDR color space for RGBA16_FLOAT swap chains

This commit is contained in:
Philip Rebohle 2024-03-15 14:34:51 +01:00 committed by Joshie
parent e857b09432
commit 1085ba713e
2 changed files with 84 additions and 22 deletions

View File

@ -32,6 +32,9 @@ namespace dxvk {
// Apply initial window mode and fullscreen state // Apply initial window mode and fullscreen state
if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr))) if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
throw DxvkError("DXGI: Failed to set initial fullscreen state"); throw DxvkError("DXGI: Failed to set initial fullscreen state");
// Ensure that RGBA16 swap chains are scRGB if supported
UpdateColorSpace(m_desc.Format, m_colorSpace);
} }
@ -398,7 +401,13 @@ namespace dxvk {
if (Format != DXGI_FORMAT_UNKNOWN) if (Format != DXGI_FORMAT_UNKNOWN)
m_desc.Format = Format; m_desc.Format = Format;
return m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue); HRESULT hr = m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
if (FAILED(hr))
return hr;
UpdateColorSpace(m_desc.Format, m_colorSpace);
return hr;
} }
@ -572,36 +581,31 @@ namespace dxvk {
if (!pColorSpaceSupport) if (!pColorSpaceSupport)
return E_INVALIDARG; return E_INVALIDARG;
// Don't expose any color spaces other than standard std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
// sRGB if the enableHDR option is not set.
// if (ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
// If we ever have a use for the non-SRGB non-HDR colorspaces *pColorSpaceSupport = DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
// some day, we may want to revisit this. else
if (ColorSpace != DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 *pColorSpaceSupport = 0;
&& !m_factory->GetOptions()->enableHDR) {
*pColorSpaceSupport = 0;
return S_OK;
}
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
*pColorSpaceSupport = support;
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) { HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) {
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace); std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
if (!support) if (!ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
return E_INVALIDARG; return E_INVALIDARG;
std::lock_guard<dxvk::mutex> lock(m_lockBuffer); // Write back color space if setting it up succeeded. This way, we preserve
HRESULT hr = m_presenter->SetColorSpace(ColorSpace); // the current color space even if the swap chain temporarily switches to a
if (SUCCEEDED(hr)) { // back buffer format which does not support it.
// If this was a colorspace other than our current one, HRESULT hr = UpdateColorSpace(m_desc.Format, ColorSpace);
// punt us into that one on the DXGI output.
m_monitorInfo->PuntColorSpace(ColorSpace); if (SUCCEEDED(hr))
} m_colorSpace = ColorSpace;
return hr; return hr;
} }
@ -869,6 +873,7 @@ namespace dxvk {
m_monitorInfo->ReleaseMonitorData(); m_monitorInfo->ReleaseMonitorData();
} }
void DxgiSwapChain::UpdateGlobalHDRState() { void DxgiSwapChain::UpdateGlobalHDRState() {
// Update the global HDR state if called from the legacy NVAPI // Update the global HDR state if called from the legacy NVAPI
// interfaces, etc. // interfaces, etc.
@ -893,4 +898,51 @@ namespace dxvk {
} }
} }
bool DxgiSwapChain::ValidateColorSpaceSupport(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace) {
// RGBA16 swap chains are treated as scRGB even on SDR displays,
// and regular sRGB is not exposed when this format is used.
if (Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
return ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
// For everything else, we will always expose plain sRGB
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
return true;
// Only expose HDR10 color space if HDR option is enabled
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
return m_factory->GetOptions()->enableHDR && m_presenter->CheckColorSpaceSupport(ColorSpace);
return false;
}
HRESULT DxgiSwapChain::UpdateColorSpace(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace) {
// Don't do anything if the explicitly sepected color space
// is compatible with the back buffer format already
if (!ValidateColorSpaceSupport(Format, ColorSpace)) {
ColorSpace = Format == DXGI_FORMAT_R16G16B16A16_FLOAT
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
}
// Ensure that we pick a supported color space. This is relevant for
// mapping scRGB to sRGB on SDR setups, matching Windows behaviour.
if (!m_presenter->CheckColorSpaceSupport(ColorSpace))
ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
// If this was a colorspace other than our current one,
// punt us into that one on the DXGI output.
if (SUCCEEDED(hr))
m_monitorInfo->PuntColorSpace(ColorSpace);
return hr;
}
} }

View File

@ -193,6 +193,8 @@ namespace dxvk {
bool m_frameStatisticsDisjoint = true; bool m_frameStatisticsDisjoint = true;
wsi::DxvkWindowState m_windowState; wsi::DxvkWindowState m_windowState;
DXGI_COLOR_SPACE_TYPE m_colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
uint32_t m_globalHDRStateSerial = 0; uint32_t m_globalHDRStateSerial = 0;
HRESULT EnterFullscreenMode( HRESULT EnterFullscreenMode(
@ -223,6 +225,14 @@ namespace dxvk {
void UpdateGlobalHDRState(); void UpdateGlobalHDRState();
bool ValidateColorSpaceSupport(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace);
HRESULT UpdateColorSpace(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace);
}; };
} }