hrydgard / ppsspp

A PSP emulator for Android, Windows, Mac and Linux, written in C++. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues. For discussion use the forums at forums.ppsspp.org.
https://www.ppsspp.org
Other
11.43k stars 2.19k forks source link

ULJS00218 - Hitman Reborn Battle Arena 2 - Player 2 side broken/reversed/broken kick animation #12900

Closed somepunkid closed 3 years ago

somepunkid commented 4 years ago

What happens?

In-Game/Fights, particle effects and physics only applying correctly on Player 1 side during fights. On Player 2 side, properties operate as if they are being performed from P1 side. This leads to reversed effects and physics being applied to everything from P2 side. This effectively makes the game unstable/unplayable, since only one player side functions correctly.

What should happen?

Here is the direct comparison with the same variables on both hardware and emulation. https://youtu.be/q1YjrLXTq7c

What hardware, operating system, and PPSSPP version? On desktop, GPU matters for graphical issues:

This was most recently tested with the UMD directly, to ensure there wasn't an issue with the source file being tested.

Win10 / Android (unknown config for android, was tested on two devices in the past and not working) PPSSPP v1.9.3 Direct3D11/9, OpenGL, Vulkan Nvidia 2080 Max-Q and Nvidia 970m tested with current build. Many other configs have been tested with previous builds over multiple years.

hrydgard commented 4 years ago

Very very odd! That has to be a CPU emulation bug... and likely not just a JIT bug. If you switch CPU core to the interpreter in developer settings, it's still the same, right?

somepunkid commented 4 years ago

Very very odd! That has to be a CPU emulation bug... and likely not just a JIT bug. If you switch CPU core to the interpreter in developer settings, it's still the same, right?

This is odd, and kind of hilarious! I have now tested the Interpreter/IR Interpreter settings with the same result. PPSSPP v1.9.3 Direct3D11 / Nvidia 2080 Max-Q / i7-8750H

hrydgard commented 4 years ago

Thanks for testing that!

somepunkid commented 4 years ago

Thanks for testing that!

Of course! Let me know if there's any other variables I should test using the emulator. Would be a dream to get it running 100%, big enthusiast for this specific title.

I was going through the other logs in here and it seems like these CPU emulation bugs are not super common now? Saw some older ones for Warriors Orochi/Metal Gear Acid etc I believe...

hrydgard commented 4 years ago

No, they are rare indeed, we've got pretty good hardware tests for most of the CPU's functionality. So something like this that looks like a really bad sign error is kind of surprising indeed...

somepunkid commented 4 years ago

No, they are rare indeed, we've got pretty good hardware tests for most of the CPU's functionality. So something like this that looks like a really bad sign error is kind of surprising indeed...

Is this something that is even fixable? I actually just tested it's prequel game (Reborn Battle Arena) and it is impacted with the same issue, which isn't surprising given that they share assets.

Other than that, I have not seen this in another game.

unknownbrackets commented 4 years ago

I definitely see the reversed thing where one character grabs another character and throws them on the ground, but I'm not sure which particle effects are wrong.

Just to be sure, could you try exporting a GE frame dump? It should be taken right when the character is being thrown wrong. I don't think it's a graphics issue, but this'll allow me to check on a PSP to make sure the wrong data is being sent to render.

The reason I say this is just because - unless I'm mistaken - it looked like the results of all the actions are "correct." So it could be possible that it's drawing it wrong, although pretty unlikely.

See here for instructions - it's not hard and works on Android too: https://github.com/hrydgard/ppsspp/wiki/How-to-create-a-frame-dump

You can zip that and then drag and drop it into a reply here.

And wanted to note here that this was noted to happen on both Windows and Android, so it's not likely specific to any jit. That it even happens in interpreter and IR means it must either be a CPU bug that's everywhere (definitely possible) or else actually an HLE or GPU bug.

-[Unknown]

somepunkid commented 4 years ago

I've created a new video clip demonstrating the issue, with effects and properties being demonstrated from both sides. Directional Inputs (left right only) also reverse on the player 2 side. https://youtu.be/TEIJRklmKTw

This causes the AI to walk the wrong way, and the properties of the moves being used to only have hit effects as if they were on the Player 1 side (see 0:19)

I took a frame dump during a different instance of the effects performing incorrectly (the shot at 0:45 posted in the above video) along with a couple other instances of reversed (Player 2 side) effects. The first file in the zip should mirror the moment at 0:45. I can create more.

Frame dump.zip

I would correct this by saying that the effects themselves are not necessarily wrong, but the impact they are having and their positioning is wrong. The correct effect is displayed, just always facing to the right.

somepunkid commented 4 years ago

This was done on the machine with the specs listed above, using the Direct3D 11 backend / Dynarec (JIT) CPU core option. The result of all actions play out in game as if they are only being performed from the player 1 side, except the invisible hitboxes. What is bizarre is that the hitboxes for the projectiles still appear to be impacting, but the hit effect performs as if the player is on P1, and sucks the opposing model forward rather than pushing it, and also appears on screen as if it was initiated from the player 1 side. This applies to all characters when used on the P2 side in both games.

somepunkid commented 4 years ago

Ah, just realized you specifically requested a dump from the throw scene. Hopefully that dump works, given that it was during one of the issues. If not, I will recreate this.

I'm thinking this might be a CPU bug/everywhere as first noted, given the game properties/issues.

unknownbrackets commented 4 years ago

Oh, okay, the new video makes it very obvious - sorry for not getting it before. So it does indeed affect the result.

For posterity in case it's helpful: characters are drawn using weights, and effects are not.

As a quick confirmation, this video seems to show PSP gameplay without any reversing happening (just wanted to confirm this wasn't actually just a game bug, although that seems unlikely): https://www.youtube.com/watch?v=T3Q4v7vKTlA

-[Unknown]

somepunkid commented 4 years ago

All other clips can be ignored. I created this to eliminate any confusion and log this bizarre issue. This is a comparison of the game running on Hardware and immediately after in emulation, same characters and moves on the same stage.

Hardware test starts at 1:00 Emulation test starts at 3:35

https://youtu.be/q1YjrLXTq7c

hrydgard commented 4 years ago

That's a really, really good report video! Thanks!

No idea where to even start looking on this one though :) No clues from your interpreter, and it's clearly not just rendering...

somepunkid commented 4 years ago

That's a really, really good report video! Thanks!

No idea where to even start looking on this one though :) No clues from your interpreter, and it's clearly not just rendering...

Yeah, just making sure it's recorded correctly somewhere. Easier than looking through old videos. I actually tested another emulator with the exact same result.

hrydgard commented 4 years ago

Almost smells like we're triggering some kind of bizarre anti-piracy/anti-emulator trap...

somepunkid commented 4 years ago

Almost smells like we're triggering some kind of bizarre anti-piracy/anti-emulator trap...

Interesting that you'd mention this, I just started looking into that possibility. Just now. For that to be included with the first game as well, however, would be rather interesting.

unknownbrackets commented 4 years ago

Okay, crazy idea here, but can you also just try the software renderer? I still don't think this is graphics related, but there's an off possibility this is some crazy readback or depth thing, like Danganronpa.

Trying to think of things we do wrong even in interpreter. Some others:

Not sure what else...

-[Unknown]

somepunkid commented 4 years ago

Issue is the same with Software Rendering.

After more testing, I'm wondering if this would be the case (DRM) or if there would be a way to confirm this. The prequel with the same issue released in 2008 and I haven't known any other game to have this...this is the second release, which was pushed out in 2009.

I tried running the UMD in a PSP over USB through PPSSPP, which is where I sourced the file from. Tested multiple file/patch ideas in addition, still ran into the same thing. Tried the java-based emu as well, just for more variable tests, but no. Same deal.

I've heard of bizarre, one-off cases of games implementing obscure methods before, and I remember a number of titles around 09 had interesting attempts at destroying gameplay if it was a copy (DJMAX Portable 3 comes to mind) but I can't seem to replicate the behavior on the PSP/PSTV as well. The only thing I could think of is if it's possibly looking for specific root/directory files to be present...but I suppose it could really be anything if that can of worms gets opened.

What's the likelihood of this being something like that versus a bug I wonder?

hrydgard commented 4 years ago

We have seen piracy detection on the PSP, most prominently DJ MAX games that scan your memory stick and error out if they see an ISO file. So it wouldn't be the first one... That detection method was visible in our logs (once we realized what it was doing...).

somepunkid commented 4 years ago

We have seen piracy detection on the PSP, most prominently DJ MAX games that scan your memory stick and error out if they see an ISO file. So it wouldn't be the first one... That detection method was visible in our logs (once we realized what it was doing...).

Yes, I was aware of these methods with DJMAX. The only instance I've seen with this game running incorrectly is via emulation, however. Never on say, a PSP that has been altered. The earlier footage was from a PSTV as well. I attempted the Memory Stick Inserted unchecked option as well with this possibility in mind...

hrydgard commented 4 years ago

Right, okay. Really running out of ideas here...

somepunkid commented 4 years ago

All good! Well, if it is similar to DJMAX somehow, that's pretty funny. Some of the game protection methods can get really creative.

If it's possibly one of [Unknown]s listed ideas, well, wouldn't that be something. Some sound like a possibility!

Thanks for taking the time, to you both. It's my favorite game on the system, and I've been on a fun chase the last couple days testing the emulators and looking into older patching methods/reading old articles to see if this one had these issues on hardware.

somepunkid commented 4 years ago

Hey all, I did find something interesting.

https://www.youtube.com/watch?v=AqL0PlBsI5k

This is a video of someone running it on PPSSPP v.0.9.8, and it is running correctly. Supposedly on Windows. This would be the only emulated footage I've found of it running right. Is there anywhere I can test these older revisions?

hrydgard commented 4 years ago

Did you post the wrong link? That's just somebody scrolling in the menus.

But if it did work correctly in 0.9.8, then you know what to do - start downloading builds and find where it broke :)

somepunkid commented 4 years ago

Heh. It was the wrong link, corrected it. Found the build here, just had an issue with my browser. Disregard that.

unknownbrackets commented 4 years ago

You can download v0.9.8 here: https://github.com/hrydgard/ppsspp/releases/tag/v0.9.8

At least the stable releases from back then are available there: https://github.com/hrydgard/ppsspp/releases

Even knowing it broke between say v0.9.9.1 and v1.0.0 would help. The build bot doesn't keep builds that old, but we can build some as needed.

-[Unknown]

somepunkid commented 4 years ago

I've confirmed v0.9.8 works with default settings. I will continue testing revisions.

hrydgard commented 4 years ago

Cool! Seems we got lucky here that it worked back then - can't wait to see what caused this...

somepunkid commented 4 years ago

The break actually takes place between 0.9.8 and 0.9.9. This is just with default settings tested. I would continue testing the unstable releases, but they appear to be inaccessible. I can't seem to recreate full functionality in 0.9.9.

hrydgard commented 4 years ago

Alright, some serious archeology will be needed then... Good to have a starting point though!

As for full functionality in 0.9.9, does the game just not work there?

somepunkid commented 4 years ago

Alright, some serious archeology will be needed then... Good to have a starting point though!

As for full functionality in 0.9.9, does the game just not work there?

It works, but with the exact same issues as the most recent builds (v1.9.3) The game starts having the issues I made the video on in v0.9.9, but everything else seems fine!

hrydgard commented 4 years ago

Ah good, I feared that the game had broken in other ways so it would be hard to distinguish the problem.

I'll see how hard it is to build these old versions later...

Oh and here's the haystack :) https://github.com/hrydgard/ppsspp/compare/v0.9.8..v0.9.9

unknownbrackets commented 4 years ago

We definitely made a lot of changes there.

Lots of timing changes, but a big thing we did was handle replacements and invalidate jit during memcpy and avoid reading jit codes during some memcpys.

Maybe the game has cheat detection and it's now noticing a difference in the game code because of replacements?

Does anything change if you set FuncReplacements = False in the ini instead of FuncReplacements = True? You'll also want to use the interpreter (sorry, it may be slow) and make sure not to use any save states or save data if possible. This would be in the latest version.

-[Unknown]

somepunkid commented 4 years ago

FuncReplacements = False CPU Core - interpreter This was on a fresh 1.9.3, no game config or states (since a separate ini is created for the game config)

Same issue unfortunately.

unknownbrackets commented 4 years ago

Here's a build in between v0.9.8 and v.0.9.9 (sorry for the zipped 7z, GitHub upload is restrictive): ppsspp-v0.9.8-859-g8d84c912e-windows-amd64.7z.zip

If that build works, here's a version halfway closer to v0.9.9: ppsspp-v0.9.8-1285-gef390c5c4-windows-amd64.7z.zip

On the other hand, if v0.9.8-859-g8d84c912e is bad just like v0.9.9, this is halfway closer to v0.9.8: ppsspp-v0.9.8-429-g7d34c2041-windows-amd64.7z.zip

It's possible these have totally other bugs, but hopefully this narrows it down. If you can test two builds here, it would narrow it down to ~400 commits instead of ~1700. After this, a couple more builds would cut it down even more.

-[Unknown]

somepunkid commented 4 years ago

Tried both of these, default settings

Working in ppsspp-v0.9.8-859-g8d84c912e-windows-amd64

Broken in ppsspp-v0.9.8-1285-gef390c5c4-windows-amd64

somepunkid commented 4 years ago

Feel free to send more builds in between these for testing!

unknownbrackets commented 4 years ago

Okay, this is halfway between those two: ppsspp-v0.9.8-1072-gc3dfb6483-windows-amd64.7z.zip

-[Unknown]

somepunkid commented 4 years ago

This revision is working! Did some extra testing. No instances of reversing. Was some missing font on one menu, but this is likely unrelated/part of older issues.

unknownbrackets commented 4 years ago

There are vfpu sin/cos changes in that range, which is suspicious. Also rescheduling changes.

Here's the next one: ppsspp-v0.9.8-1178-g036cde776-windows-amd64.7z.zip

Depending on this result I'm probably going to try reverting things on the current latest build, because almost all of the changes left are graphics related and unlikely to be the problem.

-[Unknown]

somepunkid commented 4 years ago

There are vfpu sin/cos changes in that range, which is suspicious. Also rescheduling changes.

Here's the next one: ppsspp-v0.9.8-1178-g036cde776-windows-amd64.7z.zip

Depending on this result I'm probably going to try reverting things on the current latest build, because almost all of the changes left are graphics related and unlikely to be the problem.

-[Unknown]

This version is also working.

unknownbrackets commented 4 years ago

Thanks, that's really helpful. These are the remaining commits: https://github.com/hrydgard/ppsspp/compare/036cde776...ef390c5c4

There's a lot of Qt/Ui/debugger changes in that range, which aren't likely to be related. Then there's a bunch of graphics changes.

The change that stands out is definitely #6329. Let me revert that on latest master and see what happens.

-[Unknown]

hrydgard commented 4 years ago

Nice work, does sound very plausible that it's relying on some edge case of that...

unknownbrackets commented 4 years ago

Okay here's a new build. Use this with assets from a recent git build - I built this locally so I'm just uploading the exe.

PPSSPPWindows64-revert-sincos.zip

For reference, here are the changes I made:

diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp
index 94cd0d811..e0d6e227f 100644
--- a/Core/MIPS/ARM/ArmCompVFPU.cpp
+++ b/Core/MIPS/ARM/ArmCompVFPU.cpp
@@ -2185,6 +2185,7 @@ namespace MIPSComp
        // calling the math library.
        // Apparently this may not work on hardfp. I don't think we have any platforms using this though.
        void ArmJit::Comp_VRot(MIPSOpcode op) {
+               DISABLE;
                NEON_IF_AVAILABLE(CompNEON_VRot);
                // VRot probably doesn't accept prefixes anyway.
                CONDITIONAL_DISABLE(VFPU_VEC);
diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp
index 69d6a302c..c77d6767e 100644
--- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp
+++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp
@@ -1907,6 +1907,7 @@ namespace MIPSComp {
        // Very heavily used by FF:CC. Should be replaced by a fast approximation instead of
        // calling the math library.
        void Arm64Jit::Comp_VRot(MIPSOpcode op) {
+               DISABLE;
                // VRot probably doesn't accept prefixes anyway.
                CONDITIONAL_DISABLE(VFPU_VEC);
                if (js.HasUnknownPrefix()) {
diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp
index 8e3ad0ba0..d34b8eeb3 100644
--- a/Core/MIPS/MIPSIntVFPU.cpp
+++ b/Core/MIPS/MIPSIntVFPU.cpp
@@ -624,14 +624,14 @@ namespace MIPSInt
                        case 16: d[i] = 1.0f / s[i]; break; //vrcp
                        case 17: d[i] = USE_VPFU_SQRT ? vfpu_rsqrt(s[i]) : 1.0f / sqrtf(s[i]); break; //vrsq

-                       case 18: { d[i] = vfpu_sin(s[i]); } break; //vsin
-                       case 19: { d[i] = vfpu_cos(s[i]); } break; //vcos
+                       case 18: d[i] = sinf((float)M_PI_2 * s[i]); break; //vsin
+                       case 19: d[i] = cosf((float)M_PI_2 * s[i]); break; //vcos
                        case 20: d[i] = powf(2.0f, s[i]); break; //vexp2
                        case 21: d[i] = logf(s[i])/log(2.0f); break; //vlog2
                        case 22: d[i] = USE_VPFU_SQRT ? vfpu_sqrt(s[i])  : fabsf(sqrtf(s[i])); break; //vsqrt
                        case 23: d[i] = asinf(s[i]) / M_PI_2; break; //vasin
                        case 24: d[i] = -1.0f / s[i]; break; // vnrcp
-                       case 26: { d[i] = -vfpu_sin(s[i]); } break; // vnsin
+                       case 26: d[i] = -sinf((float)M_PI_2 * s[i]); break; // vnsin
                        case 28: d[i] = 1.0f / powf(2.0, s[i]); break; // vrexp2
                        default:
                                _dbg_assert_msg_(CPU,0,"Trying to interpret VV2Op instruction that can't be interpreted");
@@ -1576,7 +1576,9 @@ namespace MIPSInt

                float sine, cosine;
                if (currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX] == 0x000E4) {
-                       vfpu_sincos(V(vs), sine, cosine);
+                       float angle = V(vs) * M_PI_2;
+                       sine = sinf(angle);
+                       cosine = cosf(angle);
                        if (negSin)
                                sine = -sine;
                } else {
@@ -1589,8 +1591,8 @@ namespace MIPSInt
                        ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Single);

                        // Cosine ignores all prefixes, so take the original.
-                       cosine = vfpu_cos(V(vs));
-                       sine = vfpu_sin(s[0]);
+                       sine = sinf(s[0] * (float)M_PI_2);
+                       cosine = cosf(V(vs) * (float)M_PI_2);

                        if (negSin)
                                sine = -sine;
diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp
index ff7bd79f2..d04130205 100644
--- a/Core/MIPS/x86/CompVFPU.cpp
+++ b/Core/MIPS/x86/CompVFPU.cpp
@@ -2201,6 +2201,7 @@ void SinCosNegSin(SinCosArg angle, float *output) {
 }

 void Jit::Comp_VV2Op(MIPSOpcode op) {
+       DISABLE;
        CONDITIONAL_DISABLE(VFPU_VEC);

        if (js.HasUnknownPrefix())
@@ -3526,6 +3527,7 @@ void Jit::CompVrotShuffle(u8 *dregs, int imm, int n, bool negSin) {

 // Very heavily used by FF:CC
 void Jit::Comp_VRot(MIPSOpcode op) {
+       DISABLE;
        CONDITIONAL_DISABLE(VFPU_VEC);
        if (js.HasUnknownPrefix()) {
                DISABLE;

-[Unknown]

unknownbrackets commented 4 years ago

I made a silly mistake so if you downloaded it within 2 minutes of my above comment, download again. Sorry.

-[Unknown]

somepunkid commented 4 years ago

Tested with ppsspp-v1.9.3-908-g192164c5f. This is working!

unknownbrackets commented 4 years ago

Okay, here's a build that logs the differences.

PPSSPPWindows64-sincos-log.zip

If you run this, it should show lines in the log (Debug -> Log Console or use InfoLog.cmd) like this:

Vrot sine difference: 1.0000 vs -1.0000 -- 123.0000 / 0000000E4

You can go to gist.github.com and paste the log there, and then link to that. Or if it's just a couple lines, paste it directly in a comment here.

It's also possible there are no significant differences and it's all minor rounding, but I'm hoping there's a more major deviation that we can write a hardware test for to confirm.

Changes, for reference: https://github.com/hrydgard/ppsspp/compare/master...unknownbrackets:sincos-log

-[Unknown]

somepunkid commented 4 years ago

https://gist.github.com/somepunkid/4e40195133424b3acec3777b12780f94

I was in-game, this was on the debug console. It appears to continue logging differences. If more is needed, let me know.

unknownbrackets commented 4 years ago

Sorry - just to confirm, you reproduced the issue during this log, right?

There's some minor variance here but nothing major. That change fixed things in Final Fantasy 3 because games rely on sin or cos of multiples of pi/4 being specific values, which the sinf() and cosf() functions normally don't guarantee.

Was hoping to see some difference in sign like -0.00 and +0.00...

-[Unknown]

somepunkid commented 4 years ago

When ran with this log executable, with revision ppsspp-v1.9.3-908-g192164c5f, the game is running normally. Did I miss a step here? I've been unable to reproduce the issue with these variables, at least so far.

However, I tested ppsspp-v1.9.3-908-g192164c5f and it was not working, until I utilized the log executable. In other words, I could reproduce the errors right before with a fresh file pack, then while using the log executable, the issues were resolved immediately after.