Skip to content

Commit

Permalink
Merge pull request #24689 from CrystalP/fix-wcg-detection
Browse files Browse the repository at this point in the history
[windows] Identify SDR WCG screens as non HDR-capable
  • Loading branch information
CrystalP committed Jun 22, 2024
2 parents c3e1d12 + bfe89ee commit 6818de7
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 65 deletions.
2 changes: 1 addition & 1 deletion cmake/scripts/windows/ArchSetup.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Minimum SDK version we support
set(VS_MINIMUM_SDK_VERSION 10.0.18362.0)
set(VS_MINIMUM_SDK_VERSION 10.0.22621.0)

if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS VS_MINIMUM_SDK_VERSION)
message(FATAL_ERROR "Detected Windows SDK version is ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}.\n"
Expand Down
2 changes: 1 addition & 1 deletion cmake/scripts/windowsstore/ArchSetup.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Minimum SDK version we support
set(VS_MINIMUM_SDK_VERSION 10.0.18362.0)
set(VS_MINIMUM_SDK_VERSION 10.0.22621.0)

if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS VS_MINIMUM_SDK_VERSION)
message(FATAL_ERROR "Detected Windows SDK version is ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}.\n"
Expand Down
3 changes: 2 additions & 1 deletion docs/README.Windows.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![Kodi Logo](resources/banner_slim.png)

# Windows build guide
This guide has been tested with Windows 10 Pro x64, version 21H2, build 19044.1415. Please read it in full before you proceed to familiarize yourself with the build procedure.
This guide has been tested with Windows 10 Pro x64, version 22H2, build 19045.4529. Please read it in full before you proceed to familiarize yourself with the build procedure.

## Table of Contents
1. **[Document conventions](#1-document-conventions)**
Expand Down Expand Up @@ -83,6 +83,7 @@ Default options are fine.
Start the Visual Studio installer and click **Workloads** select
* Under **Desktop & Mobile** section select
* `Desktop development with C++`
* Select the optional element Windows 11 SDK (10.0.22621.0)
* `Universal Windows Platform development` (if compiling for UWP or UWP-ARM)

Click in **Individual components** select
Expand Down
1 change: 1 addition & 0 deletions xbmc/HDRStatus.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

enum class HDR_STATUS
{
HDR_UNKNOWN = -2,
HDR_TOGGLE_FAILED = -1,
HDR_UNSUPPORTED = 0,
HDR_OFF = 1,
Expand Down
4 changes: 3 additions & 1 deletion xbmc/platform/win10/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(SOURCES CPUInfoWin10.cpp
../win32/MemUtils.cpp
../win32/pch.cpp
../win32/WIN32Util.cpp
../win32/WinRtUtil.cpp
../win32/XTimeUtils.cpp)

set(HEADERS AsyncHelpers.h
Expand All @@ -29,6 +30,7 @@ set(HEADERS AsyncHelpers.h
../win32/PlatformDefs.h
../win32/resource.h
../win32/unistd.h
../win32/WIN32Util.h)
../win32/WIN32Util.h
../win32/WinRtUtil.h)

core_add_library(platform_win10)
4 changes: 3 additions & 1 deletion xbmc/platform/win32/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(SOURCES CharsetConverter.cpp
PlatformWin32.cpp
WIN32Util.cpp
WindowHelper.cpp
WinRtUtil.cpp
XTimeUtils.cpp)

set(HEADERS CharsetConverter.h
Expand All @@ -27,6 +28,7 @@ set(HEADERS CharsetConverter.h
resource.h
unistd.h
WIN32Util.h
WindowHelper.h)
WindowHelper.h
WinRtUtil.h)

core_add_library(platform_win32)
75 changes: 30 additions & 45 deletions xbmc/platform/win32/WIN32Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "CompileInfo.h"
#include "ServiceBroker.h"
#include "Util.h"
#include "WinRtUtil.h"
#include "WindowHelper.h"
#include "guilib/LocalizeStrings.h"
#include "my_ntddscsi.h"
Expand Down Expand Up @@ -1347,53 +1348,13 @@ HDR_STATUS CWIN32Util::ToggleWindowsHDR(DXGI_MODE_DESC& modeDesc)
return status;
}

HDR_STATUS CWIN32Util::GetWindowsHDRStatus()
HDR_STATUS CWIN32Util::GetWindowsHDRStatusWin32()
{
HDR_STATUS status = HDR_STATUS::HDR_UNKNOWN;

#ifdef TARGET_WINDOWS_DESKTOP
bool advancedColorSupported = false;
bool advancedColorEnabled = false;
HDR_STATUS status = HDR_STATUS::HDR_UNSUPPORTED;

#ifdef TARGET_WINDOWS_STORE
auto displayInformation = DisplayInformation::GetForCurrentView();

if (displayInformation)
{
auto advancedColorInfo = displayInformation.GetAdvancedColorInfo();

if (advancedColorInfo)
{
if (advancedColorInfo.CurrentAdvancedColorKind() == AdvancedColorKind::HighDynamicRange)
{
advancedColorSupported = true;
advancedColorEnabled = true;
}
}
}
// Try to find out if the display supports HDR even if Windows HDR switch is OFF
if (!advancedColorEnabled)
{
auto displayManager = DisplayManager::Create(DisplayManagerOptions::None);

if (displayManager)
{
auto targets = displayManager.GetCurrentTargets();

for (const auto& target : targets)
{
if (target.IsConnected())
{
auto displayMonitor = target.TryGetMonitor();
if (displayMonitor.MaxLuminanceInNits() >= 400.0f)
{
advancedColorSupported = true;
break;
}
}
}
displayManager.Close();
}
}
#else
uint32_t pathCount = 0;
uint32_t modeCount = 0;

Expand Down Expand Up @@ -1451,7 +1412,6 @@ HDR_STATUS CWIN32Util::GetWindowsHDRStatus()
}
}
}
#endif

if (!advancedColorSupported)
{
Expand All @@ -1466,10 +1426,35 @@ HDR_STATUS CWIN32Util::GetWindowsHDRStatus()
CLog::LogF(LOGDEBUG, "Display is HDR capable and current HDR status is {}",
advancedColorEnabled ? "ON" : "OFF");
}
#endif // TARGET_WINDOWS_DESKTOP

return status;
}

HDR_STATUS CWIN32Util::GetWindowsHDRStatus()
{
HDR_STATUS status = HDR_STATUS::HDR_UNKNOWN;

#ifdef TARGET_WINDOWS_STORE
if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::Xbox &&
HDR_STATUS::HDR_UNKNOWN != (status = CWinRtUtil::GetWindowsHDRStatus()))
return status;

// Not Xbox or detection failure: fallback to traditional UWP method
status = CWinRtUtil::GetWindowsHDRStatusUWP();
return status == HDR_STATUS::HDR_UNKNOWN ? HDR_STATUS::HDR_UNSUPPORTED : status;
#else
// WinRT detection available for Win 11 22621 and above.
if (CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin11_22H2) &&
HDR_STATUS::HDR_UNKNOWN != (status = CWinRtUtil::GetWindowsHDRStatus()))
return status;

// Not Win11 or detection failure: fallback to traditional Win32 method
status = GetWindowsHDRStatusWin32();
return status == HDR_STATUS::HDR_UNKNOWN ? HDR_STATUS::HDR_UNSUPPORTED : status;
#endif
}

/*!
* \brief Retrieve from the system the max luminance of SDR content in HDR.
*
Expand Down
3 changes: 3 additions & 0 deletions xbmc/platform/win32/WIN32Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,7 @@ class CWIN32Util
* Undefined results when the strings are not formatted properly.
*/
static bool IsDriverVersionAtLeast(const std::string& version1, const std::string& version2);

private:
static HDR_STATUS GetWindowsHDRStatusWin32();
};
202 changes: 202 additions & 0 deletions xbmc/platform/win32/WinRtUtil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Copyright (C) 2024 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.
*/

#include "WinRtUtil.h"

#include "rendering/dx/DirectXHelper.h"
#include "utils/SystemInfo.h"
#include "utils/log.h"

#ifdef TARGET_WINDOWS_DESKTOP
#include <Windows.Graphics.Display.Interop.h>

#else
#include <winrt/Windows.Devices.Display.Core.h>

using namespace winrt::Windows::Devices::Display::Core;
#endif

#include <winrt/Windows.Graphics.Display.h>

using namespace winrt::Windows::Graphics::Display;

#ifdef TARGET_WINDOWS_DESKTOP
extern HWND g_hWnd;
#endif

static constexpr std::string_view AdvancedColorKindToString(AdvancedColorKind kind)
{
switch (kind)
{
case AdvancedColorKind::StandardDynamicRange:
return "SDR";
case AdvancedColorKind::WideColorGamut:
return "WCG";
case AdvancedColorKind::HighDynamicRange:
return "HDR";
default:
return "unknown";
}
}

static void LogAdvancedColorInfo(AdvancedColorInfo colorInfo)
{
std::string availableKinds;
static constexpr std::array<AdvancedColorKind, 3> kinds{AdvancedColorKind::StandardDynamicRange,
AdvancedColorKind::WideColorGamut,
AdvancedColorKind::HighDynamicRange};

for (const AdvancedColorKind& kind : kinds)
{
if (colorInfo.IsAdvancedColorKindAvailable(kind))
availableKinds.append(AdvancedColorKindToString(kind)).append(" ");
}

CLog::LogF(LOGDEBUG, "Current advanced color kind: {}, supported kinds: {}",
AdvancedColorKindToString(colorInfo.CurrentAdvancedColorKind()), availableKinds);
}

HDR_STATUS CWinRtUtil::GetWindowsHDRStatus()
{
DisplayInformation displayInformation{nullptr};

#ifdef TARGET_WINDOWS_STORE
displayInformation = DisplayInformation::GetForCurrentView();

if (!displayInformation)
{
CLog::LogF(LOGERROR, "unable to retrieve DisplayInformation.");
return HDR_STATUS::HDR_UNKNOWN;
}
#else
auto factory{
winrt::try_get_activation_factory<DisplayInformation, IDisplayInformationStaticsInterop>()};

if (!factory)
{
CLog::LogF(LOGERROR,
"unable to activate IDisplayInformationStaticsInterop. Windows version too low?");
return HDR_STATUS::HDR_UNKNOWN;
}

HMONITOR hm{};
if (g_hWnd)
{
RECT rect{};

if (FALSE == GetWindowRect(g_hWnd, &rect))
{
CLog::LogF(LOGERROR, "unable to retrieve window rect, error {}",
DX::GetErrorDescription(GetLastError()));
return HDR_STATUS::HDR_UNKNOWN;
}

hm = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);

if (hm == NULL)
{
CLog::LogF(LOGERROR, "unable to retrieve monitor intersecting with application window");
return HDR_STATUS::HDR_UNKNOWN;
}
}
else
{
POINT point{};

hm = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);

if (hm == NULL)
{
CLog::LogF(LOGERROR, "unable to retrieve primary monitor");
return HDR_STATUS::HDR_UNKNOWN;
}
}

HRESULT hr = factory->GetForMonitor(hm, winrt::guid_of<DisplayInformation>(),
winrt::put_abi(displayInformation));
if (FAILED(hr))
{
CLog::LogF(LOGERROR, "unable to retrieve DisplayInformation for window, error {}",
DX::GetErrorDescription(hr));
return HDR_STATUS::HDR_UNKNOWN;
}
#endif

AdvancedColorInfo colorInfo{displayInformation.GetAdvancedColorInfo()};

if (!colorInfo)
{
CLog::LogF(LOGERROR, "unable to retrieve advanced color info");
return HDR_STATUS::HDR_UNKNOWN;
}

LogAdvancedColorInfo(colorInfo);

if (colorInfo.CurrentAdvancedColorKind() == AdvancedColorKind::HighDynamicRange)
return HDR_STATUS::HDR_ON;

// IsAdvancedColorKindAvailable works for desktop Windows 11 22H2+ and Xbox
if (colorInfo.IsAdvancedColorKindAvailable(AdvancedColorKind::HighDynamicRange))
return HDR_STATUS::HDR_OFF;
else
return HDR_STATUS::HDR_UNSUPPORTED;
}

HDR_STATUS CWinRtUtil::GetWindowsHDRStatusUWP()
{
#ifdef TARGET_WINDOWS_STORE
// Legacy detection, useful for UWP desktop at this point
DisplayInformation displayInformation = DisplayInformation::GetForCurrentView();

if (!displayInformation)
{
CLog::LogF(LOGERROR, "unable to retrieve DisplayInformation.");
return HDR_STATUS::HDR_UNKNOWN;
}

AdvancedColorInfo colorInfo{displayInformation.GetAdvancedColorInfo()};

if (!colorInfo)
{
CLog::LogF(LOGERROR, "unable to retrieve advanced color info");
return HDR_STATUS::HDR_UNKNOWN;
}

if (colorInfo.CurrentAdvancedColorKind() == AdvancedColorKind::HighDynamicRange)
return HDR_STATUS::HDR_ON;

// Detects any hdr-capable screen connected to the system, not necessarily the one that contains
// the Kodi window
bool hdrSupported{false};
auto displayManager = DisplayManager::Create(DisplayManagerOptions::None);

if (displayManager)
{
auto targets = displayManager.GetCurrentTargets();

for (const auto& target : targets)
{
if (target.IsConnected())
{
auto displayMonitor = target.TryGetMonitor();
if (displayMonitor.MaxLuminanceInNits() >= 400.0f)
{
hdrSupported = true;
break;
}
}
}
displayManager.Close();
}

if (hdrSupported)
return HDR_STATUS::HDR_OFF;
#endif // TARGET_WINDOWS_STORE

return HDR_STATUS::HDR_UNSUPPORTED;
}
Loading

0 comments on commit 6818de7

Please sign in to comment.