Try add sudovda driver support
This commit is contained in:
199
src/platform/windows/virtual_display.cpp
Normal file
199
src/platform/windows/virtual_display.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user