Skip to content

Commit cb551ad

Browse files
committed
Add JzAzBz "color space"
1 parent 1fbe0a2 commit cb551ad

File tree

4 files changed

+86
-6
lines changed

4 files changed

+86
-6
lines changed

Shaders/Includes/Color.hlsl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,8 @@ static const float PQ_constant_C2 = 18.8515625f;
398398
static const float PQ_constant_C3 = 18.6875f;
399399

400400
// PQ (Perceptual Quantizer - ST.2084) encode/decode used for HDR10 BT.2100.
401-
float3 Linear_to_PQ(float3 LinearColor, int clampType = GCT_DEFAULT)
401+
// Input is expected to be pre-normalized in 0-1 range, supposedly, but not necessarily in the HDR10 range ("HDR10_MaxWhiteNits").
402+
float3 Linear_to_PQ(float3 LinearColor, int clampType = GCT_DEFAULT, float Exponent = 1.0)
402403
{
403404
float3 LinearColorSign = sign(LinearColor);
404405
if (clampType == GCT_POSITIVE)
@@ -410,13 +411,13 @@ float3 Linear_to_PQ(float3 LinearColor, int clampType = GCT_DEFAULT)
410411
float3 colorPow = pow(LinearColor, PQ_constant_M1);
411412
float3 numerator = PQ_constant_C1 + PQ_constant_C2 * colorPow;
412413
float3 denominator = 1.f + PQ_constant_C3 * colorPow;
413-
float3 pq = pow(numerator / denominator, PQ_constant_M2);
414+
float3 pq = pow(numerator / denominator, PQ_constant_M2 * Exponent);
414415
if (clampType == GCT_MIRROR)
415416
return pq * LinearColorSign;
416417
return pq;
417418
}
418419

419-
float3 PQ_to_Linear(float3 ST2084Color, int clampType = GCT_DEFAULT)
420+
float3 PQ_to_Linear(float3 ST2084Color, int clampType = GCT_DEFAULT, float Exponent = 1.0)
420421
{
421422
float3 ST2084ColorSign = sign(ST2084Color);
422423
if (clampType == GCT_POSITIVE)
@@ -425,7 +426,7 @@ float3 PQ_to_Linear(float3 ST2084Color, int clampType = GCT_DEFAULT)
425426
ST2084Color = saturate(ST2084Color);
426427
else if (clampType == GCT_MIRROR)
427428
ST2084Color = abs(ST2084Color);
428-
float3 colorPow = pow(ST2084Color, 1.f / PQ_constant_M2);
429+
float3 colorPow = pow(ST2084Color, 1.f / (PQ_constant_M2 * Exponent));
429430
float3 numerator = max(colorPow - PQ_constant_C1, 0.f);
430431
float3 denominator = PQ_constant_C2 - (PQ_constant_C3 * colorPow);
431432
float3 linearColor = pow(numerator / denominator, 1.f / PQ_constant_M1);

Shaders/Includes/DarktableUCS.hlsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ namespace DarktableUcs
372372
{
373373
float3 XYZ = CieXYZ::RGBTo::XZY(rgb);
374374
s_xyY xyY = CieXYZ::XYZTo::xyY(XYZ);
375-
float3 JCH = xyYTo::LUV(xyY);
376-
return JCH;
375+
float3 UCSLUV = xyYTo::LUV(xyY);
376+
return UCSLUV;
377377
}
378378

379379
// scRGB/BT.709

Shaders/Includes/JzAzBz.hlsl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#ifndef SRC_JZAZBZ_HLSL
2+
#define SRC_JZAZBZ_HLSL
3+
4+
#include "Color.hlsl"
5+
6+
// -----------------------------------------------------------------------------
7+
// Jzazbz
8+
//
9+
// Reference:
10+
// Muhammad Safdar, Guihua Cui, Youn Jin Kim, and Ming Ronnier Luo,
11+
// "Perceptually uniform color space for image signals including high dynamic
12+
// range and wide gamut," Opt. Express 25, 15131-15151 (2017)
13+
// -----------------------------------------------------------------------------
14+
namespace JzAzBz
15+
{
16+
#define JZAZBZ_EXPONENT_SCALE_FACTOR 1.7f // Scale factor for exponent
17+
18+
// Input: linear rgb with a paper white of ~100 nits (SDR neutral)
19+
// Jz Luminance-like
20+
// Az Red–Green opponent axis
21+
// Bz Blue–Yellow opponent axis
22+
float3 rgbToJzazbz(float3 rgb, uint colorSpace = CS_DEFAULT)
23+
{
24+
// The matrix below is for BT.2020 input.
25+
// The transforms should fold with the ones below when compiled.
26+
if (colorSpace == CS_BT709)
27+
{
28+
rgb = BT709_To_BT2020(rgb);
29+
}
30+
else if (colorSpace == CS_AP1)
31+
{
32+
rgb = float3(1, 0, 1); // Not done
33+
}
34+
35+
float3 lms;
36+
lms.x = rgb[0] * 0.530004f + rgb[1] * 0.355704f + rgb[2] * 0.086090f;
37+
lms.y = rgb[0] * 0.289388f + rgb[1] * 0.525395f + rgb[2] * 0.157481f;
38+
lms.z = rgb[0] * 0.091098f + rgb[1] * 0.147588f + rgb[2] * 0.734234f;
39+
40+
float3 lmsPQ = Linear_to_PQ(lms / (HDR10_MaxWhiteNits / Rec709_WhiteLevelNits), GCT_MIRROR, JZAZBZ_EXPONENT_SCALE_FACTOR);
41+
42+
float iz = 0.5f * lmsPQ.x + 0.5f * lmsPQ.y;
43+
44+
float3 jab;
45+
jab.x = (0.44f * iz) / (1.0f - 0.56f * iz) - 1.6295499532821566e-11f;
46+
jab.y = 3.524000f * lmsPQ.x - 4.066708f * lmsPQ.y + 0.542708f * lmsPQ.z;
47+
jab.z = 0.199076f * lmsPQ.x + 1.096799f * lmsPQ.y - 1.295875f * lmsPQ.z;
48+
return jab;
49+
}
50+
51+
// Output: linear rgb
52+
float3 jzazbzToRgb(float3 jab, uint colorSpace = CS_DEFAULT)
53+
{
54+
float jz = jab[0] + 1.6295499532821566e-11f;
55+
float iz = jz / (0.44f + 0.56f * jz);
56+
float a = jab[1];
57+
float b = jab[2];
58+
59+
float3 lms;
60+
lms.x = iz + a * 1.386050432715393e-1f + b * 5.804731615611869e-2f;
61+
lms.y = iz + a * -1.386050432715393e-1f + b * -5.804731615611869e-2f;
62+
lms.z = iz + a * -9.601924202631895e-2f + b * -8.118918960560390e-1f;
63+
64+
float3 lmsLin = PQ_to_Linear(lms, GCT_MIRROR, JZAZBZ_EXPONENT_SCALE_FACTOR) * (HDR10_MaxWhiteNits / Rec709_WhiteLevelNits);
65+
66+
float3 rgb;
67+
rgb.x = lmsLin.x * 2.990669f + lmsLin.y * -2.049742f + lmsLin.z * 0.088977f;
68+
rgb.y = lmsLin.x * -1.634525f + lmsLin.y * 3.145627f + lmsLin.z * -0.483037f;
69+
rgb.z = lmsLin.x * -0.042505f + lmsLin.y * -0.377983f + lmsLin.z * 1.448019f;
70+
if (colorSpace == CS_BT709)
71+
{
72+
rgb = BT2020_To_BT709(rgb);
73+
}
74+
return rgb;
75+
}
76+
}
77+
78+
#endif // SRC_JZAZBZ_HLSL

Source/Core/utils/resource.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ bool CopyBuffer(com_ptr<ID3D11Buffer> cb, ID3D11DeviceContext* native_device_con
912912
}
913913

914914
D3D11_MAPPED_SUBRESOURCE mapped = {};
915+
// Map in DX11 here can seemengly be done on deferred contexts too, it will stall the CPU until the GPU has the latest values (no need to flush the command list)
915916
HRESULT hr = native_device_context->Map(cb.get(), 0, D3D11_MAP_READ, 0, &mapped);
916917
if (FAILED(hr))
917918
{

0 commit comments

Comments
 (0)