Episode 1: Snes9x
For a project aiming to bring a common set of features, RA/libretro suffers a lot from inconsistency.
I’ve been trying various cores and I just don’t understand what the different options do.
This option has no effect in SNES9x (I guess this is good)
Example:
This is snes9x, crop overscan off
crop overscan on
There is an auto option that seems to default to AUTO which seems to be… ON, I don’t see any real auto behavior in the code (I may be wrong)
if (crop_overscan_mode == OVERSCAN_CROP_ON)
height = SNES_HEIGHT;
else if (crop_overscan_mode == OVERSCAN_CROP_OFF)
height = SNES_HEIGHT_EXTENDED;
info->geometry.base_width = width;
info->geometry.base_height = height;
info->geometry.max_width = MAX_SNES_WIDTH;
info->geometry.max_height = MAX_SNES_HEIGHT;
info->geometry.aspect_ratio = get_aspect_ratio(width, height);
info->timing.sample_rate = 32040;
info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0;
This is done at startup, basically it has two defined height values depending on overscan on or off. It can also change whenever the option is called.
That’s what the options do at least, basically a geometry change.
Then there is this code here:
bool8 S9xDeinitUpdate(int width, int height)
{
int overscan_offset = 0;
if (crop_overscan_mode == OVERSCAN_CROP_ON)
{
if (height > SNES_HEIGHT * 2)
{
overscan_offset = 14;
height = SNES_HEIGHT * 2;
}
else if ((height > SNES_HEIGHT) && (height != SNES_HEIGHT * 2))
{
overscan_offset = 7;
height = SNES_HEIGHT;
}
}
else if (crop_overscan_mode == OVERSCAN_CROP_OFF)
{
if (height > SNES_HEIGHT_EXTENDED)
{
if (height < SNES_HEIGHT_EXTENDED * 2)
{
overscan_offset = -16;
memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * ((SNES_HEIGHT_EXTENDED << 1) - height));
}
height = SNES_HEIGHT_EXTENDED * 2;
}
else
{
if (height < SNES_HEIGHT_EXTENDED)
{
overscan_offset = -8;
memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * (SNES_HEIGHT_EXTENDED - height));
}
height = SNES_HEIGHT_EXTENDED;
}
}
if (width == MAX_SNES_WIDTH && hires_blend)
{
#define AVERAGE_565(el0, el1) (((el0) & (el1)) + ((((el0) ^ (el1)) & 0xF7DE) >> 1))
if (hires_blend == 1) /* Blur method */
{
for (int y = 0; y < height; y++)
{
uint16 *input = (uint16 *) ((uint8 *) GFX.Screen + y * GFX.Pitch);
uint16 *output = (uint16 *) ((uint8 *) GFX.Screen + y * GFX.Pitch);
uint16 l, r;
l = 0;
for (int x = 0; x < (width >> 1); x++)
{
r = *input++;
*output++ = AVERAGE_565 (l, r);
l = r;
r = *input++;
*output++ = AVERAGE_565 (l, r);
l = r;
}
}
}
else if (hires_blend == 2) /* Merge method */
{
for (int y = 0; y < height; y++)
{
uint16 *input = (uint16 *) ((uint8 *) GFX.Screen + y * GFX.Pitch);
uint16 *output = (uint16 *) ((uint8 *) GFX.Screen + y * GFX.Pitch);
uint16 l, r;
for (int x = 0; x < (width >> 1); x++)
{
l = *input++;
r = *input++;
*output++ = AVERAGE_565 (l, r);
}
}
width >>= 1;
}
video_cb(GFX.Screen + ((int)(GFX.Pitch >> 1) * overscan_offset), width, height, GFX.Pitch);
}
else
{
video_cb(GFX.Screen + ((int)(GFX.Pitch >> 1) * overscan_offset), width, height, GFX.Pitch);
}
return TRUE;
}
This seems to calculate which part of the framebuffer is “forwarded to the frontend” All good here, now for aspect ratio, I always use core provided, that’s what everyone should do imho assuming the core is nice enough to provide a correct aspect ratio, so let’s see the options
auto|ntsc|pal|4:3|uncorrected
auto seems to be ntsc on NTSC games and pal on PAL games, which seems correct. Then there is 4:3 and uncorrected
Auto
4:3
Uncorrected seems to be 1:1?
Can anyone explain uncorrected? and also NTSC vs 4:3, there is a minor difference but no idea of what it is.
Also what aspect do you use for SNES9x?