diff --git a/src/client/main.cpp b/src/client/main.cpp index 1dfdb9ae..c6559941 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -212,6 +212,26 @@ namespace } } + void trigger_high_performance_gpu_switch() + { + // Make sure to link D3D11, as this might trigger high performance GPU + static volatile auto _ = &D3D11CreateDevice; + + const auto key = utils::nt::open_or_create_registry_key( + HKEY_CURRENT_USER, R"(Software\Microsoft\DirectX\UserGpuPreferences)"); + if (!key) + { + return; + } + + const auto self = utils::nt::library::get_by_address(&trigger_high_performance_gpu_switch); + + const std::wstring data = L"GpuPreference=2;"; + RegSetValueExW(key, self.get_path().make_preferred().wstring().data(), 0, REG_SZ, + reinterpret_cast(data.data()), + static_cast((data.size() + 1u) * 2)); + } + int main() { if (handle_process_runner()) @@ -246,9 +266,14 @@ namespace const auto is_server = utils::flags::has_flag("dedicated") || (!has_client && has_server); - if (!is_server && !launcher::run()) + if (!is_server) { - return 0; + trigger_high_performance_gpu_switch(); + + if (!launcher::run()) + { + return 0; + } } if (!component_loader::activate(is_server)) diff --git a/src/client/std_include.cpp b/src/client/std_include.cpp index a28d1f38..a3f3a99f 100644 --- a/src/client/std_include.cpp +++ b/src/client/std_include.cpp @@ -24,3 +24,9 @@ extern "C" return -1; } } + +extern "C" +{ + __declspec(dllexport) DWORD NvOptimusEnablement = 1; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +} diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index a29aa2a6..bbb4779c 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -51,6 +51,7 @@ #include #include #include +#include // min and max is required by gdi, therefore NOMINMAX won't work #ifdef max @@ -101,5 +102,6 @@ #pragma comment(lib, "urlmon.lib" ) #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "Crypt32.lib") +#pragma comment(lib, "d3d11.lib") using namespace std::literals; diff --git a/src/common/utils/nt.cpp b/src/common/utils/nt.cpp index c57ab267..45f3cebc 100644 --- a/src/common/utils/nt.cpp +++ b/src/common/utils/nt.cpp @@ -1,4 +1,5 @@ #include "nt.hpp" +#include "string.hpp" namespace utils::nt { @@ -223,6 +224,34 @@ namespace utils::nt return nullptr; } + registry_key open_or_create_registry_key(const HKEY base, const std::string& input) + { + const auto parts = string::split(input, '\\'); + + registry_key current_key = base; + + for (const auto& part : parts) + { + registry_key new_key{}; + if (RegOpenKeyExA(current_key, part.data(), 0, + KEY_ALL_ACCESS, &new_key) == ERROR_SUCCESS) + { + current_key = std::move(new_key); + continue; + } + + if (RegCreateKeyExA(current_key, part.data(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, + nullptr, &new_key, nullptr) != ERROR_SUCCESS) + { + return {}; + } + + current_key = std::move(new_key); + } + + return current_key; + } + bool is_wine() { static const auto has_wine_export = []() -> bool diff --git a/src/common/utils/nt.hpp b/src/common/utils/nt.hpp index 02b06dc1..4ca36860 100644 --- a/src/common/utils/nt.hpp +++ b/src/common/utils/nt.hpp @@ -173,6 +173,77 @@ namespace utils::nt HANDLE handle_{InvalidHandle}; }; + + class registry_key + { + public: + registry_key() = default; + + registry_key(HKEY key) + : key_(key) + { + } + + registry_key(const registry_key&) = delete; + registry_key& operator=(const registry_key&) = delete; + + registry_key(registry_key&& obj) noexcept + : registry_key() + { + this->operator=(std::move(obj)); + } + + registry_key& operator=(registry_key&& obj) noexcept + { + if (this != obj.GetRef()) + { + this->~registry_key(); + this->key_ = obj.key_; + obj.key_ = nullptr; + } + + return *this; + } + + ~registry_key() + { + if (this->key_) + { + RegCloseKey(this->key_); + } + } + + operator HKEY() const + { + return this->key_; + } + + operator bool() const + { + return this->key_ != nullptr; + } + + HKEY* operator&() + { + return &this->key_; + } + + registry_key* GetRef() + { + return this; + } + + const registry_key* GetRef() const + { + return this; + } + + private: + HKEY key_{}; + }; + + registry_key open_or_create_registry_key(const HKEY base, const std::string& input); + bool is_wine(); bool is_shutdown_in_progress();