314 lines
10 KiB
C++
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
|