Open abaire opened 2 years ago
I think this is an interaction w/ anti-aliasing.
According to VLC the source for the video is 640x480 mpeg2.
I see the surface being created with that size but w/ AA set to NV097_SET_SURFACE_FORMAT_ANTI_ALIASING_CENTER_CORNER_2
:
nv2a: Target: [COLOR @ 2dd0000] (ln) aa:1 clip:x=0,w=640,y=0,h=480
nv2a: Adding surface region at [2dd0000: 3028000)
nv2a: Create: [COLOR @ 2dd0000 (1280x480)] (ln) aa:1, clip:x=0,w=640,y=0,h=480
nv2a: [RAM->GPU] COLOR (lin) surface @ 2dd0000 (w=1280,h=480,p=5120,bpp=4)
...
nv2a: Target: [COLOR @ 2dd0000] (ln) aa:1 clip:x=0,w=640,y=0,h=480
nv2a: Match: [COLOR @ 2dd0000 (1280x480)] (ln) aa:1, clip:x=0,w=640,y=0,h=480
nv2a: Hit: [COLOR @ 2dd0000 (1280x480)] (ln) aa:1, clip:x=0,w=640,y=0,h=480
If I disable the width doubling in pgraph_apply_anti_aliasing_factor
the videos render correctly (though obviously it breaks other things).
I'm guessing the problem is that anti-aliasing isn't actually being applied anywhere. As far as I can see the video frames are decoded someplace and then uploaded via pgraph_upload_surface_data
without any obvious pgraph class interactions. Initially I assumed this would be something related to PVPE
but I don't see any interactions going on there.
I think the problem is that a surface's shape is set based on whatever the anti-aliasing flag happens to be set to when it is first created, and it stays stuck in that state forever. Based on the observed behavior, it seems like the SET_SURFACE_FORMAT
setting is intended to apply retroactively, so the cache needs to be broken if the values no longer match up.
Copying over some later findings from when I dug further into fixing this:
Updating to capture the context:
The problem is that the game does 3D rendering to the framebuffer with anti-aliasing enabled, then switches to doing direct CPU writes. xemu creates a SurfaceBinding for the 0x97-based renders, then erroneously continues to use it for the final blit in nv2a_get_framebuffer_surface. In hardware, only AvSetDisplayMode should have an effect on the interpretation of the framebuffer.
xemu 0.7.55 results of the tests:
This is caused by 0x1021 - Should be 0x1121 This is used for resolution modes (i think) and helps set AA in games.
I have some awkward notes on finding this, but have not been able to narrow down what its actually doing..
Pirates Video Fix (MOD) 00 2A 00 00 00 C7 05 30 5B 20 00 21 10 00 00 89 = 00 2A 00 00 00 C7 05 30 5B 20 00 11 21 00 00 89
There's no problem with the game code, and the behavior is more easily identifiable by looking at the pgraph commands than by reversing the game code :)
The game sets up anti-aliased rendering to the framebuffer for 3D for a draw, then later writes decompressed FMV frames directly to the framebuffer via the CPU. xemu has a bug that causes it to assume that if a 3d surface was set up pointing at the framebuffer than its (host) GL contents contain the framebuffer data and can be displayed. It has a further bug where it assumes that VRAM will be in the same format as the surface configuration, so when it sees that the guest VRAM has been modified, it reads it in as anti-aliased data, so when it's finally rendered the pitch is double what it should be.
The draft PR fixes the xemu bug, but there is a remaining issue with how xemu grabs the framebuffer in a UI thread unrelated to the guest.
Title
https://xemu.app/titles/45410015/#Pirates-The-Legend-of-Black-Kat
Bug Description
The intro FMVs are duplicated side-by-side:
Expected Behavior
On hardware the videos are not duplicated:
xemu Version
Latest master
Version: 0.6.2-51-g3fd15218c7 Branch: master Commit: 3fd15218c76cedd89496db637c7ef5369ef35a63 Date: Thu Jan 13 04:44:48 PM UTC 2022
System Information
OS: Kubuntu 21.04 - 5.11.0-38-generic CPU: Core i7-6700K @ 4GHz GPU: NVIDIA GeForce GTX 1070 GPU Driver: 4.6.0 NVIDIA 470.74
Additional Context
I started writing up a more detailed description of the problem here: https://gist.github.com/abaire/8345ff167c4d89d4ff4a3a78e87b9ae4