Skip to content

Commit

Permalink
Improved handling of wide gamut scRGB colors when doing HDR->SDR tone…
Browse files Browse the repository at this point in the history
…mapping
  • Loading branch information
Kaldaien committed Aug 11, 2024
1 parent 904a1c7 commit 1a322fa
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 133 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
24.8.9
24.8.11
=======
+ Improved handling of wide gamut scRGB colors when doing HDR->SDR tonemapping

24.8.9
======
+ Apply IDXGISwapChain3::SetColorSpace1 (...) whenever a D3D11/D3D12 SwapChain
overlay instance is (re)created, for compatibility with RenoDX / ReShade.
Expand Down
2 changes: 1 addition & 1 deletion include/SpecialK/DLL_VERSION.H
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#define SK_YEAR 24
#define SK_MONTH 8
#define SK_DATE 9
#define SK_DATE 11
#define SK_REV_N 0
#define SK_REV 0

Expand Down
1 change: 1 addition & 0 deletions include/SpecialK/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
#include <DirectXMathVector.inl>
#include <DirectXMathMatrix.inl>
#include <DirectXMathMisc.inl>
#include <DirectXPackedVector.h>

#include <LibLoaderAPI.h>

Expand Down
21 changes: 15 additions & 6 deletions resource/shaders/HDR/common_defs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ static const ParamsPQ PQ =
float4 LinearToPQ (float4 x, float maxPQValue)
{
x =
sign ( x / maxPQValue) *
PositivePow ( x / maxPQValue,
PQ.N );

Expand All @@ -871,12 +872,13 @@ float4 LinearToPQ (float4 x, float maxPQValue)
(1.0 + PQ.C3 * x);

return
PositivePow (nd, PQ.M);
sign (nd) * PositivePow (nd, PQ.M);
}

float3 LinearToPQ (float3 x, float maxPQValue)
{
x =
sign ( x / maxPQValue) *
PositivePow ( x / maxPQValue,
PQ.N );

Expand All @@ -885,12 +887,13 @@ float3 LinearToPQ (float3 x, float maxPQValue)
(1.0 + PQ.C3 * x);

return
PositivePow (nd, PQ.M);
sign (nd) * PositivePow (nd, PQ.M);
}

float LinearToPQ (float x, float maxPQValue)
{
x =
sign ( x / maxPQValue) *
PositivePow ( x / maxPQValue,
PQ.N );

Expand All @@ -899,7 +902,7 @@ float LinearToPQ (float x, float maxPQValue)
(1.0 + PQ.C3 * x);

return
PositivePow (nd, PQ.M);
sign (nd) * PositivePow (nd, PQ.M);
}

float3 LinearToPQ (float3 x)
Expand All @@ -910,6 +913,8 @@ float3 LinearToPQ (float3 x)

float PQToLinear (float x, float maxPQValue)
{
float sign_x = sign (x);

x =
PositivePow (x, PQ.rcpM);

Expand All @@ -918,11 +923,13 @@ float PQToLinear (float x, float maxPQValue)
(PQ.C2 - (PQ.C3 * x));

return
PositivePow (nd, PQ.rcpN) * maxPQValue;
sign_x * PositivePow (nd, PQ.rcpN) * maxPQValue;
}

float3 PQToLinear (float3 x, float maxPQValue)
{
float3 sign_x = sign (x);

x =
PositivePow (x, PQ.rcpM);

Expand All @@ -931,11 +938,13 @@ float3 PQToLinear (float3 x, float maxPQValue)
(PQ.C2 - (PQ.C3 * x));

return
PositivePow (nd, PQ.rcpN) * maxPQValue;
sign_x * PositivePow (nd, PQ.rcpN) * maxPQValue;
}

float4 PQToLinear (float4 x, float maxPQValue)
{
float4 sign_x = sign (x);

x =
PositivePow (x, PQ.rcpM);

Expand All @@ -944,7 +953,7 @@ float4 PQToLinear (float4 x, float maxPQValue)
(PQ.C2 - (PQ.C3 * x));

return
PositivePow (nd, PQ.rcpN) * maxPQValue;
sign_x * PositivePow (nd, PQ.rcpN) * maxPQValue;
}

float3 PQToLinear (float3 x)
Expand Down
72 changes: 62 additions & 10 deletions src/render/d3d11/d3d11_screenshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,11 +1115,22 @@ static const DirectX::XMMATRIX c_fromXYZto709 = // Transposed
static const DirectX::XMVECTOR g_MaxPQValue =
DirectX::XMVectorReplicate (125.0f);

auto XMVectorSign = [](DirectX::XMVECTOR v)
{
using namespace DirectX;

XMVECTOR Control = XMVectorLess (v, g_XMZero);
XMVECTOR Sign = XMVectorSelect (g_XMOne, g_XMNegativeOne, Control);

return Sign;
};

auto PQToLinear = [](DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue = g_MaxPQValue)
{
using namespace DirectX;

XMVECTOR ret;
XMVECTOR sign_N = XMVectorSign (N);

ret =
XMVectorPow (XMVectorAbs (N), XMVectorDivide (g_XMOne, PQ.M));
Expand All @@ -1133,7 +1144,7 @@ using namespace DirectX;
XMVectorMultiply (PQ.C3, ret)));

ret =
XMVectorMultiply (XMVectorPow (XMVectorAbs (nd), XMVectorDivide (g_XMOne, PQ.N)), maxPQValue);
XMVectorMultiply (sign_N, XMVectorMultiply (XMVectorPow (XMVectorAbs (nd), XMVectorDivide (g_XMOne, PQ.N)), maxPQValue));

return ret;
};
Expand All @@ -1145,7 +1156,7 @@ auto LinearToPQ = [](DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue = g_MaxPQ
XMVECTOR ret;

ret =
XMVectorPow (XMVectorAbs (XMVectorDivide (N, maxPQValue)), PQ.N);
XMVectorMultiply (XMVectorSign (XMVectorDivide (N, maxPQValue)), XMVectorPow (XMVectorAbs (XMVectorDivide (N, maxPQValue)), PQ.N));

XMVECTOR nd =
XMVectorDivide (
Expand All @@ -1154,7 +1165,7 @@ auto LinearToPQ = [](DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue = g_MaxPQ
);

return
XMVectorPow (XMVectorAbs (nd), PQ.M);
XMVectorMultiply (XMVectorSign (nd), XMVectorPow (XMVectorAbs (nd), PQ.M));
};

float LinearToPQY (float N)
Expand Down Expand Up @@ -1661,6 +1672,48 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
// on their display should be clipped in the tonemapped SDR image.
float _maxNitsToTonemap = rb.displays [rb.active_display].gamut.maxLocalY / 80.0f;

static unsigned int luminance_freq [100000];

ZeroMemory (luminance_freq, sizeof (unsigned int) * 100000);

float fLumRange =
XMVectorGetY (maxLum) -
XMVectorGetY (minLum);

EvaluateImage ( un_srgb.GetImages (),
un_srgb.GetImageCount (),
un_srgb.GetMetadata (),
[&](const XMVECTOR* pixels, size_t width, size_t y)
{
UNREFERENCED_PARAMETER(y);

for (size_t j = 0; j < width; ++j)
{
XMVECTOR v = *pixels++;

v =
XMVector3Transform (v, c_from709toXYZ);

luminance_freq [std::clamp ((int)std::roundf ((XMVectorGetY (v) - XMVectorGetY (minLum)) / (fLumRange / 100000.0f)), 0, 99999)]++;
}
});

double percent = 0.0;

for (auto i = 0 ; i < 100000; ++i)
{
percent +=
(100.0 * ((double)luminance_freq [i] / ((double)un_srgb.GetMetadata ().width * (double)un_srgb.GetMetadata ().height)));

if (percent >= 99.0)
{
maxLum =
XMVectorReplicate (XMVectorGetY (minLum) + (fLumRange * ((float)i / 100000.0f)));

break;
}
}

const float SDR_YInPQ =
LinearToPQY (1.5f);

Expand Down Expand Up @@ -2085,17 +2138,16 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,

case DXGI_FORMAT_R16G16B16A16_FLOAT:
{
using namespace DirectX::PackedVector;

static const HALF g_XMOneFP16 (XMConvertFloatToHalf (1.0f));

for ( UINT j = 0 ;
j < pFrameData->PackedDstPitch ;
j += 8 )
{
glm::vec4 color =
glm::unpackHalf4x16 (*((uint64*)&(pDst [j])));

color.a = 1.0f;

*((uint64*)& (pDst[j])) =
glm::packHalf4x16 (color);
((XMHALF4 *)&(pDst [j]))->w =
g_XMOneFP16;
}
} break;
}
Expand Down
55 changes: 48 additions & 7 deletions src/render/d3d12/d3d12_screenshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1952,6 +1952,48 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
// on their display should be clipped in the tonemapped SDR image.
float _maxNitsToTonemap = rb.displays [rb.active_display].gamut.maxLocalY / 80.0f;

static unsigned int luminance_freq [100000];

ZeroMemory (luminance_freq, sizeof (unsigned int) * 100000);

float fLumRange =
XMVectorGetY (maxLum) -
XMVectorGetY (minLum);

EvaluateImage ( un_srgb.GetImages (),
un_srgb.GetImageCount (),
un_srgb.GetMetadata (),
[&](const XMVECTOR* pixels, size_t width, size_t y)
{
UNREFERENCED_PARAMETER(y);

for (size_t j = 0; j < width; ++j)
{
XMVECTOR v = *pixels++;

v =
XMVector3Transform (v, c_from709toXYZ);

luminance_freq [std::clamp ((int)std::roundf ((XMVectorGetY (v) - XMVectorGetY (minLum)) / (fLumRange / 100000.0f)), 0, 99999)]++;
}
});

double percent = 0.0;

for (auto i = 0 ; i < 100000; ++i)
{
percent +=
(100.0 * ((double)luminance_freq [i] / ((double)un_srgb.GetMetadata ().width * (double)un_srgb.GetMetadata ().height)));

if (percent >= 99.0)
{
maxLum =
XMVectorReplicate (XMVectorGetY (minLum) + (fLumRange * ((float)i / 100000.0f)));

break;
}
}

const float SDR_YInPQ =
LinearToPQY (1.5f);

Expand Down Expand Up @@ -2375,17 +2417,16 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta

case DXGI_FORMAT_R16G16B16A16_FLOAT:
{
using namespace DirectX::PackedVector;

static const HALF g_XMOneFP16 (XMConvertFloatToHalf (1.0f));

for ( UINT j = 0 ;
j < pFrameData->PackedDstPitch ;
j += 8 )
{
glm::vec4 color =
glm::unpackHalf4x16 (*((uint64*)&(pDst [j])));

color.a = 1.0f;

*((uint64*)& (pDst[j])) =
glm::packHalf4x16 (color);
((XMHALF4 *)&(pDst [j]))->w =
g_XMOneFP16;
}
} break;
}
Expand Down
Loading

0 comments on commit 1a322fa

Please sign in to comment.