mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-08-23 19:06:11 -05:00
Merge pull request #14665 from cristian64/simulated_memory_size
Core: Adjust emulated memory size automatically.
This commit is contained in:
@@ -400,7 +400,7 @@
|
||||
<string name="overclock_title_description">Adjusts the emulated CPU\'s clock rate if \"Override Emulated CPU Clock Speed\" is enabled.</string>
|
||||
<string name="memory_override">Memory Override</string>
|
||||
<string name="enable_memory_size_override">Enable Emulated Memory Size Override</string>
|
||||
<string name="enable_memory_size_override_description">Adjusts the amount of RAM in the emulated console.\n\nWARNING: Enabling this will completely break many games. Only a small number of games can benefit from this.</string>
|
||||
<string name="enable_memory_size_override_description">Sets the amount of RAM in the emulated console to the values provided.\n\nWARNING: Enabling this will completely break many games. By default, Dolphin determines what value is required based on the game information.</string>
|
||||
<string name="main_mem1_size">MEM1 Size</string>
|
||||
<string name="main_mem2_size">MEM2 Size</string>
|
||||
<string name="gpu_options">GPU Options</string>
|
||||
|
||||
@@ -154,27 +154,35 @@ u16 SConfig::GetRevision() const
|
||||
return m_revision;
|
||||
}
|
||||
|
||||
u32 SConfig::GetSimulatedMemorySize() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_simulated_memory_size;
|
||||
}
|
||||
|
||||
void SConfig::ResetRunningGameMetadata()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
SetRunningGameMetadata("00000000", "", 0, 0, DiscIO::Region::Unknown);
|
||||
SetRunningGameMetadata("00000000", "", 0, 0, DiscIO::Region::Unknown, 0);
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume,
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
|
||||
if (partition == volume.GetGamePartition())
|
||||
{
|
||||
SetRunningGameMetadata(volume.GetGameID(), volume.GetGameTDBID(),
|
||||
volume.GetTitleID().value_or(0), volume.GetRevision().value_or(0),
|
||||
volume.GetRegion());
|
||||
volume.GetRegion(), volume.GetSimulatedMemorySize());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRunningGameMetadata(volume.GetGameID(partition), volume.GetGameTDBID(partition),
|
||||
volume.GetTitleID(partition).value_or(0),
|
||||
volume.GetRevision(partition).value_or(0), volume.GetRegion());
|
||||
volume.GetRevision(partition).value_or(0), volume.GetRegion(),
|
||||
volume.GetSimulatedMemorySize());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,26 +200,29 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Plat
|
||||
{
|
||||
// If not launching a disc game, just read everything from the TMD.
|
||||
SetRunningGameMetadata(tmd.GetGameID(), tmd.GetGameTDBID(), tmd_title_id, tmd.GetTitleVersion(),
|
||||
tmd.GetRegion());
|
||||
tmd.GetRegion(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const std::string& game_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
SetRunningGameMetadata(game_id, "", 0, 0, DiscIO::Region::Unknown);
|
||||
SetRunningGameMetadata(game_id, "", 0, 0, DiscIO::Region::Unknown, 0);
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id,
|
||||
u64 title_id, u16 revision, DiscIO::Region region)
|
||||
u64 title_id, u16 revision, DiscIO::Region region,
|
||||
u32 simulated_memory_size)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
const bool was_changed = m_game_id != game_id || m_gametdb_id != gametdb_id ||
|
||||
m_title_id != title_id || m_revision != revision;
|
||||
m_title_id != title_id || m_revision != revision ||
|
||||
m_simulated_memory_size != simulated_memory_size;
|
||||
m_game_id = game_id;
|
||||
m_gametdb_id = gametdb_id;
|
||||
m_title_id = title_id;
|
||||
m_revision = revision;
|
||||
m_simulated_memory_size = simulated_memory_size;
|
||||
|
||||
if (game_id.length() == 6)
|
||||
{
|
||||
|
||||
@@ -65,6 +65,7 @@ struct SConfig
|
||||
const std::string GetTitleDescription() const;
|
||||
u64 GetTitleID() const;
|
||||
u16 GetRevision() const;
|
||||
u32 GetSimulatedMemorySize() const;
|
||||
void ResetRunningGameMetadata();
|
||||
void SetRunningGameMetadata(const DiscIO::Volume& volume, const DiscIO::Partition& partition);
|
||||
void SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Platform platform);
|
||||
@@ -119,7 +120,8 @@ private:
|
||||
static void ReloadTextures(Core::System& system);
|
||||
|
||||
void SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id,
|
||||
u64 title_id, u16 revision, DiscIO::Region region);
|
||||
u64 title_id, u16 revision, DiscIO::Region region,
|
||||
u32 simulated_memory_size);
|
||||
|
||||
static SConfig* m_Instance;
|
||||
mutable std::recursive_mutex m_metadata_lock;
|
||||
@@ -130,4 +132,6 @@ private:
|
||||
std::string m_title_description;
|
||||
u64 m_title_id;
|
||||
u16 m_revision;
|
||||
// Memory size requested by game's header.
|
||||
u32 m_simulated_memory_size;
|
||||
};
|
||||
|
||||
@@ -354,6 +354,9 @@ void DolphinAnalytics::MakePerGameBuilder()
|
||||
// Unique id bound to the gameid.
|
||||
builder.AddData("id", MakeUniqueId(SConfig::GetInstance().GetGameID()));
|
||||
|
||||
// Other game-specific fields.
|
||||
builder.AddData("simulated-memory-size", SConfig::GetInstance().GetSimulatedMemorySize());
|
||||
|
||||
// Configuration.
|
||||
builder.AddData("cfg-dsp-hle", Config::Get(Config::MAIN_DSP_HLE));
|
||||
builder.AddData("cfg-dsp-jit", Config::Get(Config::MAIN_DSP_JIT));
|
||||
|
||||
@@ -140,7 +140,8 @@ bool FifoDataFile::Save(const std::string& filename)
|
||||
header.fileId = FILE_ID;
|
||||
header.file_version = VERSION_NUMBER;
|
||||
// Maintain backwards compatibility so long as the RAM sizes aren't overridden.
|
||||
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
|
||||
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE) ||
|
||||
SConfig::GetInstance().GetSimulatedMemorySize() > Memory::MEM1_SIZE_RETAIL)
|
||||
header.min_loader_version = MIN_LOADER_VERSION_FOR_RAM_OVERRIDE;
|
||||
else
|
||||
header.min_loader_version = MIN_LOADER_VERSION;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Swap.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/AudioInterface.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
@@ -87,10 +88,18 @@ void MemoryManager::InitMMIO(Core::System& system)
|
||||
|
||||
void MemoryManager::Init()
|
||||
{
|
||||
const auto get_mem1_size = [] {
|
||||
const auto get_mem1_size = [this] {
|
||||
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
|
||||
return Config::Get(Config::MAIN_MEM1_SIZE);
|
||||
return Memory::MEM1_SIZE_RETAIL;
|
||||
// The simulated memory size in the game's header was originally used to ask the Apploader to
|
||||
// simulate a smaller memory size than that in development systems. That is, it could make the
|
||||
// 48 MiB devkit act like a 24 MiB retail console during testing, or any other config.
|
||||
//
|
||||
// Dolphin is reusing this as a signal to automatically adjust the emulated memory size. The
|
||||
// upper bound is clamped to 64 MiB (maximum supported by Flipper's memory controller),
|
||||
// reflecting Apploader behaviour of clamping the simulated size to physical memory size. It is
|
||||
// never desired to emulate less than a retail console, so the lower bound is clapped to 24 MiB.
|
||||
return std::clamp(m_system.GetSimulatedMemorySize(), MEM1_SIZE_RETAIL, MEM1_SIZE_MAX);
|
||||
};
|
||||
const auto get_mem2_size = [] {
|
||||
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
|
||||
|
||||
@@ -34,8 +34,10 @@ constexpr u32 MEM1_BASE_ADDR = 0x80000000U;
|
||||
constexpr u32 MEM2_BASE_ADDR = 0x90000000U;
|
||||
constexpr u32 MEM1_SIZE_RETAIL = 0x01800000U;
|
||||
constexpr u32 MEM1_SIZE_GDEV = 0x04000000U;
|
||||
constexpr u32 MEM1_SIZE_MAX = 0x04000000U;
|
||||
constexpr u32 MEM2_SIZE_RETAIL = 0x04000000U;
|
||||
constexpr u32 MEM2_SIZE_NDEV = 0x08000000U;
|
||||
constexpr u32 MEM2_SIZE_MAX = 0x08000000U;
|
||||
|
||||
struct PhysicalMemoryRegion
|
||||
{
|
||||
|
||||
@@ -221,8 +221,11 @@ static void ReleasePPCAncast(Core::System& system)
|
||||
void RAMOverrideForIOSMemoryValues(Memory::MemoryManager& memory, MemorySetupType setup_type)
|
||||
{
|
||||
// Don't touch anything if the feature isn't enabled.
|
||||
if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
|
||||
if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE) ||
|
||||
SConfig::GetInstance().GetSimulatedMemorySize() <= Memory::MEM1_SIZE_RETAIL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Some unstated constants that can be inferred.
|
||||
const u32 ipc_buffer_size =
|
||||
|
||||
@@ -119,6 +119,7 @@ void System::Initialize()
|
||||
m_separate_cpu_and_gpu_threads = Config::Get(Config::MAIN_CPU_THREAD);
|
||||
m_mmu_enabled = Config::Get(Config::MAIN_MMU);
|
||||
m_pause_on_panic_enabled = Config::Get(Config::MAIN_PAUSE_ON_PANIC);
|
||||
m_simulated_memory_size = SConfig::GetInstance().GetSimulatedMemorySize();
|
||||
}
|
||||
|
||||
SoundStream* System::GetSoundStream() const
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class GeometryShaderManager;
|
||||
class Interpreter;
|
||||
class JitInterface;
|
||||
@@ -147,6 +149,7 @@ public:
|
||||
bool IsTriforce() const { return m_is_triforce; }
|
||||
bool IsWii() const { return m_is_wii; }
|
||||
bool IsBranchWatchIgnoreApploader() { return m_branch_watch_ignore_apploader; }
|
||||
u32 GetSimulatedMemorySize() const { return m_simulated_memory_size; }
|
||||
|
||||
void SetIsMIOS(bool is_mios) { m_is_mios = is_mios; }
|
||||
void SetIsTriforce(bool is_triforce) { m_is_triforce = is_triforce; }
|
||||
@@ -216,5 +219,6 @@ private:
|
||||
bool m_is_triforce = false;
|
||||
bool m_is_wii = false;
|
||||
bool m_branch_watch_ignore_apploader = false;
|
||||
u32 m_simulated_memory_size{0};
|
||||
};
|
||||
} // namespace Core
|
||||
|
||||
@@ -126,6 +126,7 @@ public:
|
||||
}
|
||||
virtual Region GetRegion() const = 0;
|
||||
virtual Country GetCountry(const Partition& partition = PARTITION_NONE) const = 0;
|
||||
virtual u32 GetSimulatedMemorySize() const = 0;
|
||||
virtual BlobType GetBlobType() const = 0;
|
||||
// Size of virtual disc (may be inaccurate depending on the blob type)
|
||||
virtual u64 GetDataSize() const = 0;
|
||||
|
||||
@@ -179,6 +179,14 @@ std::optional<u8> VolumeDisc::GetDiscNumber(const Partition& partition) const
|
||||
return ReadSwapped<u8>(6, partition);
|
||||
}
|
||||
|
||||
u32 VolumeDisc::GetSimulatedMemorySize() const
|
||||
{
|
||||
// Simulated memory size is a 32-bit unsigned integer in the `bi2.bin` file at offset `0x04`.
|
||||
// Apploader reads this and "simulates" a smaller memory size. Originally useful for simulating
|
||||
// 24 MiB of memory on devkits with 48 MiB.
|
||||
return ReadSwapped<u32>(BI2_ADDRESS + 0x04, GetGamePartition()).value_or(0);
|
||||
}
|
||||
|
||||
bool VolumeDisc::IsNKit() const
|
||||
{
|
||||
constexpr u32 NKIT_MAGIC = 0x4E4B4954; // "NKIT"
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
std::string GetInternalName(const Partition& partition = PARTITION_NONE) const override;
|
||||
std::string GetApploaderDate(const Partition& partition) const override;
|
||||
std::optional<u8> GetDiscNumber(const Partition& partition = PARTITION_NONE) const override;
|
||||
u32 GetSimulatedMemorySize() const override;
|
||||
bool IsNKit() const override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
bool IsNKit() const override;
|
||||
Region GetRegion() const override;
|
||||
Country GetCountry(const Partition& partition = PARTITION_NONE) const override;
|
||||
u32 GetSimulatedMemorySize() const override { return 0; }
|
||||
|
||||
BlobType GetBlobType() const override;
|
||||
u64 GetDataSize() const override;
|
||||
|
||||
@@ -276,10 +276,9 @@ void AdvancedPane::CreateLayout()
|
||||
});
|
||||
|
||||
m_ram_override_checkbox->SetDescription(
|
||||
tr("Adjusts the amount of RAM in the emulated console.<br><br>"
|
||||
"<b>WARNING</b>: Enabling this will completely break many games.<br>Only a small "
|
||||
"number "
|
||||
"of games can benefit from this."
|
||||
tr("Sets the amount of RAM in the emulated console to the values provided.<br><br>"
|
||||
"<b>WARNING</b>: Enabling this will completely break many games. By default, Dolphin "
|
||||
"determines what value is required based on the game information."
|
||||
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||
|
||||
auto* rtc_options = new QGroupBox(tr("Custom RTC Options"));
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Common/Align.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Swap.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/MemTools.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
@@ -131,6 +132,8 @@ public:
|
||||
if (!EMM::IsExceptionHandlerSupported())
|
||||
GTEST_SKIP() << "Skipping PageTableHostMappingTest because exception handler is unsupported.";
|
||||
|
||||
SConfig::Init();
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
const u32 host_page_size = memory.GetHostPageSize();
|
||||
@@ -177,6 +180,8 @@ public:
|
||||
EMM::UninstallExceptionHandler();
|
||||
Core::UndeclareAsCPUThread();
|
||||
system.GetMemory().Shutdown();
|
||||
|
||||
SConfig::Shutdown();
|
||||
}
|
||||
|
||||
static void SetSR(size_t index, u32 vsid)
|
||||
|
||||
Reference in New Issue
Block a user