Skip to content

Splitscreen multiplayer#318

Open
SomeoneIsWorking wants to merge 10 commits intolibretro:masterfrom
SomeoneIsWorking:splitscreen-new
Open

Splitscreen multiplayer#318
SomeoneIsWorking wants to merge 10 commits intolibretro:masterfrom
SomeoneIsWorking:splitscreen-new

Conversation

@SomeoneIsWorking
Copy link

@SomeoneIsWorking SomeoneIsWorking commented Feb 22, 2026

I wanted to play Kirby & The Amazing Mirror split-screen co-op.
This works but I need a second opinion.
I have no idea if it's implemented correctly.

@hizzlekizzle
Copy link

I'm not sure it makes sense to have the core_controller, CoreController and multiplayer_controller all split up like that.

Looks like a lot of this would simpler if we took the core-level turbo out, which endrift would rather we did, as well.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 22, 2026

I'm not sure it makes sense to have the core_controller, CoreController and multiplayer_controller all split up like that.

I don't really understand what's going on. I'm not an emulator guy.
I just ported CoreController and MultiplayerController from the Qt app.

I actually had a better working version for SDL client, not in this repo.
Maybe I should try that instead.

@SomeoneIsWorking SomeoneIsWorking marked this pull request as draft February 22, 2026 22:31
@endrift
Copy link
Collaborator

endrift commented Feb 23, 2026

Judiciously avoiding mentioning that this is vibe coded this time I see.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 23, 2026

I wasn't trying to avoid it. I'm just trying to figure out.
But you are right, I should've mentioned it.
I don't remember why I did that but I think I thought it wasn't worth mentioning.
I might have gotten a bit excited to see it was working.

@hizzlekizzle
Copy link

I assumed it was, based on (the code itself, obviously, but also) the remark about not knowing if it was implemented correctly. I had also assumed that was why it was split into 3 separate headers and files, but it sounds like it's that way because the Qt frontend does it that way, too. That makes it much more acceptable, IMO, if it makes it easier to track upstream changes to those Qt frontend files.

@endrift
Copy link
Collaborator

endrift commented Feb 23, 2026

Generally speaking, tracking reimplementations of those files is suboptimal. One of the things I'm planning to do in 0.12 with the netplay support code is lower-level implementations of core coordination for multiplayer purpose, for cases like this. It should be possible to do with even single-threaded code, akin to how TGB-Dual swaps between cores every so often. But it may be a year before I even get there, so who knows i it's worth waiting or just yanking it out and replacing it later.

@SomeoneIsWorking
Copy link
Author

It should be possible to do with even single-threaded code, akin to how TGB-Dual swaps between cores every so often.

I tried this a while ago because it makes perfect sense. Why do lockstep and mutex on the same thread, just run the cores one after another. But I could NOT get it working.

@SomeoneIsWorking
Copy link
Author

What the hell I'm going to try anyway.
I attempted so many different multiplayer implementations.
In my forks there is multiplayer via ffmpeg streams, Qt split screen, SDL split screen.
I also made a Python GUI and tried to add splitscreen which failed.

By "I" you get the point. 1% I, 99% Autocomplete bots.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 23, 2026

Hey I got lucky. Working singlethreaded lockstep.
I started fresh and focused on single-thread without copying MultiplayerController.
I instead copied lockstep.c as libretro_lockstep.c to make it mutex-free.

I faced timing and desync issues and solved it with "pumping" (and cycle skips if pumping occurred)
Which is not super ideal but I tried playing for a while and nothing went wrong.

@SomeoneIsWorking SomeoneIsWorking marked this pull request as ready for review February 23, 2026 18:27
@SomeoneIsWorking
Copy link
Author

Don't mind the last two force pushes, they are just cosmetics.

@hizzlekizzle
Copy link

Sounds good. I'll see if we can get some testers.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 24, 2026

I tested it on macOS when developing.
I just tested it on Bazzite also (used distrobox to build it)

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 24, 2026

One thing eating my brain is Network possibility because technically let's say.

You have 2 people running the game.
Both players run both instances locally (only their own view is visible)
They send inputs to each other using rollback.
Theoretically I don't see why this can't work.

But I have no idea where someone would even begin with this.
I also do not know a single thing about how libretro network works.

Edit: I got netplay working but uhhh that discussion should be for another PR...

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Feb 27, 2026

Okay I said I want to keep netplay related comments out of this PR but I had a problem regarding RA rollback netplay not exposing player index and I made a PR to RetroArch which got merged so now rollback netplay is playable but I still want to make it a separate PR because it has some parts that I want to talk about separately.

image

@SomeoneIsWorking
Copy link
Author

Replaced "pumping" with individual running based on state
Replaced player1 player2 with cores array
Added 4 players

@hizzlekizzle
Copy link

@SomeoneIsWorking is this ready to go, from your perspective? or are you still actively working on it?

@endrift do you have any thoughts on any of it? I/we don't want to step on your toes merging something you think would be a problem down the road. I haven't actually done any testing on it myself, yet, so it wouldn't be merged immediately anyway, just to be clear.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Mar 7, 2026

@hizzlekizzle it is ready to go IMO. I'm going to submit the netplay PR after this which contains some further refactoring.

@hizzlekizzle
Copy link

Advance Wars is the only link cable game I had handy, and I was able to get through the menus to choose either single-cart mode or, if I chose multi-cart, it would get through the setup menus, but in both cases it eventually stalls out and RetroArch becomes unresponsive.

The last debug messages were:

[libretro DEBUG] GBA Serial I/O: All players acked, waking primary
[libretro INFO] GBA Serial I/O: MULTI transfer finished: 5FFF 5FFF FFFF FFFF
[libretro DEBUG] GBA Serial I/O: Enqueuing event of type 2 from 0 for target E at timestamp 7FFE4F16
[libretro DEBUG] GBA Serial I/O: Primary waiting for players to ack
[libretro INFO] GBA Serial I/O: MULTI transfer finished: 5FFF 5FFF FFFF FFFF
[libretro DEBUG] GBA Serial I/O: Got event of type 2 from 0 at timestamp 7FFE4F16
[libretro DEBUG] GBA Serial I/O: All players acked, waking primary
[libretro DEBUG] GBA Serial I/O: Lockstep: SIOCNT <- 601F
[libretro DEBUG] GBA Serial I/O: MULTI 1 write: SIOMLT_SEND <- 7FFF
[libretro DEBUG] GBA Serial I/O: MULTI 1 write: SIOMLT_SEND <- 5FFF
[libretro DEBUG] GBA Serial I/O: Lockstep: SIOCNT <- 600B
[libretro DEBUG] GBA Serial I/O: MULTI 0 write: SIOMLT_SEND <- 7FFF
Killed

Any thoughts? In the meantime, I'll try to dump some other link-able games to try.

@SomeoneIsWorking
Copy link
Author

I can't reproduce this but maybe I need to play for longer Advance Wars (USA) (Rev 1)

@hizzlekizzle
Copy link

I was able to play Kirby and the Amazing Mirror for a bit, but it ended up freezing the same way after a couple of minutes.

[libretro DEBUG] GBA Serial I/O: All players acked, waking primary
[libretro INFO] GBA Serial I/O: MULTI transfer finished: FEFE 1041 FFFF FFFF
[libretro INFO] GBA Serial I/O: MULTI transfer finished: FEFE 1041 FFFF FFFF
[libretro DEBUG] GBA Serial I/O: Enqueuing event of type 2 from 0 for target E at timestamp 7FFFE76D
[libretro DEBUG] GBA Serial I/O: Primary waiting for players to ack
[libretro DEBUG] GBA Serial I/O: Got event of type 2 from 0 at timestamp 7FFFE76D
[libretro DEBUG] GBA Serial I/O: All players acked, waking primary
[libretro DEBUG] GBA Serial I/O: MULTI 1 write: SIOMLT_SEND <- 4104

@SomeoneIsWorking
Copy link
Author

I had a freezing issue around 10-30 minutes in the earlier versions but the latest should be working fine.

@SomeoneIsWorking
Copy link
Author

Oh wait. I discovered something. I was always building with DEBUG=1
Without it Advance Wars just crashes on me shortly after starting.
But it shouldn't be freezing in the latest version at least because there are hard asserts against getting stuck.
And it hits one for me (Cooperative scheduling watchdog expired)
Didn't run into trouble with Kirby.
I don't know how I can fix Advance Wars.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Mar 8, 2026

Sorry I was testing on netplay branch (I swear I had switched).
I backported the delay sanitation.
Now Kirby works but Advance Wars crashes without DEBUG=1, I'll try to resolve it.

@SomeoneIsWorking
Copy link
Author

I found a strange case with Advance Wars
It makes a problem if player 1 has named their character and player 2 is still naming theirs.
I'm trying to solve it.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Mar 8, 2026

Okay I added something that bypasses lockstep when transfer is not active.
Seems to fix Advance Wars without breaking Kirby.
And thank you so much for testing and informing me.

@hizzlekizzle
Copy link

my pleasure! Unfortunately, since the syncArmed commit, neither Advance Wars nor Kirby will actually link. They just sit at the linking screen waiting for the other player(s). On the bright side, they haven't frozen since, either.

@SomeoneIsWorking
Copy link
Author

That's strange. Try a clean build maybe.

make -f Makefile.libretro clean && make -f Makefile.libretro -j$(sysctl -n hw.ncpu)

This is how I always build it.

@hizzlekizzle
Copy link

The tree was clean, but what did help was reverting the syncArmed commit while leaving the sanitizeDelay one intact. That brought linking back and I didn't experience any freezes through entire games of both Kirby and Advance Wars.

I do like the concept behind the syncArmed commit, though, so if that could be brought back without breakage, it seems like a smart addition.

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Mar 9, 2026

I tested on macOS first and I just tried syncArmed commit on Bazzite and it worked there too.

@kaysedwards
Copy link

I'm trying this for testing, but I'm having no luck.

I have Kirby and the Amazing Mirror on my SteamDeck; can you kind of walk me through setting up the game for two players using your commit?

@SomeoneIsWorking
Copy link
Author

SomeoneIsWorking commented Mar 10, 2026

If steps include compiling you need to setup a distrobox then install dependencies and build the core and copy/move it to RA cores directory
Then you just open RA, load the game, go into core options -> system -> find splitscreen option -> set two players side-by-side -> reset the game
Then go to Start Game -> Multiplayer with both players -> wait a second
image
Then press A on P1 then select a save file then the game should start

Or are you facing the same issue as hizzlekizzle?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants