From 79c4b15b1a139acbb7989e7dfe7a7d3f4ab01c2b Mon Sep 17 00:00:00 2001 From: Yukino Song Date: Tue, 20 Aug 2024 13:01:49 +0800 Subject: [PATCH] More detailed vdisplay driver state --- src/confighttp.cpp | 2 +- src/nvhttp.cpp | 6 ++- src/platform/windows/virtual_display.cpp | 54 +++++++++++++++--------- src/platform/windows/virtual_display.h | 15 ++++++- src/process.cpp | 33 ++++++++++----- src/process.h | 6 ++- 6 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/confighttp.cpp b/src/confighttp.cpp index 86fa17f8..7e38cbd7 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -547,7 +547,7 @@ namespace confighttp { outputTree.put("platform", SUNSHINE_PLATFORM); outputTree.put("version", PROJECT_VER); #ifdef _WIN32 - outputTree.put("vdisplayStatus", proc::vdisplayDriverInitialized ? "true" : "false"); + outputTree.put("vdisplayStatus", (int)proc::vDisplayDriverStatus); #endif auto vars = config::parse_config(file_handler::read_file(config::sunshine.config_file.c_str())); diff --git a/src/nvhttp.cpp b/src/nvhttp.cpp index 38ff4d88..11c32bdd 100644 --- a/src/nvhttp.cpp +++ b/src/nvhttp.cpp @@ -36,6 +36,10 @@ #include "uuid.h" #include "video.h" +#ifdef _WIN32 + #include "platform/windows/virtual_display.h" +#endif + using namespace std::literals; namespace nvhttp { @@ -708,7 +712,7 @@ namespace nvhttp { #ifdef _WIN32 tree.put("root.VirtualDisplayCapable", true); - tree.put("root.VirtualDisplayDriverReady", proc::vdisplayDriverInitialized); + tree.put("root.VirtualDisplayDriverReady", proc::vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK); #endif // Only include the MAC address for requests sent from paired clients over HTTPS. diff --git a/src/platform/windows/virtual_display.cpp b/src/platform/windows/virtual_display.cpp index 2a1920f3..45700090 100644 --- a/src/platform/windows/virtual_display.cpp +++ b/src/platform/windows/virtual_display.cpp @@ -102,7 +102,32 @@ bool setPrimaryDisplay(const wchar_t* primaryDeviceName) { return true; } -bool startPingThread() { +void closeVDisplayDevice() { + if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) { + return; + } + + CloseHandle(SUDOVDA_DRIVER_HANDLE); + + SUDOVDA_DRIVER_HANDLE = INVALID_HANDLE_VALUE; +} + +DRIVER_STATUS openVDisplayDevice() { + SUDOVDA_DRIVER_HANDLE = OpenDevice(&SUVDA_INTERFACE_GUID); + if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) { + return DRIVER_STATUS::FAILED; + } + + if (!CheckProtocolCompatible(SUDOVDA_DRIVER_HANDLE)) { + printf("[SUDOVDA] SUDOVDA protocol not compatible with driver!\n"); + closeVDisplayDevice(); + return DRIVER_STATUS::VERSION_INCOMPATIBLE; + } + + return DRIVER_STATUS::OK; +} + +bool startPingThread(std::function failCb) { if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) { return false; } @@ -117,10 +142,17 @@ bool startPingThread() { if (watchdogOut.Timeout) { auto sleepInterval = watchdogOut.Timeout * 1000 / 2; - std::thread ping_thread([sleepInterval]{ + std::thread ping_thread([sleepInterval, failCb = std::move(failCb)]{ + uint8_t fail_count = 0; for (;;) { if (!sleepInterval) return; - if (!PingDriver(SUDOVDA_DRIVER_HANDLE)) return; + if (!PingDriver(SUDOVDA_DRIVER_HANDLE)) { + fail_count += 1; + if (fail_count > 3) { + failCb(); + return; + } + }; Sleep(sleepInterval); } }); @@ -131,22 +163,6 @@ bool startPingThread() { return true; } -bool openVDisplayDevice() { - SUDOVDA_DRIVER_HANDLE = OpenDevice(&SUVDA_INTERFACE_GUID); - if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) { - return false; - } - - if (!CheckProtocolCompatible(SUDOVDA_DRIVER_HANDLE)) { - printf("[SUDOVDA] SUDOVDA protocol not compatible with driver!\n"); - CloseHandle(SUDOVDA_DRIVER_HANDLE); - SUDOVDA_DRIVER_HANDLE = INVALID_HANDLE_VALUE; - return false; - } - - return startPingThread(); -} - std::wstring createVirtualDisplay( const char* s_client_uid, const char* s_client_name, diff --git a/src/platform/windows/virtual_display.h b/src/platform/windows/virtual_display.h index 7a0010e9..7e9f76bb 100644 --- a/src/platform/windows/virtual_display.h +++ b/src/platform/windows/virtual_display.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifndef FILE_DEVICE_UNKNOWN #define FILE_DEVICE_UNKNOWN 0x00000022 #endif @@ -9,6 +11,14 @@ #include namespace VDISPLAY { + enum class DRIVER_STATUS { + UNKNOWN = 1, + OK = 0, + FAILED = -1, + VERSION_INCOMPATIBLE = -2, + WATCHDOG_FAILED = -3 + }; + extern HANDLE SUDOVDA_DRIVER_HANDLE; LONG getDeviceSettings(const wchar_t* deviceName, DEVMODEW& devMode); @@ -16,8 +26,9 @@ namespace VDISPLAY { std::wstring getPrimaryDisplay(); bool setPrimaryDisplay(const wchar_t* primaryDeviceName); - bool startPingThread(); - bool openVDisplayDevice(); + void closeVDisplayDevice(); + DRIVER_STATUS openVDisplayDevice(); + bool startPingThread(std::function failCb); std::wstring createVirtualDisplay( const char* s_client_uid, const char* s_client_name, diff --git a/src/process.cpp b/src/process.cpp index 0ed9ca4a..a3fd89cc 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -32,7 +32,6 @@ #ifdef _WIN32 // from_utf8() string conversion function #include "platform/windows/misc.h" - #include "platform/windows/virtual_display.h" // _SH constants for _wfsopen() #include @@ -47,7 +46,21 @@ namespace proc { proc_t proc; #ifdef _WIN32 - bool vdisplayDriverInitialized = false; + VDISPLAY::DRIVER_STATUS vDisplayDriverStatus = VDISPLAY::DRIVER_STATUS::UNKNOWN; + + void onVDisplayWatchdogFailed() { + vDisplayDriverStatus = VDISPLAY::DRIVER_STATUS::WATCHDOG_FAILED; + VDISPLAY::closeVDisplayDevice(); + } + + void initVDisplayDriver() { + vDisplayDriverStatus = VDISPLAY::openVDisplayDevice(); + if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK) { + if (!VDISPLAY::startPingThread(onVDisplayWatchdogFailed)) { + onVDisplayWatchdogFailed(); + } + } + } #endif class deinit_t: public platf::deinit_t { @@ -225,15 +238,15 @@ namespace proc { #ifdef _WIN32 if (launch_session->virtual_display || _app.virtual_display) { - if (!vdisplayDriverInitialized) { + if (vDisplayDriverStatus != VDISPLAY::DRIVER_STATUS::OK) { // Try init driver again - vdisplayDriverInitialized = VDISPLAY::openVDisplayDevice(); + initVDisplayDriver(); } - if (vdisplayDriverInitialized) { + if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK) { std::wstring prevPrimaryDisplayName = VDISPLAY::getPrimaryDisplay(); - launch_session->display_guid = *(GUID*)(void*)&http::uuid; + memcpy(&launch_session->display_guid, &http::uuid, sizeof(GUID)); std::wstring vdisplayName = VDISPLAY::createVirtualDisplay( launch_session->unique_id.c_str(), @@ -410,7 +423,7 @@ namespace proc { _pipe.reset(); #ifdef _WIN32 - if (vdisplayDriverInitialized && _launch_session && this->virtual_display) { + if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK && _launch_session && this->virtual_display) { VDISPLAY::removeVirtualDisplay(_launch_session->display_guid); } #endif @@ -677,7 +690,7 @@ namespace proc { std::vector apps; int i = 0; - if (vdisplayDriverInitialized) { + if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK) { proc::ctx_t ctx; ctx.name = "Virtual Display"; ctx.image_path = parse_env_val(this_env, "virtual_desktop.png"); @@ -822,8 +835,8 @@ namespace proc { void refresh(const std::string &file_name) { #ifdef _WIN32 - if (!vdisplayDriverInitialized) { - vdisplayDriverInitialized = VDISPLAY::openVDisplayDevice(); + if (vDisplayDriverStatus != VDISPLAY::DRIVER_STATUS::OK) { + initVDisplayDriver(); } #endif diff --git a/src/process.h b/src/process.h index da696b66..7dbc349b 100644 --- a/src/process.h +++ b/src/process.h @@ -18,11 +18,15 @@ #include "rtsp.h" #include "utility.h" +#ifdef _WIN32 + #include "platform/windows/virtual_display.h" +#endif + namespace proc { using file_t = util::safe_ptr_v2; #ifdef _WIN32 - extern bool vdisplayDriverInitialized; + extern VDISPLAY::DRIVER_STATUS vDisplayDriverStatus; #endif typedef config::prep_cmd_t cmd_t;