Skip to content

Commit

Permalink
feat: desktop image sync
Browse files Browse the repository at this point in the history
  • Loading branch information
qiin2333 committed Sep 26, 2024
1 parent 9ef80ad commit e9ca627
Show file tree
Hide file tree
Showing 12 changed files with 9,974 additions and 145 deletions.
46 changes: 32 additions & 14 deletions src/display_device/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,17 @@ namespace display_device {

std::unique_ptr<session_t::deinit_t>
session_t::init() {
const auto devices { enum_available_devices() };
const auto vdd_devices { display_device::find_device_by_friendlyname(zako_name) };
if (!devices.empty()) {
BOOST_LOG(info) << "Available display devices: " << to_string(devices);
zako_device_id = vdd_devices;
// 大多数哔叽本开机默认虚拟屏优先导致黑屏
if (!vdd_devices.empty() && devices.size() > 1) {
session_t::get().disable_vdd();
Sleep(2333);
if (session_t::get().settings.is_changing_settings_going_to_fail()) {
const auto devices { enum_available_devices() };
const auto vdd_devices { display_device::find_device_by_friendlyname(zako_name) };
if (!devices.empty()) {
BOOST_LOG(info) << "Available display devices: " << to_string(devices);
zako_device_id = vdd_devices;
// 大多数哔叽本开机默认虚拟屏优先导致黑屏
if (!vdd_devices.empty() && devices.size() > 1) {
session_t::get().disable_vdd();
std::this_thread::sleep_for(2333ms);
}
}
}

Expand Down Expand Up @@ -201,7 +203,7 @@ namespace display_device {
auto working_dir = boost::filesystem::path();

std::error_code ec;
std::string cmd = "C:\\Program Files\\Sunshine\\tools\\device-toggler.exe 1 2 \"Virtual Display with HDR\"";
std::string cmd = "C:\\Program Files\\Sunshine\\tools\\DevManView.exe /enable \"Virtual Display with HDR\"";

auto child = platf::run_command(true, true, cmd, working_dir, _env, nullptr, ec, nullptr);
if (ec) {
Expand All @@ -219,7 +221,25 @@ namespace display_device {
auto working_dir = boost::filesystem::path();

std::error_code ec;
std::string cmd = "C:\\Program Files\\Sunshine\\tools\\device-toggler.exe 2 2 \"Virtual Display with HDR\"";
std::string cmd = "C:\\Program Files\\Sunshine\\tools\\DevManView.exe /disable \"Virtual Display with HDR\"";

auto child = platf::run_command(true, true, cmd, working_dir, _env, nullptr, ec, nullptr);
if (ec) {
BOOST_LOG(warning) << "Couldn't run cmd ["sv << cmd << "]: System: "sv << ec.message();
}
else {
BOOST_LOG(info) << "Executing idd cmd ["sv << cmd << "]"sv;
child.detach();
}
}

void
session_t::disable_enable_vdd() {
boost::process::environment _env = boost::this_process::environment();
auto working_dir = boost::filesystem::path();

std::error_code ec;
std::string cmd = "C:\\Program Files\\Sunshine\\tools\\DevManView.exe /disable_enable \"Virtual Display with HDR\"";

auto child = platf::run_command(true, true, cmd, working_dir, _env, nullptr, ec, nullptr);
if (ec) {
Expand All @@ -233,7 +253,6 @@ namespace display_device {

void
session_t::prepare_vdd(parsed_config_t &config, const rtsp_stream::launch_session_t &session) {
// std::lock_guard lock { mutex };
// resolutions and fps from parsed
bool is_cached_res { false };
bool is_cached_fps { false };
Expand Down Expand Up @@ -306,9 +325,8 @@ namespace display_device {
session_t::get().enable_vdd();
}
else if (should_toggle_vdd) {
session_t::get().disable_vdd();
session_t::get().disable_enable_vdd();
std::this_thread::sleep_for(2333ms);
session_t::get().enable_vdd();
should_reset_zako_hdr = true;
}

Expand Down
3 changes: 3 additions & 0 deletions src/display_device/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ namespace display_device {
void
disable_vdd();

void
disable_enable_vdd();

void
prepare_vdd(parsed_config_t &config, const rtsp_stream::launch_session_t &session);

Expand Down
103 changes: 57 additions & 46 deletions src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,26 +354,8 @@ namespace platf::dxgi {
return true;
}

// On hybrid graphics systems, Windows will change the order of GPUs reported by
// DXGI in accordance with the user's GPU preference. If the selected GPU is a
// render-only device with no displays, DXGI will add virtual outputs to the
// that device to avoid confusing applications. While this works properly for most
// applications, it breaks the Desktop Duplication API because DXGI doesn't proxy
// the virtual DXGIOutput to the real GPU it is attached to. When trying to call
// DuplicateOutput() on one of these virtual outputs, it fails with DXGI_ERROR_UNSUPPORTED
// (even if you try sneaky stuff like passing the ID3D11Device for the iGPU and the
// virtual DXGIOutput from the dGPU). Because the GPU preference is once-per-process,
// we spawn a helper tool to probe for us before we set our own GPU preference.
bool
probe_for_gpu_preference(const std::string &display_name) {
static bool set_gpu_preference = false;
static bool verify_frame_capture = true;

// If we've already been through here, there's nothing to do this time.
if (set_gpu_preference) {
return true;
}

validate_and_test_gpu_preference(const std::string &display_name, bool verify_frame_capture) {
std::string cmd = "tools\\ddprobe.exe";

// We start at 1 because 0 is automatic selection which can be overridden by
Expand All @@ -383,12 +365,12 @@ namespace platf::dxgi {
for (int i = 1; i < 5; i++) {
// Run the probe tool. It returns the status of DuplicateOutput().
//
// Arg format: [GPU preference] [Display name] [--verify--frame-capture]
// Arg format: [GPU preference] [Display name] [--verify-frame-capture]
HRESULT result;
std::vector<std::string> args = { std::to_string(i), display_name };
try {
if (verify_frame_capture) {
args.push_back("--verify-frame-capture");
args.emplace_back("--verify-frame-capture");
}
result = bp::system(cmd, bp::args(args), bp::std_out > bp::null, bp::std_err > bp::null);
}
Expand All @@ -397,7 +379,7 @@ namespace platf::dxgi {
return false;
}

BOOST_LOG(info) << "ddprobe.exe " << boost::algorithm::join(args, " ") << "returned 0x"
BOOST_LOG(info) << "ddprobe.exe " << boost::algorithm::join(args, " ") << " returned 0x"
<< util::hex(result).to_string_view();

// E_ACCESSDENIED can happen at the login screen. If we get this error,
Expand All @@ -406,22 +388,66 @@ namespace platf::dxgi {
if (result == S_OK || result == E_ACCESSDENIED) {
// We found a working GPU preference, so set ourselves to use that.
if (set_gpu_preference_on_self(i)) {
set_gpu_preference = true;
return true;
}
else {
return false;
}
}
else {
// This configuration didn't work, so continue testing others
continue;
}
}

// If none of the manual options worked, leave the GPU preference alone
// And set the verify frame capture option to false, just in case there is a chance for a false negative.
verify_frame_capture = false;
// If no valid configuration was found, return false
return false;
}

// On hybrid graphics systems, Windows will change the order of GPUs reported by
// DXGI in accordance with the user's GPU preference. If the selected GPU is a
// render-only device with no displays, DXGI will add virtual outputs to the
// that device to avoid confusing applications. While this works properly for most
// applications, it breaks the Desktop Duplication API because DXGI doesn't proxy
// the virtual DXGIOutput to the real GPU it is attached to. When trying to call
// DuplicateOutput() on one of these virtual outputs, it fails with DXGI_ERROR_UNSUPPORTED
// (even if you try sneaky stuff like passing the ID3D11Device for the iGPU and the
// virtual DXGIOutput from the dGPU). Because the GPU preference is once-per-process,
// we spawn a helper tool to probe for us before we set our own GPU preference.
bool
probe_for_gpu_preference(const std::string &display_name) {
static bool set_gpu_preference = false;

// if (!config::video.adapter_name.empty()) {
// std::vector<std::string> adapters = { adapter_names() };
// auto it = std::find(adapters.begin(), adapters.end(), config::video.adapter_name);
// if (it != adapters.end()) {
// int preference = std::distance(adapters.begin(), it);
// set_gpu_preference_on_self(preference);
// set_gpu_preference = true;
// } else {
// set_gpu_preference = false;
// }
// }

// 由于win的多GPU管理摸不透,使用哪个还是让win自己撅腚吧,去测试反而更糟
if (config::video.preferUseVdd) {
set_gpu_preference_on_self(0);
set_gpu_preference = true;
}

// If we've already been through here, there's nothing to do this time.
if (set_gpu_preference) {
return true;
}

// Try probing with different GPU preferences and verify_frame_capture flag
if (validate_and_test_gpu_preference(display_name, true)) {
return true;
}

// If no valid configuration was found, try again with verify_frame_capture == false
if (validate_and_test_gpu_preference(display_name, false)) {
return true;
}

// If neither worked, return false
return false;
}

Expand Down Expand Up @@ -536,9 +562,6 @@ namespace platf::dxgi {
auto adapter_name = from_utf8(config::video.adapter_name);
auto output_display_name = from_utf8(display_device::get_display_name(device_name));

BOOST_LOG(info) << "config::video.adapter_name: " << adapter_name << "!";
BOOST_LOG(info) << "output_display_name: " << output_display_name << "!";

adapter_t::pointer adapter_p;
for (int tries = 0; tries < 2; ++tries) {
for (int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
Expand All @@ -563,7 +586,6 @@ namespace platf::dxgi {
}

if (desc.AttachedToDesktop && test_dxgi_duplication(adapter_tmp, output_tmp, false)) {
output_index = y;
output = std::move(output_tmp);

offset_x = desc.DesktopCoordinates.left;
Expand Down Expand Up @@ -592,7 +614,6 @@ namespace platf::dxgi {
}

if (output) {
adapter_index = x;
adapter = std::move(adapter_tmp);
break;
}
Expand Down Expand Up @@ -1069,16 +1090,6 @@ namespace platf {
}
}

if (config::video.capture == "amd") {
if (hwdevice_type == mem_type_e::dxgi) {
auto disp = std::make_shared<dxgi::display_amd_vram_t>();

if (!disp->init(config, display_name)) {
return disp;
}
}
}

if (config::video.capture == "wgc" || config::video.capture.empty()) {
if (hwdevice_type == mem_type_e::dxgi) {
auto disp = std::make_shared<dxgi::display_wgc_vram_t>();
Expand Down Expand Up @@ -1229,4 +1240,4 @@ namespace platf {
return false;
}
}
} // namespace platf
} // namespace platf
25 changes: 25 additions & 0 deletions src/platform/windows/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,31 @@ namespace platf {
return output;
}

std::wstring
GetRegistryStringValue(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName) {
DWORD dwType, dwSize, dwLength;
HKEY hKeyResult;
LONG lResult;
std::wstring strValue;

// 打开子键
lResult = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, &hKeyResult);
if (lResult == ERROR_SUCCESS) {
dwType = REG_SZ;
dwSize = MAX_PATH;
strValue.resize(dwSize);

lResult = RegQueryValueExW(hKeyResult, lpValueName, NULL, &dwType, (LPBYTE) strValue.c_str(), &dwSize);
if (lResult == ERROR_SUCCESS) {
// 获取字符串长度并调整字符串
dwLength = lstrlenW(strValue.c_str());
strValue.resize(dwLength);
}
RegCloseKey(hKeyResult);
}
return strValue;
}

class win32_high_precision_timer: public high_precision_timer {
public:
win32_high_precision_timer() {
Expand Down
21 changes: 20 additions & 1 deletion src/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@

// _SH constants for _wfsopen()
#include <share.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#endif

#define DEFAULT_APP_IMAGE_PATH SUNSHINE_ASSETS_DIR "/box.png"
Expand Down Expand Up @@ -495,8 +500,22 @@ namespace proc {
auto image_extension = std::filesystem::path(app_image_path).extension().string();
boost::to_lower(image_extension);

if (app_image_path == "desktop") {
char wallpaperPath[MAX_PATH];
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaperPath, 0);
BOOST_LOG(info) << "Use desktop image ["sv << wallpaperPath << ']';

// int width, height, channels;
// unsigned char *data = stbi_load((LPCSTR) wallpaperPath, &width, &height, &channels, 0);
// if (data) {
// stbi_write_png(SUNSHINE_ASSETS_DIR "desktop.png", width, height, channels, data, width * channels);
// stbi_image_free(data);
// }
return wallpaperPath;
}

// return the default box image if extension is not "png"
if (image_extension != ".png") {
if (image_extension != ".png" && image_extension != ".jpg") {
return DEFAULT_APP_IMAGE_PATH;
}

Expand Down
Loading

0 comments on commit e9ca627

Please sign in to comment.