dolphin/Data/Sys/Shaders/default_pre_post_process.glsl

86 lines
2.4 KiB
GLSL

// References:
// https://www.unravel.com.au/understanding-color-spaces
// SMPTE 170M - BT.601 (NTSC-M) -> BT.709
mat3 from_NTSCM = transpose(mat3(
0.939497225737661, 0.0502268452914346, 0.0102759289709032,
0.0177558637510127, 0.965824605885027, 0.0164195303639603,
-0.00162163209967010, -0.00437400622653655, 1.00599563832621));
// ARIB TR-B9 (9300K+27MPCD with chromatic adaptation) (NTSC-J) -> BT.709
mat3 from_NTSCJ = transpose(mat3(
0.823613036967492, -0.0943227111084757, 0.00799341532931119,
0.0289258355537324, 1.02310733489462, 0.00243547111576797,
-0.00569501554980891, 0.0161828357559315, 1.22328453915712));
// EBU - BT.470BG/BT.601 (PAL) -> BT.709
mat3 from_PAL = transpose(mat3(
1.04408168421813, -0.0440816842181253, 0.000000000000000,
0.000000000000000, 1.00000000000000, 0.000000000000000,
0.000000000000000, 0.0118044782106489, 0.988195521789351));
float3 LinearTosRGBGamma(float3 color)
{
float a = 0.055;
for (int i = 0; i < 3; ++i)
{
float x = color[i];
if (x <= 0.0031308)
x = x * 12.92;
else
x = (1.0 + a) * pow(x, 1.0 / 2.4) - a;
color[i] = x;
}
return color;
}
void main()
{
// Note: sampling in gamma space is "wrong" if the source
// and target resolution don't match exactly.
// Fortunately at the moment here they always should but to do this correctly,
// we'd need to sample from 4 pixels, de-apply the gamma from each of these,
// and then do linear sampling on their corrected value.
float4 color = Sample();
// Convert to linear space to do any other kind of operation
color.rgb = pow(color.rgb, float3(game_gamma));
if (OptionEnabled(correct_color_space))
{
if (game_color_space == 0)
color.rgb = color.rgb * from_NTSCM;
else if (game_color_space == 1)
color.rgb = color.rgb * from_NTSCJ;
else if (game_color_space == 2)
color.rgb = color.rgb * from_PAL;
}
if (OptionEnabled(hdr_output))
{
float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits;
color.rgb *= hdr_paper_white;
}
if (OptionEnabled(linear_space_output))
{
// Nothing to do here
}
// Correct the SDR gamma for sRGB (PC/Monitor) or ~2.2 (Common TV gamma)
else if (OptionEnabled(correct_gamma))
{
if (OptionEnabled(sdr_display_gamma_sRGB))
color.rgb = LinearTosRGBGamma(color.rgb);
else
color.rgb = pow(color.rgb, float3(1.0 / sdr_display_custom_gamma));
}
// Restore the original gamma without changes
else
{
color.rgb = pow(color.rgb, float3(1.0 / game_gamma));
}
SetOutput(color);
}