Skip to content

Commit

Permalink
Windows HDR passthrough support
Browse files Browse the repository at this point in the history
  • Loading branch information
thexai committed Jun 18, 2020
1 parent de0a960 commit e0c4fff
Show file tree
Hide file tree
Showing 27 changed files with 906 additions and 140 deletions.
1 change: 1 addition & 0 deletions system/keymaps/keyboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
<k mod="ctrl,shift">ReloadKeymaps</k>
<d mod="ctrl,shift">ToggleDebug</d>
<r mod="ctrl,shift">ToggleDirtyRegionVisualization</r>
<f11>HDRToggle</f11>
</keyboard>
</global>
<LoginScreen>
Expand Down
80 changes: 54 additions & 26 deletions xbmc/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,45 @@
* See LICENSES/README.md for more information.
*/

#include "network/EventServer.h"
#include "network/Network.h"
#include "threads/SystemClock.h"
#include "Application.h"
#include "AppParamParser.h"

#include "AppInboundProtocol.h"
#include "dialogs/GUIDialogBusy.h"
#include "events/EventLog.h"
#include "events/NotificationEvent.h"
#include "interfaces/builtins/Builtins.h"
#include "utils/JobManager.h"
#include "utils/Variant.h"
#include "AppParamParser.h"
#include "Autorun.h"
#include "GUIInfoManager.h"
#include "HDRStatus.h"
#include "LangInfo.h"
#include "utils/Screenshot.h"
#include "Util.h"
#include "PlayListPlayer.h"
#include "URL.h"
#include "guilib/GUIComponent.h"
#include "guilib/TextureManager.h"
#include "cores/IPlayer.h"
#include "Util.h"
#include "addons/Skin.h"
#include "addons/VFSEntry.h"
#include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
#include "cores/IPlayer.h"
#include "cores/playercorefactory/PlayerCoreFactory.h"
#include "PlayListPlayer.h"
#include "Autorun.h"
#include "video/Bookmark.h"
#include "video/VideoLibraryQueue.h"
#include "music/MusicLibraryQueue.h"
#include "dialogs/GUIDialogBusy.h"
#include "dialogs/GUIDialogKaiToast.h"
#include "events/EventLog.h"
#include "events/NotificationEvent.h"
#include "guilib/GUIColorManager.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIControlProfiler.h"
#include "utils/LangCodeExpander.h"
#include "GUIInfoManager.h"
#include "playlists/PlayListFactory.h"
#include "guilib/GUIFontManager.h"
#include "guilib/GUIColorManager.h"
#include "guilib/StereoscopicsManager.h"
#include "addons/Skin.h"
#include "addons/VFSEntry.h"
#include "guilib/TextureManager.h"
#include "interfaces/builtins/Builtins.h"
#include "interfaces/generic/ScriptInvocationManager.h"
#include "music/MusicLibraryQueue.h"
#include "network/EventServer.h"
#include "network/Network.h"
#include "playlists/PlayListFactory.h"
#include "threads/SystemClock.h"
#include "utils/JobManager.h"
#include "utils/LangCodeExpander.h"
#include "utils/Screenshot.h"
#include "utils/Variant.h"
#include "video/Bookmark.h"
#include "video/VideoLibraryQueue.h"
#ifdef HAS_PYTHON
#include "interfaces/python/XBPython.h"
#endif
Expand Down Expand Up @@ -497,6 +500,12 @@ bool CApplication::Create(const CAppParamParser &params)
(CWIN32Util::IsCurrentUserLocalAdministrator() == TRUE) ? "administrator"
: "restricted");
CLog::Log(LOGINFO, "Aero is %s", (g_sysinfo.IsAeroDisabled() == true) ? "disabled" : "enabled");
HDR_STATUS hdrStatus = CWIN32Util::GetWindowsHDRStatus();
if (hdrStatus == HDR_STATUS::HDR_UNSUPPORTED)
CLog::Log(LOGINFO, "Display is not HDR capable or cannot be detected");
else
CLog::Log(LOGINFO, "Display HDR capable is detected and Windows HDR switch is %s",
(hdrStatus == HDR_STATUS::HDR_ON) ? "ON" : "OFF");
#endif
#if defined(TARGET_ANDROID)
CLog::Log(
Expand Down Expand Up @@ -1656,6 +1665,25 @@ bool CApplication::OnAction(const CAction &action)
CScreenShot::TakeScreenshot();
return true;
}
// Display HDR : toggle HDR on/off
if (action.GetID() == ACTION_HDR_TOGGLE)
{
HDR_STATUS hdrStatus = CServiceBroker::GetWinSystem()->ToggleHDR();

if (hdrStatus == HDR_STATUS::HDR_OFF)
{
CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::eMessageType::Info, "HDR is OFF",
"Display HDR is Off", TOAST_DISPLAY_TIME, true,
TOAST_DISPLAY_TIME);
}
else if (hdrStatus == HDR_STATUS::HDR_ON)
{
CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::eMessageType::Info, "HDR is ON",
"Display HDR is On", TOAST_DISPLAY_TIME, true,
TOAST_DISPLAY_TIME);
}
return true;
}
// built in functions : execute the built-in
if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
{
Expand Down
1 change: 1 addition & 0 deletions xbmc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ set(HEADERS AppParamParser.h
GUILargeTextureManager.h
GUIPassword.h
GUIUserMessages.h
HDRStatus.h
IFileItemListModifier.h
IProgressCallback.h
InfoScanner.h
Expand Down
17 changes: 17 additions & 0 deletions xbmc/HDRStatus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/

#pragma once

enum class HDR_STATUS : int
{
HDR_TOGGLE_FAILED = -1,
HDR_UNSUPPORTED = 0,
HDR_OFF = 1,
HDR_ON = 2
};
50 changes: 28 additions & 22 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,32 +281,38 @@ bool CContext::CreateContext()
ComPtr<ID3D11DeviceContext> pD3DDeviceContext;
m_sharingAllowed = DX::DeviceResources::Get()->DoesTextureSharingWork();

// Workaround for Nvidia stuttering on 4K HDR playback
// Some tests/feedback on Windows 10 2004 / NV driver 446.14
// Not needed: GTX 1650, GTX 1060, ...
// Needed: RTX 2080 Ti, ...
if (m_sharingAllowed &&
CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_disableDXVAdiscreteDecoding)
{
m_sharingAllowed = false;
CLog::LogF(LOGWARNING, "disabled discrete d3d11va device for decoding due advancedsettings "
"option 'disableDXVAdiscretedecoder'.");
}

if (m_sharingAllowed)
{
CLog::LogF(LOGWARNING, "creating discrete d3d11va device for decoding.");

D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};

hr = D3D11CreateDevice(
DX::DeviceResources::Get()->GetAdapter(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&pD3DDevice,
nullptr,
&pD3DDeviceContext);
std::vector<D3D_FEATURE_LEVEL> featureLevels;
if (CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin10))
featureLevels.push_back(D3D_FEATURE_LEVEL_12_0);
if (CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin8))
featureLevels.push_back(D3D_FEATURE_LEVEL_11_1);
featureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
featureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
featureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
featureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
featureLevels.push_back(D3D_FEATURE_LEVEL_9_2);
featureLevels.push_back(D3D_FEATURE_LEVEL_9_1);

hr = D3D11CreateDevice(DX::DeviceResources::Get()->GetAdapter(), D3D_DRIVER_TYPE_UNKNOWN,
nullptr, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, featureLevels.data(),
featureLevels.size(), D3D11_SDK_VERSION, &pD3DDevice, nullptr,
&pD3DDeviceContext);

if (SUCCEEDED(hr))
{
Expand Down
100 changes: 48 additions & 52 deletions xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@
#define DEFAULT_STREAM_INDEX (0)

#include "DXVAHD.h"
#include "platform/win32/WIN32Util.h"
#include "rendering/dx/RenderContext.h"
#include "rendering/dx/DeviceResources.h"
#include "VideoRenderers/RenderManager.h"

#include "VideoRenderers/RenderFlags.h"
#include "VideoRenderers/RenderManager.h"
#include "VideoRenderers/windows/RendererBase.h"
#include "rendering/dx/RenderContext.h"
#include "utils/log.h"

#include <Windows.h>
#include <dxgi1_5.h>
#include <d3d11_4.h>
#include <dxgi1_5.h>

using namespace DXVA;
using namespace Microsoft::WRL;
Expand All @@ -36,12 +35,6 @@ do { \
} \
} while(0);

template<typename T>
T from_rational(uint64_t default_factor, AVRational rat)
{
return static_cast<T>(default_factor * rat.num / rat.den);
}

CProcessorHD::CProcessorHD()
{
DX::Windowing()->Register(this);
Expand Down Expand Up @@ -146,7 +139,7 @@ bool CProcessorHD::InitProcessor()
CLog::LogF(LOGDEBUG, "video processor has %#x input format caps.", m_vcaps.InputFormatCaps);
CLog::LogF(LOGDEBUG, "video processor has %d max input streams.", m_vcaps.MaxInputStreams);
CLog::LogF(LOGDEBUG, "video processor has %d max stream states.", m_vcaps.MaxStreamStates);
if ((m_bSupportHDR10 = m_vcaps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10))
if (m_vcaps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10)
CLog::LogF(LOGDEBUG, "video processor supports HDR10.");

if (0 != (m_vcaps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_LEGACY))
Expand Down Expand Up @@ -331,7 +324,7 @@ ID3D11VideoProcessorInputView* CProcessorHD::GetInputView(CRenderBuffer* view) c
return inputView.Detach();
}

DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpace(CRenderBuffer* view, bool supportHDR)
DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpaceSource(CRenderBuffer* view, bool supportHDR)
{
// RGB
if (view->color_space == AVCOL_SPC_RGB)
Expand Down Expand Up @@ -364,11 +357,14 @@ DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpace(CRenderBuffer* view, bool
// UHDTV
if (view->primaries == AVCOL_PRI_BT2020)
{
if (view->color_transfer == AVCOL_TRC_SMPTEST2084 && supportHDR) // HDR
if (view->color_transfer == AVCOL_TRC_SMPTEST2084 && supportHDR) // HDR10
// Could also be:
// DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;

if (view->color_transfer == AVCOL_TRC_ARIB_STD_B67) // HLG
return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;

if (view->full_range)
return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;

Expand Down Expand Up @@ -397,6 +393,38 @@ DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpace(CRenderBuffer* view, bool
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
}

DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpaceTarget(CRenderBuffer* view)
{
DXGI_COLOR_SPACE_TYPE color;

// HDR10
if (view->color_transfer == AVCOL_TRC_SMPTE2084 && DX::Windowing()->IsHDROutput())
{
color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
// HLG
else if (view->color_transfer == AVCOL_TRC_ARIB_STD_B67 && view->primaries == AVCOL_PRI_BT2020)
{
color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020
: DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020;
}
// Rec.2020
else if (view->color_transfer != AVCOL_TRC_SMPTE2084 && 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;
}
// SRD - Default
else
{
color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
}

return color;
}

bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, CRenderBuffer** views, DWORD flags, UINT frameIdx, UINT rotation, float contrast, float brightness)
{
CSingleLock lock(m_section);
Expand Down Expand Up @@ -504,47 +532,15 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, CRenderB
ComPtr<ID3D11VideoContext1> videoCtx1;
if (SUCCEEDED(m_pVideoContext.As(&videoCtx1)))
{
const DXGI_COLOR_SPACE_TYPE source_color = GetDXGIColorSpace(views[2], m_bSupportHDR10);
const DXGI_COLOR_SPACE_TYPE target_color = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
const DXGI_COLOR_SPACE_TYPE sourceColor =
GetDXGIColorSpaceSource(views[2], DX::Windowing()->IsHDROutput());
const DXGI_COLOR_SPACE_TYPE targetColor = GetDXGIColorSpaceTarget(views[2]);

videoCtx1->VideoProcessorSetStreamColorSpace1(m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX, source_color);
videoCtx1->VideoProcessorSetOutputColorSpace1(m_pVideoProcessor.Get(), target_color);
videoCtx1->VideoProcessorSetStreamColorSpace1(m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX,
sourceColor);
videoCtx1->VideoProcessorSetOutputColorSpace1(m_pVideoProcessor.Get(), targetColor);
// makes target available for processing in shaders
videoCtx1->VideoProcessorSetOutputShaderUsage(m_pVideoProcessor.Get(), 1);

if (m_bSupportHDR10)
{
ComPtr<ID3D11VideoContext2> videoCtx2;
if (SUCCEEDED(m_pVideoContext.As(&videoCtx2)) && views[2]->hasDisplayMetadata)
{
DXGI_HDR_METADATA_HDR10 hdr10 = {};
hdr10.WhitePoint[0] = from_rational<uint16_t>(50000, views[2]->displayMetadata.white_point[0]);
hdr10.WhitePoint[1] = from_rational<uint16_t>(50000, views[2]->displayMetadata.white_point[1]);
if (views[2]->displayMetadata.has_primaries)
{
hdr10.RedPrimary[0] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[0][0]);
hdr10.RedPrimary[1] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[0][1]);
hdr10.GreenPrimary[0] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[1][0]);
hdr10.GreenPrimary[1] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[1][1]);
hdr10.BluePrimary[0] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[2][0]);
hdr10.BluePrimary[1] = from_rational<uint16_t>(50000, views[2]->displayMetadata.display_primaries[2][1]);
}
if (views[2]->displayMetadata.has_luminance)
{
hdr10.MinMasteringLuminance = from_rational<uint32_t>(10000, views[2]->displayMetadata.min_luminance);
hdr10.MaxMasteringLuminance = from_rational<uint32_t>(10000, views[2]->displayMetadata.max_luminance);
}
if (views[2]->hasLightMetadata)
{
hdr10.MaxContentLightLevel = static_cast<uint16_t>(views[2]->lightMetadata.MaxCLL);
hdr10.MaxFrameAverageLightLevel = static_cast<uint16_t>(views[2]->lightMetadata.MaxFALL);
}
videoCtx2->VideoProcessorSetStreamHDRMetaData(m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX,
DXGI_HDR_METADATA_TYPE_HDR10, sizeof(hdr10), &hdr10);
}
}
}
else
{
Expand Down
3 changes: 2 additions & 1 deletion xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class CProcessorHD : public ID3DResource
void OnCreateDevice() override {}
void OnDestroyDevice(bool) override { CSingleLock lock(m_section); UnInit(); }

static DXGI_COLOR_SPACE_TYPE GetDXGIColorSpace(CRenderBuffer*, bool);
static DXGI_COLOR_SPACE_TYPE GetDXGIColorSpaceSource(CRenderBuffer* view, bool supportHDR);
static DXGI_COLOR_SPACE_TYPE GetDXGIColorSpaceTarget(CRenderBuffer* view);

protected:
bool ReInit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "VideoRenderers/windows/RendererBase.h"
#include "cores/VideoPlayer/VideoRenderers/VideoShaders/dither.h"
#include "filesystem/File.h"
#include "rendering/dx/DeviceResources.h"
#include "rendering/dx/RenderContext.h"
#include "utils/MemUtils.h"
#include "utils/log.h"
Expand Down Expand Up @@ -228,7 +227,7 @@ bool COutputShader::Create(bool useLUT, bool useDithering, int ditherDepth, bool
{
m_useLut = useLUT;
m_ditherDepth = ditherDepth;
m_toneMapping = toneMapping;
m_toneMapping = toneMapping && !DX::Windowing()->IsHDROutput();

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

Expand Down
Loading

0 comments on commit e0c4fff

Please sign in to comment.