Register - Login
Views: 100735570
Main - Memberlist - Active users - Calendar - Wiki - IRC Chat - Online users
Ranks - Rules/FAQ - Stats - Latest Posts - Color Chart - Smilies
06-04-23 10:41:38 PM
Jul - General Game/ROM Hacking - Super Mario Sunshine 60fps patch (NTSC-U) New poll - New thread - New reply
Next newer thread | Next older thread
koolaidman
Member
Level: 24


Posts: 82/108
EXP: 76992
For next: 1133

Since: 07-17-10


Since last post: 4.5 years
Last activity: 2.3 years

Posted on 01-25-15 03:26:08 PM Link | Quote
Hey guys.

A few weeks a go I worked on a small patch that will allow Super Mario Sunshine to render double the amount of frames it normally outputs. By changing Dolphin's frame limit (either by use of the VBeam hack or the frame limiter set to 120), we can take advantage of the extra frames by forcing all 60 frames to display in 1 second, thus making the game run at 60fps.

Watch a video here:
http://www.youtube.com/watch?v=9uoBTZxC3Rs

To use in Dolphin, just follow these steps (make sure you have the NTSC-U versions of SMS, GMSE01):
1.) Right click on the game in the game list and go to Properties
2.) Click the "Patches" tab and click "Add..."
3.) Give the patch a name, tick "dword", and set the Offset to 804167B8 and Value to 3F800000
4.) Click "OK", and make sure the patch is ticked.
5.) Click "Config" at the top of the main window, and under the "General" tab set "Framelimit:" to 120. OR - enable the Vbeam hack by right clicking the game in the games list, go to Properties, and put a checkmark next to the Vbeam hack.
6.) Click "OK" and play!

The patch has some side effects though:

1.) By increasing Dolphin's frame limiter, we also speed up the output of the audio. The video cut scenes are unaffected by the value change and so will play at the normal rate normally. But by increasing the Dolphin's frame limiter, the videos now play at double speed. Remarkably, the animations seem to work quite well and don't appear to break anything.
2.) The biggest problem with this patch is that the game won't allow you to enter the worlds from the rainbow goop on walls for some reason. You'd have to hack yourself into the worlds in order to play them (the video was taken from the demo version, so I could warp to those areas from a map select).
3.) Since the developers had to cut the framerate in half during development to improve the water effects, performance can take a hit here and there when using the turbo nozzle in ocean water. You can probably fix this by using the CPU overclock branch (or Tino's Iishiruka custom builds).
4.) You can't seem to finish Shadow Mario off with one last squirt.


As far as I can tell, there are 3 functions that look at the value that I modified for the patch. "drawDVDErr", "SMSGetAnmFrameRate", and "SMSGetVSyncTimesPerSec". It seems that most of the game's other functions take advantage of SMSGetAnmFrameRate the most. The function itself is relatively simple:

(NOTE: These addresses/function names come from the NTSC-U demo version of the game. For some reason, the developers decided to include the debug symbols only in the demo versions. The final retail versions don't have this. You can download the symbol mappings here, but if you want to look at the function in the NTSC-U final the function can be found at 0x802A7BD8)

.text:802A690C # =============== S U B R O U T I N E =======================================

.text:802A690C
.text:802A690C
.text:802A690C # SMSGetAnmFrameRate(void)
.text:802A690C SMSGetAnmFrameRate__Fv: # CODE XREF: TAnimalBase::execWalk((bool))+38p
.text:802A690C # TAnimalBase::execWalk((bool))+40p ...
.text:802A690C
.text:802A690C .set var_8, -8
.text:802A690C .set arg_4, 4
.text:802A690C
.text:802A690C mfspr r0, LR # Move from sprg,
.text:802A6910 stw r0, arg_4(r1) # Store Word
.text:802A6914 stwu r1, -0x18(r1) # Store Word with Update
.text:802A6918 stfd f31, 0x18+var_8(r1) # Store Floating-Point Double-Precision
.text:802A691C lfs f31, -0x3E8(r2) # Load Floating-Point Single-Precision
.text:802A6920 bl VIGetTvFormat # Branch
.text:802A6924 cmpwi r3, 2 # Compare Word Immediate
.text:802A6928 beq is_ntsc # load default ntsc framerate (60)?
.text:802A692C bge loc_802A6940 # Branch if greater than or equal
.text:802A6930 cmpwi r3, 0 # Compare Word Immediate
.text:802A6934 beq is_ntsc # load default ntsc framerate (60)?
.text:802A6938 bge is_pal # load default pal framerate (50)?
.text:802A693C b calc_basefps # patch: frame multiplier value? .5 by default
.text:802A6940 # ---------------------------------------------------------------------------
.text:802A6940
.text:802A6940 loc_802A6940: # CODE XREF: SMSGetAnmFrameRate(void)+20j
.text:802A6940 cmpwi r3, 5 # Compare Word Immediate
.text:802A6944 beq is_ntsc # load default ntsc framerate (60)?
.text:802A6948 b calc_basefps # patch: frame multiplier value? .5 by default
.text:802A694C # ---------------------------------------------------------------------------
.text:802A694C
.text:802A694C is_ntsc: # CODE XREF: SMSGetAnmFrameRate(void)+1Cj
.text:802A694C # SMSGetAnmFrameRate(void)+28j ...
.text:802A694C lfs f31, -0x3E8(r2) # load default ntsc framerate (60)?
.text:802A6950 b calc_basefps # patch: frame multiplier value? .5 by default
.text:802A6954 # ---------------------------------------------------------------------------
.text:802A6954
.text:802A6954 is_pal: # CODE XREF: SMSGetAnmFrameRate(void)+2Cj
.text:802A6954 lfs f31, -0x3E4(r2) # load default pal framerate (50)?
.text:802A6958
.text:802A6958 calc_basefps: # CODE XREF: SMSGetAnmFrameRate(void)+30j
.text:802A6958 # SMSGetAnmFrameRate(void)+3Cj ...
.text:802A6958 lfs f0, -0x408(r2) # patch: frame multiplier value? .5 by default
.text:802A695C lfs f1, -0x3E8(r2) # load default ntsc framerate? (60)
.text:802A6960 fmuls f0, f31, f0 # 60 * .5 = 30
.text:802A6964 fdivs f1, f1, f0 # 60/30 = 2
.text:802A6968 lwz r0, 0x18+arg_4(r1) # Load Word and Zero
.text:802A696C lfd f31, 0x18+var_8(r1) # Load Floating-Point Double-Precision
.text:802A6970 addi r1, r1, 0x18 # Add Immediate
.text:802A6974 mtspr LR, r0 # Move to sprg,
.text:802A6978 blr # Branch unconditionally
.text:802A6978 # End of function SMSGetAnmFrameRate(void)



The function basically looks at your current TV Render Mode and branches off to load what I assume is either the refresh rate or base framerate (in single precision floating point) for that particular render mode. After loading the value, the game loads a second value that pretty much serves as some kind of frame multiplier value that halves the base framerate by default. The patch I made modifies the value that gets multiplied into the base framerate so that instead of multiplying 60 by .5, it multiplies by 1.

This patch could definitely be more refined to help fix the other issues. I believe this patch could work on hardware as well, but we would need to find a way to change the game's frame buffer to allow 60 frames to be displayed in 1 second.

Since I kind of cheated by using a symbol list, I imagine that finding the values that affect the frame rate can be easily found in other games as well. Unfortunately, I spent many days trying to find something equivalent in Wind Waker but couldn't find anything that actually affects the frame rate. The symbol list in that game references the word 'framerate' a few times but they all seem to be related to the player actor's animations, not the game itself. The game seems to set the frame buffer somewhere during the "phase" functions, but I'm not sure how it works. The function names are difficult to understand and tracing calls the disassembly manually in IDA Pro alone is almost impossible unless you use Dolphin's debugger. I looked for data that could be modified in a similar way to the SMS patch (like 1.0/0.5/30.0/25.0 in floating point), but nothing seems to be relevant to the frame rate and affects entirely different functions. The game even seems to have it's own version of the GX NTSC rendering mode (g_ntscZeldaIntDf/g_ntscZeldaProg), for some reason.

I'm less than an amateur when it comes to this stuff, so I would love if someone could figure out how to unlock the framerate in Wind Waker/Twilight Princess, or any other game for that matter now that Dolphin can allow overclocking.
Rachel Mae

Creature of Chaos
Level: 142


Posts: 5671/5931
EXP: 34832915
For next: 135514

Since: 07-03-07

Pronouns: she/her
From: Foxglen

Since last post: 201 days
Last activity: 3 hours

Posted on 02-03-15 08:33:53 AM Link | Quote
Originally posted by koolaidman
2.) The biggest problem with this patch is that the game won't allow you to enter the worlds from the rainbow goop on walls for some reason. You'd have to hack yourself into the worlds in order to play them (the video was taken from the demo version, so I could warp to those areas from a map select).
...
4.) You can't seem to finish Shadow Mario off with one last squirt.

How bizarre. This reminds me of some kind of evil copy protection more than anything...

____________________
Kazinsal

Level: 54


Posts: 537/674
EXP: 1176390
For next: 57480

Since: 01-19-11

Pronouns: he/him
From: Vancouver, Canada

Since last post: 1.8 years
Last activity: 1.6 years

Posted on 02-07-15 08:23:35 PM Link | Quote
Dude, you got linked to on Dolphin's official blog, way to go!

Awesome patch.

____________________
theboy181
Random nobody
Level: 4


Posts: 1/2
EXP: 155
For next: 124

Since: 02-08-15


Since last post: 8.3 years
Last activity: 8.3 years

Posted on 02-08-15 01:38:43 AM Link | Quote
I'm impressed. I wish this type of patch could be created for N64 emulator like PJ64.

I am unable to get the sound to playback at the correct speed. I'm using Ishiiruka-Dolphin Custom Version, but fail to see a setting for the audio.

any ideas?


Rena
I had one (1) message in Discord deleted and proceeded to make a huge, huge mess about how it was a violation of free speech and how moderators are supposed to be spam janitors and nobody should have the right to tell me not to talk about school shootings
Level: 137


Posts: 5192/5390
EXP: 30127337
For next: 745518

Since: 07-22-07

Pronouns: he/him/whatever
From: RSP Segment 6

Since last post: 2.0 years
Last activity: 2.0 years

Posted on 02-08-15 06:33:41 AM Link | Quote
Post #5192 ยท Sun 150208 023341
Originally posted by BMF54123
Originally posted by koolaidman
2.) The biggest problem with this patch is that the game won't allow you to enter the worlds from the rainbow goop on walls for some reason. You'd have to hack yourself into the worlds in order to play them (the video was taken from the demo version, so I could warp to those areas from a map select).
...
4.) You can't seem to finish Shadow Mario off with one last squirt.

How bizarre. This reminds me of some kind of evil copy protection more than anything...

I wonder if it's just that the physics engine and enemy hitstun/animation timers are tied to the frame rate, so changing this multiplier affects them. It could be that halving the frame rate was a quick and dirty hack to fix some physics issues.

It might be worth patching only SMSGetVSyncTimesPerSec to double the value. If nothing else that might fix the animations.

____________________
koolaidman
Member
Level: 24


Posts: 88/108
EXP: 76992
For next: 1133

Since: 07-17-10


Since last post: 4.5 years
Last activity: 2.3 years

Posted on 02-08-15 01:46:34 PM (last edited by koolaidman at 02-08-15 02:02:44 PM) Link | Quote
Originally posted by Rena
Originally posted by BMF54123
Originally posted by koolaidman
2.) The biggest problem with this patch is that the game won't allow you to enter the worlds from the rainbow goop on walls for some reason. You'd have to hack yourself into the worlds in order to play them (the video was taken from the demo version, so I could warp to those areas from a map select).
...
4.) You can't seem to finish Shadow Mario off with one last squirt.

How bizarre. This reminds me of some kind of evil copy protection more than anything...

I wonder if it's just that the physics engine and enemy hitstun/animation timers are tied to the frame rate, so changing this multiplier affects them. It could be that halving the frame rate was a quick and dirty hack to fix some physics issues.

It might be worth patching only SMSGetVSyncTimesPerSec to double the value. If nothing else that might fix the animations.


This is definitely the case. If you mess with the modifier value on the patch to be a smaller value than 1.0 (but no less than .5), the illuminated goop/super imposed animated picture of the level actually does show up albeit very very slowly (I clocked 3 minutes before I could jump in when the modifier value was around .8 or so). There have been some reports of saving issues because I suppose the game is going through the save menus faster than it can actually save the game. Although I haven't personally encountered such problem, it might be caused by people who try to create a completely new saved game (which would obviously take longer the first time). There is a function called "MActor::getFrameCtrl((int))", which might be what we need to look at if I can find the warp actors.

When the modifier is at 1.0, however, there are a few moments where the goop warp/shadow mario stuff actually works. In the begining of the game, the first chase with Shadow Mario actually works. When he creates the first warp goop for the first level you go to, that actually does work in that instance after he jumps into it himself. After completing the first level's mission and returning to Delfino Plaza, that's when the issues seem to come up.

SMSGetVsyncTimesPerSec is actually very very similar to SMSGetAnmFrameRate. The only difference is the function isn't getting the rate, it's not dividing the contents of f1 after multiplying .5 and 60 together. The locations of the two values are the same as the equivalent values that are read by the AnmFrameRate function. You can even change the value '60' to something like '120' and it'll have the same effect. I believe I tried changing both, but they all have the same effect.



.text:802A697C # SMSGetVSyncTimesPerSec(void)
.text:802A697C SMSGetVSyncTimesPerSec__Fv: # CODE XREF: TConsoleStr::getWipeCloseTime((void))+Cp
.text:802A697C # sub_80175B54+1D4p ...
.text:802A697C
.text:802A697C .set var_8, -8
.text:802A697C .set arg_4, 4
.text:802A697C
.text:802A697C mflr r0 # Move from link register
.text:802A6980 stw r0, arg_4(r1) # Store Word
.text:802A6984 stwu r1, -0x10(r1) # Store Word with Update
.text:802A6988 stfd f31, 0x10+var_8(r1) # Store Floating-Point Double-Precision
.text:802A698C lfs f31, -0x3E8(r2) # Load Floating-Point Single-Precision
.text:802A6990 bl VIGetTvFormat # Branch
.text:802A6994 cmpwi r3, 2 # Compare Word Immediate
.text:802A6998 beq loc_802A69BC # load 60
.text:802A699C bge loc_802A69B0 # Branch if greater than or equal
.text:802A69A0 cmpwi r3, 0 # Compare Word Immediate
.text:802A69A4 beq loc_802A69BC # load 60
.text:802A69A8 bge loc_802A69C4 # Branch if greater than or equal
.text:802A69AC b loc_802A69C8 # load .5
.text:802A69B0 # ---------------------------------------------------------------------------
.text:802A69B0
.text:802A69B0 loc_802A69B0: # CODE XREF: SMSGetVSyncTimesPerSec(void)+20j
.text:802A69B0 cmpwi r3, 5 # Compare Word Immediate
.text:802A69B4 beq loc_802A69BC # load 60
.text:802A69B8 b loc_802A69C8 # load .5
.text:802A69BC # ---------------------------------------------------------------------------
.text:802A69BC
.text:802A69BC loc_802A69BC: # CODE XREF: SMSGetVSyncTimesPerSec(void)+1Cj
.text:802A69BC # SMSGetVSyncTimesPerSec(void)+28j ...
.text:802A69BC lfs f31, -0x3E8(r2) # load 60
.text:802A69C0 b loc_802A69C8 # load .5
.text:802A69C4 # ---------------------------------------------------------------------------
.text:802A69C4
.text:802A69C4 loc_802A69C4: # CODE XREF: SMSGetVSyncTimesPerSec(void)+2Cj
.text:802A69C4 lfs f31, -0x3E4(r2) # Load Floating-Point Single-Precision
.text:802A69C8
.text:802A69C8 loc_802A69C8: # CODE XREF: SMSGetVSyncTimesPerSec(void)+30j
.text:802A69C8 # SMSGetVSyncTimesPerSec(void)+3Cj ...
.text:802A69C8 lfs f0, -0x408(r2) # load .5
.text:802A69CC lwz r0, 0x10+arg_4(r1) # Load Word and Zero
.text:802A69D0 fmuls f1, f31, f0 # Floating-Point Multiply Single-Precision
.text:802A69D4 lfd f31, 0x10+var_8(r1) # Load Floating-Point Double-Precision
.text:802A69D8 addi r1, r1, 0x10 # Add Immediate
.text:802A69DC mtlr r0 # Move to link register
.text:802A69E0 blr # Branch unconditionally
.text:802A69E0 # End of function SMSGetVSyncTimesPerSec(void)



This seems to me that we'll have to look at what other functions look at not only these values, but these two functions. I don't know what the rainbow goop could be called, or what functions are tied to the Shadow Mario hit count. Most of the problems I have with finding the functions to change are in the naming conventions they used on the functions themselves. It might also be possible that the functions that call both of these functions take the return values and throw them into other functions many instructions down the road, which also make things a little tricky (although not impossible).

One of the things I'd like to do is figure out how to change the "frame buffer" or frame cap of the game so that it will display all 60 frames in 1 second. I use the term frame buffer loosely because even though the game calls certain things by that name I have no idea what names they could've been thinking of that limits the max framerate like that. Right now it's still limited to 30, which forces everyone to use Vbeam. The values generated with these two functions seem unrelated to whatever function sets the frame buffer. While I don't think this could fix the frame timing issues that saving/Shadow Mario/the warp stuff depends on, it would be ideal to make the patch just a bit more complete.

EDIT: As a side note since this topic is gaining more activity than the other one - about Wind Waker. I was given a disassembly that incorporates the symbol mappings that are included in the NTSC-U version. I went through every value in the .sdata2 segment that is used by interesting/obvious objects and such and surprisingly, absolutely no value seems to directly correlate with the number of frames rendered. I know there are other segments that could hold important values, but this makes me wonder either or not the values are hard coded into the instructions. I think I've proven that the NTSC version of the game contains little to no PAL references (in fact, the PAL version takes similar label names for pieces of data that are NTSC specific and change them for PAL, i.e g_ntscZeldaIntDf). I was wondering if someone wouldn't mind taking all the symbols included in the PAL version and doing the same as the database I was given for the NTSC version. I want to compare the two versions side by side to see where there might be slight changes in the subroutines that might be making the framerates run at 25/30 and what not.
Arisotura
Member
Level: 50


Posts: 107/617
EXP: 938782
For next: 8535

Since: 02-24-13

From: your dreams

Since last post: 308 days
Last activity: 160 days

Posted on 02-08-15 01:49:56 PM Link | Quote
I saw the video, and it's awesomesauce. You need to use Chrome because it's the only thing that can view 60FPS videos, but the difference is visible. A lot smoother.

I wonder how well that would run on a Gamecube, though.

____________________
Kuribo64 -- SM64DS hacking
theboy181
Random nobody
Level: 4


Posts: 2/2
EXP: 155
For next: 124

Since: 02-08-15


Since last post: 8.3 years
Last activity: 8.3 years

Posted on 02-08-15 06:10:03 PM Link | Quote
I was hoping to get this hack working in Wave Race Bluestorm. What do I need to locate the values to make a working patch ?


Brandondorf9999
User
Level: 10


Posts: 11/16
EXP: 3560
For next: 854

Since: 12-13-14


Since last post: 7.1 years
Last activity: 7.0 years

Posted on 07-31-15 03:33:12 AM Link | Quote
That can also be done in the Start.dol file as well. It's at the address of "003EF058".
Next newer thread | Next older thread
Jul - General Game/ROM Hacking - Super Mario Sunshine 60fps patch (NTSC-U) New poll - New thread - New reply


Rusted Logic

Acmlmboard - commit 47be4dc [2021-08-23]
©2000-2023 Acmlm, Xkeeper, et al.

29 database queries, 2 query cache hits.
Query execution time: 0.120738 seconds
Script execution time: 0.040729 seconds
Total render time: 0.161467 seconds