libobs-d3d11: Log display color space info

Add DXGI_COLOR_SPACE_TYPE and SDR white level when available for HDR
characteristics.

GetPathInfo/IsInternalVideoOutput functions were copied from MS docs.
master
jpark37 2022-01-06 01:13:57 -08:00 committed by Jim
parent e7cfaa0def
commit 83c89d06b5
2 changed files with 195 additions and 3 deletions

View File

@ -997,6 +997,180 @@ static bool GetMonitorTarget(const MONITORINFOEX &info,
return found;
}
static DXGI_COLOR_SPACE_TYPE GetColorSpace(IDXGIOutput *const output)
{
DXGI_COLOR_SPACE_TYPE space = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
ComPtr<IDXGIOutput6> output6;
HRESULT hr = output->QueryInterface(IID_PPV_ARGS(output6.Assign()));
if (SUCCEEDED(hr)) {
DXGI_OUTPUT_DESC1 desc1;
hr = output6->GetDesc1(&desc1);
if (SUCCEEDED(hr)) {
space = desc1.ColorSpace;
} else {
blog(LOG_WARNING,
"IDXGIOutput6::GetDesc1 failed: 0x%08lX", hr);
}
}
return space;
}
// Returns true if this is an integrated display panel e.g. the screen attached to tablets or laptops.
static bool IsInternalVideoOutput(
const DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY VideoOutputTechnologyType)
{
switch (VideoOutputTechnologyType) {
case DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL:
case DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED:
case DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED:
return TRUE;
default:
return FALSE;
}
}
// Note: Since an hmon can represent multiple monitors while in clone, this function as written will return
// the value for the internal monitor if one exists, and otherwise the highest clone-path priority.
static HRESULT GetPathInfo(_In_ PCWSTR pszDeviceName,
_Out_ DISPLAYCONFIG_PATH_INFO *pPathInfo)
{
HRESULT hr = S_OK;
UINT32 NumPathArrayElements = 0;
UINT32 NumModeInfoArrayElements = 0;
DISPLAYCONFIG_PATH_INFO *PathInfoArray = nullptr;
DISPLAYCONFIG_MODE_INFO *ModeInfoArray = nullptr;
do {
// In case this isn't the first time through the loop, delete the buffers allocated
delete[] PathInfoArray;
PathInfoArray = nullptr;
delete[] ModeInfoArray;
ModeInfoArray = nullptr;
hr = HRESULT_FROM_WIN32(GetDisplayConfigBufferSizes(
QDC_ONLY_ACTIVE_PATHS, &NumPathArrayElements,
&NumModeInfoArrayElements));
if (FAILED(hr)) {
break;
}
PathInfoArray = new (std::nothrow)
DISPLAYCONFIG_PATH_INFO[NumPathArrayElements];
if (PathInfoArray == nullptr) {
hr = E_OUTOFMEMORY;
break;
}
ModeInfoArray = new (std::nothrow)
DISPLAYCONFIG_MODE_INFO[NumModeInfoArrayElements];
if (ModeInfoArray == nullptr) {
hr = E_OUTOFMEMORY;
break;
}
hr = HRESULT_FROM_WIN32(QueryDisplayConfig(
QDC_ONLY_ACTIVE_PATHS, &NumPathArrayElements,
PathInfoArray, &NumModeInfoArrayElements, ModeInfoArray,
nullptr));
} while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
INT DesiredPathIdx = -1;
if (SUCCEEDED(hr)) {
// Loop through all sources until the one which matches the 'monitor' is found.
for (UINT PathIdx = 0; PathIdx < NumPathArrayElements;
++PathIdx) {
DISPLAYCONFIG_SOURCE_DEVICE_NAME SourceName = {};
SourceName.header.type =
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
SourceName.header.size = sizeof(SourceName);
SourceName.header.adapterId =
PathInfoArray[PathIdx].sourceInfo.adapterId;
SourceName.header.id =
PathInfoArray[PathIdx].sourceInfo.id;
hr = HRESULT_FROM_WIN32(
DisplayConfigGetDeviceInfo(&SourceName.header));
if (SUCCEEDED(hr)) {
if (wcscmp(pszDeviceName,
SourceName.viewGdiDeviceName) == 0) {
// Found the source which matches this hmonitor. The paths are given in path-priority order
// so the first found is the most desired, unless we later find an internal.
if (DesiredPathIdx == -1 ||
IsInternalVideoOutput(
PathInfoArray[PathIdx]
.targetInfo
.outputTechnology)) {
DesiredPathIdx = PathIdx;
}
}
}
}
}
if (DesiredPathIdx != -1) {
*pPathInfo = PathInfoArray[DesiredPathIdx];
} else {
hr = E_INVALIDARG;
}
delete[] PathInfoArray;
PathInfoArray = nullptr;
delete[] ModeInfoArray;
ModeInfoArray = nullptr;
return hr;
}
// Overloaded function accepts an HMONITOR and converts to DeviceName
static HRESULT GetPathInfo(HMONITOR hMonitor,
_Out_ DISPLAYCONFIG_PATH_INFO *pPathInfo)
{
HRESULT hr = S_OK;
// Get the name of the 'monitor' being requested
MONITORINFOEXW ViewInfo;
RtlZeroMemory(&ViewInfo, sizeof(ViewInfo));
ViewInfo.cbSize = sizeof(ViewInfo);
if (!GetMonitorInfoW(hMonitor, &ViewInfo)) {
// Error condition, likely invalid monitor handle, could log error
hr = HRESULT_FROM_WIN32(GetLastError());
}
if (SUCCEEDED(hr)) {
hr = GetPathInfo(ViewInfo.szDevice, pPathInfo);
}
return hr;
}
static ULONG GetSdrWhiteNits(HMONITOR monitor)
{
ULONG nits = 0;
DISPLAYCONFIG_PATH_INFO info;
if (SUCCEEDED(GetPathInfo(monitor, &info))) {
const DISPLAYCONFIG_PATH_TARGET_INFO &targetInfo =
info.targetInfo;
DISPLAYCONFIG_SDR_WHITE_LEVEL level;
DISPLAYCONFIG_DEVICE_INFO_HEADER &header = level.header;
header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
header.size = sizeof(level);
header.adapterId = targetInfo.adapterId;
header.id = targetInfo.id;
if (DisplayConfigGetDeviceInfo(&header) == ERROR_SUCCESS)
nits = (level.SDRWhiteLevel * 80) / 1000;
}
return nits;
}
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
{
UINT i;
@ -1030,18 +1204,36 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
target.monitorFriendlyDeviceName[0] = 0;
}
const char *space = "Unknown";
const DXGI_COLOR_SPACE_TYPE type = GetColorSpace(output);
switch (type) {
case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709:
space = "RGB_FULL_G22_NONE_P709";
break;
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
space = "RGB_FULL_G2084_NONE_P2020";
break;
default:
blog(LOG_WARNING,
"Unexpected DXGI_COLOR_SPACE_TYPE: %u",
(unsigned)type);
}
const RECT &rect = desc.DesktopCoordinates;
const ULONG nits = GetSdrWhiteNits(desc.Monitor);
blog(LOG_INFO,
"\t output %u: "
"pos={%d, %d}, "
"size={%d, %d}, "
"attached=%s, "
"space=%s, "
"sdr_white_nits=%lu, "
"refresh=%u, "
"name=%ls",
i, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top,
desc.AttachedToDesktop ? "true" : "false", refresh,
target.monitorFriendlyDeviceName);
desc.AttachedToDesktop ? "true" : "false", space, nits,
refresh, target.monitorFriendlyDeviceName);
}
}

View File

@ -25,7 +25,7 @@
#include <memory>
#include <windows.h>
#include <dxgi1_5.h>
#include <dxgi1_6.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>