Homebrew RetroArch Switch

DogParty

Well-Known Member
Member
Joined
Sep 15, 2015
Messages
172
Trophies
0
Age
32
XP
908
Country
United States
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)
 

ShadowOne333

QVID PRO QVO
OP
Editorial Team
Joined
Jan 17, 2013
Messages
12,197
Trophies
2
XP
33,814
Country
Mexico
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 :)
 

CatmanFan

Anxious and regretful
Member
Joined
Aug 14, 2016
Messages
1,962
Trophies
0
Website
www.youtube.com
XP
2,589
Country
Morocco

the_randomizer

The Temp's official fox whisperer
Member
Joined
Apr 29, 2011
Messages
31,284
Trophies
2
Age
38
Location
Dr. Wahwee's castle
XP
18,969
Country
United States
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.
 

Fadi5555

Well-Known Member
Member
Joined
Jan 3, 2018
Messages
499
Trophies
0
Age
35
XP
2,393
Country
United States
Last edited by Fadi5555,
  • Like
Reactions: ploggy

DogParty

Well-Known Member
Member
Joined
Sep 15, 2015
Messages
172
Trophies
0
Age
32
XP
908
Country
United States
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!
 

Klavice Gavin

Active Member
Newcomer
Joined
Feb 25, 2016
Messages
43
Trophies
0
Age
30
XP
202
Country
Canada
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!
 

yesimnathan

Well-Known Member
Newcomer
Joined
May 11, 2018
Messages
66
Trophies
0
Age
37
XP
301
Country
United States
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!
 

CatmanFan

Anxious and regretful
Member
Joined
Aug 14, 2016
Messages
1,962
Trophies
0
Website
www.youtube.com
XP
2,589
Country
Morocco
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?
 

synce

だいこんちゃんのだいふぁん
Member
Joined
Nov 5, 2009
Messages
537
Trophies
0
XP
574
Country
Comoros
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?
 

DogParty

Well-Known Member
Member
Joined
Sep 15, 2015
Messages
172
Trophies
0
Age
32
XP
908
Country
United States
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

catlover007

Developer
Developer
Joined
Oct 23, 2015
Messages
720
Trophies
1
XP
3,924
Country
Germany
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.
 

yesimnathan

Well-Known Member
Newcomer
Joined
May 11, 2018
Messages
66
Trophies
0
Age
37
XP
301
Country
United States
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?
 

DogParty

Well-Known Member
Member
Joined
Sep 15, 2015
Messages
172
Trophies
0
Age
32
XP
908
Country
United States
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

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: Yeah search Google