Simplest way to downscale?

Many are a familiar with the super-sampling effect you can achieve in Mupen64-Plus and Beetle PSX HW, where the core renders at a 2, 4, or 8x multiple of native res and then downsamples back to 1x native res for a smooth but faithful image. I’m trying to figure out if there’s a shader or preset that can accomplish this with other cores like DeSmuME. It should just be a simple bilinear downsample right? Except I can’t seem to find one that does that. If it doesn’t exist yet I can’t imagine it would be hard to write one. Any help would be much appreciated.

(Note: must be Slang shaders)

Super-sampling is an emulator feature for games with 3D graphics, 2D games have fixed pixel matrix and you can’t alter the image rendering.
In DeSmuME, I think it has a high resolution mode for 2D and 3D (I have to test this).

If you want a smoother image, there are several image smoothing shaders, the “xbr, sabr, etc”.
If you are looking for something similar to super-sampling, “snalenx” works magic, at the cost of performance, scalefx and scalehq are also very good.
If what you want is to downscale, as the title says, there are many that downscale the resolution, crt-hyllian-3d is one of my favorites.

You can try the g-sharp_resampler in the /dithering folder.

With this preset you can try out the downsampling effect, ofc you can adjust it. I must note that filter range and sigma should be increased for a better downsampling effect.

shaders = 2

shader0 = shaders/g-sharp_resampler.slang
scale_type_x0 = absolute
scale_x0 = 320.0
scale_type_y0 = absolute
scale_y0 = 240.0


shader1 = ../stock.slang
filter_linear1 = false
scale_type_x1 = viewport
scale_x1 = 1.0
scale_type_y1 = viewport
scale_y1 = 1.0
2 Likes

@alexb3d I should have clarified that this is meant for 3D cores that are capable of rendering at higher than original resolution. DeSmuME is one such example. Anyway I figured it out after a bit of messing around so I’ll share my solution:

shaders = "3"
shader0 = "stock.slang
filter_linear0 = "true"
scale_type_x0 = "source"
scale_x0 = "0.5"
scale_type_y0 = "source"
scale_y0 = "0.5"
shader1 = "stock.slang
filter_linear1 = "true"
scale_type_x1 = "source"
scale_x1 = "0.5"
scale_type_y1 = "source"
scale_y1 = "0.5"
shader2 = "stock.slang"
filter_linear2 = "false"

It’s just a few passes of the stock shader. First one halves the resolution, second one halves it again, and the last one is just for presenting the results with nearest neighbor sampling. I half the resolution twice because the emulator is rendering at 4x. A single pass with the scale set to 0.25 didn’t look as good for some reason that I’m too lazy to figure out.

Here are the results in New Super Mario Bros. Notice 3D elements like Mario, the cheep cheeps, sign and seaweed have enhanced smoothness and detail but still match resolution with the tile art, which is untouched.

Why not just use DeSmuME’s MSAA setting with 1x resolution you might be wondering. It doesn’t look quite as good and it causes artifacts in a lot of games. In this game for example it produces a weird dark outline around 3D objects due to the way they are composited onto the 2D background. Super sampling fixes that.

2 Likes

Nice results!

I think if you change bilinear by a cubic downscaler, the results wil be even better. From my experience, b-spline inside cubic folder is the best for this task.

Sounds interesting but I’m not sure how to do this with the separate b-spline-x and b-spline-y shaders. I don’t see a combined version. And I’m not sure how to modify the b-spline-fast preset for high quality downsampling. Would you be able to provide an example?

1 Like

They work in each dimension. They’re orthogonals.

Well, a first attempt would be downscale by 4x like this:

shaders = "3"
shader0 = "cubic/shaders/b-spline-x.slang"
filter_linear0 = "false"
scale_type_x0 = "source"
scale_x0 = "0.25"
scale_type_y0 = "source"
scale_y0 = "1.0"
shader1 = "cubic/shaders/b-spline-y.slang"
filter_linear1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.0"
scale_type_y1 = "source"
scale_y1 = "0.25"
shader2 = "stock.slang"
filter_linear2 = "true"

Doesn’t really seem like an improvement over bilinear to me. Since I did two passes it’s already integrating 16 samples for every output pixel. Thanks though.

1 Like

Ok. It can be used in steps too like bilinear. Anyway, if you’re already satisfied, no need for further experiments.