libTAS icon indicating copy to clipboard operation
libTAS copied to clipboard

FS-UAE desync

Open vadosnaprimer opened this issue 6 years ago • 22 comments

The release that is available to apt seems to be the latest stable, so simply installing it using sudo apt install fs-uae should be enough to verify this problem.

In Documents/Floppies I have Turrican (1990)(Rainbow Arts)[cr TRSi].adf:

CRC32: 4B863522
MD5: B4826447461DBEF37994D04B40814BF9
SHA-1: 2C6286CDB96D073BA87E5202FBDFFB5F78D81040
901,120 bytes

Kickstart ROM doesn't seem to be needed as an implementation of it is embedded into fs-uae.

Here's the config in Documents/Configurations: Default.zip

Here's the movie I'm trying to play (nothing in lib options or command line arguments, I tried feeding the config explicitly from command line, doesn't change anything): fs-uae.zip

Every time I replay it, I see different outcome. And not even once it matched what I got when recording it. I noticed it randomly stutters around frames 2-4 even if you start unpaused. If you start paused, the first frame it pauses at changes between those 3. It seemed to be a little but more consistent while dumping avi, but still never synced.

This is using the latest build of libTAS. I couldn't find a libTAS option that improves sync, but I didn't try all the fs-uae options either. There's too many of them, and I wouldn't know what I'm doing.

vadosnaprimer avatar Feb 22 '19 17:02 vadosnaprimer

There is at least a problem at startup with the code that initializes multiple mice (manymouse 3rd party library). The mouse init and input polling is done in a separate thread, and the main thread waits with usleep() calls until all mice have been detected.

This code is unnecessary, because fs-uae also reads inputs from the system mouse. There doesn't seem to be a configuration option to disable it. Also, the link above is to version 2.6, but when looking at the master commit, the manymouse code does not seem to be executed anymore. It was removed in ~~2.6.9dev~~ 2.9.6dev version (current Debian testing version is 2.8.4).

clementgallet avatar Feb 23 '19 16:02 clementgallet

I was testing on FS-UAE 2.8.4. Oh and I even have mouse input disabled in libTAS.

vadosnaprimer avatar Feb 23 '19 16:02 vadosnaprimer

Sorry, I meant it was removed in 2.9.6dev, so after 2.8.4. Having mouse disabled does not matter unfortunately. It still creates the thread.

clementgallet avatar Feb 23 '19 16:02 clementgallet

I tried with https://launchpad.net/~fengestad/+archive/ubuntu/devel/+files/fs-uae_2.9.7~dev4-0bionic_amd64.deb

It pauses at frame 1 now, but still never works the same.

vadosnaprimer avatar Feb 24 '19 09:02 vadosnaprimer

After a bit a research, here's what I understand. The program has a main thread doing the rendering and an emulator thread that generates each frame.

If we have video_sync on, the main thread renders continuously, using the video_sync_method parameter (eventually sleep, using fence, etc.) but does not check if the rendered frame is different from the previous one. So when fast-forwarding, we are getting multiple duplicate frames (relevent code in render_iteration_vsync()).

If we have video_sync off, then the main thread waits until a new frame is available before displaying it (in fs_ml_render_iteration()). This is good, but there is an issue with the first emulated frame, as the main thread waits for the emulator thread, but the later waits for time to pass. The main thread uses glib API (here g_cond_wait_until()) instead of pthread API (pthread_cond_timedwait()). As a result, we don't catch the implied sleep, so we don't advance time and the program softlocks. Setting time tracking > main thread > clock_gettime() allow the program to continue (although the freeze is annoyingly long).

Once the first frame is done, both threads are synced regarding virtual time, so there is no problem anymore, and the emulator seems to be deterministic. The difference between libTAS frame count and emulator frame count is always 8 in my case, and the garbled blue screen appears at frame 1071 for me everytime.

We could implement part of glib API to help this, but I'm not sure what to put in g_cond_wait_until(). If we want to prevent softlocks while being as deterministic as possible, we could check the conditional variable for a "long" time, then if it fails, advance time for the whole duration and either returns or do another check on the conditional variable.

clementgallet avatar Feb 24 '19 14:02 clementgallet

Still never syncs to me. I removed the option setting video_sync, now it pauses on frame 7 for a minute, but otherwise it's still different every time. I even recorded a new movie, and result is still that it never plays the same way. Setting just clock_gettime() or all the time options doesn't help.

I also noticed that it pauses at frame 1 even if I have Pause unchecked in libTAS. When I click on the empty Pause checkbox, it flashes for a moment and the emulator reaches frame 7. IIRC Mari0 behaves the same way. Dunno if it matters. I think the older version of fs-uae didn't have this.

vadosnaprimer avatar Feb 24 '19 20:02 vadosnaprimer

This sounds less functional than ppsspp is..

InfamousKnight avatar Feb 27 '19 16:02 InfamousKnight

I've added an option for handling wait timeouts in 54fae7a2ad5359e9dad4f4bb1792278750382d8d. You can set Runtime > Wait timeout to Finite waits so that you don't have the freeze at the beginning.

clementgallet avatar Feb 28 '19 10:02 clementgallet

Using this setting, I'm getting consistent game loading. However, there's a different kind of desync now. Although the movements of my character are always the same, the type, number and behavior of enemies are completely different each time. It may have to do with the PRNG implemented in the emulator.

clementgallet avatar Mar 03 '19 17:03 clementgallet

Yeah that's what I was getting when it was lagging at the start.

vadosnaprimer avatar Mar 03 '19 19:03 vadosnaprimer

PRNG values are consistent every time. So I have no idea. It is possible that the emulator is intrinsically non-deterministic (even if single-threaded) and that libTAS does not fix it? I tried to use the input replay option of UAE by patching FS-UAE to forward the relevant parameters, but I failed.

Mhhh, using savestates, fast-forwarding during gameplay consistently affects the enemy patterns.

clementgallet avatar Mar 08 '19 11:03 clementgallet

I'd expect at least something helpful to be printed in the messages that libTAS can output. Going from that I believe there's something that we should be able to either patch out or prove that it won't work unless totally reworked.

vadosnaprimer avatar Mar 08 '19 11:03 vadosnaprimer

I managed to patch fs-uae to get deterministic behavior! The problem is with the video_sync option:

  • if the option is on, and additionally if the screen framerate matches the game framerate, the emulator will enable a full video sync, and the emulation thread will always wait for the rendering thread to render a frame before processing the next one. However, if the rendering thread wants to draw before the emulation thread finished its processing, the rendering thread will draw a duplicate frame, which will mess up the timing in libTAS (each draw increments the time).

  • if the option is off, the rendering thread will never draw duplicate frames. However, the emulation thread will not wait for the rendering thread to draw the frame, it will start processing the next frame, with incorrect system time values in libTAS.

So I copied the wait on conditional variable in fs_ml_frame_update_end() to the case when g_fs_ml_video_sync is off, and added the conditional variable signaling from the vsync case to the non-vsync case, and it worked fine! The two threads are synchronized.

clementgallet avatar Mar 08 '19 16:03 clementgallet

Hooray! I'll test it soon!

vadosnaprimer avatar Mar 08 '19 16:03 vadosnaprimer

What's your setup to make it rerecord? When I use one vsync option the game goes to the ending screen from the start, and when I use another, I load a state and fs-uae crashes.

vadosnaprimer avatar Mar 16 '19 13:03 vadosnaprimer

Sorry I didn't get your message.

I set video_sync = 0 in Default.fs-uae file. Otherwise, I use standard libTAS config, except for Runtime > Wait timeout > Finite waits.

Here my modified libfsemu/src/ml/render.c : https://gist.github.com/clementgallet/b96fea3a3c8f52fc37856835fbc47720

clementgallet avatar Mar 25 '19 11:03 clementgallet

Since I don't understand what that patch does internally, but I want to send it as a PR to fs-uae, can you come up with some explanation that would convince the upstream dev? Basically, why should they want this patch?

vadosnaprimer avatar Mar 27 '19 18:03 vadosnaprimer

They may not want that exact patch, because it decreases the efficiency of having separate threads if each one is waiting for the other. It is not useful for casual play. What do you think about making this an option?

clementgallet avatar Mar 27 '19 23:03 clementgallet

You mean an option in fs-uae? That should be okay for all parties, provided they even care enough to accept such an option.

vadosnaprimer avatar Mar 28 '19 14:03 vadosnaprimer

There's actually a deterministic option that doesn't do much, so I reused it to enforce a sequential execution of the rendering and emulation threads (https://github.com/FrodeSolheim/fs-uae/pull/195)

clementgallet avatar Apr 01 '19 21:04 clementgallet

I updated fs-uae and pushed https://github.com/TASEmulators/fs-uae/commits/v3.1.66_f5bf027/ but when running in libTAS it gives this strange warning:

[libTAS f:0] Thread 15890 (main) OpenGL vendor: Mesa
[libTAS f:0] Thread 15890 (main) OpenGL renderer: llvmpipe (LLVM 15.0.7, 256 bits)
WARNING: No HW OpenGL driver: llvmpipe (LLVM 15.0.7, 256 bits)

and only runs at 10fps with this config Default.zip

Does any of it sound suspicions?

EDIT: Turns out the speed was so low because I was running A4000. Runs above normal fps with A500.

vadosnaprimer avatar Mar 12 '24 12:03 vadosnaprimer

So I tried recording a movie in both original patch and an updated build, and unfortunately I'm still getting the same desyncs as before.

I recorded this movie with a bunch of savestates and saveloads, but after replaying it I get different item spawns and behavior of flying enemies every time I replay it, as well as after loading read-only savestates.

I used this fs-uae config and Finite waits.

vadosnaprimer avatar Mar 13 '24 10:03 vadosnaprimer