Sunshine/src/platform/windows/nvprefs/driver_settings.cpp

314 lines
10 KiB
C++

/**
* @file src/platform/windows/nvprefs/driver_settings.cpp
* @brief Definitions for nvidia driver settings.
*/
// local includes
#include "driver_settings.h"
#include "nvprefs_common.h"
namespace {
const auto sunshine_application_profile_name = L"SunshineStream";
const auto sunshine_application_path = L"sunshine.exe";
void
nvapi_error_message(NvAPI_Status status) {
NvAPI_ShortString message = {};
NvAPI_GetErrorMessage(status, message);
nvprefs::error_message(std::string("NvAPI error: ") + message);
}
void
fill_nvapi_string(NvAPI_UnicodeString &dest, const wchar_t *src) {
static_assert(sizeof(NvU16) == sizeof(wchar_t));
memcpy_s(dest, NVAPI_UNICODE_STRING_MAX * sizeof(NvU16), src, (wcslen(src) + 1) * sizeof(wchar_t));
}
} // namespace
namespace nvprefs {
driver_settings_t::~driver_settings_t() {
if (session_handle) {
NvAPI_DRS_DestroySession(session_handle);
}
}
bool
driver_settings_t::init() {
if (session_handle) return true;
NvAPI_Status status;
status = NvAPI_Initialize();
if (status != NVAPI_OK) {
info_message("NvAPI_Initialize() failed, ignore if you don't have NVIDIA video card");
return false;
}
status = NvAPI_DRS_CreateSession(&session_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_CreateSession() failed");
return false;
}
return load_settings();
}
void
driver_settings_t::destroy() {
if (session_handle) {
NvAPI_DRS_DestroySession(session_handle);
session_handle = 0;
}
NvAPI_Unload();
}
bool
driver_settings_t::load_settings() {
if (!session_handle) return false;
NvAPI_Status status = NvAPI_DRS_LoadSettings(session_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_LoadSettings() failed");
destroy();
return false;
}
return true;
}
bool
driver_settings_t::save_settings() {
if (!session_handle) return false;
NvAPI_Status status = NvAPI_DRS_SaveSettings(session_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_SaveSettings() failed");
return false;
}
return true;
}
bool
driver_settings_t::restore_global_profile_to_undo(const undo_data_t &undo_data) {
if (!session_handle) return false;
const auto &swapchain_data = undo_data.get_opengl_swapchain();
if (swapchain_data) {
NvAPI_Status status;
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_GetBaseProfile(session_handle, &profile_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_GetBaseProfile() failed");
return false;
}
NVDRS_SETTING setting = {};
setting.version = NVDRS_SETTING_VER;
status = NvAPI_DRS_GetSetting(session_handle, profile_handle, OGL_CPL_PREFER_DXPRESENT_ID, &setting);
if (status == NVAPI_OK && setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION && setting.u32CurrentValue == swapchain_data->our_value) {
if (swapchain_data->undo_value) {
setting = {};
setting.version = NVDRS_SETTING_VER1;
setting.settingId = OGL_CPL_PREFER_DXPRESENT_ID;
setting.settingType = NVDRS_DWORD_TYPE;
setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION;
setting.u32CurrentValue = *swapchain_data->undo_value;
status = NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_SetSetting() OGL_CPL_PREFER_DXPRESENT failed");
return false;
}
}
else {
status = NvAPI_DRS_DeleteProfileSetting(session_handle, profile_handle, OGL_CPL_PREFER_DXPRESENT_ID);
if (status != NVAPI_OK && status != NVAPI_SETTING_NOT_FOUND) {
nvapi_error_message(status);
error_message("NvAPI_DRS_DeleteProfileSetting() OGL_CPL_PREFER_DXPRESENT failed");
return false;
}
}
info_message("Restored OGL_CPL_PREFER_DXPRESENT for base profile");
}
else if (status == NVAPI_OK || status == NVAPI_SETTING_NOT_FOUND) {
info_message("OGL_CPL_PREFER_DXPRESENT has been changed from our value in base profile, not restoring");
}
else {
error_message("NvAPI_DRS_GetSetting() OGL_CPL_PREFER_DXPRESENT failed");
return false;
}
}
return true;
}
bool
driver_settings_t::check_and_modify_global_profile(std::optional<undo_data_t> &undo_data) {
if (!session_handle) return false;
undo_data.reset();
NvAPI_Status status;
if (!get_nvprefs_options().opengl_vulkan_on_dxgi) {
// User requested to leave OpenGL/Vulkan DXGI swapchain setting alone
return true;
}
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_GetBaseProfile(session_handle, &profile_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_GetBaseProfile() failed");
return false;
}
NVDRS_SETTING setting = {};
setting.version = NVDRS_SETTING_VER;
status = NvAPI_DRS_GetSetting(session_handle, profile_handle, OGL_CPL_PREFER_DXPRESENT_ID, &setting);
// Remember current OpenGL/Vulkan DXGI swapchain setting and change it if needed
if (status == NVAPI_SETTING_NOT_FOUND || (status == NVAPI_OK && setting.u32CurrentValue != OGL_CPL_PREFER_DXPRESENT_PREFER_ENABLED)) {
undo_data = undo_data_t();
if (status == NVAPI_OK) {
undo_data->set_opengl_swapchain(OGL_CPL_PREFER_DXPRESENT_PREFER_ENABLED, setting.u32CurrentValue);
}
else {
undo_data->set_opengl_swapchain(OGL_CPL_PREFER_DXPRESENT_PREFER_ENABLED, std::nullopt);
}
setting = {};
setting.version = NVDRS_SETTING_VER1;
setting.settingId = OGL_CPL_PREFER_DXPRESENT_ID;
setting.settingType = NVDRS_DWORD_TYPE;
setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION;
setting.u32CurrentValue = OGL_CPL_PREFER_DXPRESENT_PREFER_ENABLED;
status = NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_SetSetting() OGL_CPL_PREFER_DXPRESENT failed");
return false;
}
info_message("Changed OGL_CPL_PREFER_DXPRESENT to OGL_CPL_PREFER_DXPRESENT_PREFER_ENABLED for base profile");
}
else if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_GetSetting() OGL_CPL_PREFER_DXPRESENT failed");
return false;
}
return true;
}
bool
driver_settings_t::check_and_modify_application_profile(bool &modified) {
if (!session_handle) return false;
modified = false;
NvAPI_Status status;
NvAPI_UnicodeString profile_name = {};
fill_nvapi_string(profile_name, sunshine_application_profile_name);
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_FindProfileByName(session_handle, profile_name, &profile_handle);
if (status != NVAPI_OK) {
// Create application profile if missing
NVDRS_PROFILE profile = {};
profile.version = NVDRS_PROFILE_VER1;
fill_nvapi_string(profile.profileName, sunshine_application_profile_name);
status = NvAPI_DRS_CreateProfile(session_handle, &profile, &profile_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_CreateProfile() failed");
return false;
}
modified = true;
}
NvAPI_UnicodeString sunshine_path = {};
fill_nvapi_string(sunshine_path, sunshine_application_path);
NVDRS_APPLICATION application = {};
application.version = NVDRS_APPLICATION_VER_V1;
status = NvAPI_DRS_GetApplicationInfo(session_handle, profile_handle, sunshine_path, &application);
if (status != NVAPI_OK) {
// Add application to application profile if missing
application.version = NVDRS_APPLICATION_VER_V1;
application.isPredefined = 0;
fill_nvapi_string(application.appName, sunshine_application_path);
fill_nvapi_string(application.userFriendlyName, sunshine_application_path);
fill_nvapi_string(application.launcher, L"");
status = NvAPI_DRS_CreateApplication(session_handle, profile_handle, &application);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_CreateApplication() failed");
return false;
}
modified = true;
}
NVDRS_SETTING setting = {};
setting.version = NVDRS_SETTING_VER1;
status = NvAPI_DRS_GetSetting(session_handle, profile_handle, PREFERRED_PSTATE_ID, &setting);
if (!get_nvprefs_options().sunshine_high_power_mode) {
if (status == NVAPI_OK &&
setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION) {
// User requested to not use high power mode for sunshine.exe,
// remove the setting from application profile if it's been set previously
status = NvAPI_DRS_DeleteProfileSetting(session_handle, profile_handle, PREFERRED_PSTATE_ID);
if (status != NVAPI_OK && status != NVAPI_SETTING_NOT_FOUND) {
nvapi_error_message(status);
error_message("NvAPI_DRS_DeleteProfileSetting() PREFERRED_PSTATE failed");
return false;
}
modified = true;
info_message(std::wstring(L"Removed PREFERRED_PSTATE for ") + sunshine_application_path);
}
}
else if (status != NVAPI_OK ||
setting.settingLocation != NVDRS_CURRENT_PROFILE_LOCATION ||
setting.u32CurrentValue != PREFERRED_PSTATE_PREFER_MAX) {
// Set power setting if needed
setting = {};
setting.version = NVDRS_SETTING_VER1;
setting.settingId = PREFERRED_PSTATE_ID;
setting.settingType = NVDRS_DWORD_TYPE;
setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION;
setting.u32CurrentValue = PREFERRED_PSTATE_PREFER_MAX;
status = NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting);
if (status != NVAPI_OK) {
nvapi_error_message(status);
error_message("NvAPI_DRS_SetSetting() PREFERRED_PSTATE failed");
return false;
}
modified = true;
info_message(std::wstring(L"Changed PREFERRED_PSTATE to PREFERRED_PSTATE_PREFER_MAX for ") + sunshine_application_path);
}
return true;
}
} // namespace nvprefs