Skip to content

Commit 3719666

Browse files
committed
Improve iOS graphics and ARM64 EE timing
1 parent 4237df8 commit 3719666

4 files changed

Lines changed: 70 additions & 9 deletions

File tree

app/src/main/cpp/ios_main.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4255,7 +4255,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
42554255
#endif
42564256
fprintf(stderr, "@@BUILD_ID@@ ARMSX2_iOS v%s %s %s %s\n",
42574257
ARMSX2_VERSION_STR, ARMSX2_GIT_HASH, __DATE__, __TIME__);
4258-
fprintf(stderr, "@@TEST_MARKER@@ armsx2_ios_28_ff_presentcap60_v1\n");
4258+
fprintf(stderr, "@@TEST_MARKER@@ armsx2_ios_30_mac_ee_timing_sonic_v1\n");
42594259
fprintf(stderr, "@@FF_FIX@@ offspeed_present_skip=1 present_cap60=1 adaptive_backoff=1 drawable_wait_probe=1 vm_pace_probe=1 turbo_only_toggle=1\n");
42604260
fprintf(stderr, "@@DIAG_MODE@@ ee_hotpath=%d\n", ARMSX2_ENABLE_EE_HOTPATH_DIAGNOSTICS);
42614261

app/src/main/cpp/pcsx2/Counters.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include <time.h>
55
#include <cmath>
6+
#include <cstdio>
7+
#include <string>
68

79
#include "Common.h"
810
#include "R3000A.h"
@@ -21,6 +23,10 @@
2123
#include "VMManager.h"
2224
#include "VUmicro.h"
2325

26+
#if defined(__APPLE__)
27+
#include <TargetConditionals.h>
28+
#endif
29+
2430
static const uint EECNT_FUTURE_TARGET = 0x10000000;
2531

2632
uint g_FrameCount = 0;
@@ -479,8 +485,22 @@ static __fi void DoFMVSwitch()
479485
if (EmuConfig.Gamefixes.SoftwareRendererFMVHack && EmuConfig.GS.UseHardwareRenderer())
480486
{
481487
DevCon.Warning("FMV Switch");
488+
#if defined(__APPLE__) && TARGET_OS_IPHONE
489+
const std::string serial = VMManager::GetDiscSerial();
490+
std::fprintf(stderr,
491+
"@@IOS_FMV_SWITCH_BEGIN@@ serial=\"%s\" state=%d renderer=%d interlace=%d hw=1\n",
492+
serial.c_str(), new_fmv_state ? 1 : 0, static_cast<int>(EmuConfig.GS.Renderer),
493+
static_cast<int>(EmuConfig.GS.InterlaceMode));
494+
std::fflush(stderr);
495+
#endif
482496
// we don't use the sw toggle here, because it'll change back to auto if set to sw
483497
MTGS::SetSoftwareRendering(new_fmv_state, new_fmv_state ? GSInterlaceMode::AdaptiveTFF : EmuConfig.GS.InterlaceMode, false);
498+
#if defined(__APPLE__) && TARGET_OS_IPHONE
499+
std::fprintf(stderr,
500+
"@@IOS_FMV_SWITCH_END@@ serial=\"%s\" state=%d\n",
501+
serial.c_str(), new_fmv_state ? 1 : 0);
502+
std::fflush(stderr);
503+
#endif
484504
}
485505
}
486506

app/src/main/cpp/pcsx2/GameDatabase.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,11 @@ static bool IsIOSBlackGame(const std::string& name)
465465
return name == "Black";
466466
}
467467

468+
static bool IsIOSSonicUnleashedGame(const std::string& name)
469+
{
470+
return name == "Sonic Unleashed";
471+
}
472+
468473
// Midnight Club 3 (DUB Edition + DUB Edition Remix). Its GameDB entry uses the
469474
// GSC_MidnightClub3 skip-count callback to drop broken bloom draws. The callback
470475
// only ever *skips* draws (no extra barriers or copies), which makes it one of
@@ -601,7 +606,9 @@ static bool IsIOSMetalAllowedAutoGSHWCallback(const GameDatabaseSchema::GameEntr
601606
case GameDatabaseSchema::GSHWFixId::BeforeDraw:
602607
{
603608
static const s16 burnout_games = GSLookupBeforeDrawFunctionId("OI_BurnoutGames");
604-
return (IsIOSBurnoutMetalCallbackGame(entry.name) || IsIOSBlackGame(entry.name)) && value == burnout_games;
609+
static const s16 sonic_unleashed = GSLookupBeforeDrawFunctionId("OI_SonicUnleashed");
610+
return ((IsIOSBurnoutMetalCallbackGame(entry.name) || IsIOSBlackGame(entry.name)) && value == burnout_games) ||
611+
(IsIOSSonicUnleashedGame(entry.name) && value == sonic_unleashed);
605612
}
606613

607614
default:
@@ -629,7 +636,9 @@ static bool IsIOSMetalAllowedCompatLabOffGSHWFix(const GameDatabaseSchema::GameE
629636
case GameDatabaseSchema::GSHWFixId::BeforeDraw:
630637
{
631638
static const s16 burnout_games = GSLookupBeforeDrawFunctionId("OI_BurnoutGames");
632-
return (IsIOSBurnoutMetalCallbackGame(entry.name) || IsIOSBlackGame(entry.name)) && value == burnout_games;
639+
static const s16 sonic_unleashed = GSLookupBeforeDrawFunctionId("OI_SonicUnleashed");
640+
return ((IsIOSBurnoutMetalCallbackGame(entry.name) || IsIOSBlackGame(entry.name)) && value == burnout_games) ||
641+
(IsIOSSonicUnleashedGame(entry.name) && value == sonic_unleashed);
633642
}
634643

635644
default:

app/src/main/cpp/pcsx2/arm64/aR5900.cpp

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3111,6 +3111,26 @@ static u32 recScaleBlockCycles(u32 raw)
31113111
return (scale_cycles < 1) ? 1 : scale_cycles;
31123112
}
31133113

3114+
// True for ops that run the interpreter inline AND need a live, current cpuRegs.cycle.
3115+
// COP2 / VU0-macro ops (opcode 0x12, excluding BC2 branches) sync VU state from
3116+
// cpuRegs.cycle, so commit the block's accumulated cycles before executing them.
3117+
static bool recOpNeedsCycleFlush(u32 op)
3118+
{
3119+
return (op >> 26) == 0x12 && ((op >> 21) & 0x1f) != 0x08;
3120+
}
3121+
3122+
// Emit: cpuRegs.cycle += recScaleBlockCycles(raw). Used mid-block before inline
3123+
// COP2/VU0-macro interpreter calls so they observe current EE time.
3124+
static void recEmitFlushCycles(u32 raw)
3125+
{
3126+
if (raw == 0)
3127+
return;
3128+
3129+
armAsm->Ldr(RSCRATCHADDR, a64::MemOperand(RESTATEPTR, EE_CYCLE_OFFSET));
3130+
armAsm->Add(RSCRATCHADDR, RSCRATCHADDR, recScaleBlockCycles(raw));
3131+
armAsm->Str(RSCRATCHADDR, a64::MemOperand(RESTATEPTR, EE_CYCLE_OFFSET));
3132+
}
3133+
31143134
// Install a freshly-compiled block's self-modifying-code protection and return the pointer
31153135
// to record in its recLUT slot. Direct port of x86 memory_protect_recompiled_code
31163136
// (iR5900.cpp), adapted to this port's body-first layout: the caller has already emitted
@@ -3463,6 +3483,10 @@ static void recRecompile(u32 startpc)
34633483
u32 pc = startpc;
34643484
u32 endpc = startpc;
34653485
u32 raw_cycles = 0;
3486+
const u32 ee_cycle_mult = 2 - ((cpuRegs.CP0.n.Config >> 18) & 0x1);
3487+
const auto eeOpCycles = [ee_cycle_mult](u32 opc) -> u32 {
3488+
return (opc == 0 ? 9u : static_cast<u32>(R5900::GetInstruction(opc).cycles)) * ee_cycle_mult;
3489+
};
34663490
u32 compiled = 0;
34673491
bool interp_step = false;
34683492
bool known_dispatch_pc = false;
@@ -3491,12 +3515,11 @@ static void recRecompile(u32 startpc)
34913515
}
34923516

34933517
const u32 op = memRead32(pc);
3494-
const R5900::OPCODE& info = R5900::GetInstruction(op);
34953518

34963519
if (recIsHandledBranch(op))
34973520
{
34983521
// Terminate the block: branch generator + delay slot + dispatch tail.
3499-
raw_cycles += info.cycles;
3522+
raw_cycles += eeOpCycles(op);
35003523
branch_tail = true;
35013524
tail_reason = "branch";
35023525
known_dispatch_pc = recGetKnownBranchTarget(op, pc, const_state, &dispatch_pc);
@@ -3506,7 +3529,7 @@ static void recRecompile(u32 startpc)
35063529
recConstApplyBranchLink(op, pc, const_state);
35073530

35083531
const u32 delay_op = memRead32(pc + 4);
3509-
raw_cycles += R5900::GetInstruction(delay_op).cycles;
3532+
raw_cycles += eeOpCycles(delay_op);
35103533
recEmitOp(delay_op, const_state, cache_state); // delay slot — must not write cpuRegs.pc
35113534
endpc = pc + 8;
35123535

@@ -3543,7 +3566,7 @@ static void recRecompile(u32 startpc)
35433566
// test + PC select, then jump over the delay-slot code when not taken.
35443567
// The cache/const state diverges across the two paths, so it is flushed
35453568
// and discarded inside the taken path before the skip label.
3546-
raw_cycles += info.cycles;
3569+
raw_cycles += eeOpCycles(op);
35473570
branch_tail = true;
35483571
tail_reason = "branch_likely";
35493572

@@ -3558,7 +3581,7 @@ static void recRecompile(u32 startpc)
35583581
armAsm->B(&skip_delay, a64::InvertCondition(taken));
35593582

35603583
const u32 delay_op = memRead32(pc + 4);
3561-
raw_cycles += R5900::GetInstruction(delay_op).cycles;
3584+
raw_cycles += eeOpCycles(delay_op);
35623585
recEmitOp(delay_op, const_state, cache_state);
35633586
recCacheFlushAll(cache_state);
35643587
recCacheKillAll(cache_state);
@@ -3572,6 +3595,14 @@ static void recRecompile(u32 startpc)
35723595
break;
35733596
}
35743597

3598+
const bool needs_cycle_flush = recOpNeedsCycleFlush(op);
3599+
if (needs_cycle_flush)
3600+
{
3601+
raw_cycles += eeOpCycles(op);
3602+
recEmitFlushCycles(raw_cycles);
3603+
raw_cycles = 0;
3604+
}
3605+
35753606
// Straight-line op we can codegen? (Generators decode from `op` directly;
35763607
// they never read cpuRegs.code, so nothing to set here at compile time.)
35773608
if (recTranslateOpOptimized(op, const_state, cache_state))
@@ -3582,7 +3613,8 @@ static void recRecompile(u32 startpc)
35823613
else
35833614
waitloop_possible = false;
35843615

3585-
raw_cycles += info.cycles;
3616+
if (!needs_cycle_flush)
3617+
raw_cycles += eeOpCycles(op);
35863618
pc += 4;
35873619
endpc = pc;
35883620
if (++compiled >= MAX_BLOCK_INSTS)

0 commit comments

Comments
 (0)