mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-17 04:42:01 +00:00
[idd] use the actual surface colorspace instead of guessing
This commit is contained in:
@@ -161,6 +161,11 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
UINT dirtyRectCount = 0;
|
UINT dirtyRectCount = 0;
|
||||||
ComPtr<IDXGIResource> surface;
|
ComPtr<IDXGIResource> surface;
|
||||||
|
|
||||||
|
// The surface colour space is the source of truth for the content format.
|
||||||
|
// Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy
|
||||||
|
// path HDR is not available, so default to SDR.
|
||||||
|
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||||
|
|
||||||
#ifdef HAS_IDDCX_110
|
#ifdef HAS_IDDCX_110
|
||||||
if (m_devContext->CanProcessFP16())
|
if (m_devContext->CanProcessFP16())
|
||||||
{
|
{
|
||||||
@@ -177,6 +182,7 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
frameNumber = buffer.MetaData.PresentationFrameNumber;
|
frameNumber = buffer.MetaData.PresentationFrameNumber;
|
||||||
dirtyRectCount = buffer.MetaData.DirtyRectCount;
|
dirtyRectCount = buffer.MetaData.DirtyRectCount;
|
||||||
surface = buffer.MetaData.pSurface;
|
surface = buffer.MetaData.pSurface;
|
||||||
|
colorSpace = buffer.MetaData.SurfaceColorSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -216,7 +222,7 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
if (frameNumber != lastFrameNumber)
|
if (frameNumber != lastFrameNumber)
|
||||||
{
|
{
|
||||||
lastFrameNumber = frameNumber;
|
lastFrameNumber = frameNumber;
|
||||||
SwapChainNewFrame(surface, dirtyRectCount);
|
SwapChainNewFrame(surface, dirtyRectCount, colorSpace);
|
||||||
|
|
||||||
// report that all GPU processing for this frame has been queued
|
// report that all GPU processing for this frame has been queued
|
||||||
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
||||||
@@ -327,7 +333,8 @@ static FrameType GetFrameType(DXGI_FORMAT format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount)
|
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
||||||
|
DXGI_COLOR_SPACE_TYPE colorSpace)
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11Texture2D> texture;
|
ComPtr<ID3D11Texture2D> texture;
|
||||||
HRESULT hr = acquiredBuffer.As(&texture);
|
HRESULT hr = acquiredBuffer.As(&texture);
|
||||||
@@ -380,58 +387,74 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
srcFormat.height = srcDesc.Height;
|
srcFormat.height = srcDesc.Height;
|
||||||
srcFormat.format = GetFrameType(srcDesc.Format);
|
srcFormat.format = GetFrameType(srcDesc.Format);
|
||||||
|
|
||||||
// Only HDR-capable formats can carry HDR content.
|
switch (colorSpace)
|
||||||
// 8-bit formats (BGRA, RGBA) cannot represent HDR,
|
|
||||||
// even if IsHDRActive() is momentarily stale during mode switches.
|
|
||||||
if (srcDesc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT &&
|
|
||||||
srcDesc.Format != DXGI_FORMAT_R10G10B10A2_UNORM)
|
|
||||||
{
|
{
|
||||||
srcFormat.hdr = false;
|
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
|
||||||
srcFormat.hdrPQ = false;
|
case DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020:
|
||||||
}
|
// HDR10: BT.2020 primaries with the PQ (ST.2084) transfer function
|
||||||
else if (srcDesc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
|
// already applied to the pixel data.
|
||||||
{
|
srcFormat.hdr = true;
|
||||||
// FP16 is HDR content (scRGB / linear, not PQ-curve).
|
srcFormat.hdrPQ = true;
|
||||||
// FP16 always carries HDR color data regardless of OS HDR mode,
|
if (!m_devContext->GetHDRMetadata(srcFormat))
|
||||||
// but metadata (primaries, luminances) may be unavailable.
|
{
|
||||||
srcFormat.hdr = true;
|
// HDR is active but the OS has not delivered static metadata yet
|
||||||
srcFormat.hdrPQ = false;
|
// (e.g. a brief window during a mode switch). The pixels are still
|
||||||
if (!m_devContext->GetHDRMetadata(srcFormat))
|
// PQ-encoded, so keep the PQ flag and supply BT.2020/PQ defaults
|
||||||
{
|
// rather than mislabel the frame as SDR.
|
||||||
// No HDR metadata from the OS; provide reasonable defaults
|
// BT.2020 primaries (in 0.00002 units):
|
||||||
// so downstream consumers have valid primaries and luminances.
|
srcFormat.displayPrimary[0][0] = 35400; // Rx
|
||||||
// BT.709/sRGB primaries (in 0.00002 units):
|
srcFormat.displayPrimary[0][1] = 14600; // Ry
|
||||||
srcFormat.displayPrimary[0][0] = 13250; // Rx
|
srcFormat.displayPrimary[1][0] = 8500; // Gx
|
||||||
srcFormat.displayPrimary[0][1] = 34500; // Ry
|
srcFormat.displayPrimary[1][1] = 39850; // Gy
|
||||||
srcFormat.displayPrimary[1][0] = 7500; // Gx
|
srcFormat.displayPrimary[2][0] = 6550; // Bx
|
||||||
srcFormat.displayPrimary[1][1] = 30000; // Gy
|
srcFormat.displayPrimary[2][1] = 2300; // By
|
||||||
srcFormat.displayPrimary[2][0] = 34000; // Bx
|
// D65 white point (in 0.00002 units):
|
||||||
srcFormat.displayPrimary[2][1] = 16000; // By
|
srcFormat.whitePoint[0] = 15635;
|
||||||
// D65 white point (in 0.00002 units):
|
srcFormat.whitePoint[1] = 16450;
|
||||||
srcFormat.whitePoint[0] = 15635;
|
// Mastering luminances follow SMPTE ST 2086 units: max in whole cd/m²,
|
||||||
srcFormat.whitePoint[1] = 16450;
|
// min in 0.0001 cd/m². 1000 cd/m² display, 0.0001 cd/m² black:
|
||||||
// Mastering luminances follow SMPTE ST 2086 units: max in whole cd/m²,
|
srcFormat.maxDisplayLuminance = 1000;
|
||||||
// min in 0.0001 cd/m². 80 cd/m² display, 0.005 cd/m² black:
|
srcFormat.minDisplayLuminance = 1;
|
||||||
srcFormat.maxDisplayLuminance = 80;
|
// Content light levels unknown:
|
||||||
srcFormat.minDisplayLuminance = 50;
|
srcFormat.maxContentLightLevel = 0;
|
||||||
// Content light levels unknown:
|
srcFormat.maxFrameAverageLightLevel = 0;
|
||||||
srcFormat.maxContentLightLevel = 0;
|
}
|
||||||
srcFormat.maxFrameAverageLightLevel = 0;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_devContext->CanProcessFP16() && m_devContext->IsHDRActive())
|
|
||||||
{
|
|
||||||
// Non-FP16 format (e.g., RGBA10) with OS HDR mode active.
|
|
||||||
// Windows applies the PQ (ST.2084) transfer function for non-FP16 HDR.
|
|
||||||
srcFormat.hdr = true;
|
|
||||||
srcFormat.hdrPQ = true;
|
|
||||||
|
|
||||||
// Load HDR metadata; if none is available the frame is not HDR.
|
case DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709:
|
||||||
if (!m_devContext->GetHDRMetadata(srcFormat))
|
// scRGB: linear (FP16) content with BT.709 primaries. HDR, but the PQ
|
||||||
{
|
// curve has not been applied.
|
||||||
|
srcFormat.hdr = true;
|
||||||
|
srcFormat.hdrPQ = false;
|
||||||
|
if (!m_devContext->GetHDRMetadata(srcFormat))
|
||||||
|
{
|
||||||
|
// No HDR metadata from the OS; provide reasonable defaults
|
||||||
|
// so downstream consumers have valid primaries and luminances.
|
||||||
|
// BT.709/sRGB primaries (in 0.00002 units):
|
||||||
|
srcFormat.displayPrimary[0][0] = 13250; // Rx
|
||||||
|
srcFormat.displayPrimary[0][1] = 34500; // Ry
|
||||||
|
srcFormat.displayPrimary[1][0] = 7500; // Gx
|
||||||
|
srcFormat.displayPrimary[1][1] = 30000; // Gy
|
||||||
|
srcFormat.displayPrimary[2][0] = 34000; // Bx
|
||||||
|
srcFormat.displayPrimary[2][1] = 16000; // By
|
||||||
|
// D65 white point (in 0.00002 units):
|
||||||
|
srcFormat.whitePoint[0] = 15635;
|
||||||
|
srcFormat.whitePoint[1] = 16450;
|
||||||
|
// Mastering luminances follow SMPTE ST 2086 units: max in whole cd/m²,
|
||||||
|
// min in 0.0001 cd/m². 80 cd/m² display, 0.005 cd/m² black:
|
||||||
|
srcFormat.maxDisplayLuminance = 80;
|
||||||
|
srcFormat.minDisplayLuminance = 50;
|
||||||
|
// Content light levels unknown:
|
||||||
|
srcFormat.maxContentLightLevel = 0;
|
||||||
|
srcFormat.maxFrameAverageLightLevel = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Everything else (e.g. RGB_FULL_G22_NONE_P709) is SDR.
|
||||||
srcFormat.hdr = false;
|
srcFormat.hdr = false;
|
||||||
srcFormat.hdrPQ = false;
|
srcFormat.hdrPQ = false;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool postProcessFormatChanged = false;
|
bool postProcessFormatChanged = false;
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ private:
|
|||||||
|
|
||||||
static void CompletionFunction(
|
static void CompletionFunction(
|
||||||
CD3D12CommandQueue * queue, bool result, void * param1, void * param2);
|
CD3D12CommandQueue * queue, bool result, void * param1, void * param2);
|
||||||
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount);
|
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
||||||
|
DXGI_COLOR_SPACE_TYPE colorSpace);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||||
|
|||||||
Reference in New Issue
Block a user