mirror of
https://github.com/libretro/RetroArch
synced 2025-02-08 15:40:14 +00:00
* Fix for warning and fix for incorrect comment * Fixed contrast to be more correct - now scales from 0-10 linearly and behaves more the way you'd expect it to - changed name to ditch legacy settings users may have Added ability to skip inverse tonemapper to the shader via the constant buffer using 'inverse_tonemap' - set to 0.0f to skip Fixed potential bug when swapping between hdr and sdr and the bit depth not being set correctly Fixed dx11's blend, rasterizer and topology states not being set to the sames when using hdr and leaving the menu - caused issues with PCSX2's Shadow of the Colossus Added numerous helper functions to help create the correct values to colour the UI - normally the white UI elements should be rendered at paper white not max brightness for various reasons * Fix stylistic issues - * Don't use camelcase for variables and function names * Use '(void)' for function declarations instead of () in C code * Declare variables at the top of a function or code block * Make sure functions that return a value always have a default return path that is not encapsulated by an else block * Use more unique names for retro_math functions which are less likely to overlap with other libraries' function symbols Co-authored-by: twinaphex <libretro@gmail.com>
131 lines
4.9 KiB
C
131 lines
4.9 KiB
C
|
|
#define SRC(...) #__VA_ARGS__
|
|
SRC(
|
|
struct UBO
|
|
{
|
|
float4x4 modelViewProj;
|
|
float contrast; /* 2.0f; */
|
|
float paper_white_nits; /* 200.0f; */
|
|
float max_nits; /* 1000.0f; */
|
|
float expand_gamut; /* 1.0f; */
|
|
float inverse_tonemap;
|
|
};
|
|
uniform UBO global;
|
|
|
|
struct PSInput
|
|
{
|
|
float4 position : SV_POSITION;
|
|
float2 texcoord : TEXCOORD0;
|
|
float4 color : COLOR;
|
|
};
|
|
PSInput VSMain(float4 position : POSITION, float2 texcoord : TEXCOORD0, float4 color : COLOR)
|
|
{
|
|
PSInput result;
|
|
result.position = mul(global.modelViewProj, position);
|
|
result.texcoord = texcoord;
|
|
result.color = color;
|
|
return result;
|
|
}
|
|
uniform sampler s0;
|
|
uniform Texture2D <float4> t0;
|
|
|
|
static const float kMaxNitsFor2084 = 10000.0f;
|
|
static const float kEpsilon = 0.0001f;
|
|
static const float kLumaChannelRatio = 0.25f;
|
|
|
|
static const float3x3 k709to2020 =
|
|
{
|
|
{ 0.6274040f, 0.3292820f, 0.0433136f },
|
|
{ 0.0690970f, 0.9195400f, 0.0113612f },
|
|
{ 0.0163916f, 0.0880132f, 0.8955950f }
|
|
};
|
|
|
|
static const float3x3 kP3to2020 =
|
|
{
|
|
{ 0.753845f, 0.198593f, 0.047562f },
|
|
{ 0.0457456f, 0.941777f, 0.0124772f },
|
|
{ -0.00121055f, 0.0176041f, 0.983607f }
|
|
};
|
|
|
|
/* START Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
|
|
static const float3x3 kExpanded709to2020 =
|
|
{
|
|
{ 0.6274040f, 0.3292820f, 0.0433136f },
|
|
{ 0.0457456, 0.941777, 0.0124772 },
|
|
{ -0.00121055, 0.0176041, 0.983607 }
|
|
};
|
|
|
|
float3 LinearToST2084(float3 normalizedLinearValue)
|
|
{
|
|
float3 ST2084 = pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), 0.1593017578f)) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), 0.1593017578f)), 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 */
|
|
|
|
float3 SRGBToLinear(float3 color)
|
|
{
|
|
float3 scale = color / 12.92f;
|
|
float3 gamma = pow(abs(color + 0.055f) / 1.055f, 2.4f);
|
|
|
|
return float3( color.x < 0.04045f ? scale.x : gamma.x,
|
|
color.y < 0.04045f ? scale.y : gamma.y,
|
|
color.z < 0.04045f ? scale.z : gamma.z);
|
|
}
|
|
|
|
float4 Hdr(float4 sdr)
|
|
{
|
|
float3 hdr;
|
|
|
|
if(global.inverse_tonemap)
|
|
{
|
|
sdr.xyz = pow(abs(sdr.xyz), global.contrast / 2.2f ); /* Display Gamma - needs to be determined by calibration screen */
|
|
|
|
float luma = dot(sdr.xyz, float3(0.2126, 0.7152, 0.0722)); /* Rec BT.709 luma coefficients - https://en.wikipedia.org/wiki/Luma_(video) */
|
|
|
|
/* Inverse reinhard tonemap */
|
|
float maxValue = (global.max_nits / global.paper_white_nits) + kEpsilon;
|
|
float elbow = maxValue / (maxValue - 1.0f); /* Convert (1.0 + epsilon) to infinite to range 1001 -> 1.0 */
|
|
float offset = 1.0f - ((0.5f * elbow) / (elbow - 0.5f)); /* Convert 1001 to 1.0 to range 0.5 -> 1.0 */
|
|
|
|
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;
|
|
float3 perLuma = sdr.xyz / (luma + kEpsilon) * lumaInvTonemap;
|
|
|
|
float3 hdrInvTonemap = offset + ((sdr.xyz * elbow) / (elbow - sdr.xyz));
|
|
float3 sdrInvTonemap = sdr.xyz / ((1.0f + kEpsilon) - sdr.xyz); /* Convert the srd < 0.5 to 0.0 -> 1.0 range */
|
|
|
|
float3 perChannel = float3(sdr.x > 0.5f ? hdrInvTonemap.x : sdrInvTonemap.x,
|
|
sdr.y > 0.5f ? hdrInvTonemap.y : sdrInvTonemap.y,
|
|
sdr.z > 0.5f ? hdrInvTonemap.z : sdrInvTonemap.z);
|
|
|
|
hdr = lerp(perLuma, perChannel, kLumaChannelRatio);
|
|
}
|
|
else
|
|
{
|
|
hdr = SRGBToLinear(sdr.xyz);
|
|
}
|
|
|
|
/* Now convert into HDR10 */
|
|
float3 rec2020 = mul(k709to2020, hdr);
|
|
|
|
if(global.expand_gamut > 0.0f)
|
|
{
|
|
rec2020 = mul( kExpanded709to2020, hdr);
|
|
}
|
|
|
|
float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084);
|
|
float3 hdr10 = LinearToST2084(linearColour);
|
|
|
|
return float4(hdr10, sdr.w);
|
|
}
|
|
|
|
float4 PSMain(PSInput input) : SV_TARGET
|
|
{
|
|
float4 sdr = input.color * t0.Sample(s0, input.texcoord);
|
|
|
|
return Hdr(sdr);
|
|
};
|
|
)
|