jpd002 / Play-

Play! - PlayStation2 Emulator
http://purei.org
Other
2.13k stars 258 forks source link

KOF series too low Z precision in XYZ2/3 cause graphical issues #1025

Open ghost opened 3 years ago

ghost commented 3 years ago

Every King of Fighters game that use 3D backgrounds send XYZ2 (u16,u16,u32) as 0000xxxx 0000yyyy FFFFzzzz. It seems that Play! handle that similarly to pcsx2, and convert that to single precision float which is causing that last most important bits are lost. So result is something like FFFFzz00, that create various issues depending on game. I made simple test and filtered XYZ2 packets that have Z with FFFFzzzz, and changed it to 00FFzzzz, and that worked. Since first bits are unused by game, float precision improved due to lower initial value. Game worked as expected.

Affected games (thx to Immersion95): KOF 2002 (not very obvious but still is affected like Stage D1) KOF 2003 (https://github.com/jpd002/Play-Compatibility/issues/795) KOF XI (https://github.com/jpd002/Play-Compatibility/issues/796) KOF '94 Re-Bout KOF '98 Ultimate Match (https://github.com/jpd002/Play-Compatibility/issues/794) KOF 2002 Unlimited Match KOF 2002 Unlimited Match (Tougeki) KOF Neowave NeoGeo Battle Coliseum

Current master: master Hack applied: ok

To test that following code were used in GIF.cpp line 135: if ((packet.nV[2] & 0xFFFF0000) == 0xFFFF0000) temp |= (uint64)(packet.nV[2] & 0x00FFFFFF) << 32; else temp |= (uint64)(packet.nV[2] & 0xFFFFFFFF) << 32;

Keep in mind this isn't solution, just hack to confirm theory, and make tests. Thanks to kojin for figuring out what is real KOF games issue.

jpd002 commented 3 years ago

Yup, that thing is kinda annoying. I tried solving this problem a while ago, but I didn't find a definitive solution. Down the line, the problem is that GPUs can only interpolate floats (AFAIK).

https://github.com/jpd002/Play-/blob/master/Source/gs/GSH_OpenGL/GSH_OpenGL_Shader.cpp#L114

If we're thinking outside of the box, maybe there would be a way to find a proper scaling factor (or maybe a linear formulae, ie.: depth = ax - b) for the line above using known values of Z that we got inside a frame. Maybe I'm not thinking this through, so, I'm open to other ideas :)

rcaridade145 commented 3 years ago

ARB_gpu_shader_int64 could be of any use?

jpd002 commented 3 years ago

From what I know, OpenGL/Vulkan won't interpolate integers.

There's also ARB_gpu_shader_fp64, but the extension doc (https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gpu_shader_fp64.txt) specifies that interpolation is not supported for doubles:

      Interpolation not supported in this extension for double-precision
      floating-point components.  As with integer types in OpenGL 3.0,
      double-precision floating-point fragment shader inputs must be qualified
      as "flat".
rcaridade145 commented 3 years ago

I was considering something like Java's https://docs.oracle.com/javase/7/docs/api/java/lang/Float.html#floatToRawIntBits(float) . https://www.khronos.org/registry/OpenGL/extensions/NV/NV_gpu_shader5.txt seems like it could be used to implement it.