From f22e02cf1488c3201682a00abcc2cf1c4dceb30d Mon Sep 17 00:00:00 2001 From: Yukino Song Date: Fri, 6 Sep 2024 05:42:20 +0800 Subject: [PATCH] Set HDR of screen according to client request --- src/platform/windows/virtual_display.cpp | 123 ++++++++++++----------- src/platform/windows/virtual_display.h | 3 +- src/process.cpp | 31 ++++-- src/process.h | 2 + third-party/sudovda/sudovda.h | 4 + 5 files changed, 99 insertions(+), 64 deletions(-) diff --git a/src/platform/windows/virtual_display.cpp b/src/platform/windows/virtual_display.cpp index 06c1ba0f..4c77790c 100644 --- a/src/platform/windows/virtual_display.cpp +++ b/src/platform/windows/virtual_display.cpp @@ -108,25 +108,21 @@ bool setPrimaryDisplay(const wchar_t* primaryDeviceName) { return true; } - -bool ensureDisplayHDR(const wchar_t* displayName) { - UINT32 pathCount = 0, modeCount = 0; - - if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) != ERROR_SUCCESS) { - printf("Failed to query display configuration.\n"); +bool findDisplayIds(const wchar_t* displayName, LUID& adapterId, uint32_t& targetId) { + UINT pathCount; + UINT modeCount; + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount)) { return false; } - std::vector pathArray(pathCount); - std::vector modeArray(modeCount); - - if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, pathArray.data(), &modeCount, modeArray.data(), NULL) != ERROR_SUCCESS) { - printf("Failed to query display paths.\n"); + std::vector paths(pathCount); + std::vector modes(modeCount); + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr)) { return false; } - for (const auto& path : pathArray) { - DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo = path.sourceInfo; + auto path = std::find_if(paths.begin(), paths.end(), [&displayName](DISPLAYCONFIG_PATH_INFO _path) { + DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo = _path.sourceInfo; DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = {}; deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; @@ -135,54 +131,67 @@ bool ensureDisplayHDR(const wchar_t* displayName) { deviceName.header.id = sourceInfo.id; if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) { - continue; - } - - if (std::wstring_view(displayName) == deviceName.viewGdiDeviceName) { - DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO hdrInfo = {}; - hdrInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; - hdrInfo.header.size = sizeof(hdrInfo); - hdrInfo.header.adapterId = path.targetInfo.adapterId; - hdrInfo.header.id = path.targetInfo.id; - - if (DisplayConfigGetDeviceInfo(&hdrInfo.header) != ERROR_SUCCESS) { - wprintf(L"Failed to get HDR info for display: %ls\n", std::wstring(deviceName.viewGdiDeviceName)); - return false; - } - - if (hdrInfo.advancedColorSupported) { - if (hdrInfo.advancedColorEnabled) { - DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE setHdrInfo = {}; - setHdrInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE; - setHdrInfo.header.size = sizeof(setHdrInfo); - setHdrInfo.header.adapterId = path.targetInfo.adapterId; - setHdrInfo.header.id = path.targetInfo.id; - setHdrInfo.enableAdvancedColor = FALSE; // Disable HDR - - if (DisplayConfigSetDeviceInfo(&setHdrInfo.header) == ERROR_SUCCESS) { - wprintf(L"HDR toggled off for display: %ls\n", displayName); - } else { - wprintf(L"Failed to toggle HDR off for display: %ls\n", std::wstring(deviceName.viewGdiDeviceName)); - } - - setHdrInfo.enableAdvancedColor = TRUE; // Enable HDR back on - - if (DisplayConfigSetDeviceInfo(&setHdrInfo.header) == ERROR_SUCCESS) { - wprintf(L"HDR toggled on for display: %ls\n", displayName); - return true; - } else { - wprintf(L"Failed to toggle HDR on for display: %ls\n", std::wstring(deviceName.viewGdiDeviceName)); - } - } else { - wprintf(L"HDR is not enabled on display: %ls\n", displayName); - } - } return false; } + + return std::wstring_view(displayName) == deviceName.viewGdiDeviceName; + }); + + if (path == paths.end()) { + return false; } - wprintf(L"Display not found or HDR not supported: %ls\n", displayName); - return false; + adapterId = path->sourceInfo.adapterId; + targetId = path->targetInfo.id; + + return true; +} + +bool getDisplayHDR(const LUID& adapterId, const uint32_t& targetId) { + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO hdrInfo = {}; + hdrInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + hdrInfo.header.size = sizeof(hdrInfo); + hdrInfo.header.adapterId = adapterId; + hdrInfo.header.id = targetId; + + if (DisplayConfigGetDeviceInfo(&hdrInfo.header) != ERROR_SUCCESS) { + return false; + } + + return hdrInfo.advancedColorSupported && hdrInfo.advancedColorEnabled; +} + +bool setDisplayHDR(const LUID& adapterId, const uint32_t& targetId, bool enableAdvancedColor) { + DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE setHdrInfo = {}; + setHdrInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE; + setHdrInfo.header.size = sizeof(setHdrInfo); + setHdrInfo.header.adapterId = adapterId; + setHdrInfo.header.id = targetId; + setHdrInfo.enableAdvancedColor = enableAdvancedColor; + + return DisplayConfigSetDeviceInfo(&setHdrInfo.header) == ERROR_SUCCESS; +} + +bool getDisplayHDRByName(const wchar_t* displayName) { + LUID adapterId; + uint32_t targetId; + + if (!findDisplayIds(displayName, adapterId, targetId)) { + return false; + } + + return getDisplayHDR(adapterId, targetId); +} + +bool setDisplayHDRByName(const wchar_t* displayName, bool enableAdvancedColor) { + LUID adapterId; + uint32_t targetId; + + if (!findDisplayIds(displayName, adapterId, targetId)) { + return false; + } + + return setDisplayHDR(adapterId, targetId, enableAdvancedColor); } void closeVDisplayDevice() { diff --git a/src/platform/windows/virtual_display.h b/src/platform/windows/virtual_display.h index ea27f0bf..b4d726be 100644 --- a/src/platform/windows/virtual_display.h +++ b/src/platform/windows/virtual_display.h @@ -25,7 +25,8 @@ namespace VDISPLAY { LONG changeDisplaySettings(const wchar_t* deviceName, int width, int height, int refresh_rate); std::wstring getPrimaryDisplay(); bool setPrimaryDisplay(const wchar_t* primaryDeviceName); - bool ensureDisplayHDR(const wchar_t* displayName); + bool getDisplayHDRByName(const wchar_t* displayName); + bool setDisplayHDRByName(const wchar_t* displayName, bool enableAdvancedColor); void closeVDisplayDevice(); DRIVER_STATUS openVDisplayDevice(); diff --git a/src/process.cpp b/src/process.cpp index 13d4a464..05d1c9c2 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -369,17 +369,28 @@ namespace proc { _app_launch_time = std::chrono::steady_clock::now(); #ifdef _WIN32 - auto resetHDRThread = std::thread([this]{ + auto resetHDRThread = std::thread([this, enable_hdr = launch_session->enable_hdr]{ std::this_thread::sleep_for(1s); // Windows doesn't seem to be able to set HDR correctly when a display is just connected, // so we have tooggle HDR for the virtual display manually. + // We should have got the actual streaming display by now std::string currentDisplay = this->display_name; if (!currentDisplay.empty()) { - if (VDISPLAY::ensureDisplayHDR(platf::from_utf8(currentDisplay).c_str())) { - BOOST_LOG(info) << "HDR rsestted for display " << currentDisplay; - } else { - BOOST_LOG(info) << "HDR not applied for display " << currentDisplay; - }; + auto currentDisplayW = platf::from_utf8(currentDisplay).c_str(); + + this->initial_display = currentDisplay; + this->initial_hdr = VDISPLAY::getDisplayHDRByName(currentDisplayW); + if (!VDISPLAY::setDisplayHDRByName(currentDisplayW, false)) { + return; + } + + if (enable_hdr) { + if (VDISPLAY::setDisplayHDRByName(currentDisplayW, true)) { + BOOST_LOG(info) << "HDR enabled for display " << currentDisplay; + } else { + BOOST_LOG(info) << "HDR enable failed for display " << currentDisplay; + } + } } }); @@ -462,6 +473,14 @@ namespace proc { _pipe.reset(); #ifdef _WIN32 + if (!this->initial_display.empty()) { + if (VDISPLAY::setDisplayHDRByName(platf::from_utf8(this->initial_display).c_str(), this->initial_hdr)) { + BOOST_LOG(info) << "HDR restored successfully for display " << this->initial_display; + } else { + BOOST_LOG(info) << "HDR restore failed for display " << this->initial_display; + }; + } + if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK && _launch_session && this->virtual_display) { if (VDISPLAY::removeVirtualDisplay(_launch_session->display_guid)) { BOOST_LOG(info) << "Virtual Display removed successfully"; diff --git a/src/process.h b/src/process.h index a23ff9a1..377e07dd 100644 --- a/src/process.h +++ b/src/process.h @@ -79,7 +79,9 @@ namespace proc { KITTY_DEFAULT_CONSTR_MOVE_THROW(proc_t) std::string display_name; + std::string initial_display; bool virtual_display; + bool initial_hdr; proc_t( boost::process::environment &&env, diff --git a/third-party/sudovda/sudovda.h b/third-party/sudovda/sudovda.h index 1e585d07..9c682764 100644 --- a/third-party/sudovda/sudovda.h +++ b/third-party/sudovda/sudovda.h @@ -228,6 +228,10 @@ static const bool GetAddedDisplayName(const VIRTUAL_DISPLAY_ADD_OUT& addedDispla return _path.targetInfo.id == addedDisplay.TargetId; }); + if (path == paths.end()) { + return false; + } + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {}; sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; sourceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);