mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-30 03:11:31 +11:00
Merge pull request #209 from MajorPainTheCactus/master
Added HDR shader chain to be used with associated pull request 'Added…
This commit is contained in:
commit
f8651de0f5
78
crt/crt-sony-pvm-4k-hdr.slangp
Normal file
78
crt/crt-sony-pvm-4k-hdr.slangp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
A group of shaders that tries to emulate a sony PVM type aperture grille screen but with full brightness.
|
||||||
|
|
||||||
|
The novel thing about this group of shaders is that it transforms the image output by the 'console/arcade/computer' into HDR space first i.e brightens it first and then applies
|
||||||
|
an aperture grille afterwards which is kind of what a CRT would actually do - its kind of a kin to the electron beam (but nothing like it lol).
|
||||||
|
|
||||||
|
My HDR 700 monitors does seem to get reasonably close to the brightness of my PVM's - its not quite there but its close.
|
||||||
|
|
||||||
|
To use:
|
||||||
|
Please Enable HDR in RetroArch,
|
||||||
|
|
||||||
|
You'll need a version of RetroArch post Christmas 2021 that disables the HDR chain when it detects a HDR render target in the render chain
|
||||||
|
|
||||||
|
NOTE: when the hdr10 and inverse_tonemap shaders are envoked the Peak Luminance and Paper White Luminance in the menu *do nothing* instead set those values through the 'Shader Parameters' instead
|
||||||
|
|
||||||
|
Set Peak Luminance to the 'Peak Luminance' of your monitor and set Paper White Luminance to roughly half dependent on the game and the monitor.
|
||||||
|
|
||||||
|
Also try to use a integer scaling - its just better - overscaling is fine/great.
|
||||||
|
|
||||||
|
This shader doesn't do any geometry warping or bouncing of light around inside the screen - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them
|
||||||
|
|
||||||
|
Works only with the D3D11/D3D12 drivers currently
|
||||||
|
|
||||||
|
If taking fullscreen at 4K it currently emulates lower than a 600TVL screen - ie 3840(res) / 6(aperture grille pattern) = 640 TVL.
|
||||||
|
But 600TVL on a 4:3 TV actually means 800 vertical lines as the TVL figure relates to the screen height across the width.
|
||||||
|
|
||||||
|
We need 8K to really start to get round the right ballpark. We need 9600 resolution to have the full 12 pixel apperture grille (800TVL * 12 (aperture grille pattern))
|
||||||
|
|
||||||
|
TODO: Make the horizontal scanlines more blurry in the vertical direction - we're working in HDR space at this point so its trickier than normal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
shaders = "4"
|
||||||
|
feedback_pass = "0"
|
||||||
|
|
||||||
|
shader0 = "../../slang-shaders/stock.slang"
|
||||||
|
filter_linear0 = false
|
||||||
|
wrap_mode0 = "clamp_to_border"
|
||||||
|
mipmap_input0 = "false"
|
||||||
|
alias0 = "StockPass"
|
||||||
|
float_framebuffer0 = "false"
|
||||||
|
srgb_framebuffer0 = "false"
|
||||||
|
scale_type_x0 = "source"
|
||||||
|
scale_x0 = "1.000000"
|
||||||
|
scale_type_y0 = "source"
|
||||||
|
scale_y0 = "1.000000"
|
||||||
|
|
||||||
|
shader1 = "../../slang-shaders/misc/inverse_tonemap.slang"
|
||||||
|
filter_linear1 = "false"
|
||||||
|
wrap_mode1 = "clamp_to_border"
|
||||||
|
mipmap_input1 = "false"
|
||||||
|
alias1 = ""
|
||||||
|
float_framebuffer1 = "false"
|
||||||
|
srgb_framebuffer1 = "false"
|
||||||
|
scale_type_x1 = "source"
|
||||||
|
scale_x1 = "1.000000"
|
||||||
|
scale_type_y1 = "source"
|
||||||
|
scale_y1 = "1.000000"
|
||||||
|
|
||||||
|
shader2 = "../../slang-shaders/misc/hdr10.slang"
|
||||||
|
filter_linear2 = "false"
|
||||||
|
wrap_mode2 = "clamp_to_border"
|
||||||
|
mipmap_input2 = "false"
|
||||||
|
alias2 = ""
|
||||||
|
float_framebuffer2 = "false"
|
||||||
|
srgb_framebuffer2 = "false"
|
||||||
|
scale_type_x2 = "source"
|
||||||
|
scale_x2 = "1.000000"
|
||||||
|
scale_type_y2 = "source"
|
||||||
|
scale_y2 = "1.000000"
|
||||||
|
|
||||||
|
shader3 = "../../slang-shaders/crt/shaders/crt-sony-pvm-4k-hdr.slang"
|
||||||
|
filter_linear3 = "false"
|
||||||
|
wrap_mode3 = "clamp_to_border"
|
||||||
|
mipmap_input3 = "false"
|
||||||
|
alias3 = ""
|
||||||
|
float_framebuffer3 = "false"
|
||||||
|
srgb_framebuffer3 = "false"
|
||||||
|
ScanlineWidth = "1.000000"
|
253
crt/shaders/crt-sony-pvm-4k-hdr.slang
Normal file
253
crt/shaders/crt-sony-pvm-4k-hdr.slang
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
/*
|
||||||
|
A shader that tries to emulate a sony PVM type aperture grille screen but with full brightness.
|
||||||
|
|
||||||
|
The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when
|
||||||
|
we apply this shader which emulates the apperture grille the resulting screen isn't left too dark.
|
||||||
|
|
||||||
|
I think you'd need a HDR 1000 monitor to get close to CRT levels of brightness but my HDR 700 does an alright job of it.
|
||||||
|
|
||||||
|
Please Enable HDR in RetroArch NOTE: when the hdr10 and inverse_tonemap shaders are envoked the Peak Luminance and Paper White Luminance in the menu do nothing instead set those values through the shader parameters instead
|
||||||
|
|
||||||
|
Set Peak Luminance to the peak luminance of your monitor and set Paper White Luminance to roughly half dependent on the game and the monitor.
|
||||||
|
|
||||||
|
Also try to use a integer scaling - its just better - overscaling is fine.
|
||||||
|
|
||||||
|
This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them
|
||||||
|
|
||||||
|
Dont use this shader directly - use the crt\crt-sony-pvm-4k-hdr.slangp to have the proper chain of effects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma format A2B10G10R10_UNORM_PACK32
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float ScanlineWidth;
|
||||||
|
float ScreenWidth;
|
||||||
|
float ScreenHeight;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
/* #pragma parameter ScanlineWidth "Scanline Width" 4.0 0.0 20.0 1.0 */
|
||||||
|
#pragma parameter ScanlineWidth "Scanline Width" 0.5 0.0 1.0 0.01
|
||||||
|
#pragma parameter ScreenWidth "Screen Width" 3840.0 0.0 7680.0 1.0
|
||||||
|
#pragma parameter ScreenHeight "Screen Height" 2160.0 0.0 4320.0 1.0
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
layout(location = 1) out float Scale;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
|
||||||
|
vec2 ScreenSize = max(params.OutputSize.xy, vec2(params.ScreenWidth, params.ScreenHeight));
|
||||||
|
|
||||||
|
if((params.SourceSize.x > ScreenSize.x) || (params.SourceSize.y > ScreenSize.y))
|
||||||
|
{
|
||||||
|
Scale = 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float ScaleFactor = 2.0;
|
||||||
|
|
||||||
|
while(((params.SourceSize.x * ScaleFactor) <= ScreenSize.x) && ((params.SourceSize.y * ScaleFactor) <= ScreenSize.y))
|
||||||
|
{
|
||||||
|
ScaleFactor += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scale = ScaleFactor - 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 1) in float Scale;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D StockPass;
|
||||||
|
|
||||||
|
float ModInteger(float a, float b)
|
||||||
|
{
|
||||||
|
float m = a - floor((a + 0.5) / b) * b;
|
||||||
|
return floor(m + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define kPi 3.1415926536
|
||||||
|
#define kEuler 2.718281828459
|
||||||
|
#define kMax 1.0
|
||||||
|
|
||||||
|
#define kGuassianMin 1.1
|
||||||
|
#define kGuassianMax 3.0
|
||||||
|
#define Sharpness 2.5
|
||||||
|
|
||||||
|
float Ramp(const float gaussian, float colour)
|
||||||
|
{
|
||||||
|
return clamp(gaussian * colour, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float ScanlineSize = params.OutputSize.y / params.SourceSize.y;
|
||||||
|
|
||||||
|
/* vec2 InPixels = (vTexCoord * params.SourceSize.xy) * vec2(Scale); */
|
||||||
|
const vec2 InPixels = (vTexCoord * params.OutputSize.xy);
|
||||||
|
|
||||||
|
const float ScanlinePosition = (floor(vTexCoord.y * params.SourceSize.y) * ScanlineSize) + (ScanlineSize * 0.5);
|
||||||
|
|
||||||
|
float ScanlineDistance = ScanlinePosition - (floor(InPixels.y) + 0.5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(ModInteger(floor(InPixels.y), Scale) < params.ScanlineWidth)
|
||||||
|
{
|
||||||
|
FragColor = vec4(texture(Source, vTexCoord).xyz, 1.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0,0.0,0.0,1.0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ScanlineDistance /= ScanlineSize * params.ScanlineWidth;
|
||||||
|
ScanlineDistance = clamp(abs(ScanlineDistance * 2.0), 0.0, 1.0);
|
||||||
|
|
||||||
|
/* Gaussian distribution */
|
||||||
|
const float gaussian = pow(kEuler, -0.5 * pow(ScanlineDistance/0.3, 2.0));
|
||||||
|
|
||||||
|
//const float guassianf = gaussian * clamp(ScanlineSize / 2, 1.2, 5.0);
|
||||||
|
//const float guassian_clamp = clamp(guassianf, 0.0, 1.0);
|
||||||
|
|
||||||
|
float Ratio = (vTexCoord.x * params.SourceSize.x) - (floor(vTexCoord.x * params.SourceSize.x));
|
||||||
|
Ratio = clamp(((Ratio - 0.5) * Sharpness) + 0.5, 0.0f, 1.0);
|
||||||
|
|
||||||
|
const vec2 SourceTexCoord0 = vec2(vTexCoord.x, ScanlinePosition / params.OutputSize.y);
|
||||||
|
|
||||||
|
vec3 hdr_colour0 = texture(Source, SourceTexCoord0).xyz;
|
||||||
|
vec3 sdr_colour0 = texture(StockPass, SourceTexCoord0).xyz;
|
||||||
|
|
||||||
|
const vec2 SourceTexCoord1 = vec2(vTexCoord.x + (1.0 / params.SourceSize.x), ScanlinePosition / params.OutputSize.y);
|
||||||
|
|
||||||
|
vec3 hdr_colour1 = texture(Source, SourceTexCoord1).xyz;
|
||||||
|
vec3 sdr_colour1 = texture(StockPass, SourceTexCoord1).xyz;
|
||||||
|
|
||||||
|
vec3 hdr_colour = mix(hdr_colour0, hdr_colour1, vec3(Ratio));
|
||||||
|
vec3 sdr_colour = mix(sdr_colour0, sdr_colour1, vec3(Ratio));
|
||||||
|
|
||||||
|
/* TODO: Below needs optimising - just needs a mask array rather than doing if's! Ran out of time */
|
||||||
|
|
||||||
|
#if 0 /* 12 pattern - 8K screens */
|
||||||
|
float x = ModInteger(floor(InPixels.x), 12.0);
|
||||||
|
|
||||||
|
if(x < 3.0)
|
||||||
|
{
|
||||||
|
float red = Ramp(gaussian, (sdr_colour.x * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(red * hdr_colour.x, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 4.0)
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
else if(x < 7.0)
|
||||||
|
{
|
||||||
|
float green = Ramp(gaussian, (sdr_colour.y * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, green * hdr_colour.y, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 8.0)
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
else if(x < 11.0)
|
||||||
|
{
|
||||||
|
float blue = Ramp(gaussian, (sdr_colour.z * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, 0.0, blue * hdr_colour.z, 1.0);
|
||||||
|
}
|
||||||
|
else /* if(x < 12.0) */
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
|
||||||
|
#if 0 /* 9 pattern - 8K screens */
|
||||||
|
float x = ModInteger(floor(InPixels.x), 9.0);
|
||||||
|
|
||||||
|
if(x < 2.0)
|
||||||
|
{
|
||||||
|
float red = Ramp(gaussian, (sdr_colour.x * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(red * hdr_colour.x, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 3.0)
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
else if(x < 5.0)
|
||||||
|
{
|
||||||
|
float green = Ramp(gaussian, (sdr_colour.y * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, green * hdr_colour.y, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 6.0)
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
else if(x < 8.0)
|
||||||
|
{
|
||||||
|
float blue = Ramp(gaussian, (sdr_colour.z * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, 0.0, blue * hdr_colour.z, 1.0);
|
||||||
|
}
|
||||||
|
else /* if(x < 9.0) */
|
||||||
|
{
|
||||||
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0); /* black */
|
||||||
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
|
||||||
|
#if 1 /* 6 pattern - 4K screens */
|
||||||
|
float x = ModInteger(floor(InPixels.x), 6.0);
|
||||||
|
|
||||||
|
if(x < 2.0)
|
||||||
|
{
|
||||||
|
float red = Ramp(gaussian, (sdr_colour.x * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(red * hdr_colour.x, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 4.0)
|
||||||
|
{
|
||||||
|
float green = Ramp(gaussian, (sdr_colour.y * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, green * hdr_colour.y, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else /* if(x < 6.0) */
|
||||||
|
{
|
||||||
|
float blue = Ramp(gaussian, (sdr_colour.z * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, 0.0, blue * hdr_colour.z, 1.0);
|
||||||
|
}
|
||||||
|
#endif /* 1 */
|
||||||
|
|
||||||
|
#if 0 /* 3 pattern - 1080-1440p screens */
|
||||||
|
float x = ModInteger(floor(InPixels.x), 3.0);
|
||||||
|
|
||||||
|
if(x < 1.0)
|
||||||
|
{
|
||||||
|
float red = Ramp(gaussian, (sdr_colour.x * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(red * hdr_colour.x, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else if(x < 2.0)
|
||||||
|
{
|
||||||
|
float green = Ramp(gaussian, (sdr_colour.y * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, green * hdr_colour.y, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else /* if(x < 3.0) */
|
||||||
|
{
|
||||||
|
float blue = Ramp(gaussian, (sdr_colour.z * kGuassianMax) + kGuassianMin);
|
||||||
|
FragColor = vec4(0.0, 0.0, blue * hdr_colour.z, 1.0);
|
||||||
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
}
|
88
misc/hdr10.slang
Normal file
88
misc/hdr10.slang
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
/*
|
||||||
|
Part of the crt-sony-pvm-4k-hdr shader group. Does the exact same thing as RetroArch does internally to map into HDR10 space.
|
||||||
|
|
||||||
|
This is used to do this mapping BEFORE screen effects are applied.
|
||||||
|
|
||||||
|
Originally part of the crt\crt-sony-pvm-4k-hdr.slangp but can be used for any shader
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma format A2B10G10R10_UNORM_PACK32
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float PaperWhiteNits;
|
||||||
|
float ExpandGamut;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter PaperWhiteNits "Paper White Luminance" 400.0 0.0 10000.0 10.0
|
||||||
|
#pragma parameter ExpandGamut "ExpandGamut" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
|
||||||
|
#define kMaxNitsFor2084 10000.0f
|
||||||
|
|
||||||
|
const mat3 k709to2020 = mat3 (
|
||||||
|
0.6274040f, 0.3292820f, 0.0433136f,
|
||||||
|
0.0690970f, 0.9195400f, 0.0113612f,
|
||||||
|
0.0163916f, 0.0880132f, 0.8955950f);
|
||||||
|
|
||||||
|
/* START Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
|
||||||
|
const mat3 kExpanded709to2020 = mat3 (
|
||||||
|
0.6274040f, 0.3292820f, 0.0433136f,
|
||||||
|
0.0457456, 0.941777, 0.0124772,
|
||||||
|
-0.00121055, 0.0176041, 0.983607);
|
||||||
|
|
||||||
|
vec3 LinearToST2084(vec3 normalizedLinearValue)
|
||||||
|
{
|
||||||
|
vec3 ST2084 = pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), vec3(0.1593017578f))) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), vec3(0.1593017578f))), vec3(78.84375f));
|
||||||
|
return ST2084; /* Don't clamp between [0..1], so we can still perform operations on scene values higher than 10,000 nits */
|
||||||
|
}
|
||||||
|
/* END Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
|
||||||
|
|
||||||
|
vec3 Hdr10(vec3 hdr)
|
||||||
|
{
|
||||||
|
/* Now convert into HDR10 */
|
||||||
|
vec3 rec2020 = hdr * k709to2020;
|
||||||
|
|
||||||
|
if(params.ExpandGamut > 0.0f)
|
||||||
|
{
|
||||||
|
rec2020 = hdr * kExpanded709to2020;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 linearColour = rec2020 * (params.PaperWhiteNits / kMaxNitsFor2084);
|
||||||
|
vec3 hdr10 = LinearToST2084(linearColour);
|
||||||
|
|
||||||
|
return hdr10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 hdr = texture(Source, vTexCoord);
|
||||||
|
FragColor = vec4(Hdr10(hdr.rgb), hdr.a);
|
||||||
|
}
|
||||||
|
|
87
misc/inverse_tonemap.slang
Normal file
87
misc/inverse_tonemap.slang
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
/*
|
||||||
|
Part of the crt-sony-pvm-4k-hdr shader group. Does the exact same thing as RetroArch does internally to inverse tonemap from a SDR image to HDR.
|
||||||
|
|
||||||
|
This is used to do this mapping BEFORE screen effects are applied.
|
||||||
|
|
||||||
|
Originally part of the crt\crt-sony-pvm-4k-hdr.slangp but can be used for any shader
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma format R16G16B16A16_SFLOAT
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float Contrast;
|
||||||
|
float PaperWhiteNits;
|
||||||
|
float MaxNits;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter Contrast "Contrast" 5.0 0.0 10.0 0.01
|
||||||
|
#pragma parameter PaperWhiteNits "Paper White Luminance" 400.0 0.0 10000.0 10.0
|
||||||
|
#pragma parameter MaxNits "Peak Luminance" 700.0 0.0 10000.0 10.0
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
|
||||||
|
#define kMaxNitsFor2084 10000.0f
|
||||||
|
#define kEpsilon 0.0001f
|
||||||
|
#define kLumaChannelRatio 0.25f
|
||||||
|
|
||||||
|
vec3 InverseTonemap(vec3 sdr)
|
||||||
|
{
|
||||||
|
sdr = pow(abs(sdr), vec3(params.Contrast / 2.2f)); /* Display Gamma - needs to be determined by calibration screen */
|
||||||
|
|
||||||
|
float luma = dot(sdr, vec3(0.2126, 0.7152, 0.0722)); /* Rec BT.709 luma coefficients - https://en.wikipedia.org/wiki/Luma_(video) */
|
||||||
|
|
||||||
|
/* Inverse reinhard tonemap */
|
||||||
|
float maxValue = (params.MaxNits / params.PaperWhiteNits) + kEpsilon;
|
||||||
|
float elbow = maxValue / (maxValue - 1.0f);
|
||||||
|
float offset = 1.0f - ((0.5f * elbow) / (elbow - 0.5f));
|
||||||
|
|
||||||
|
float hdrLumaInvTonemap = offset + ((luma * elbow) / (elbow - luma));
|
||||||
|
float sdrLumaInvTonemap = luma / ((1.0f + kEpsilon) - luma); /* Convert the srd < 0.5 to 0.0 -> 1.0 range */
|
||||||
|
|
||||||
|
float lumaInvTonemap = (luma > 0.5f) ? hdrLumaInvTonemap : sdrLumaInvTonemap;
|
||||||
|
vec3 perLuma = sdr / (luma + kEpsilon) * lumaInvTonemap;
|
||||||
|
|
||||||
|
vec3 hdrInvTonemap = offset + ((sdr * elbow) / (elbow - sdr));
|
||||||
|
vec3 sdrInvTonemap = sdr / ((1.0f + kEpsilon) - sdr); /* Convert the srd < 0.5 to 0.0 -> 1.0 range */
|
||||||
|
|
||||||
|
vec3 perChannel = vec3(sdr.x > 0.5f ? hdrInvTonemap.x : sdrInvTonemap.x,
|
||||||
|
sdr.y > 0.5f ? hdrInvTonemap.y : sdrInvTonemap.y,
|
||||||
|
sdr.z > 0.5f ? hdrInvTonemap.z : sdrInvTonemap.z);
|
||||||
|
|
||||||
|
vec3 hdr = mix(perLuma, perChannel, vec3(kLumaChannelRatio));
|
||||||
|
|
||||||
|
return hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 sdr = texture(Source, vTexCoord);
|
||||||
|
FragColor = vec4(InverseTonemap(sdr.rgb), sdr.a);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue