niuus / FCEUltraRX

FCEUltra RX - A port of FCE Ultra for Wii, forked from FCEUltra GX
19 stars 3 forks source link

Correct aspect ratio by changing viWidth to 644. #2

Open vaguerant opened 4 years ago

vaguerant commented 4 years ago

In gcvideo.cpp, you're currently setting the viWidth to 640, the default and lowest possible value. You should set this to 644 instead for a slightly more accurate aspect ratio.

With apologies if you know all of this, a quick an explanation: the Wii (and GameCube) have both an embedded framebuffer (EFB; generally the thing you think of as a framebuffer and the one your software is most likely to interact directly with) as well as an external framebuffer (XFB). The embedded framebuffer is the one that can be resized up to 640*480 (at least when set to 60 Hz mode), while the external framebuffer can have a width between 640 and 720 pixels. Its primary purpose is to reduce the effects of underscan--the image not filling up the user's entire TV--on the horizontal axis. For example, Nintendo games tend to use a minimum viWidth of 650, and usually more. The external framebuffer scales with 8x oversampling, so the impact of its scaling is not overly blurry.

The GameCube and Wii both use the same 13.5 MHz pixel clock, which is used to determine how long a single pixel is sampled before moving on, and which in turn determines how wide each pixel becomes in the analog video signal output by the Wii. This clock has the result of causing XFB pixels to have an aspect ratio of 10:11. That is the GameCube/Wii's pixel aspect ratio (distinct from the image's aspect ratio). This is the same pixel clock/PAR as many other devices from the period, like the Sega Dreamcast, consumer DVD players, etc.

The NES, SNES, TurboGrafx-16, and many other consoles of the era use a 5.37 MHz pixel clock, resulting in a pixel aspect ratio of 8:7. Since that's different to the PAR of the Wii, you ideally want to correct the aspect ratio by adjusting the viWidth--because the 8x oversampled scaling is so much cleaner than doing it with a bilinear or nearest-neighbor filter, which IIRC is how the GX/RX emulator family manages all scaling currently.

So, the math to get a correct NES/SNES/etc. image on GameCube/Wii is: 512 * (11/10) * (8/7) = 643.657143 ≈ 644 emulator's output resolution * inverse GameCube/Wii PAR * NES/SNES PAR = ideal viWidth ≈ possible viWidth

The idea here is that in one step, you're both negating the GameCube/Wii's PAR and applying the NES/SNES's, all using the reasonably clean scaling of the XFB. All of this assumes that the user is not manually adjusting the image with the video settings in the emulator, but if the user wants to mess with the aspect ratio, that's not your problem. The best you can do is offer the correct aspect ratio as the default settings and let users do as they wish with the rest.

Sorry this was so long. The short version is, switch from 640 to 644 for a more accurate NES/SNES picture. The same fix should be able to be made to Snes9xRX as well, but I won't file an issue separately over there.

dborth commented 4 years ago

sounds convincing. applied this to upstream Snes9x GX / FCE Ultra GX here: https://github.com/dborth/fceugx/commit/c6bfed392be8304ddef50ffa9682755bc0eb72b1 and here: https://github.com/dborth/snes9xgx/commit/5df5747c540f2b0a3088f55116bfe5e557b394de