code: Add nvapi profile support

This commit is contained in:
GPUCode
2023-05-04 14:15:03 +03:00
parent 8bb68d1137
commit 91a2cebe6c
5 changed files with 215 additions and 0 deletions

View File

@ -466,6 +466,8 @@ add_library(citra_core STATIC
tracer/citrace.h
tracer/recorder.cpp
tracer/recorder.h
tools/nvapi.cpp
tools/nvapi.h
)
if (ENABLE_FFMPEG_VIDEO_DUMPER)
@ -511,3 +513,12 @@ endif()
if (CITRA_USE_PRECOMPILED_HEADERS)
target_precompile_headers(citra_core PRIVATE precompiled_headers.h)
endif()
if (WIN32)
target_sources(citra_core PUBLIC
${PROJECT_SOURCE_DIR}/externals/nvapi/nvapi.h
${PROJECT_SOURCE_DIR}/externals/nvapi/NvApiDriverSettings.h
)
target_link_libraries(citra_core PRIVATE ${PROJECT_SOURCE_DIR}/externals/nvapi/amd64/nvapi64.lib)
else()
endif()

View File

@ -46,6 +46,7 @@
#include "core/loader/loader.h"
#include "core/movie.h"
#include "core/rpc/rpc_server.h"
#include "core/tools/nvapi.h"
#include "network/network.h"
#include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/renderer_base.h"
@ -70,6 +71,8 @@ Core::Timing& Global() {
return System::GetInstance().CoreTiming();
}
std::unique_ptr<Core::NvApi> nvapi;
System::~System() = default;
System::ResultStatus System::RunLoop(bool tight_loop) {
@ -440,6 +443,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
VideoCore::Init(emu_window, secondary_window, *this);
ToggleNvidiaProfile(true);
LOG_DEBUG(Core, "Initialized OK");
is_powered_on = true;
@ -671,4 +676,12 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
SERIALIZE_IMPL(System)
void System::ToggleNvidiaProfile(bool enable) const {
if (!nvapi) {
nvapi = std::make_unique<Core::NvApi>();
}
nvapi->Initialize();
nvapi->SetSettings(enable);
}
} // namespace Core

View File

@ -328,6 +328,8 @@ public:
return false;
}
void ToggleNvidiaProfile(bool enable) const;
private:
/**
* Initialize the emulated system.

164
src/core/tools/nvapi.cpp Normal file
View File

@ -0,0 +1,164 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include "common/string_util.h"
#include "core/tools/nvapi.h"
namespace {
constexpr char PROFILE_NAME[] = "Citra (Auto)";
constexpr char APPLICATION_NAME[] = "citra.exe";
// TODO: orig_value should be read from the global profile instead of hard-coded here,
// but trying to read from the global or base profile throws an error.
struct SettingInfo {
NvU32 id;
NVDRS_SETTING_TYPE type;
NvU32 orig_value;
NvU32 target_value;
};
constexpr std::array SETTINGS{
/* SettingInfo{
.id = PREFERRED_PSTATE_ID,
.type = NVDRS_DWORD_TYPE,
.orig_value = PREFERRED_PSTATE_OPTIMAL_POWER,
.target_value = PREFERRED_PSTATE_PREFER_MAX,
},
*/
SettingInfo{
.id = OGL_THREAD_CONTROL_ID,
.type = NVDRS_DWORD_TYPE,
.orig_value = OGL_THREAD_CONTROL_DEFAULT,
.target_value = OGL_THREAD_CONTROL_ENABLE,
},
};
} // namespace
namespace Core {
NvApi::NvApi() {}
void NvApi::Initialize() {
#ifndef _WIN32
return;
#else
if (initialized) {
return;
}
if (NvAPI_Initialize() != NVAPI_OK) {
// Non-nVidia GPU
return;
}
if (NvAPI_DRS_CreateSession(&session_handle) != NVAPI_OK) {
LOG_ERROR(Config, "Failed to create Nvidia profile session");
return;
}
if (NvAPI_DRS_LoadSettings(session_handle) != NVAPI_OK) {
LOG_ERROR(Config, "Failed to load Nvidia profile settings");
return;
}
auto nv_profile_name = Common::UTF8ToUTF16W(PROFILE_NAME);
auto nv_profile_name_size = (nv_profile_name.size()) * 2;
auto nv_app_name = Common::UTF8ToUTF16W(APPLICATION_NAME);
auto nv_app_name_size = (nv_app_name.size()) * 2;
switch (NvAPI_DRS_FindProfileByName(session_handle, (NvU16*)nv_profile_name.c_str(),
&profile_handle)) {
case NVAPI_PROFILE_NOT_FOUND: {
LOG_ERROR(Config, "NVAPI_PROFILE_NOT_FOUND");
break;
}
case NVAPI_ERROR:
LOG_ERROR(Config, "Nvidia profile FindProfileByName failed");
break;
case NVAPI_OK:
default:
LOG_INFO(Config, "Successfully loaded existing yuzu Nvidia profile: {}", PROFILE_NAME);
break;
}
NVDRS_PROFILE nv_profile = {
.version = NVDRS_PROFILE_VER1,
.gpuSupport = std::numeric_limits<u32>::max(),
.isPredefined = false,
/* .numOfApps = 1,
.numOfSettings = 0,*/
};
std::memcpy(&nv_profile.profileName, nv_profile_name.data(), nv_profile_name_size);
if (NvAPI_DRS_CreateProfile(session_handle, &nv_profile, &profile_handle) != NVAPI_OK) {
LOG_ERROR(Config, "Failed to create nVidia profile");
// return;
}
NVDRS_APPLICATION nv_app{
.version = NVDRS_APPLICATION_VER_V4,
.isPredefined = false,
.isMetro = false,
.isCommandLine = false,
};
std::memcpy(&nv_app.appName, nv_app_name.data(), nv_app_name_size);
std::memcpy(&nv_app.userFriendlyName, nv_profile_name.data(), nv_profile_name_size);
if (NvAPI_DRS_CreateApplication(session_handle, profile_handle, &nv_app) != NVAPI_OK) {
LOG_ERROR(Config, "Failed to create Nvidia application");
return;
}
initialized = true;
LOG_CRITICAL(Frontend, "Inited");
#endif
}
NvApi::~NvApi() {
#ifndef _WIN32
return;
#else
if (session_handle) {
NvAPI_DRS_DestroySession(session_handle);
}
NvAPI_Unload();
#endif
}
void NvApi::SetSettings(bool enable) const {
#ifndef _WIN32
return;
#else
if (!initialized) {
return;
}
for (auto& setting : SETTINGS) {
NVDRS_SETTING nv_setting{
.version = NVDRS_SETTING_VER1,
.settingId = setting.id,
.settingType = setting.type,
.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION,
.isCurrentPredefined = false,
.isPredefinedValid = false,
.u32CurrentValue = enable ? setting.target_value : setting.orig_value,
};
NvAPI_DRS_GetSettingNameFromId(setting.id, &nv_setting.settingName);
if (NvAPI_DRS_SetSetting(session_handle, profile_handle, &nv_setting) != NVAPI_OK) {
auto id_name{Common::UTF16ToUTF8((wchar_t*)nv_setting.settingName)};
LOG_ERROR(Config, "Failed to set Nvidia setting {}", id_name);
return;
}
}
if (NvAPI_DRS_SaveSettings(session_handle) != NVAPI_OK) {
LOG_ERROR(Config, "Failed to save Nvidia profile settings");
return;
}
LOG_CRITICAL(Frontend, "Settings set");
#endif
}
} // namespace Core

25
src/core/tools/nvapi.h Normal file
View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// nvapi.h must be included first
// clang-format off
#include "../externals/nvapi/nvapi.h"
#include "../externals/nvapi/NvApiDriverSettings.h"
// clang-format on
namespace Core {
class NvApi {
public:
NvApi();
~NvApi();
void Initialize();
void SetSettings(bool enable) const;
private:
NvDRSSessionHandle session_handle{};
NvDRSProfileHandle profile_handle{};
bool initialized{false};
};
} // namespace Core