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:
Zephyron 2025-02-07 14:52:36 +10:00
parent d4eca46bba
commit 1d379a30dc
No known key found for this signature in database
GPG key ID: 2177ADED8AC966AF
9 changed files with 123 additions and 39 deletions

View file

@ -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 {

View file

@ -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(),
{ {

View file

@ -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);

View file

@ -195,30 +195,77 @@ 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;
auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs"); if (is_ctgp) {
if (exefs_dir != nullptr) { LOG_INFO(Loader, "Processing CTGP patch directory: {}", subdir->GetName());
for (const auto& file : exefs_dir->GetFiles()) {
if (file->GetExtension() == "ips") {
auto name = file->GetName();
const auto this_build_id = auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
fmt::format("{:0<64}", name.substr(0, name.find('.'))); if (exefs_dir != nullptr) {
if (nso_build_id == this_build_id) bool main_npdm_found = false;
out.push_back(file); bool subsdk1_found = false;
} else if (file->GetExtension() == "pchtxt") { for (const auto& file : exefs_dir->GetFiles()) {
IPSwitchCompiler compiler{file}; if (file->GetName() == "main.npdm") {
if (!compiler.IsValid()) main_npdm_found = true;
continue; 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 = Common::HexToString(compiler.GetBuildID()); const auto this_build_id =
if (nso_build_id == this_build_id) fmt::format("{:0<64}", name.substr(0, name.find('.')));
out.push_back(file); 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");
if (exefs_dir != nullptr) {
for (const auto& file : exefs_dir->GetFiles()) {
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);
}
} }
} }
} }
@ -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) {

View file

@ -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;
} }

View file

@ -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;

View file

@ -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) {

View file

@ -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 {

View file

@ -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);
} }