diff --git a/src/games/1000xresist/common.hlsl b/src/games/1000xresist/common.hlsl index 8bac6061..b0a5618a 100644 --- a/src/games/1000xresist/common.hlsl +++ b/src/games/1000xresist/common.hlsl @@ -31,7 +31,7 @@ float3 FinalizeOutput(float3 color) { } float3 lutShaper(float3 color, bool builder = false) { - color = builder ? renodx::color::pq::Decode(color, 100.f) + color = builder ? renodx::color::pq::DecodeSafe(color, 100.f) : renodx::color::pq::Encode(color, 100.f); return color; diff --git a/src/games/acecombat7/Output_MainMenu_0xE227F502.ps_5_0.hlsl b/src/games/acecombat7/Output_MainMenu_0xE227F502.ps_5_0.hlsl index 40eab541..4dcfa073 100644 --- a/src/games/acecombat7/Output_MainMenu_0xE227F502.ps_5_0.hlsl +++ b/src/games/acecombat7/Output_MainMenu_0xE227F502.ps_5_0.hlsl @@ -99,7 +99,7 @@ void main( float3 lut_input = renodx::color::pq::Encode(untonemapped, 100.f); float3 sampled = renodx::lut::Sample(t3, s3_s, lut_input); - float3 post_lut = renodx::color::pq::Decode(sampled, 100.f); + float3 post_lut = renodx::color::pq::DecodeSafe(sampled, 100.f); r1.xyz = post_lut; o0.w = saturate(dot(r1.xyz, float3(0.298999995,0.587000012,0.114))); diff --git a/src/games/dbzspark/final00_0x4156562D.ps_5_1.hlsl b/src/games/dbzspark/final00_0x4156562D.ps_5_1.hlsl index afd307ba..cf9ac9bb 100644 --- a/src/games/dbzspark/final00_0x4156562D.ps_5_1.hlsl +++ b/src/games/dbzspark/final00_0x4156562D.ps_5_1.hlsl @@ -41,7 +41,7 @@ void main( r0.xyz = cb0[7].www * r1.xyz; r1.xyz = t1.Sample(s1_s, v0.xy).xyz; // Game in PQ - r1.rgb = renodx::color::pq::Decode(r1.rgb, injectedData.toneMapGameNits); + r1.rgb = renodx::color::pq::DecodeSafe(r1.rgb, injectedData.toneMapGameNits); r1.rgb = renodx::color::bt709::from::BT2020(r1.rgb); r1.rgb = renodx::color::grade::UserColorGrading( @@ -76,7 +76,7 @@ void main( r1.rgb = renodx::color::bt2020::from::BT709(r1.rgb); r1.rgb = renodx::color::pq::Encode(r1.rgb, injectedData.toneMapGameNits); - r1.rgb = renodx::color::pq::Decode(r1.rgb, 1.f); // We need it to merge with UI + r1.rgb = renodx::color::pq::DecodeSafe(r1.rgb, 1.f); // We need it to merge with UI /* // pow(in_color, 1.f / M2) r1.xyz = log2(r1.xyz); diff --git a/src/games/dbzspark/tonemapper.hlsl b/src/games/dbzspark/tonemapper.hlsl index d0eea3e6..05432836 100644 --- a/src/games/dbzspark/tonemapper.hlsl +++ b/src/games/dbzspark/tonemapper.hlsl @@ -78,7 +78,7 @@ float3 pqTosRGB(float3 input, float customDecode = 0.f, bool clamp = false) { if (injectedData.toneMapType == 1.f) { output = input; } else { - output = renodx::color::pq::Decode(input, customDecode != 0.f ? customDecode : injectedData.toneMapGameNits); + output = renodx::color::pq::DecodeSafe(input, customDecode != 0.f ? customDecode : injectedData.toneMapGameNits); if (clamp) { output = clampForSRGB(output); } @@ -95,7 +95,7 @@ float3 upgradeSRGBtoPQ(float3 tonemapped, float3 post_srgb, float customDecode = if (injectedData.toneMapType == 1.f) { output = tonemapped; } else { - hdr = renodx::color::pq::Decode(tonemapped, customDecode != 0.f ? customDecode : injectedData.toneMapGameNits); + hdr = renodx::color::pq::DecodeSafe(tonemapped, customDecode != 0.f ? customDecode : injectedData.toneMapGameNits); hdr = renodx::color::bt709::from::BT2020(hdr); post = post_srgb; diff --git a/src/games/honkai-starrail/common.hlsl b/src/games/honkai-starrail/common.hlsl index d0740354..2b530075 100644 --- a/src/games/honkai-starrail/common.hlsl +++ b/src/games/honkai-starrail/common.hlsl @@ -32,7 +32,7 @@ float3 FinalizeOutput(float3 color) { } float3 lutShaper(float3 color, bool builder = false) { - color = builder ? renodx::color::pq::Decode(color, 100.f) + color = builder ? renodx::color::pq::DecodeSafe(color, 100.f) : renodx::color::pq::Encode(color, 100.f); return color; diff --git a/src/games/outerwilds/common.hlsl b/src/games/outerwilds/common.hlsl index b9ad7ea4..5ac56027 100644 --- a/src/games/outerwilds/common.hlsl +++ b/src/games/outerwilds/common.hlsl @@ -20,7 +20,7 @@ float3 FinalizeOutput(float3 color) { } float3 lutShaper(float3 color, bool builder = false) { - color = builder ? renodx::color::pq::Decode(color, 100.f) + color = builder ? renodx::color::pq::DecodeSafe(color, 100.f) : renodx::color::pq::Encode(color, 100.f); return color; diff --git a/src/games/seaofstars/lutbuilder_new_0x77850945.ps_4_0.hlsl b/src/games/seaofstars/lutbuilder_new_0x77850945.ps_4_0.hlsl index 336c31f7..d1ba2049 100644 --- a/src/games/seaofstars/lutbuilder_new_0x77850945.ps_4_0.hlsl +++ b/src/games/seaofstars/lutbuilder_new_0x77850945.ps_4_0.hlsl @@ -34,7 +34,7 @@ void main(float4 v0: SV_POSITION0, float2 v1: TEXCOORD0, out float4 o0: SV_Targe r0.w = -r1.x + r0.y; if (injectedData.processingInternalSampling == 1.f) { - r0.xyz = renodx::color::pq::Decode(r0.xzw, 100.f); + r0.xyz = renodx::color::pq::DecodeSafe(r0.xzw, 100.f); } else { r0.xyz = r0.xzw * cb0[129].www; r0.xyz += float3(-0.386036009, -0.386036009, -0.386036009); diff --git a/src/games/stalker2/final00_0xA7EFB8C2.ps_6_6.hlsl b/src/games/stalker2/final00_0xA7EFB8C2.ps_6_6.hlsl index 4b4d04ec..29a0fa58 100644 --- a/src/games/stalker2/final00_0xA7EFB8C2.ps_6_6.hlsl +++ b/src/games/stalker2/final00_0xA7EFB8C2.ps_6_6.hlsl @@ -84,7 +84,7 @@ float4 main( // Scene will always be PQ sRGB bt709 float4 _59 = SceneTexture.Sample(SceneSampler, float2(_7, _8)); float3 scene = _59.rgb; - scene = renodx::color::pq::Decode(scene.rgb, injectedData.toneMapGameNits); + scene = renodx::color::pq::DecodeSafe(scene.rgb, injectedData.toneMapGameNits); uiTexture.rgb = correctGamma(uiTexture.rgb); // Multiple by games because we're encoding PQ later diff --git a/src/games/stalker2/tonemapper.hlsl b/src/games/stalker2/tonemapper.hlsl index 963c33e0..0874e0ef 100644 --- a/src/games/stalker2/tonemapper.hlsl +++ b/src/games/stalker2/tonemapper.hlsl @@ -53,7 +53,7 @@ float3 decodedTosRGB(float3 input_linear) { float3 pqToDecoded(float3 input_pq) { float3 output = input_pq; if (injectedData.toneMapType > 1.f) { - output = renodx::color::pq::Decode(input_pq, injectedData.toneMapGameNits); + output = renodx::color::pq::DecodeSafe(input_pq, injectedData.toneMapGameNits); } return output; diff --git a/src/shaders/color.hlsl b/src/shaders/color.hlsl index aae3dc9e..80117e9c 100644 --- a/src/shaders/color.hlsl +++ b/src/shaders/color.hlsl @@ -269,7 +269,21 @@ float3 Encode(float3 color, float scaling = 10000.f) { float3 Decode(float3 in_color, float scaling = 10000.f) { float3 e_m12 = pow(in_color, 1.f / M2); - float3 out_color = pow(max(e_m12 - C1, 0) / (C2 - C3 * e_m12), 1.f / M1); + float3 out_color = pow(e_m12 - C1 / (C2 - C3 * e_m12), 1.f / M1); + return out_color * (10000.f / scaling); +} + +float3 EncodeSafe(float3 color, float scaling = 10000.f) { + color *= (scaling / 10000.f); + color = max(0, color); + float3 y_m1 = pow(color, M1); + return pow((C1 + C2 * y_m1) / (1.f + C3 * y_m1), M2); +} + +float3 DecodeSafe(float3 in_color, float scaling = 10000.f) { + in_color = max(0, in_color); + float3 e_m12 = pow(in_color, 1.f / M2); + float3 out_color = pow((e_m12 - C1) / (C2 - C3 * e_m12), 1.f / M1); return out_color * (10000.f / scaling); } @@ -584,7 +598,7 @@ namespace bt2020 { namespace from { /// @deprecated - Use pq::Decode float3 PQ(float3 pq_color, float scaling = 10000.f) { - return pq::Decode(pq_color, scaling); + return pq::DecodeSafe(pq_color, scaling); } } // namespace from } // namespace bt2020 @@ -815,7 +829,7 @@ float3 ICtCp(float3 col) { col = mul(ictcp_to_lms, col); // 1.0f = 100 nits, 100.0f = 10k nits - col = pq::Decode(max(0, col), 100.f); + col = pq::DecodeSafe(col, 100.f); return mul(ICTCP_LMS_TO_BT709_MAT, col); }