code: Add nvapi profile support
This commit is contained in:
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
164
src/core/tools/nvapi.cpp
Normal 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
25
src/core/tools/nvapi.h
Normal 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
|
Reference in New Issue
Block a user