From b9530ae80f9994f4a10143f8336f2b9bee4416fc Mon Sep 17 00:00:00 2001 From: Kleidis Date: Wed, 17 Dec 2025 03:59:27 +0100 Subject: [PATCH] [core] Add overridable game setting functionality (#2963) Adds a place to override specific game settings for specific vendors Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2963 Reviewed-by: Caio Oliveira Reviewed-by: Maufeat Co-authored-by: Kleidis Co-committed-by: Kleidis --- src/core/CMakeLists.txt | 2 + src/core/core.cpp | 46 +----------- src/core/game_settings.cpp | 140 +++++++++++++++++++++++++++++++++++++ src/core/game_settings.h | 60 ++++++++++++++++ 4 files changed, 205 insertions(+), 43 deletions(-) create mode 100644 src/core/game_settings.cpp create mode 100644 src/core/game_settings.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6a8b9b93b3..a961eff8bf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -17,6 +17,8 @@ add_library(core STATIC constants.h core.cpp core.h + game_settings.cpp + game_settings.h core_timing.cpp core_timing.h cpu_manager.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index edc2df4851..bf97184f8f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -6,6 +6,7 @@ #include #include +#include "game_settings.h" #include "audio_core/audio_core.h" #include "common/fs/fs.h" #include "common/logging/log.h" @@ -292,48 +293,6 @@ struct System::Impl { return SystemResultStatus::Success; } - - void LoadOverrides(u64 programId) const { - std::string vendor = gpu_core->Renderer().GetDeviceVendor(); - LOG_INFO(Core, "GPU Vendor: {}", vendor); - - // Reset all per-game flags - Settings::values.use_squashed_iterated_blend = false; - - // Insert PC overrides here - - #ifdef ANDROID - // Example on how to set a setting based on the program ID and vendor - if (programId == 0x010028600EBDA000 && vendor == "Mali") { // Mario 3d World - // Settings::values.example = true; - } - - // Example array of program IDs - const std::array example_array = { - //0xprogramId - 0x0004000000033400, // Game 1 - 0x0004000000033500 // Game 2 - // And so on - }; - - for (auto id : example_array) { - if (programId == id) { - // Settings::values.example = true; - break; - } - } - - #endif - - // Ninja Gaiden Ragebound - constexpr u64 ngr = 0x0100781020710000ULL; - - if (programId == ngr) { - LOG_INFO(Core, "Enabling game specifc override: use_squashed_iterated_blend"); - Settings::values.use_squashed_iterated_blend = true; - } - } - SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) { @@ -419,7 +378,8 @@ struct System::Impl { LOG_ERROR(Core, "Failed to find program id for ROM"); } - LoadOverrides(program_id); + + GameSettings::LoadOverrides(program_id, gpu_core->Renderer()); if (auto room_member = Network::GetRoomMember().lock()) { Network::GameInfo game_info; game_info.name = name; diff --git a/src/core/game_settings.cpp b/src/core/game_settings.cpp new file mode 100644 index 0000000000..da1530e026 --- /dev/null +++ b/src/core/game_settings.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/game_settings.h" + +#include +#include + +#include "common/logging/log.h" +#include "common/settings.h" +#include "video_core/renderer_base.h" + +#if defined(__APPLE__) +#include +#endif + +namespace Core::GameSettings { + +static GPUVendor GetGPU(const std::string& gpu_vendor_string) { + struct Entry { const char* name; GPUVendor vendor; }; + static constexpr Entry GpuVendor[] = { + // NVIDIA + {"NVIDIA", GPUVendor::Nvidia}, + {"Nouveau", GPUVendor::Nvidia}, + {"NVK", GPUVendor::Nvidia}, + {"Tegra", GPUVendor::Nvidia}, + // AMD + {"AMD", GPUVendor::AMD}, + {"RadeonSI", GPUVendor::AMD}, + {"RADV", GPUVendor::AMD}, + {"AMDVLK", GPUVendor::AMD}, + {"R600", GPUVendor::AMD}, + // Intel + {"Intel", GPUVendor::Intel}, + {"ANV", GPUVendor::Intel}, + {"i965", GPUVendor::Intel}, + {"i915", GPUVendor::Intel}, + {"OpenSWR", GPUVendor::Intel}, + // Apple + {"Apple", GPUVendor::Apple}, + {"MoltenVK", GPUVendor::Apple}, + // Qualcomm / Adreno + {"Qualcomm", GPUVendor::Qualcomm}, + {"Turnip", GPUVendor::Qualcomm}, + // ARM / Mali + {"Mali", GPUVendor::ARM}, + {"PanVK", GPUVendor::ARM}, + // Imagination / PowerVR + {"PowerVR", GPUVendor::Imagination}, + {"PVR", GPUVendor::Imagination}, + // Microsoft / WARP / D3D12 GL + {"D3D12", GPUVendor::Microsoft}, + {"Microsoft", GPUVendor::Microsoft}, + {"WARP", GPUVendor::Microsoft}, + }; + + for (const auto& entry : GpuVendor) { + if (gpu_vendor_string == entry.name) { + return entry.vendor; + } + } + + // legacy (shouldn't be needed anymore, but just in case) + std::string gpu = gpu_vendor_string; + std::transform(gpu.begin(), gpu.end(), gpu.begin(), [](unsigned char c){ return (char)std::tolower(c); }); + if (gpu.find("geforce") != std::string::npos) { + return GPUVendor::Nvidia; + } + if (gpu.find("radeon") != std::string::npos || gpu.find("ati") != std::string::npos) { + return GPUVendor::AMD; + } + + return GPUVendor::Unknown; +} + +static OS DetectOS() { +#if defined(_WIN32) + return OS::Windows; +#elif defined(__FIREOS__) + return OS::FireOS; +#elif defined(__ANDROID__) + return OS::Android; +#elif defined(__OHOS__) + return OS::HarmonyOS; +#elif defined(__HAIKU__) + return OS::HaikuOS; +#elif defined(__DragonFly__) + return OS::DragonFlyBSD; +#elif defined(__NetBSD__) + return OS::NetBSD; +#elif defined(__OpenBSD__) + return OS::OpenBSD; +#elif defined(_AIX) + return OS::AIX; +#elif defined(__managarm__) + return OS::Managarm; +#elif defined(__redox__) + return OS::RedoxOS; +#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE + return OS::IOS; +#elif defined(__APPLE__) + return OS::MacOS; +#elif defined(__FreeBSD__) + return OS::FreeBSD; +#elif defined(__sun) && defined(__SVR4) + return OS::Solaris; +#elif defined(__linux__) + return OS::Linux; +#else + return OS::Unknown; +#endif +} + +EnvironmentInfo DetectEnvironment(const VideoCore::RendererBase& renderer) { + EnvironmentInfo env{}; + env.os = DetectOS(); + env.vendor_string = renderer.GetDeviceVendor(); + env.vendor = GetGPU(env.vendor_string); + return env; +} + +void LoadOverrides(std::uint64_t program_id, const VideoCore::RendererBase& renderer) { + const auto env = DetectEnvironment(renderer); + + switch (static_cast(program_id)) { + case TitleID::NinjaGaidenRagebound: + Settings::values.use_squashed_iterated_blend = true; + break; + default: + break; + } + + LOG_INFO(Core, "Applied game settings for title ID {:016X} on OS {}, GPU vendor {} ({})", + program_id, + static_cast(env.os), + static_cast(env.vendor), + env.vendor_string); +} + +} // namespace Core::GameSettings diff --git a/src/core/game_settings.h b/src/core/game_settings.h new file mode 100644 index 0000000000..327a1a4e2c --- /dev/null +++ b/src/core/game_settings.h @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +namespace VideoCore { class RendererBase; } + +namespace Core::GameSettings { + +enum class OS { + Windows, + Linux, + MacOS, + IOS, + Android, + FireOS, + HarmonyOS, + FreeBSD, + DragonFlyBSD, + NetBSD, + OpenBSD, + HaikuOS, + AIX, + Managarm, + RedoxOS, + Solaris, + Unknown, +}; + +enum class GPUVendor { + Nvidia, + AMD, + Intel, + Apple, + Qualcomm, + ARM, + Imagination, + Microsoft, + Unknown, +}; + +enum class TitleID : std::uint64_t { + NinjaGaidenRagebound = 0x0100781020710000ULL +}; + +struct EnvironmentInfo { + OS os{OS::Unknown}; + GPUVendor vendor{GPUVendor::Unknown}; + std::string vendor_string; // raw string from driver +}; + +EnvironmentInfo DetectEnvironment(const VideoCore::RendererBase& renderer); + +void LoadOverrides(std::uint64_t program_id, const VideoCore::RendererBase& renderer); + +} // namespace Core::GameSettings