Skip to content

Commit

Permalink
[Windows] Enables HLG passthrough using HLG to PQ shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
thexai committed Oct 18, 2020
1 parent a792065 commit 4cf3a2e
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 61 deletions.
37 changes: 37 additions & 0 deletions system/shaders/output_d3d.fx
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,50 @@ float tonemap(float val)
return val * (1 + val/(g_toneP1*g_toneP1))/(1 + val);
}
#endif
#if defined(KODI_HLG_TO_PQ)
float inverseHLG(float x)
{
const float B67_a = 0.17883277;
const float B67_b = 0.28466892;
const float B67_c = 0.55991073;
const float B67_inv_r2 = 4.0;
if (x <= 0.5)
x = x * x * B67_inv_r2;
else
x = exp((x - B67_c) / B67_a) + B67_b;
return x;
}

float4 tranferPQ(float4 color)
{
const float ST2084_m1 = 2610.0 / (4096.0 * 4.0);
const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;
const float ST2084_c1 = 3424.0 / 4096.0;
const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;
const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;
color = pow(color / 1000.0, ST2084_m1);
color = (ST2084_c1 + ST2084_c2 * color) / (1 + ST2084_c3 * color);
color = pow(color, ST2084_m2);
return color;
}
#endif


float4 output4(float4 color, float2 uv)
{
#if defined(KODI_TONE_MAPPING)
float luma = dot(color.rgb, g_coefsDst);
color.rgb *= tonemap(luma) / luma;
#endif
#if defined(KODI_HLG_TO_PQ)
color.r = inverseHLG(color.r);
color.g = inverseHLG(color.g);
color.b = inverseHLG(color.b);
float3 ootf_2020 = float3(0.2627, 0.6780, 0.0593);
float ootf_ys = 2000.0 * dot(ootf_2020, color);
color = color * pow(ootf_ys, 0.200);
color = tranferPQ(color);
#endif
#if defined(KODI_3DLUT)
half3 scale = m_LUTParams.x;
half3 offset = m_LUTParams.y;
Expand Down
20 changes: 7 additions & 13 deletions xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,19 +372,18 @@ DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpaceSource(CRenderBuffer* view,
// UHDTV
if (view->primaries == AVCOL_PRI_BT2020)
{
if (view->color_transfer == AVCOL_TRC_SMPTEST2084 && supportHDR) // HDR10
// Could also be:
// DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
// Windows 10 does not support HLG passthrough. Always is used PQ for HDR passthrough
if ((view->color_transfer == AVCOL_TRC_SMPTEST2084 ||
view->color_transfer == AVCOL_TRC_ARIB_STD_B67) && supportHDR) // HDR10
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;

// Native HLG transfer can be used for HLG source in SDR display
if (view->color_transfer == AVCOL_TRC_ARIB_STD_B67 && supportHLG) // HLG
return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;

if (view->full_range)
return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;

// Could also be:
// DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020;
}
// SDTV
Expand Down Expand Up @@ -418,18 +417,13 @@ DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpaceTarget(CRenderBuffer* view)
if (!DX::Windowing()->IsHDROutput())
return color;

// HDR10
if (view->color_transfer == AVCOL_TRC_SMPTE2084 && view->primaries == AVCOL_PRI_BT2020)
// HDR10 or HLG
if (view->primaries == AVCOL_PRI_BT2020 && (view->color_transfer == AVCOL_TRC_SMPTE2084 ||
view->color_transfer == AVCOL_TRC_ARIB_STD_B67))
{
color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
// HLG or Rec.2020
else if (view->primaries == AVCOL_PRI_BT2020)
{
color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020;
}

return color;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,18 @@ void COutputShader::GetDefines(DefinesMap& map) const
{
map["KODI_TONE_MAPPING"] = "";
}
if (m_useHLGtoPQ)
{
map["KODI_HLG_TO_PQ"] = "";
}
}

bool COutputShader::Create(bool useLUT, bool useDithering, int ditherDepth, bool toneMapping)
bool COutputShader::Create(bool useLUT, bool useDithering, int ditherDepth, bool toneMapping, bool HLGtoPQ)
{
m_useLut = useLUT;
m_ditherDepth = ditherDepth;
m_toneMapping = toneMapping && !DX::Windowing()->IsHDROutput();
m_useHLGtoPQ = HLGtoPQ;

CWinShader::CreateVertexBuffer(4, sizeof(Vertex));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class COutputShader : public CWinShader

void ApplyEffectParameters(CD3DEffect &effect, unsigned sourceWidth, unsigned sourceHeight);
void GetDefines(DefinesMap &map) const;
bool Create(bool useLUT, bool useDithering, int ditherDepth, bool toneMapping);
bool Create(bool useLUT, bool useDithering, int ditherDepth, bool toneMapping, bool HLGtoPQ);
void Render(CD3DTexture& sourceTexture, CRect sourceRect, const CPoint points[4]
, CD3DTexture& target, unsigned range = 0, float contrast = 0.5f, float brightness = 0.5f);
void Render(CD3DTexture& sourceTexture, CRect sourceRect, CRect destRect
Expand All @@ -87,6 +87,8 @@ class COutputShader : public CWinShader
bool m_useLut = false;
bool m_useDithering = false;
bool m_toneMapping = false;
bool m_useHLGtoPQ = false;

bool m_hasDisplayMetadata = false;
bool m_hasLightMetadata = false;
unsigned m_sourceWidth = 0;
Expand Down
77 changes: 40 additions & 37 deletions xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,19 @@ bool CRendererBase::Configure(const VideoPicture& picture, float fps, unsigned o
m_renderOrientation = orientation;

m_lastHdr10 = {};
m_iCntMetaData = 0;
m_HdrType = HDR_TYPE::HDR_NONE_SDR;
m_useHLGtoPQ = false;
m_AutoSwitchHDR = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
DX::Windowing()->SETTING_WINSYSTEM_IS_HDR_DISPLAY) &&
DX::Windowing()->IsHDRDisplay();

// Auto switch HDR only if supported and "Settings/Player/Use HDR display capabilities" = ON
if (m_AutoSwitchHDR)
{
// Stream is HDR10 or HLG or Rec.2020 (wide color)
if (picture.color_primaries == AVCOL_PRI_BT2020)
// Stream is HDR10 or HLG
if (picture.color_primaries == AVCOL_PRI_BT2020 &&
(picture.color_transfer == AVCOL_TRC_SMPTE2084 ||
picture.color_transfer == AVCOL_TRC_ARIB_STD_B67))
{
if (!DX::Windowing()->IsHDROutput())
DX::Windowing()->ToggleHDR(); // Toggle disply HDR ON
Expand Down Expand Up @@ -412,7 +414,7 @@ void CRendererBase::UpdateVideoFilters()
if (!m_outputShader)
{
m_outputShader = std::make_shared<COutputShader>();
if (!m_outputShader->Create(m_cmsOn, m_useDithering, m_ditherDepth, UseToneMapping()))
if (!m_outputShader->Create(m_cmsOn, m_useDithering, m_ditherDepth, UseToneMapping(), m_useHLGtoPQ))
{
CLog::LogF(LOGDEBUG, "unable to create output shader.");
m_outputShader.reset();
Expand All @@ -434,7 +436,15 @@ void CRendererBase::CheckVideoParameters()
if (buf->hasLightMetadata || buf->hasDisplayMetadata && buf->displayMetadata.has_luminance)
toneMap = true;
}
if (toneMap != m_toneMapping || m_cmsOn != m_colorManager->IsEnabled())
bool reset = false;
if (m_HdrType == HDR_TYPE::HDR_HLG)
{
if (m_useHLGtoPQ != DX::Windowing()->IsHDROutput())
{
reset = true;
}
}
if (toneMap != m_toneMapping || m_cmsOn != m_colorManager->IsEnabled() || reset)
{
m_toneMapping = toneMap;
m_cmsOn = m_colorManager->IsEnabled();
Expand Down Expand Up @@ -513,7 +523,9 @@ DXGI_HDR_METADATA_HDR10 CRendererBase::GetDXGIHDR10MetaData(CRenderBuffer* rb)

void CRendererBase::ProcessHDR(CRenderBuffer* rb)
{
if (m_AutoSwitchHDR && rb->primaries == AVCOL_PRI_BT2020 && !DX::Windowing()->IsHDROutput())
if (m_AutoSwitchHDR && rb->primaries == AVCOL_PRI_BT2020 &&
(rb->color_transfer == AVCOL_TRC_SMPTE2084 || rb->color_transfer == AVCOL_TRC_ARIB_STD_B67) &&
!DX::Windowing()->IsHDROutput())
{
DX::Windowing()->ToggleHDR(); // Toggle display HDR ON
}
Expand All @@ -524,6 +536,7 @@ void CRendererBase::ProcessHDR(CRenderBuffer* rb)
m_lastHdr10 = {};
if (m_HdrType != HDR_TYPE::HDR_NONE_SDR)
m_HdrType = HDR_TYPE::HDR_NONE_SDR;
m_useHLGtoPQ = false;
return;
}

Expand All @@ -550,53 +563,43 @@ void CRendererBase::ProcessHDR(CRenderBuffer* rb)
m_HdrType = HDR_TYPE::HDR_HDR10;
m_lastHdr10 = hdr10;
}
m_iCntMetaData = 0;
}
// HLG
else if (rb->color_transfer == AVCOL_TRC_ARIB_STD_B67 && rb->primaries == AVCOL_PRI_BT2020)
{
if (m_HdrType != HDR_TYPE::HDR_HLG)
{
// Switch to HLG rendering
CLog::LogF(LOGINFO, "Switching to HLG rendering");
DX::Windowing()->SetHdrColorSpace(DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020);
// Windows 10 does not support HLG pass-through
// It's used HDR10 with dummy metadata and shaders to convert HLG transfer to PQ transfer
DXGI_HDR_METADATA_HDR10 hdr10 = {};
hdr10.RedPrimary[0] = 34000;
hdr10.RedPrimary[1] = 16000;
hdr10.GreenPrimary[0] = 13250;
hdr10.GreenPrimary[1] = 34500;
hdr10.BluePrimary[0] = 7500;
hdr10.BluePrimary[1] = 3000;
hdr10.WhitePoint[0] = 15635;
hdr10.WhitePoint[1] = 16450;
hdr10.MaxMasteringLuminance = 1000 * 10000;
hdr10.MinMasteringLuminance = 100;
DX::Windowing()->SetHdrMetaData(hdr10);
CLog::LogF(LOGINFO, "Switching to HDR rendering");
DX::Windowing()->SetHdrColorSpace(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
m_HdrType = HDR_TYPE::HDR_HLG;
m_useHLGtoPQ = true;
}
}
// Rec. 2020
else if (rb->primaries == AVCOL_PRI_BT2020)
{
if (m_HdrType != HDR_TYPE::HDR_REC2020)
{
// Switch to Rec.2020 rendering
CLog::LogF(LOGINFO, "Switching to Rec.2020 rendering");
DX::Windowing()->SetHdrColorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020);
m_HdrType = HDR_TYPE::HDR_REC2020;
}
}
// SDR
else
{
if (m_HdrType == HDR_TYPE::HDR_HDR10)
{
m_iCntMetaData++;
if (m_iCntMetaData > 60)
{
// If more than 60 frames are received without HDR10 metadata switch to SDR rendering
CLog::LogF(LOGINFO, "Switching to SDR rendering");
DX::Windowing()->SetHdrColorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
m_HdrType = HDR_TYPE::HDR_NONE_SDR;
m_iCntMetaData = 0;
m_lastHdr10 = {};
if (m_AutoSwitchHDR)
DX::Windowing()->ToggleHDR(); // Toggle display HDR OFF
}
}
if (m_HdrType == HDR_TYPE::HDR_HLG || m_HdrType == HDR_TYPE::HDR_REC2020)
if (m_HdrType == HDR_TYPE::HDR_HDR10 || m_HdrType == HDR_TYPE::HDR_HLG)
{
// Switch to SDR rendering
CLog::LogF(LOGINFO, "Switching to SDR rendering");
DX::Windowing()->SetHdrColorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
m_HdrType = HDR_TYPE::HDR_NONE_SDR;
m_lastHdr10 = {};
m_useHLGtoPQ = false;
if (m_AutoSwitchHDR)
DX::Windowing()->ToggleHDR(); // Toggle display HDR OFF
}
Expand Down
5 changes: 2 additions & 3 deletions xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ enum class HDR_TYPE : uint32_t
{
HDR_NONE_SDR = 0x00,
HDR_HDR10 = 0x01,
HDR_HLG = 0x02,
HDR_REC2020 = 0x03
HDR_HLG = 0x02
};

class CRenderBuffer
Expand Down Expand Up @@ -158,6 +157,7 @@ class CRendererBase
bool m_useDithering = false;
bool m_cmsOn = false;
bool m_clutLoaded = false;
bool m_useHLGtoPQ = false;

int m_iBufferIndex = 0;
int m_iNumBuffers = 0;
Expand All @@ -183,6 +183,5 @@ class CRendererBase

DXGI_HDR_METADATA_HDR10 m_lastHdr10 = {};
HDR_TYPE m_HdrType = HDR_TYPE::HDR_NONE_SDR;
int m_iCntMetaData = 0;
bool m_AutoSwitchHDR = false;
};
6 changes: 0 additions & 6 deletions xbmc/rendering/dx/DeviceResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,12 +1183,6 @@ void DX::DeviceResources::SetHdrColorSpace(const DXGI_COLOR_SPACE_TYPE colorSpac
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
cs = DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020;
break;
case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020:
cs = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020;
break;
case DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020:
cs = DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;
break;
}
}
if (SUCCEEDED(swapChain3->SetColorSpace1(cs)))
Expand Down

0 comments on commit 4cf3a2e

Please sign in to comment.