From c5923b9b4d7ea005482c01baf41fac7a60c64fdd Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 22 Oct 2023 17:38:42 +1100 Subject: [PATCH] [host] dxgi: obtain HDR color space and monitor information --- host/platform/Windows/capture/DXGI/src/dxgi.c | 129 +++++++++++++++++- .../Windows/capture/DXGI/src/dxgi_capture.h | 3 + host/platform/Windows/capture/DXGI/src/util.c | 40 ++++++ 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/host/platform/Windows/capture/DXGI/src/dxgi.c b/host/platform/Windows/capture/DXGI/src/dxgi.c index 00d04df3..a38064a5 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/host/platform/Windows/capture/DXGI/src/dxgi.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,109 @@ static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostP return true; } +static bool dxgi_getDisplayPathInfo(HMONITOR monitor, + DISPLAYCONFIG_PATH_INFO * info) +{ + bool result = false; + UINT32 numPath, numMode; + + MONITORINFOEXW viewInfo = { .cbSize = sizeof(viewInfo) }; + if (!GetMonitorInfoW(monitor, (MONITORINFO*)&viewInfo)) + { + DEBUG_ERROR("Failed to get the monitor info"); + goto err; + } + +err_retry: + if (FAILED(GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, &numMode))) + goto err; + + DISPLAYCONFIG_PATH_INFO * pathInfo = calloc(sizeof(*pathInfo), numPath); + if (!pathInfo) + goto err_mem_pathInfo; + + DISPLAYCONFIG_MODE_INFO * modeInfo = calloc(sizeof(*modeInfo), numMode); + if (!modeInfo) + goto err_mem_modeInfo; + + LONG status = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, + &numPath, pathInfo, + &numMode, modeInfo, + NULL); + + if (status != ERROR_SUCCESS) + { + if (status == ERROR_INSUFFICIENT_BUFFER) + { + free(modeInfo); + free(pathInfo); + goto err_retry; + } + + DEBUG_ERROR("QueryDisplayConfig failed with 0x%lx", status); + goto err_queryDisplay; + } + + for(unsigned i = 0; i < numPath; ++i) + { + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = + { + .header = + { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, + .size = sizeof(sourceName), + .adapterId = pathInfo[i].sourceInfo.adapterId, + .id = pathInfo[i].sourceInfo.id, + } + }; + + if (FAILED(DisplayConfigGetDeviceInfo(&sourceName.header))) + continue; + + if (wcscmp(viewInfo.szDevice, sourceName.viewGdiDeviceName) != 0) + continue; + + *info = pathInfo[i]; + result = true; + break; + } + +err_queryDisplay: + free(modeInfo); + +err_mem_modeInfo: + free(pathInfo); + +err_mem_pathInfo: + +err: + return result; +} + +static float dxgi_getSDRWhiteLevel(HMONITOR monitor) +{ + float nits = 80.0f; + DISPLAYCONFIG_PATH_INFO info; + if (!dxgi_getDisplayPathInfo(monitor, &info)) + return nits; + + DISPLAYCONFIG_SDR_WHITE_LEVEL level = + { + .header = + { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL, + .size = sizeof(level), + .adapterId = info.targetInfo.adapterId, + .id = info.targetInfo.id, + } + }; + + if (SUCCEEDED(DisplayConfigGetDeviceInfo(&level.header))) + nits = level.SDRWhiteLevel / 1000.0f * 80.0f; + + return nits; +} + static bool dxgi_init(void) { DEBUG_ASSERT(this); @@ -590,6 +694,24 @@ next_output: IDXGIOutput5_Release(output5); goto fail; } + + IDXGIOutput6 * output6 = NULL; + status = IDXGIOutput_QueryInterface(this->output, &IID_IDXGIOutput6, (void **)&output6); + if (SUCCEEDED(status)) + { + DXGI_OUTPUT_DESC1 desc1; + IDXGIOutput6_GetDesc1(output6, &desc1); + this->dxgiColorSpace = desc1.ColorSpace; + this->sdrWhiteLevel = dxgi_getSDRWhiteLevel(desc1.Monitor); + + DEBUG_INFO("Bits Per Color : %u" , desc1.BitsPerColor); + DEBUG_INFO("Color Space : %s" , GetDXGIColorSpaceTypeStr(this->dxgiColorSpace)); + DEBUG_INFO("Min/Max Luminance : %f/%f", desc1.MinLuminance, desc1.MaxLuminance); + DEBUG_INFO("Frame Luminance : %f" , desc1.MaxFullFrameLuminance); + DEBUG_INFO("SDR White Level : %f" , this->sdrWhiteLevel); + IDXGIOutput6_Release(output6); + } + IDXGIOutput5_Release(output5); } @@ -645,12 +767,15 @@ next_output: break; case DXGI_FORMAT_R10G10B10A2_UNORM: - this->format = CAPTURE_FMT_RGBA10_HDR; + if (this->dxgiColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) + this->format = CAPTURE_FMT_RGBA10_HDR; + else + this->format = CAPTURE_FMT_RGBA10_SDR; break; case DXGI_FORMAT_R16G16B16A16_FLOAT: this->format = CAPTURE_FMT_RGBA16F; - this->bpp = 8; + this->bpp = 8; break; default: diff --git a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h index 892de7e1..c2d2e8a3 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h +++ b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h @@ -86,6 +86,8 @@ struct DXGIInterface atomic_int texReady; bool needsRelease; DXGI_FORMAT dxgiFormat; + DXGI_COLOR_SPACE_TYPE dxgiColorSpace; + float sdrWhiteLevel; struct DXGICopyBackend * backend; CaptureGetPointerBuffer getPointerBufferFn; @@ -121,3 +123,4 @@ struct DXGICopyBackend }; const char * GetDXGIFormatStr(DXGI_FORMAT format); +const char * GetDXGIColorSpaceTypeStr(DXGI_COLOR_SPACE_TYPE type); diff --git a/host/platform/Windows/capture/DXGI/src/util.c b/host/platform/Windows/capture/DXGI/src/util.c index 45a3e1d5..b67c4d0a 100644 --- a/host/platform/Windows/capture/DXGI/src/util.c +++ b/host/platform/Windows/capture/DXGI/src/util.c @@ -151,3 +151,43 @@ const char * GetDXGIFormatStr(DXGI_FORMAT format) return DXGI_FORMAT_STR[0]; return DXGI_FORMAT_STR[format]; } + +static const char * DXGI_COLOR_SPACE_TYPE_STR[] = +{ + "DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709", + "DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709", + "DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709", + "DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020", + "DXGI_COLOR_SPACE_RESERVED", + "DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601", + "DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709", + "DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020", + "DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020", + "DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020", + "DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020", + "DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020", + "DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020", + "DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709", + "DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020", + "DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020" +}; + +const char * GetDXGIColorSpaceTypeStr(DXGI_COLOR_SPACE_TYPE type) +{ + if (type == DXGI_COLOR_SPACE_CUSTOM) + return "DXGI_COLOR_SPACE_CUSTOM"; + + if (type > sizeof(DXGI_COLOR_SPACE_TYPE_STR) / sizeof(const char *)) + return "Invalid or Unknown"; + + return DXGI_COLOR_SPACE_TYPE_STR[type]; +}