Skip to content

Commit bed2dc3

Browse files
HDR: Replace expand gamut toggle with multi-mode gamut selection (#18676)
1 parent 47d122b commit bed2dc3

23 files changed

Lines changed: 1894 additions & 1597 deletions

config.def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@
506506
#define DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS 200.0f
507507

508508
/* Should we expand the colour gamut when using hdr */
509-
#define DEFAULT_VIDEO_HDR_EXPAND_GAMUT false
509+
#define DEFAULT_VIDEO_HDR_EXPAND_GAMUT 0
510510

511511
/* Enable a basic HDR scanline implementation which is the main reason for using HDR in RetroArch */
512512
#define DEFAULT_VIDEO_HDR_SCANLINES true

configuration.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,7 +1920,6 @@ static struct config_bool_setting *populate_settings_bool(
19201920
SETTING_BOOL("video_force_srgb_disable", &settings->bools.video_force_srgb_disable, true, false, false);
19211921
SETTING_BOOL("video_fullscreen", &settings->bools.video_fullscreen, true, DEFAULT_FULLSCREEN, false);
19221922
SETTING_BOOL("video_hdr_enable", &settings->bools.video_hdr_enable, true, DEFAULT_VIDEO_HDR_ENABLE, false);
1923-
SETTING_BOOL("video_hdr_expand_gamut", &settings->bools.video_hdr_expand_gamut, true, DEFAULT_VIDEO_HDR_EXPAND_GAMUT, false);
19241923
SETTING_BOOL("video_hdr_scanlines", &settings->bools.video_hdr_scanlines, true, DEFAULT_VIDEO_HDR_SCANLINES, false);
19251924
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, DEFAULT_VSYNC, false);
19261925
SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, DEFAULT_ADAPTIVE_VSYNC, false);
@@ -2560,7 +2559,8 @@ static struct config_uint_setting *populate_settings_uint(
25602559
SETTING_UINT("video_record_scale_factor", &settings->uints.video_record_scale_factor, true, 1, false);
25612560
SETTING_UINT("video_stream_scale_factor", &settings->uints.video_stream_scale_factor, true, 1, false);
25622561

2563-
SETTING_UINT("video_hdr_subpixel_layout", &settings->uints.video_hdr_subpixel_layout, true, DEFAULT_VIDEO_HDR_SUBPIXEL_LAYOUT, false);
2562+
SETTING_UINT("video_hdr_subpixel_layout", &settings->uints.video_hdr_subpixel_layout, true, DEFAULT_VIDEO_HDR_SUBPIXEL_LAYOUT, false);
2563+
SETTING_UINT("video_hdr_expand_gamut", &settings->uints.video_hdr_expand_gamut, true, DEFAULT_VIDEO_HDR_EXPAND_GAMUT, false);
25642564
#ifdef HAVE_NETWORKING
25652565
SETTING_UINT("streaming_mode", &settings->uints.streaming_mode, true, STREAMING_MODE_TWITCH, false);
25662566
#endif

configuration.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ typedef struct settings
383383
unsigned video_shader_subframes;
384384
unsigned video_autoswitch_refresh_rate;
385385
unsigned video_hdr_subpixel_layout;
386+
unsigned video_hdr_expand_gamut;
386387

387388
unsigned quit_on_close_content;
388389

@@ -689,7 +690,6 @@ typedef struct settings
689690
bool video_wiiu_prefer_drc;
690691
bool video_notch_write_over_enable;
691692
bool video_hdr_enable;
692-
bool video_hdr_expand_gamut;
693693
bool video_hdr_scanlines;
694694
bool video_use_metal_arg_buffers;
695695

gfx/common/dxgi_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ typedef struct ALIGN(16)
3838
float max_nits; /* 1000.0f */
3939
unsigned subpixel_layout; /* 0 */
4040
float scanlines; /* 1.0f */
41-
float expand_gamut; /* 0.0f */
41+
unsigned expand_gamut; /* 0 */
4242
float inverse_tonemap; /* 1.0f */
4343
float hdr10; /* 1.0f */
4444
} dxgi_hdr_uniform_t;

gfx/drivers/d3d11.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ typedef struct
412412
float enable_hdr;
413413
float paper_white_nits;
414414
float max_nits;
415-
float expand_gamut;
415+
unsigned expand_gamut;
416416
float scanlines;
417417
unsigned subpixel_layout;
418418
float inverse_tonemap;
@@ -1635,13 +1635,13 @@ static void d3d11_set_hdr_paper_white_nits(void* data, float paper_white_nits)
16351635
}
16361636
}
16371637

1638-
static void d3d11_set_hdr_expand_gamut(void* data, bool expand_gamut)
1638+
static void d3d11_set_hdr_expand_gamut(void* data, unsigned expand_gamut)
16391639
{
16401640
D3D11_MAPPED_SUBRESOURCE mapped_ubo;
16411641
dxgi_hdr_uniform_t *ubo = NULL;
16421642
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
16431643

1644-
d3d11->hdr.ubo_values.expand_gamut = expand_gamut ? 1.0f : 0.0f;
1644+
d3d11->hdr.ubo_values.expand_gamut = expand_gamut;
16451645

16461646
d3d11->context->lpVtbl->Map(
16471647
d3d11->context, (D3D11Resource)d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
@@ -1653,7 +1653,7 @@ static void d3d11_set_hdr_expand_gamut(void* data, bool expand_gamut)
16531653
{
16541654
for (unsigned i = 0; i < d3d11->shader_preset->passes; i++)
16551655
{
1656-
d3d11->pass[i].expand_gamut = expand_gamut ? 1.0f : 0.0f;
1656+
d3d11->pass[i].expand_gamut = expand_gamut;
16571657
}
16581658
}
16591659
}
@@ -2703,7 +2703,7 @@ static void *d3d11_gfx_init(const video_info_t* video,
27032703
d3d11->hdr.ubo_values.subpixel_layout =
27042704
settings->uints.video_hdr_subpixel_layout;
27052705
d3d11->hdr.ubo_values.expand_gamut =
2706-
settings->bools.video_hdr_expand_gamut;
2706+
settings->uints.video_hdr_expand_gamut;
27072707
d3d11->hdr.ubo_values.inverse_tonemap = 1.0f; /* Use this to turn on/off the inverse tonemap */
27082708
d3d11->hdr.ubo_values.hdr10 = 1.0f; /* Use this to turn on/off the hdr10 */
27092709

@@ -3619,7 +3619,7 @@ static bool d3d11_gfx_frame(
36193619
d3d11->pass[i].max_nits = settings->floats.video_hdr_max_nits;
36203620
d3d11->pass[i].scanlines = settings->bools.video_hdr_scanlines ? 1.0f : 0.0f;
36213621
d3d11->pass[i].subpixel_layout = settings->uints.video_hdr_subpixel_layout;
3622-
d3d11->pass[i].expand_gamut = settings->bools.video_hdr_expand_gamut ? 1.0f : 0.0f;
3622+
d3d11->pass[i].expand_gamut = settings->uints.video_hdr_expand_gamut;
36233623
}
36243624
#endif /* HAVE_DXGI_HDR */
36253625

gfx/drivers/d3d12.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,17 +1887,17 @@ static void d3d12_set_hdr_paper_white_nits(void* data, float paper_white_nits)
18871887
}
18881888
}
18891889

1890-
static void d3d12_set_hdr_expand_gamut(void* data, bool expand_gamut)
1890+
static void d3d12_set_hdr_expand_gamut(void* data, unsigned expand_gamut)
18911891
{
18921892
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
18931893

1894-
d3d12->hdr.ubo_values.expand_gamut = expand_gamut ? 1.0f : 0.0f;
1894+
d3d12->hdr.ubo_values.expand_gamut = expand_gamut;
18951895

18961896
if(d3d12->shader_preset)
18971897
{
18981898
for (unsigned i = 0; i < d3d12->shader_preset->passes; i++)
18991899
{
1900-
d3d12->pass[i].expand_gamut = expand_gamut ? 1.0f : 0.0f;
1900+
d3d12->pass[i].expand_gamut = expand_gamut;
19011901
}
19021902
}
19031903
}
@@ -3505,7 +3505,7 @@ static void *d3d12_gfx_init(const video_info_t* video,
35053505

35063506
d3d12->hdr.ubo_values.subpixel_layout = settings->uints.video_hdr_subpixel_layout;
35073507
d3d12->hdr.ubo_values.scanlines = settings->bools.video_hdr_scanlines;
3508-
d3d12->hdr.ubo_values.expand_gamut = settings->bools.video_hdr_expand_gamut;
3508+
d3d12->hdr.ubo_values.expand_gamut = settings->uints.video_hdr_expand_gamut;
35093509

35103510
d3d12->hdr.ubo_values.inverse_tonemap = 1.0f; /* Use this to turn on/off the inverse tonemap */
35113511
d3d12->hdr.ubo_values.hdr10 = 1.0f; /* Use this to turn on/off the hdr10 */
@@ -4185,7 +4185,7 @@ static bool d3d12_gfx_frame(
41854185
d3d12->pass[i].max_nits = settings->floats.video_hdr_max_nits;
41864186
d3d12->pass[i].scanlines = settings->bools.video_hdr_scanlines ? 1.0f : 0.0f;
41874187
d3d12->pass[i].subpixel_layout = settings->uints.video_hdr_subpixel_layout;
4188-
d3d12->pass[i].expand_gamut = settings->bools.video_hdr_expand_gamut ? 1.0f : 0.0f;
4188+
d3d12->pass[i].expand_gamut = settings->uints.video_hdr_expand_gamut;
41894189
}
41904190
#endif /* HAVE_DXGI_HDR */
41914191

gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h

Lines changed: 99 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SRC(
1010
float max_nits; /* 1000.0f */
1111
uint subpixel_layout; /* 0 */
1212
float scanlines; /* 1.0f */
13-
float expand_gamut; /* 0.0f */
13+
uint expand_gamut; /* 0 */
1414
float inverse_tonemap;
1515
float hdr10;
1616
};
@@ -82,14 +82,14 @@ static const float k_crt_green_horizontal_convergence = 0.0f;
8282
static const float k_crt_blue_horizontal_convergence = 0.0f;
8383

8484
static const float k_crt_red_scanline_min = 0.45f;
85-
static const float k_crt_red_scanline_max = 0.70f;
86-
static const float k_crt_red_scanline_attack = 0.30f;
85+
static const float k_crt_red_scanline_max = 0.90f;
86+
static const float k_crt_red_scanline_attack = 0.60f;
8787
static const float k_crt_green_scanline_min = 0.45f;
88-
static const float k_crt_green_scanline_max = 0.70f;
89-
static const float k_crt_green_scanline_attack = 0.30f;
88+
static const float k_crt_green_scanline_max = 0.90f;
89+
static const float k_crt_green_scanline_attack = 0.60f;
9090
static const float k_crt_blue_scanline_min = 0.45f;
91-
static const float k_crt_blue_scanline_max = 0.70f;
92-
static const float k_crt_blue_scanline_attack = 0.30f;
91+
static const float k_crt_blue_scanline_max = 0.90f;
92+
static const float k_crt_blue_scanline_attack = 0.60f;
9393

9494
static const float k_crt_red_beam_sharpness = 1.30f;
9595
static const float k_crt_red_beam_attack = 1.00f;
@@ -111,6 +111,13 @@ static const float3x3 k709to2020 =
111111
{ 0.0163916f, 0.0880132f, 0.8955950f }
112112
};
113113

114+
static const float3x3 k2020toP3 =
115+
{
116+
{ 1.343578f, -0.282180f, -0.061399f },
117+
{-0.065297f, 1.075788f, -0.010490f },
118+
{ 0.002822f, -0.019598f, 1.016777f }
119+
};
120+
114121
static const float4 kFallOffControlPoints = float4(0.0f, 0.0f, 0.0f, 1.0f);
115122
static const float4 kAttackControlPoints = float4(0.0f, 1.0f, 1.0f, 1.0f);
116123

@@ -122,9 +129,9 @@ static const float4x4 kCubicBezier = float4x4( 1.0f, 0.0f, 0.0f, 0.0f,
122129
/* START Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
123130
static const float3x3 kExpanded709to2020 =
124131
{
125-
{ 0.6274040f, 0.3292820f, 0.0433136f },
126-
{ 0.0457456, 0.941777, 0.0124772 },
127-
{ -0.00121055, 0.0176041, 0.983607 }
132+
{ 0.6274040, 0.3292820, 0.0433136 },
133+
{ 0.0457456, 0.941777, 0.0124772 },
134+
{-0.00121055, 0.0176041, 0.983607 }
128135
};
129136

130137
float3 LinearToST2084(float3 normalizedLinearValue)
@@ -149,59 +156,110 @@ float3 InverseTonemap(const float3 sdr_linear, const float max_nits, const float
149156
return sdr_linear * (tonemapped_val / input_val);
150157
}
151158

152-
float4 Sample(float2 texcoord)
159+
float3 Sample(float2 texcoord)
153160
{
154161
const float4 sdr = t0.Sample(s0, texcoord);
155162

156-
const float3 sdr_linear = pow(abs(sdr.rgb), 2.2f);
163+
const float3 sdr_linear = pow(abs(sdr.rgb), 2.22f);
157164

158-
return float4(sdr_linear, sdr.a);
165+
return sdr_linear;
159166
}
160167

161168
float4 Sample(float4 colour, float2 texcoord)
162169
{
163170
const float4 sdr = colour * t0.Sample(s0, texcoord);
164171

165-
const float3 sdr_linear = pow(abs(sdr.rgb), 2.2f);
172+
const float3 sdr_linear = pow(abs(sdr.rgb), 2.22f);
166173

167174
return float4(sdr_linear, sdr.a);
168175
}
169176

170-
float4 HDR(const float4 sdr_linear)
177+
float3 To2020(const float3 sdr_linear)
171178
{
172-
const float3 hdr_linear = InverseTonemap(sdr_linear.rgb, global.max_nits, global.paper_white_nits);
179+
float3 rec2020;
180+
181+
if(global.expand_gamut == 0)
182+
{
183+
rec2020 = mul(k709to2020, sdr_linear);
184+
}
185+
else if(global.expand_gamut == 1)
186+
{
187+
rec2020 = mul( kExpanded709to2020, sdr_linear);
188+
}
189+
else if(global.expand_gamut == 2)
190+
{
191+
rec2020 = mul(k709to2020, sdr_linear);
192+
rec2020 = mul(k2020toP3, rec2020);
193+
}
194+
else
195+
{
196+
rec2020 = sdr_linear;
197+
}
173198

174-
return float4(hdr_linear, sdr_linear.a);
199+
rec2020 = max(rec2020, float3(0.0f, 0.0f, 0.0f));
200+
201+
return rec2020;
175202
}
176203

177-
float3 HDR10(const float3 hdr_linear)
204+
float4 To2020(const float4 sdr_linear)
178205
{
179-
float3 rec2020 = mul(k709to2020, hdr_linear);
206+
float3 rec2020;
180207

181-
if(global.expand_gamut > 0.0f)
208+
if(global.expand_gamut == 0)
209+
{
210+
rec2020 = mul(k709to2020, sdr_linear.rgb);
211+
}
212+
else if(global.expand_gamut == 1)
213+
{
214+
rec2020 = mul( kExpanded709to2020, sdr_linear.rgb);
215+
}
216+
else if(global.expand_gamut == 2)
217+
{
218+
rec2020 = mul(k709to2020, sdr_linear.rgb);
219+
rec2020 = mul(k2020toP3, rec2020);
220+
}
221+
else
182222
{
183-
rec2020 = mul( kExpanded709to2020, hdr_linear);
223+
rec2020 = sdr_linear.rgb;
184224
}
185225

186-
const float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084);
226+
rec2020 = max(rec2020, float3(0.0f, 0.0f, 0.0f));
227+
228+
return float4(rec2020, sdr_linear.a);
229+
}
230+
231+
float3 HDR(const float3 sdr_linear)
232+
{
233+
return InverseTonemap(sdr_linear, global.max_nits, global.paper_white_nits);
234+
}
235+
236+
float4 HDR(const float4 sdr_linear)
237+
{
238+
const float3 hdr_linear = InverseTonemap(sdr_linear.rgb, global.max_nits, global.paper_white_nits);
239+
240+
return float4(hdr_linear, sdr_linear.a);
241+
}
242+
243+
float3 LinearToSignal(const float3 linear_colour)
244+
{
245+
// Always Encode to Gamma 2.4
246+
return pow(max(linear_colour.rgb, float3(0.0f, 0.0f, 0.0f)), 1.0f / 2.4f);
247+
}
248+
249+
float3 HDR10(const float3 hdr_linear)
250+
{
251+
const float3 pq_input = hdr_linear * (global.paper_white_nits / kMaxNitsFor2084);
187252

188-
const float3 hdr10 = LinearToST2084(max(linearColour, 0.0f));
253+
const float3 hdr10 = LinearToST2084(max(pq_input, 0.0f));
189254

190255
return hdr10;
191256
}
192257

193258
float4 HDR10(const float4 hdr_linear)
194259
{
195-
float3 rec2020 = mul(k709to2020, hdr_linear.rgb);
196-
197-
if(global.expand_gamut > 0.0f)
198-
{
199-
rec2020 = mul( kExpanded709to2020, hdr_linear.rgb);
200-
}
201-
202-
const float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084);
260+
const float3 pq_input = hdr_linear.rgb * (global.paper_white_nits / kMaxNitsFor2084);
203261

204-
const float3 hdr10 = LinearToST2084(max(linearColour, 0.0f));
262+
const float3 hdr10 = LinearToST2084(max(pq_input, 0.0f));
205263

206264
return float4(hdr10, hdr_linear.a);
207265
}
@@ -248,13 +306,13 @@ float ScanlineColour(const uint channel,
248306
const float2 tex_coord_0 = float2(source_tex_coord_x, source_tex_coord_y);
249307
const float2 tex_coord_1 = float2(source_tex_coord_x + (1.0f / source_size.x), source_tex_coord_y);
250308

251-
const float hdr_channel_0 = HDR(Sample(tex_coord_0))[channel];
252-
const float hdr_channel_1 = HDR(Sample(tex_coord_1))[channel];
309+
const float hdr_channel_0 = LinearToSignal(HDR(To2020(Sample(tex_coord_0))))[channel];
310+
const float hdr_channel_1 = LinearToSignal(HDR(To2020(Sample(tex_coord_1))))[channel];
253311

254312
const float horiz_interp = Bezier(narrowed_source_pixel_offset, BeamControlPoints(beam_attack, hdr_channel_0 > hdr_channel_1));
255313
const float hdr_channel = lerp(hdr_channel_0, hdr_channel_1, horiz_interp);
256314

257-
const float physics_signal = pow(max(hdr_channel, 0.0f), 1.0f / 2.2f);
315+
const float physics_signal = hdr_channel;
258316

259317
const float signal_strength = clamp(physics_signal, 0.0f, 2.5f);
260318

@@ -368,7 +426,9 @@ float3 Scanlines(float2 texcoord)
368426
scanline_colour = scanline_channel_0 * kColourMask[channel_0];
369427
}
370428

371-
return HDR10(scanline_colour);
429+
float3 linear_colour = pow(max(scanline_colour, float3(0.0f, 0.0f, 0.0f)), 2.4f);
430+
431+
return HDR10(linear_colour);
372432
}
373433

374434
float4 PSMain(PSInput input) : SV_TARGET
@@ -381,16 +441,16 @@ float4 PSMain(PSInput input) : SV_TARGET
381441
}
382442
else
383443
{
384-
return HDR10(HDR(Sample(input.color, input.texcoord)));
444+
return HDR10(HDR(To2020(Sample(input.color, input.texcoord))));
385445
}
386446
}
387447
else if(global.inverse_tonemap > 0.0f)
388448
{
389-
return HDR(Sample(input.color, input.texcoord));
449+
return HDR(To2020(Sample(input.color, input.texcoord)));
390450
}
391451
else if(global.hdr10 > 0.0f)
392452
{
393-
return HDR10(Sample(input.color, input.texcoord));
453+
return HDR10(To2020(Sample(input.color, input.texcoord)));
394454
}
395455
else
396456
{

0 commit comments

Comments
 (0)