Homebrew RetroArch Switch

  • Thread starter Thread starter ShadowOne333
  • Start date Start date
  • Views Views 2,167,553
  • Replies Replies 9,226
  • Likes Likes 100
For what it’s worth, I’ve looked into implementing a libnx-based Retroarch driver. It doesn’t seem that difficult and I’ve written a first-go at it but I’m stuck in Makefile hell. I’m able to get all of the code to compile but the linking process fails. Libtransistor uses ar to link the library and uses the flag —allow-multiple-definitions (or something along those lines). Libnx uses gcc which lags that flag :/ I haven’t looked into it in a few days but I’ll at least try to get around to pushing the rough libnx driver. Also, I don’t think I got around to the audio section of the code iirc.

It’s a shame my C skills are hella rough; a libnx port doesn’t seem too difficult. The APIs for libtransistor and libnx are sort of similar, though libtransistor is more low-level. Plus, RetroArch is architected beautifully so that really helps a bunch :) I’m mostly posting this so people don’t falsely assume a libnx driver is impossible.

(Sorry if there are typos; I’m on the train lol)
 
For what it’s worth, I’ve looked into implementing a libnx-based Retroarch driver. It doesn’t seem that difficult and I’ve written a first-go at it but I’m stuck in Makefile hell. I’m able to get all of the code to compile but the linking process fails. Libtransistor uses ar to link the library and uses the flag —allow-multiple-definitions (or something along those lines). Libnx uses gcc which lags that flag :/ I haven’t looked into it in a few days but I’ll at least try to get around to pushing the rough libnx driver. Also, I don’t think I got around to the audio section of the code iirc.

It’s a shame my C skills are hella rough; a libnx port doesn’t seem too difficult. The APIs for libtransistor and libnx are sort of similar, though libtransistor is more low-level. Plus, RetroArch is architected beautifully so that really helps a bunch :) I’m mostly posting this so people don’t falsely assume a libnx driver is impossible.

(Sorry if there are typos; I’m on the train lol)
Oh wow!
So took a stab at it, nice :)
Perhaps explaining a bit more on detail the linking issue could help so that others can try fixing it as well.
I do have some basic experience with Makefiles, so at least I could give it a shot too.

Try sending the PR on GitHub and also detail the isue there (alongside the audio thing).
Perhaps the guys in charge like Radius or Twinaphex can fix it rather easily :)
 
Well, someone needs to port RetroArch using the latest version of LibNX ASAP (if possible).
It would really save a lot for people using Fusée Gelée/RCM homebrew methods on 4.x and 5.x, like me (once again).

Seconded, no need for RA to be limited to only lower firmware IMO. Hopefully someone does.
 
Last edited by Fadi5555,
  • Like
Reactions: ploggy
Alright, my verrryyyyy WIP branch with Retroarch-libnx is up. See here for a comparison between master and my branch.

Notes:

  • Audio is commented out. Didn't even try to look into it lol.
  • Joypad support is added but will most likely not map the buttons properly. This is something I was planning on working on once/if it compiled. Sorry it's half done.
  • The joypad stuff was pretty simple because of this. The only thing to note is that I'm pretty sure we don't have to tear down the joystick HID controllers in libnx? Would love to hear input.
  • The graphics driver is seemingly there. Barring any weird pointer stuff. (shakes fist in the air at C)
  • The graphics driver changes are as follows: I removed the handler to vsync because I don't think libnx exposes that, though I could be wrong. I added a u32 address to the framebuffer which is returned from gfxGetFramebuffer(). Libtransistor's port used the framebuffer and a temporary buffer when updating the frame. It would point the temp buffer to the surface, check if it should wait for vsync and then wait for the vsync svc, sleep the thread for 10000 nano seconds (I assume), copy the stored "image" to the temp buffer, then refresh the framebuffer to use the newly-updated surface. I, in a very terrible implementation that's more or less copied from example code, use breadth first search to grab the pixels of the framebuffer and set them to the pixels from the image. I then call gfxFlushBuffers() and then gfxSwapBuffers(). If the vsync flag is on I wait for vsync using gfxWaitForVsync() and then sleep the thread. I wonder how close that is in replicating the logic from libtransistor.
  • This all compiles (though I'm not sure if the attached Makefile will compile; it's been a bit since I worked on it). As in, all of the code properly generates object files. Linking is an issue, though. I generally hate dealing with Makefiles (cmake especially is the devil) so this was bound to be my hurdle. It's pretty simple to get libtransistor-snes9x2010 to compile using libnx (it's just a Makefile change that is not attached) but I wasn't able to verify if the generated .a file worked. Upon linking the retroarch nro, I ran into issues regarding methods being defined in multiple places. I believe this has to do with how RetroArch is structured (moving things into static libraries and calling those methods from the RA app). I also believe the libtransistor port is able to get around this using "--allow-multiple-definition" when linking because it used (IIRC) ld to link the binary. Libnx's makefiles use gcc for the linking and gcc lacks that flag, though a cursory stack overflow search says "-Wl,-b,svr4,-z,multidefs" might help.

Hope this helps someone, somewhere!
 
I wish I had have known RA wouldn't work on 5.0 before booting into RCM mode using a paperclip and trying it.

Oh well, I'll just wait for emulators to be available on 5.0. Better than waiting for Nintendo to release like 30 NES Games with their online.

A question before I go though: for N64/GCN, is there even a core for them yet? I'm aware you have to download a GL plugin or something, but is there even a core compiled for it? I'd love to play some GC games on the go during summer.

Great work so far though in getting it to later firmwares!
 
Alright, my verrryyyyy WIP branch with Retroarch-libnx is up. See here for a comparison between master and my branch.

Notes:

  • Audio is commented out. Didn't even try to look into it lol.
  • Joypad support is added but will most likely not map the buttons properly. This is something I was planning on working on once/if it compiled. Sorry it's half done.
  • The joypad stuff was pretty simple because of this. The only thing to note is that I'm pretty sure we don't have to tear down the joystick HID controllers in libnx? Would love to hear input.
  • The graphics driver is seemingly there. Barring any weird pointer stuff. (shakes fist in the air at C)
  • The graphics driver changes are as follows: I removed the handler to vsync because I don't think libnx exposes that, though I could be wrong. I added a u32 address to the framebuffer which is returned from gfxGetFramebuffer(). Libtransistor's port used the framebuffer and a temporary buffer when updating the frame. It would point the temp buffer to the surface, check if it should wait for vsync and then wait for the vsync svc, sleep the thread for 10000 nano seconds (I assume), copy the stored "image" to the temp buffer, then refresh the framebuffer to use the newly-updated surface. I, in a very terrible implementation that's more or less copied from example code, use breadth first search to grab the pixels of the framebuffer and set them to the pixels from the image. I then call gfxFlushBuffers() and then gfxSwapBuffers(). If the vsync flag is on I wait for vsync using gfxWaitForVsync() and then sleep the thread. I wonder how close that is in replicating the logic from libtransistor.
  • This all compiles (though I'm not sure if the attached Makefile will compile; it's been a bit since I worked on it). As in, all of the code properly generates object files. Linking is an issue, though. I generally hate dealing with Makefiles (cmake especially is the devil) so this was bound to be my hurdle. It's pretty simple to get libtransistor-snes9x2010 to compile using libnx (it's just a Makefile change that is not attached) but I wasn't able to verify if the generated .a file worked. Upon linking the retroarch nro, I ran into issues regarding methods being defined in multiple places. I believe this has to do with how RetroArch is structured (moving things into static libraries and calling those methods from the RA app). I also believe the libtransistor port is able to get around this using "--allow-multiple-definition" when linking because it used (IIRC) ld to link the binary. Libnx's makefiles use gcc for the linking and gcc lacks that flag, though a cursory stack overflow search says "-Wl,-b,svr4,-z,multidefs" might help.

Hope this helps someone, somewhere!

I'm in a very similar boat. I started tackling libretro/mgba last night. I got all of the object files to compile with libnx & generated the .a file but I'm not well versed in the libretro ecosystem so I don't exactly know what to do with it yet haha. Taking a quick look at your branch, it seems like it might be helpful to me. Thanks!
 
Alright, my verrryyyyy WIP branch with Retroarch-libnx is up. See here for a comparison between master and my branch.

Notes:

  • Audio is commented out. Didn't even try to look into it lol.
  • Joypad support is added but will most likely not map the buttons properly. This is something I was planning on working on once/if it compiled. Sorry it's half done.
  • The joypad stuff was pretty simple because of this. The only thing to note is that I'm pretty sure we don't have to tear down the joystick HID controllers in libnx? Would love to hear input.
  • The graphics driver is seemingly there. Barring any weird pointer stuff. (shakes fist in the air at C)
  • The graphics driver changes are as follows: I removed the handler to vsync because I don't think libnx exposes that, though I could be wrong. I added a u32 address to the framebuffer which is returned from gfxGetFramebuffer(). Libtransistor's port used the framebuffer and a temporary buffer when updating the frame. It would point the temp buffer to the surface, check if it should wait for vsync and then wait for the vsync svc, sleep the thread for 10000 nano seconds (I assume), copy the stored "image" to the temp buffer, then refresh the framebuffer to use the newly-updated surface. I, in a very terrible implementation that's more or less copied from example code, use breadth first search to grab the pixels of the framebuffer and set them to the pixels from the image. I then call gfxFlushBuffers() and then gfxSwapBuffers(). If the vsync flag is on I wait for vsync using gfxWaitForVsync() and then sleep the thread. I wonder how close that is in replicating the logic from libtransistor.
  • This all compiles (though I'm not sure if the attached Makefile will compile; it's been a bit since I worked on it). As in, all of the code properly generates object files. Linking is an issue, though. I generally hate dealing with Makefiles (cmake especially is the devil) so this was bound to be my hurdle. It's pretty simple to get libtransistor-snes9x2010 to compile using libnx (it's just a Makefile change that is not attached) but I wasn't able to verify if the generated .a file worked. Upon linking the retroarch nro, I ran into issues regarding methods being defined in multiple places. I believe this has to do with how RetroArch is structured (moving things into static libraries and calling those methods from the RA app). I also believe the libtransistor port is able to get around this using "--allow-multiple-definition" when linking because it used (IIRC) ld to link the binary. Libnx's makefiles use gcc for the linking and gcc lacks that flag, though a cursory stack overflow search says "-Wl,-b,svr4,-z,multidefs" might help.

Hope this helps someone, somewhere!
Can you compile some downloadable cores so people can test them please?
 
Any chance of PS1 games ever running at full speed with Beetle? I can only find one video of Crash and it runs pretty badly. Would PCSX perform better?
 
I'm in a very similar boat. I started tackling libretro/mgba last night. I got all of the object files to compile with libnx & generated the .a file but I'm not well versed in the libretro ecosystem so I don't exactly know what to do with it yet haha. Taking a quick look at your branch, it seems like it might be helpful to me. Thanks!

Glad I could help in some way! It sounds like you compiled a core lib which is the first step to getting RetroArch to run on the Switch! :) Take the .a file, move it to the root directory of the retroarch project, rename it to "retroarch_switch.a" (if I remember correctly), then run make -f Makefile.switch. Those are the required steps for the libtransistor build, at least. Good luck!

Can you compile some downloadable cores so people can test them please?

I don't think I'm following. None of the work that I've done is in a shareable state. The individual files compile which implies there are no errors in the formatting and general syntax but they're not able to be linked at the moment. That means they can't form a complete binary that's executable.

Any chance of PS1 games ever running at full speed with Beetle? I can only find one video of Crash and it runs pretty badly. Would PCSX perform better?

Right now, libnx and libtransistor gpu/hw acceleration support. Once that's added you will see full-speed PSX emulation but it won't happen until then. Adding hw acceleration is a difficult process that involves reverse engineering how the Switch's gpu functions. I believe someone started the effort a bit ago for libnx but they've since left the scene. Feel free to pick up where they left off :) Their code is on a branch in the libnx repo.
 
  • Like
Reactions: CatmanFan
The graphics driver changes are as follows: I removed the handler to vsync because I don't think libnx exposes that, though I could be wrong. I added a u32 address to the framebuffer which is returned from gfxGetFramebuffer(). Libtransistor's port used the framebuffer and a temporary buffer when updating the frame. It would point the temp buffer to the surface, check if it should wait for vsync and then wait for the vsync svc, sleep the thread for 10000 nano seconds (I assume), copy the stored "image" to the temp buffer, then refresh the framebuffer to use the newly-updated surface. I, in a very terrible implementation that's more or less copied from example code, use breadth first search to grab the pixels of the framebuffer and set them to the pixels from the image. I then call gfxFlushBuffers() and then gfxSwapBuffers(). If the vsync flag is on I wait for vsync using gfxWaitForVsync() and then sleep the thread. I wonder how close that is in replicating the logic from libtransistor.
I had a similar problem when porting VBA-next(I wrote a bit about it here: https://github.com/RSDuck/vba-next-switch#speed-hack). It would probably be a good idea to further investigate this and then create an issue on the libnx repository.
 
Glad I could help in some way! It sounds like you compiled a core lib which is the first step to getting RetroArch to run on the Switch! :) Take the .a file, move it to the root directory of the retroarch project, rename it to "retroarch_switch.a" (if I remember correctly), then run make -f Makefile.switch. Those are the required steps for the libtransistor build, at least. Good luck!

Thanks for the info! I've been trying to get retroarch to build with your modifications but I'm encountering an odd issue when linking that seems different from what you were seeing:

Code:
$ /opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc -specs=/opt/devkitpro/libnx/switch.specs -g -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE  -finline  -L/opt/devkitpro/portlibs/switch/lib -L/opt/devkitpro/libnx/lib -L/developer -lm -lSDL2 -lnx -lm -lstdc++ -lc -lretro_switch -o /developer/retroarch_switch.elf
/opt/devkitpro/libnx/lib/libnx.a(switch_crt0.o): In function `bss_loop':
/home/fincs/pacman-packages/libnx/src/source/runtime/switch_crt0.s:60: undefined reference to `main'
collect2: error: ld returned 1 exit status

Did you happen to see this issue or have any insight?
 
Thanks for the info! I've been trying to get retroarch to build with your modifications but I'm encountering an odd issue when linking that seems different from what you were seeing:

Code:
$ /opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc -specs=/opt/devkitpro/libnx/switch.specs -g -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE  -finline  -L/opt/devkitpro/portlibs/switch/lib -L/opt/devkitpro/libnx/lib -L/developer -lm -lSDL2 -lnx -lm -lstdc++ -lc -lretro_switch -o /developer/retroarch_switch.elf
/opt/devkitpro/libnx/lib/libnx.a(switch_crt0.o): In function `bss_loop':
/home/fincs/pacman-packages/libnx/src/source/runtime/switch_crt0.s:60: undefined reference to `main'
collect2: error: ld returned 1 exit status

Did you happen to see this issue or have any insight?

Nope, don't really know what to do with that tbh. My only suggestion would be to remove -lretro_switch and try again.

I had a similar problem when porting VBA-next(I wrote a bit about it here: https://github.com/RSDuck/vba-next-switch#speed-hack). It would probably be a good idea to further investigate this and then create an issue on the libnx repository.

Interesting! I had no idea that that logic would lead to a desync issue but it makes sense. It looks like libtransistor handles vsync way better imo. It's unfortunate that libnx is seemingly "the winner" because I kinda like libtransistor's API more :(
 

Site & Scene News

Popular threads in this forum