Dolphin, the GameCube and Wii emulator - Forums

Full Version: Perfect Pixel Nearest Neighbour Integer Scaling
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I made a shader to get as clean pixels as possible out of Dolphin. Note that this means you will not see the inteded/correct aspect ratio.

[Image: XWRuGnp.png]

This was taken on a 2560x1600 monitor, using a scale of 4:3. This means each pixel in the XFB(?) became a 4:3 grid of pixels on my screen, close to widescreen aspect ratio.

By default, the shader will scale as large as possible in each direction, without cropping out any of the image. If you have dolphin aspect ratio set to 4:3 this should not cause problems, and simply upscale the output using nearest neighbour at an integer ratio, producing square pixels.
If you need widescreen stretching, this can only be achieved at integer ratios by scaling the width by 4 and the height by 3. This means the approximately 640x480 output can only be scaled up to 2560x1440, 5120x2880, 7680x4320, etc. Obviously, the resolution is not actually 640x480 and depends on the game.

The reason I made this was because there was no way to consitently do integer nearest neighbour upscaling with other shaders. integer_scaling seemed to always use bilinear to upscale, and sharp_bilinear would fill the window as much as possible, then apply bilinear. This shader produces crisper pixels at the cost of being inaccurate to the correct aspect ratios. (Note that all PAL games are stretched vertically before they are output and I believe NTSC games are stretched horizontally. This is why you may see interpolation in one direction, but the other direction should be cleaner.)

[Image: ok7ifgg.png]

I have seen other people asking for something like this before but it won't be implemented because it is far from accurate of how any game would look on actual hardware.

To use this, put the code in a .glsl file in /Sys/Shaders in the dolphin installation folder.
It will then show up in the post processing shaders list after you restart dolphin.

Code:
/*
[configuration]
[OptionBool]
GUIName = Manual Scale
OptionName = MANUAL
DefaultValue = false

[OptionRangeFloat]
GUIName = Horizontal Scale
OptionName = SCALE_X
DependentOption = MANUAL
MinValue = 1.0
MaxValue = 16.0
StepAmount = 1.0
DefaultValue = 1.0

[OptionRangeFloat]
GUIName = Vertical Scale
OptionName = SCALE_Y
DependentOption = MANUAL
MinValue = 1.0
MaxValue = 16.0
StepAmount = 1.0
DefaultValue = 1.0

[OptionBool]
GUIName = Debug Checkerboard
OptionName = DEBUG
DefaultValue = false
[/configuration]
*/

void main()
{
  float2 s_size = GetResolution();
  float2 w_size = GetWindowResolution();
 
  float2 scale;
  if (OptionEnabled(MANUAL)) {
    scale = float2(GetOption(SCALE_X), GetOption(SCALE_Y));
  } else {
    //Calculate the largest scale factor in both directions
    scale = floor(w_size / s_size);
  }
 
  float2 r_size = s_size * scale;
 
  //Centre the image with black bars
  float2 b_size = (w_size - r_size) / 2.0;
  float left = b_size.x;
  float top = b_size.y;
  float right = w_size.x - b_size.x;
  float bottom = w_size.y - b_size.y;
 
  //By default, all pixels are black
  float4 c = float4(0.0, 0.0, 0.0, 0.0);
 
  float2 coords = GetCoordinates();
  float2 w_coords = w_size * coords;
 
  //Check if the coordinates are inside the black bars
  if (w_coords.x >= left && w_coords.y >= top && w_coords.x <= right && w_coords.y <= bottom) {
    //Offset the coordinates from the black bars
    float2 r_coords = w_coords - b_size;
    //Nearest neighbour
    float2 s_coords = floor(r_coords / scale);
    //+ 0.5 takes the colour of the centre of the pixel, avoiding interpolation
    coords = (s_coords + 0.5) / s_size;
    c = SampleLocation(coords);
 
    if (OptionEnabled(DEBUG)) {
      float2 remainder = frac(s_coords / 2.0);
      if (remainder.x == remainder.y) {
        //Invert checkers
        c = float4(1.0, 1.0, 1.0, 1.0) - c;
      }
    }
  }
 
  SetOutput(c);
}

This is probably not an efficient shader because I had never seen glsl before I did this. I don't mind if anyone else wants to improve it and share Smile .