Try add sudovda driver support

This commit is contained in:
Yukino Song
2024-08-17 13:19:07 +08:00
parent 25919a9a89
commit 6fa277ec0b
13 changed files with 641 additions and 33 deletions

View File

@@ -0,0 +1,199 @@
#include <windows.h>
#include <iostream>
#include <vector>
#include <setupapi.h>
#include <initguid.h>
#include <combaseapi.h>
#include <thread>
#include "virtual_display.h"
using namespace SUDOVDA;
namespace VDISPLAY {
// {dff7fd29-5b75-41d1-9731-b32a17a17104}
static const GUID DEFAULT_DISPLAY_GUID = { 0xdff7fd29, 0x5b75, 0x41d1, { 0x97, 0x31, 0xb3, 0x2a, 0x17, 0xa1, 0x71, 0x04 } };
HANDLE SUDOVDA_DRIVER_HANDLE = INVALID_HANDLE_VALUE;
LONG getDeviceSettings(const wchar_t* deviceName, DEVMODEW& devMode) {
devMode.dmSize = sizeof(DEVMODEW);
return EnumDisplaySettingsW(deviceName, ENUM_CURRENT_SETTINGS, &devMode);
}
LONG changeDisplaySettings(const wchar_t* deviceName, int width, int height, int refresh_rate) {
DEVMODEW devMode = {0};
devMode.dmSize = sizeof(devMode);
if (EnumDisplaySettingsW(deviceName, ENUM_CURRENT_SETTINGS, &devMode)) {
devMode.dmPelsWidth = width;
devMode.dmPelsHeight = height;
devMode.dmDisplayFrequency = refresh_rate;
devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
return ChangeDisplaySettingsExW(deviceName, &devMode, NULL, CDS_UPDATEREGISTRY, NULL);
}
return 0;
}
bool setPrimaryDisplay(const wchar_t* primaryDeviceName) {
DEVMODEW primaryDevMode{};
if (!getDeviceSettings(primaryDeviceName, primaryDevMode)) {
return false;
};
int offset_x = primaryDevMode.dmPosition.x;
int offset_y = primaryDevMode.dmPosition.y;
LONG result;
DISPLAY_DEVICEW displayDevice;
displayDevice.cb = sizeof(DISPLAY_DEVICEA);
int device_index = 0;
while (EnumDisplayDevicesW(NULL, device_index, &displayDevice, 0)) {
device_index++;
if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE)) {
continue;
}
DEVMODEW devMode{};
if (getDeviceSettings(displayDevice.DeviceName, devMode)) {
devMode.dmPosition.x -= offset_x;
devMode.dmPosition.y -= offset_y;
devMode.dmFields = DM_POSITION;
result = ChangeDisplaySettingsExW(displayDevice.DeviceName, &devMode, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
if (result != DISP_CHANGE_SUCCESSFUL) {
return false;
}
}
}
// Update primary device's config to ensure it's primary
primaryDevMode.dmPosition.x = 0;
primaryDevMode.dmPosition.y = 0;
primaryDevMode.dmFields = DM_POSITION;
ChangeDisplaySettingsExW(primaryDeviceName, &primaryDevMode, NULL, CDS_UPDATEREGISTRY | CDS_NORESET | CDS_SET_PRIMARY, NULL);
result = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
if (result != DISP_CHANGE_SUCCESSFUL) {
return false;
}
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 true;
}
bool startPingThread() {
if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) {
return false;
}
VIRTUAL_DISPLAY_GET_WATCHDOG_OUT watchdogOut;
if (GetWatchdogTimeout(SUDOVDA_DRIVER_HANDLE, watchdogOut)) {
printf("[SUDOVDA] Watchdog: Timeout %d, Countdown %d\n", watchdogOut.Timeout, watchdogOut.Countdown);
} else {
printf("[SUDOVDA] Watchdog fetch failed!\n");
return false;
}
if (watchdogOut.Timeout) {
auto sleepInterval = watchdogOut.Timeout * 1000 / 2;
std::thread ping_thread([sleepInterval]{
for (;;) {
if (!sleepInterval) return;
if (!PingDriver(SUDOVDA_DRIVER_HANDLE)) return;
Sleep(sleepInterval);
}
});
ping_thread.detach();
}
return true;
}
std::wstring createVirtualDisplay(
const char* s_client_uid,
const char* s_client_name,
const char* s_app_name,
uint32_t width,
uint32_t height,
uint32_t fps,
GUID& guid
) {
if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) {
return std::wstring();
}
if (!s_app_name || !strlen(s_app_name) || !strcmp(s_app_name, "unknown")) {
s_app_name = "ApolloVDisp";
}
if (!s_client_name || !strlen(s_client_name) || !strcmp(s_client_name, "unknown")) {
s_client_name = s_app_name;
}
if (s_client_uid && strcmp(s_client_uid, "unknown")) {
size_t len = strlen(s_client_uid);
if (len > sizeof(GUID)) {
len = sizeof(GUID);
}
memcpy((void*)&guid, (void*)s_client_uid, len);
} else {
guid = DEFAULT_DISPLAY_GUID;
s_client_uid = "unknown";
}
VIRTUAL_DISPLAY_ADD_OUT output;
if (!AddVirtualDisplay(SUDOVDA_DRIVER_HANDLE, width, height, fps, guid, s_client_name, s_client_uid, output)) {
printf("[SUDOVDA] Failed to add virtual display.\n");
return std::wstring();
}
uint32_t retryInterval = 20;
wchar_t deviceName[CCHDEVICENAME]{};
while (!GetAddedDisplayName(output, deviceName)) {
Sleep(retryInterval);
if (retryInterval > 160) {
printf("[SUDOVDA] Cannot get name for newly added virtual display!\n");
return std::wstring();
}
retryInterval *= 2;
}
wprintf(L"[SUDOVDA] Virtual display added successfully: %ws\n", deviceName);
printf("[SUDOVDA] Configuration: W: %d, H: %d, FPS: %d\n", width, height, fps);
return std::wstring(deviceName);
}
bool removeVirtualDisplay(const GUID& guid) {
if (SUDOVDA_DRIVER_HANDLE == INVALID_HANDLE_VALUE) {
return false;
}
if (RemoveVirtualDisplay(SUDOVDA_DRIVER_HANDLE, guid)) {
printf("[SUDOVDA] Virtual display removed successfully.\n");
return true;
} else {
return false;
}
}
}