mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-02-07 16:56:21 +01:00
Update Android build configuration, add new CPU and memory options, and enhance patch manager handling for CTGP
- Updated the NDK version to 28.0.13004108. - Changed Java source and target compatibility to version 23. - Enabled resource shrinking and updated ProGuard files. - Added a new CPU accuracy option ("Safe") and a new memory layout option ("Software"). - Implemented special handling for CTGP patches, ensuring they are processed even if disabled. - Added logging for better traceability of patch processing. - Updated memory layout handling in various places to accommodate the new "Software" mode.
This commit is contained in:
parent
d4eca46bba
commit
1d379a30dc
9 changed files with 123 additions and 39 deletions
|
@ -28,7 +28,7 @@ android {
|
||||||
namespace = "org.citron.citron_emu"
|
namespace = "org.citron.citron_emu"
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
|
|
||||||
ndkVersion = "26.3.11579264"
|
ndkVersion = "28.0.13004108" // "26.3.11579264"
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
|
@ -36,8 +36,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_23
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_23
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
|
@ -107,9 +107,11 @@ android {
|
||||||
resValue("string", "app_name_suffixed", "Citron")
|
resValue("string", "app_name_suffixed", "Citron")
|
||||||
isDefault = true
|
isDefault = true
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = true
|
||||||
|
isJniDebuggable = false
|
||||||
isDebuggable = false
|
isDebuggable = false
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro"
|
"proguard-rules.pro"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +124,7 @@ android {
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro"
|
"proguard-rules.pro"
|
||||||
)
|
)
|
||||||
versionNameSuffix = "-relWithDebInfo"
|
versionNameSuffix = "-relWithDebInfo"
|
||||||
|
@ -181,7 +183,7 @@ android {
|
||||||
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||||
)
|
)
|
||||||
|
|
||||||
abiFilters("arm64-v8a", "x86_64")
|
abiFilters("arm64-v8a") //, "x86_64")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,8 +252,6 @@ dependencies {
|
||||||
// Third Party Libraries
|
// Third Party Libraries
|
||||||
implementation("io.coil-kt:coil:2.2.2")
|
implementation("io.coil-kt:coil:2.2.2")
|
||||||
implementation("info.debatty:java-string-similarity:2.0.0")
|
implementation("info.debatty:java-string-similarity:2.0.0")
|
||||||
|
|
||||||
]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runGitCommand(command: List<String>): String {
|
fun runGitCommand(command: List<String>): String {
|
||||||
|
|
|
@ -352,6 +352,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||||
PAIR(CpuAccuracy, Auto, tr("Auto")),
|
PAIR(CpuAccuracy, Auto, tr("Auto")),
|
||||||
PAIR(CpuAccuracy, Accurate, tr("Accurate")),
|
PAIR(CpuAccuracy, Accurate, tr("Accurate")),
|
||||||
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
||||||
|
PAIR(CpuAccuracy, Safe, tr("Safe (recommended for CTGP)")),
|
||||||
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::CpuBackend>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::CpuBackend>::Index(),
|
||||||
|
@ -513,10 +514,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||||
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
|
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
|
||||||
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
|
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM")),
|
||||||
PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")),
|
PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")),
|
||||||
PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")),
|
PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM")),
|
||||||
PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")),
|
PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM")),
|
||||||
|
PAIR(MemoryLayout, Software, tr("Software (Maximum compatibility)")),
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,9 +132,9 @@ ENUM(GpuAccuracy, Normal, High, Extreme);
|
||||||
|
|
||||||
ENUM(CpuBackend, Dynarmic, Nce);
|
ENUM(CpuBackend, Dynarmic, Nce);
|
||||||
|
|
||||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Safe);
|
||||||
|
|
||||||
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb, Memory_10Gb, Memory_12Gb);
|
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb, Memory_10Gb, Memory_12Gb, Software);
|
||||||
|
|
||||||
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||||
|
|
||||||
|
|
|
@ -195,12 +195,58 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
||||||
|
|
||||||
|
// Special handling for CTGP patches
|
||||||
|
const bool is_ctgp = patch_dirs.size() == 1 &&
|
||||||
|
Common::ToLower(patch_dirs[0]->GetName()).find("ctgp") != std::string::npos;
|
||||||
|
|
||||||
std::vector<VirtualFile> out;
|
std::vector<VirtualFile> out;
|
||||||
out.reserve(patch_dirs.size());
|
out.reserve(patch_dirs.size());
|
||||||
for (const auto& subdir : patch_dirs) {
|
for (const auto& subdir : patch_dirs) {
|
||||||
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend())
|
// For CTGP patches, ensure we load them even if disabled
|
||||||
|
if (!is_ctgp && std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (is_ctgp) {
|
||||||
|
LOG_INFO(Loader, "Processing CTGP patch directory: {}", subdir->GetName());
|
||||||
|
|
||||||
|
auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
|
||||||
|
if (exefs_dir != nullptr) {
|
||||||
|
bool main_npdm_found = false;
|
||||||
|
bool subsdk1_found = false;
|
||||||
|
for (const auto& file : exefs_dir->GetFiles()) {
|
||||||
|
if (file->GetName() == "main.npdm") {
|
||||||
|
main_npdm_found = true;
|
||||||
|
LOG_INFO(Loader, "Found main.npdm in CTGP patch directory.");
|
||||||
|
}
|
||||||
|
if (file->GetName() == "subsdk1") {
|
||||||
|
subsdk1_found = true;
|
||||||
|
LOG_INFO(Loader, "Found subsdk1 in CTGP patch directory.");
|
||||||
|
}
|
||||||
|
if (file->GetExtension() == "ips") {
|
||||||
|
auto name = file->GetName();
|
||||||
|
|
||||||
|
const auto this_build_id =
|
||||||
|
fmt::format("{:0<64}", name.substr(0, name.find('.')));
|
||||||
|
if (nso_build_id == this_build_id)
|
||||||
|
out.push_back(file);
|
||||||
|
} else if (file->GetExtension() == "pchtxt") {
|
||||||
|
IPSwitchCompiler compiler{file};
|
||||||
|
if (!compiler.IsValid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto this_build_id = Common::HexToString(compiler.GetBuildID());
|
||||||
|
if (nso_build_id == this_build_id)
|
||||||
|
out.push_back(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!main_npdm_found) {
|
||||||
|
LOG_ERROR(Loader, "main.npdm not found in CTGP patch directory.");
|
||||||
|
}
|
||||||
|
if (!subsdk1_found) {
|
||||||
|
LOG_ERROR(Loader, "subsdk1 not found in CTGP patch directory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
|
auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
|
||||||
if (exefs_dir != nullptr) {
|
if (exefs_dir != nullptr) {
|
||||||
for (const auto& file : exefs_dir->GetFiles()) {
|
for (const auto& file : exefs_dir->GetFiles()) {
|
||||||
|
@ -223,6 +269,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -263,10 +310,27 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
||||||
return nso;
|
return nso;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special handling for CTGP
|
||||||
|
if (name == "main" || name == "subsdk0") {
|
||||||
|
LOG_INFO(Loader, "Applying CTGP-specific patch handling for {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
auto patch_dirs = load_dir->GetSubdirectories();
|
auto patch_dirs = load_dir->GetSubdirectories();
|
||||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||||
const auto patches = CollectPatches(patch_dirs, build_id);
|
|
||||||
|
// Prioritize CTGP patches if present
|
||||||
|
const auto ctgp_dir = FindSubdirectoryCaseless(load_dir, "CTGP");
|
||||||
|
std::vector<VirtualFile> patches;
|
||||||
|
if (ctgp_dir != nullptr && (name == "main" || name == "subsdk0")) {
|
||||||
|
patches = CollectPatches({ctgp_dir}, build_id);
|
||||||
|
if (!patches.empty()) {
|
||||||
|
LOG_INFO(Loader, "Found CTGP-specific patches for {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (patches.empty()) {
|
||||||
|
patches = CollectPatches(patch_dirs, build_id);
|
||||||
|
}
|
||||||
|
|
||||||
auto out = nso;
|
auto out = nso;
|
||||||
for (const auto& patch_file : patches) {
|
for (const auto& patch_file : patches) {
|
||||||
|
|
|
@ -52,6 +52,8 @@ u32 GetMemorySizeForInit() {
|
||||||
return Smc::MemorySize_10GB;
|
return Smc::MemorySize_10GB;
|
||||||
case Settings::MemoryLayout::Memory_12Gb:
|
case Settings::MemoryLayout::Memory_12Gb:
|
||||||
return Smc::MemorySize_12GB;
|
return Smc::MemorySize_12GB;
|
||||||
|
case Settings::MemoryLayout::Software:
|
||||||
|
return Smc::MemorySize_12GB; // Use maximum size for software mode
|
||||||
}
|
}
|
||||||
return Smc::MemorySize_4GB;
|
return Smc::MemorySize_4GB;
|
||||||
}
|
}
|
||||||
|
@ -68,6 +70,8 @@ Smc::MemoryArrangement GetMemoryArrangeForInit() {
|
||||||
return Smc::MemoryArrangement_10GB;
|
return Smc::MemoryArrangement_10GB;
|
||||||
case Settings::MemoryLayout::Memory_12Gb:
|
case Settings::MemoryLayout::Memory_12Gb:
|
||||||
return Smc::MemoryArrangement_12GB;
|
return Smc::MemoryArrangement_12GB;
|
||||||
|
case Settings::MemoryLayout::Software:
|
||||||
|
return Smc::MemoryArrangement_12GB; // Use maximum arrangement for software mode
|
||||||
}
|
}
|
||||||
return Smc::MemoryArrangement_4GB;
|
return Smc::MemoryArrangement_4GB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
|
||||||
|
|
||||||
constexpr std::size_t MainMemorySize = 4_GiB;
|
constexpr std::size_t MainMemorySize = 4_GiB;
|
||||||
constexpr std::size_t MainMemorySizeMax = 12_GiB;
|
constexpr std::size_t MainMemorySizeMax = 12_GiB;
|
||||||
|
constexpr std::size_t SoftwareMemorySize = 4_GiB; // Fixed size for software memory management mode
|
||||||
|
|
||||||
constexpr std::size_t ReservedEarlyDramSize = 384_KiB;
|
constexpr std::size_t ReservedEarlyDramSize = 384_KiB;
|
||||||
constexpr std::size_t DramPhysicalAddress = 0x80000000;
|
constexpr std::size_t DramPhysicalAddress = 0x80000000;
|
||||||
|
|
|
@ -36,13 +36,14 @@ constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
KMemoryManager::KMemoryManager(Core::System& system)
|
KMemoryManager::KMemoryManager(Core::System& system)
|
||||||
: m_system{system}, m_memory_layout{system.Kernel().MemoryLayout()},
|
: m_system{system},
|
||||||
m_pool_locks{
|
m_memory_layout{system.Kernel().MemoryLayout()},
|
||||||
KLightLock{system.Kernel()},
|
m_pool_locks{KLightLock{system.Kernel()}, // Application
|
||||||
KLightLock{system.Kernel()},
|
KLightLock{system.Kernel()}, // Applet
|
||||||
KLightLock{system.Kernel()},
|
KLightLock{system.Kernel()}, // System
|
||||||
KLightLock{system.Kernel()},
|
KLightLock{system.Kernel()}, // SystemNonSecure
|
||||||
} {}
|
KLightLock{system.Kernel()}} { // Software
|
||||||
|
}
|
||||||
|
|
||||||
void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size) {
|
void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size) {
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
Applet = 1,
|
Applet = 1,
|
||||||
System = 2,
|
System = 2,
|
||||||
SystemNonSecure = 3,
|
SystemNonSecure = 3,
|
||||||
|
Software = 4, // Software memory management mode
|
||||||
|
|
||||||
Count,
|
Count,
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ public:
|
||||||
// Aliases.
|
// Aliases.
|
||||||
Unsafe = Application,
|
Unsafe = Application,
|
||||||
Secure = System,
|
Secure = System,
|
||||||
|
Safe = Software, // Alias for software mode
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Direction : u32 {
|
enum class Direction : u32 {
|
||||||
|
|
|
@ -182,6 +182,11 @@ struct Memory::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write8(const Common::ProcessAddress addr, const u8 data) {
|
void Write8(const Common::ProcessAddress addr, const u8 data) {
|
||||||
|
// Check for null pointer write
|
||||||
|
if (addr == 0 || addr < 0x1000) {
|
||||||
|
LOG_ERROR(HW_Memory, "Null pointer Write8 @ 0x{:016X} = 0x{:02X}", addr, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Write<u8>(addr, data);
|
Write<u8>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,6 +997,11 @@ u64 Memory::Read64(const Common::ProcessAddress addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::Write8(Common::ProcessAddress addr, u8 data) {
|
void Memory::Write8(Common::ProcessAddress addr, u8 data) {
|
||||||
|
// Check for null pointer write
|
||||||
|
if (addr == 0 || addr < 0x1000) {
|
||||||
|
LOG_ERROR(HW_Memory, "Null pointer Write8 @ 0x{:016X} = 0x{:02X}", addr, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
impl->Write8(addr, data);
|
impl->Write8(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue