Sonic and Sega Retro Message Board: Sonic 2 for PC, 3DS, & Wii - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Page 1 of 1
    Locked
    Locked Forum

Sonic 2 for PC, 3DS, & Wii

#1 User is offline Clownacy 

Posted 24 November 2017 - 11:00 AM

  • Posts: 739
  • Joined: 06-July 13
  • Gender:Not Telling
Contest page copypaste:
Spoiler


Screenshots:
Spoiler


Old video from back when this had EHZ:
Spoiler


I've been working on and off on a PC port of Sonic 2 for about two years, which I initially worked on in order to teach myself C and SDL2.

Back in August, after tiring myself out with Cave Story modding, I finally picked up the project after a year-long hiatus, and put to use what I'd learnt in that time. This included the addition of level drawing, a shortlived rebase on OpenGL, and a port of the Sonic object. This turned the port from a silly little demo program called EGGMANQUEST into something actually resembling a port of Sonic 2.

What, you think I'm joking?
Spoiler


It started to look like the project was finally coming together, and with the Hacking Contest on the horizon, I thought I'd brush up what I had so far, and let it finally make its debut.

While cleaning up the demo, I was reminded of my time porting my own game to the 3DS. Figuring it would demonstrate my port's portability (harr harr), and help set it apart from Sonic 2 HD, I began working on a 3DS version, ditching the (albeit crappy) OpenGL backend for a software renderer. Unfortunately, the renderer wasn't as efficient as it could be, limiting it to New 3DSs only.

...So why does it say 'Wii' in the thread's title?
Spoiler


Basically, to prove a point, I dropped it on the Wii in an hour or two.

Unfortunately, this was a few days after the contest deadline, so it couldn't be submitted. It was a really quick-and-dirty port, anyway: it doesn't have sound, and it's in 4:3 (why the hell does the Wii have a 4:3 framebuffer?), so I guess that's not a huge loss.

I suppose I should say how you use the thing. Extract the contents of the 'Wii' folder to the base of your Wii's SD card, and that should be all for installation. Of course, you have to run it from the Homebrew Channel.

Controls are...

Wiimote:
• D-pad - Movement
• 1 - A
• 2 - B (Debug Mode)
• Minus - C
• Home - Quit

Wii Classic Controller/Wii U Pro Controller/Wii U Gamepad:
• D-pad - Movement
• B - A
• Y - A
• X - B (Debug Mode)
• A - C
• Home - Quit

Download here.

Also, as a bonus, I dug up two old builds of EGGMANQUEST I had lying around on Dropbox, in case anyone's curious:
2015 version
2016 version
This post has been edited by Clownacy: 13 November 2018 - 06:44 PM

#2 User is offline Krigo 

Posted 26 November 2017 - 05:36 PM

  • Posts: 2303
  • Joined: 09-December 06
  • Gender:Male
  • Location:Canada
  • Wiki edits:30
Holy crap.

This is really impressive. Hands down my favorite pick for the SHC this year. I didn't see this coming at all.

#3 User is offline EnderWaffle 

Posted 27 November 2017 - 02:55 PM

  • Ghostly Friend
  • Posts: 12
  • Joined: 13-August 15
  • Gender:Male
  • Location:New Donk City, Metro Kingdom
  • Project:Sonic Legends
Just tested the Wii version, and I gotta say, this seems pretty good.
Now if only I could get my 11.6.39 New 3DS homebrew'd, then I'd have the good version of a handheld Sonic 2. Yeah, I said it. I'm not too fond of Sonic 2 SMS.

#4 User is offline Clownacy 

Posted 31 October 2018 - 05:16 AM

  • Posts: 739
  • Joined: 06-July 13
  • Gender:Not Telling
- threading (fuck no)
- proctex (lolwut)
- linked list dirty rendering (wat)
- Wii audio
- SonLVL integration (external collision arrays)
- More enemies
- AND OR blitting (nope...)
- Old 3DS Frameskip (pfft)
- New plan: move the colouriser to the second core, optimise the hell out of the blitter, and Bob's your uncle
- Blit different colours to different framebuffers, and render them with vertex colours? (nope)
- Extra new plan: switch to tile-based drawing, and merge the colouring stage with the blitting stage, to reduce palette line calculations
- Alright, let's be more clear: the current renderer is tile-scanline-based. It's simple, but slow as ass.
  My idea is to make the renderer emulate the VDP much more closely: by emulating planes, I can render
  entire tiles instead of scanlines. This allows me to cache palette line calculations for all 64 pixels.
  Also, by directly emulating planes, I can simply port the original game's level drawer, so that's cool.
  Anyway, as I said above, I could potentially merge the colouring stage with the blitting stage if I do
  so, though I'm not sure if that would be good for performance. I'm also not sure how I'd make priorities work.

Attempt 9000000:
So we start off with the two planes. We parse them, and put the high-priority ones into a list for later [NOPE].
The low background doesn't need an alpha test: just set the first colour in every palette line to the
background colour, and memcpy the pixels. The other layers need an alpha test.

We'll be using a 'flooded buffer' for the indexed bitmap: room will be given so that entire tile-lines can be
written, even if they go outside the bounds of the screen. This will allow us to do the AND OR trick with
longwords, since tiles are 8 pixels/bytes wide. [old ARM doesn't like unaligned writes, so no]

Then it will be the colourising stage that clips the flooded buffer, and rotates the framebuffer.

Also, add a mode for the foreground, so it doesn't do the per-scanline scrolling stuff. [turns out I can't]


This is a snippet of my to-do list for this port. For the last year I've been trying to figure out how to make this fast enough to run on the Old 3DS. As you can probably see, it didn't go well.

The 3DS is useless. For starters, its GPU doesn't support fragment shaders, so the one part of the drawing process I could use hardware-acceleration for - applying the palette - I now can't. So I'm stuck doing everything in software... except the CPU is slow as mud: a 268MHz ARMv6 with only one actually-usable core. Great. And to add insult to injury, the 3DS's framebuffer? It's sideways. So on top of blitting and colouring in software, I also have to rotate the framebuffer, which takes a good 20% off my cycle budget.

For the past year I've been plodding away, trying every possible optimisation I could think of, but it wouldn't help. No simple optimisation would help that the software-renderer alone was using 300% of CPU time. Was it a lost cause? Surely it had to be possible: I mean, Sonic 1/2 3D run on Old 3DSs, and they're emulators. Not to mention they have to draw two screens per frame.

So I started planning a complete rewrite of the renderer, this time emulating the VDP much more closely. As ironic as it sounds, emulating the VDP's planes is faster than skipping them entirely, so building a renderer around those could be just the breakthrough the port needed.

But something like this would take ages to write, and I've been burned before, spending days working on a fancy new drawing method, hoping to at least save some performance, only to have it thrown back in my face by making everything slower. I didn't want to try this until I had time to burn, and was sure it would work.

So months passed, until finally August rolled around. I had some spare time, and my notes were all fresh in my memory, so I got to work. While the original software-renderer was developed on PC, and merely ported to the 3DS later, this one was running on there from its earliest test builds.

Results were promising: a single plane took only a fraction of the CPU. Things got more complicated when I added sprites and the second plane, but I was still scraping by at about 90% of the CPU's threshold.

Then I plugged it into the port. The game ran at half-speed.

No, it wasn't the game itself using up the rest of the CPU (the engine only takes 1%), it was the compiler. Somehow, between the test program and the actual game, the compiler was giving up on whatever optimisations gave the test an edge. So the colour/rotate stage for instance went from 32% CPU time to 40%. When the test was already running at 90%, that's bad.

After that, I was pretty much ready to give up on the 3DS. I've been stuck trying to get this working for a year, for crying out loud. But after some more optimisations - some good, others hackish abominations that should be accompanied by animal sacrifice - things started to look up: I found a faster way to draw sprites by using an incrementing pointer, I experimented with compiler flags, and even found a crazy way to optimise plane blits while also obeying priority with a 16KB LUT.

All in all, if my checks are accurate, the newest build scrapes by at around 85%!

So why go through this much effort to support some handheld from 2011? Well... why not? This is a port of a game from 1992 - it should be able to run on the 3DS. So I figure it makes a good benchmark: if it can't run on a 3DS, I'm doing something wrong.

And I think it paid off: if I wasn't targetting the 3DS, the port would still be using its awful original software renderer. Heck, it would probably still be using its old OpenGL backend, calling multiple functions and sending numerous floats to the GPU just to draw 8 pixels of a scanline, when the software renderer can do the same thing by just copying two long ints.

And if the 3DS isn't your thing? These optimisations benefit the other builds too: back when I released the SHC 2017 demo, I was using my desktop PC. Way more of a powerhouse than the flimsy laptop I use nowadays. And that demo? It doesn't run too great on this laptop. Now, with these optimisations (and way better use of SDL2's API...), the port uses only 15% of the CPU.

With this nonsense finally behind me, I can move onto actually porting stuff again. But before that, I figured I'd clean a few things up, and make another release:

As far as the game itself goes, nothing's really changed. It's still an empty ARZ Act 1. Still, a few bugs and inaccuracies have been fixed, and I've added pausing, so there's that.

The Windows build, as well as being faster, now lets you resize the window. You can also enter fullscreen by pressing F1.

As for the Wii build, I figured out how to get a vaguely 16:9 framebuffer (432x240), so that port's finally joined the widescreen club. Still no audio though.

If you're interested, here are the download links:
Windows
3DS
Wii

On the 3DS, you can install straight from FBI using this QR code (select the 'Remote Install' option at the bottom):

Posted Image

Installation instructions and controls are the same as before, sans the 1 & 2 buttons on the Wii being swapped.
This post has been edited by Clownacy: 31 October 2018 - 02:19 PM

#5 User is offline Graxer 

Posted 31 October 2018 - 06:39 AM

  • Posts: 480
  • Joined: 05-January 08
  • Gender:Male
  • Location:Scotland
  • Wiki edits:71
This is a really cool project. It would be awesome to see the original code ported to more modern hardware.

#6 User is offline Neo 

Posted 31 October 2018 - 11:56 AM

  • Clackerjack
  • Posts: 1382
  • Joined: 10-December 04
  • Gender:Male
  • Location:Portugal
  • Project:Sonic 3 Unlocked
  • Wiki edits:1
For the record, I really appreciate the writeup. Fascinating read.

#7 User is offline sonicblur 

Posted 31 October 2018 - 07:17 PM

  • Posts: 1216
  • Joined: 18-February 08
  • Gender:Male
  • Wiki edits:6

View PostClownacy, on 31 October 2018 - 05:16 AM, said:

The 3DS is useless. For starters, its GPU doesn't support fragment shaders, so the one part of the drawing process I could use hardware-acceleration for - applying the palette - I now can't. So I'm stuck doing everything in software... except the CPU is slow as mud: a 268MHz ARMv6 with only one actually-usable core. Great. And to add insult to injury, the 3DS's framebuffer? It's sideways. So on top of blitting and colouring in software, I also have to rotate the framebuffer, which takes a good 20% off my cycle budget.

You complain about not having fragment shaders, yet you are drawing directly to the frame buffer so you wouldn't be using them in the first place. The 3DS hardware fully supports OpenGL ES 1.1, so why are you rotating the image by hand instead of using hardware for that? You just bind your generated image to a texture and draw it on a quadrilateral that fills the entire screen. This is what most of the emulators are doing. Rotation and scaling are free then. The rest of your post never indicates that you stopped drawing directly to the framebuffer, so I assume this to be the case.

If you're looking for a free performance boost, you may want to consider trying that.

#8 User is offline Clownacy 

Posted 31 October 2018 - 07:33 PM

  • Posts: 739
  • Joined: 06-July 13
  • Gender:Not Telling
I have thought about it before, but the overhead of uploading a 400x240 texture every frame scares me off from trying. The 3DS's GPU uses some weird tiled format internally, that all textures have to be converted to. I'd have to convert the image at runtime... just like I already am. With fragment shaders, I'd at least be saving the cycles the colour stage would be using, so whether or not switching to a texture would make things faster wouldn't be a problem.
This post has been edited by Clownacy: 31 October 2018 - 07:55 PM

#9 User is offline Lapper 

Posted 01 November 2018 - 08:26 PM

  • Posts: 1515
  • Joined: 15-June 08
  • Gender:Male
  • Location:England
  • Project:Sonic 2 HD, Sonic Studio, Kyle & Lucy: WW
  • Wiki edits:111
Awesome, only just discovered. I love this sort of thing, It's what I'd be doing if I was smarter. :colbert:


It's furiously accurate however there's definitely more trouble with jumping out of the water than in the original.
This post has been edited by Lapper: 01 November 2018 - 08:28 PM

#10 User is offline Clownacy 

Posted 01 November 2018 - 08:53 PM

  • Posts: 739
  • Joined: 06-July 13
  • Gender:Not Telling
You're sure it's not just this bug? There's one area in the level where you're basically guaranteed to run into that bug, but the original game has a monitor there, so most people don't notice.

EDIT: Oh wait, I double-checked the original game and you're right. Turns out I accidentally inverted a check. Thanks for pointing that out.

EDIT2: Uploaded fixed builds.
This post has been edited by Clownacy: 01 November 2018 - 09:26 PM

#11 User is offline sonicblur 

Posted 01 November 2018 - 08:56 PM

  • Posts: 1216
  • Joined: 18-February 08
  • Gender:Male
  • Wiki edits:6

View PostClownacy, on 31 October 2018 - 07:33 PM, said:

I have thought about it before, but the overhead of uploading a 400x240 texture every frame scares me off from trying. The 3DS's GPU uses some weird tiled format internally, that all textures have to be converted to. I'd have to convert the image at runtime... just like I already am. With fragment shaders, I'd at least be saving the cycles the colour stage would be using, so whether or not switching to a texture would make things faster wouldn't be a problem.

Yikes, I wasn't aware of that weirdness. It's a shame the 2D hardware from DS mode isn't accessible in 3DS mode.

Looking at what's out there, it sounds like gnu.hpp has a textureIndex() function created specifically for updating pixels inside a mapped texture. But that's a lot of math to be doing. Given the 3DS has much more memory than the original system, you should have enough RAM to avoid doing the excess math though. A pre-calculated 240x400 lookup table using 32-bit indexes into the destination texture is only 375KB. (You only need 24 bit, but of course that's not aligned) If you store your lookup table in the same pixel order as your video buffer then you can just loop and do a linear copy without having to do a bunch of calculations every frame.
texture[lookupTable[i]] = input[i]

Although at that point you're still copying every single pixel. so I guess there's no point in using the 3D hardware to rotate for you at that point. That being said, you could use the same strategy for your frame buffer rotation if you're not already.
This post has been edited by sonicblur: 01 November 2018 - 08:57 PM

#12 User is offline Clownacy 

Posted 01 November 2018 - 09:03 PM

  • Posts: 739
  • Joined: 06-July 13
  • Gender:Not Telling
Funny you mention that. I had that same idea about a rotation LUT a few days ago. It's been sitting in my todo list until I'm not so burned-out.

Page 1 of 1
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users