Fixed numerous issues with HDR (#12979)

* 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>
This commit is contained in:
MajorPainTheCactus 2021-09-13 15:54:50 +01:00 committed by GitHub
parent e24440d4a9
commit 3c6bdfd0d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 297 additions and 77 deletions

View file

@ -421,8 +421,8 @@
/* The number of nits that paper white is at */
#define DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS 200.0f
/* The contrast setting for hdr used to calculate the display gamma by dividing gamma 2.2 by this value */
#define DEFAULT_VIDEO_HDR_CONTRAST 1.0f
/* The contrast setting for hdr used to calculate the display gamma by dividing this value by gamma 2.2 */
#define DEFAULT_VIDEO_HDR_CONTRAST 5.0f
/* Should we expand the colour gamut when using hdr */
#define DEFAULT_VIDEO_HDR_EXPAND_GAMUT true

View file

@ -2043,7 +2043,7 @@ static struct config_float_setting *populate_settings_float(
SETTING_FLOAT("video_hdr_max_nits", &settings->floats.video_hdr_max_nits, true, DEFAULT_VIDEO_HDR_MAX_NITS, false);
SETTING_FLOAT("video_hdr_paper_white_nits", &settings->floats.video_hdr_paper_white_nits, true, DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS, false);
SETTING_FLOAT("video_hdr_contrast", &settings->floats.video_hdr_contrast, true, DEFAULT_VIDEO_HDR_CONTRAST, false);
SETTING_FLOAT("video_hdr_display_contrast", &settings->floats.video_hdr_display_contrast, true, DEFAULT_VIDEO_HDR_CONTRAST, false);
*size = count;

View file

@ -347,7 +347,7 @@ typedef struct settings
float video_msg_bgcolor_opacity;
float video_hdr_max_nits;
float video_hdr_paper_white_nits;
float video_hdr_contrast;
float video_hdr_display_contrast;
float menu_scale_factor;
float menu_widget_scale_factor;

View file

@ -20,10 +20,11 @@
typedef struct ALIGN(16)
{
math_matrix_4x4 mvp;
float contrast; /* 2.0f */
float paperWhiteNits; /* 200.0f */
float maxNits; /* 1000.0f */
float expandGamut; /* 1.0f */
float contrast; /* 2.0f */
float paper_white_nits; /* 200.0f */
float max_nits; /* 1000.0f */
float expand_gamut; /* 1.0f */
float inverse_tonemap; /* 1.0f */
} dxgi_hdr_uniform_t;
enum dxgi_swapchain_bit_depth

View file

@ -262,7 +262,7 @@ static void d3d11_set_hdr_max_nits(void *data, float max_nits)
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
d3d11->hdr.max_output_nits = max_nits;
d3d11->hdr.ubo_values.maxNits = max_nits;
d3d11->hdr.ubo_values.max_nits = max_nits;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo,
0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped_ubo);
@ -289,7 +289,7 @@ static void d3d11_set_hdr_paper_white_nits(void* data, float paper_white_nits)
dxgi_hdr_uniform_t *ubo = NULL;
d3d11_video_t *d3d11 = (d3d11_video_t*)data;
d3d11->hdr.ubo_values.paperWhiteNits = paper_white_nits;
d3d11->hdr.ubo_values.paper_white_nits = paper_white_nits;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo,
0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
@ -319,7 +319,7 @@ static void d3d11_set_hdr_expand_gamut(void* data, bool expand_gamut)
dxgi_hdr_uniform_t *ubo = NULL;
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
d3d11->hdr.ubo_values.expandGamut = expand_gamut;
d3d11->hdr.ubo_values.expand_gamut = expand_gamut;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData;
@ -1144,16 +1144,17 @@ static void *d3d11_gfx_init(const video_info_t* video,
D3D11_SUBRESOURCE_DATA ubo_data;
matrix_4x4_ortho(d3d11->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
d3d11->hdr.ubo_values.mvp =
d3d11->hdr.ubo_values.mvp =
d3d11->mvp_no_rot;
d3d11->hdr.ubo_values.maxNits =
d3d11->hdr.ubo_values.max_nits =
settings->floats.video_hdr_max_nits;
d3d11->hdr.ubo_values.paperWhiteNits =
d3d11->hdr.ubo_values.paper_white_nits =
settings->floats.video_hdr_paper_white_nits;
d3d11->hdr.ubo_values.contrast =
settings->floats.video_hdr_contrast;
d3d11->hdr.ubo_values.expandGamut =
d3d11->hdr.ubo_values.contrast =
VIDEO_HDR_MAX_CONTRAST - settings->floats.video_hdr_display_contrast;
d3d11->hdr.ubo_values.expand_gamut =
settings->bools.video_hdr_expand_gamut;
d3d11->hdr.ubo_values.inverse_tonemap = 1.0f; /* Use this to turn on/off the inverse tonemap */
desc.ByteWidth = sizeof(dxgi_hdr_uniform_t);
desc.Usage = D3D11_USAGE_DYNAMIC;
@ -1743,13 +1744,19 @@ static bool d3d11_gfx_frame(
d3d11->swapChain,
&d3d11->chain_color_space,
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
d3d11->chain_bit_depth = DXGI_SWAPCHAIN_BIT_DEPTH_10;
}
else
{
dxgi_swapchain_color_space(
d3d11->swapChain,
&d3d11->chain_color_space,
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
d3d11->chain_bit_depth = DXGI_SWAPCHAIN_BIT_DEPTH_8;
}
dxgi_set_hdr_metadata(
d3d11->swapChain,
d3d11->hdr.support,
@ -2103,6 +2110,9 @@ static bool d3d11_gfx_frame(
D3D11Draw(context, 4, 0);
D3D11SetPShaderResources(context, 0, 1, nullSRV);
D3D11SetRasterizerState(context, d3d11->scissor_enabled);
D3D11SetBlendState(d3d11->context, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK);
D3D11SetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
}
#endif

View file

@ -238,14 +238,6 @@ static void d3d12_get_overlay_interface(void* data, const video_overlay_interfac
}
#endif
#if 0
d3d12->hdr.max_output_nits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.maxNits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.paperWhiteNits = settings->floats.video_hdr_paper_white_nits;
d3d12->hdr.ubo_values.contrast = settings->floats.video_hdr_contrast;
d3d12->hdr.ubo_values.expandGamut = settings->bools.video_hdr_expand_gamut;
#endif
#ifdef HAVE_DXGI_HDR
static void d3d12_set_hdr_max_nits(void* data, float max_nits)
{
@ -254,7 +246,7 @@ static void d3d12_set_hdr_max_nits(void* data, float max_nits)
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.max_output_nits = max_nits;
d3d12->hdr.ubo_values.maxNits = max_nits;
d3d12->hdr.ubo_values.max_nits = max_nits;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
@ -277,7 +269,7 @@ static void d3d12_set_hdr_paper_white_nits(void* data, float paper_white_nits)
dxgi_hdr_uniform_t *mapped_ubo = NULL;
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.ubo_values.paperWhiteNits = paper_white_nits;
d3d12->hdr.ubo_values.paper_white_nits = paper_white_nits;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
@ -303,7 +295,7 @@ static void d3d12_set_hdr_expand_gamut(void* data, bool expand_gamut)
dxgi_hdr_uniform_t *mapped_ubo = NULL;
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.ubo_values.expandGamut = expand_gamut;
d3d12->hdr.ubo_values.expand_gamut = expand_gamut;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
@ -1153,10 +1145,11 @@ static void *d3d12_gfx_init(const video_info_t* video,
d3d12_create_buffer(d3d12->device, d3d12->hdr.ubo_view.SizeInBytes, &d3d12->hdr.ubo);
d3d12->hdr.ubo_values.mvp = d3d12->mvp_no_rot;
d3d12->hdr.ubo_values.maxNits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.paperWhiteNits = settings->floats.video_hdr_paper_white_nits;
d3d12->hdr.ubo_values.contrast = settings->floats.video_hdr_contrast;
d3d12->hdr.ubo_values.expandGamut = settings->bools.video_hdr_expand_gamut;
d3d12->hdr.ubo_values.max_nits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.paper_white_nits = settings->floats.video_hdr_paper_white_nits;
d3d12->hdr.ubo_values.contrast = VIDEO_HDR_MAX_CONTRAST - settings->floats.video_hdr_display_contrast;
d3d12->hdr.ubo_values.expand_gamut = settings->bools.video_hdr_expand_gamut;
d3d12->hdr.ubo_values.inverse_tonemap = 1.0f; /* Use this to turn on/off the inverse tonemap */
{
dxgi_hdr_uniform_t* mapped_ubo;
@ -1443,11 +1436,17 @@ static bool d3d12_gfx_frame(
dxgi_swapchain_color_space(d3d12->chain.handle,
&d3d12->chain.color_space,
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
d3d12->chain.bit_depth = DXGI_SWAPCHAIN_BIT_DEPTH_10;
}
else
{
dxgi_swapchain_color_space(d3d12->chain.handle,
&d3d12->chain.color_space,
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
d3d12->chain.bit_depth = DXGI_SWAPCHAIN_BIT_DEPTH_8;
}
dxgi_set_hdr_metadata(
d3d12->chain.handle,

View file

@ -4,10 +4,11 @@ SRC(
struct UBO
{
float4x4 modelViewProj;
float contrast; /* 2.0f; */
float paperWhiteNits; /* 200.0f; */
float maxNits; /* 1000.0f; */
float expandGamut; /* 1.0f; */
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;
@ -73,39 +74,48 @@ SRC(
float4 Hdr(float4 sdr)
{
sdr.xyz = pow(abs(sdr.xyz), 2.2f / global.contrast ); /* 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.maxNits / global.paperWhiteNits) + 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 */
float3 hdr;
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 */
if(global.inverse_tonemap)
{
sdr.xyz = pow(abs(sdr.xyz), global.contrast / 2.2f ); /* Display Gamma - needs to be determined by calibration screen */
float lumaInvTonemap = (luma > 0.5f) ? hdrLumaInvTonemap : sdrLumaInvTonemap;
float3 perLuma = sdr.xyz / (luma + kEpsilon) * lumaInvTonemap;
float luma = dot(sdr.xyz, float3(0.2126, 0.7152, 0.0722)); /* Rec BT.709 luma coefficients - https://en.wikipedia.org/wiki/Luma_(video) */
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 */
/* 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 */
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);
float lumaInvTonemap = (luma > 0.5f) ? hdrLumaInvTonemap : sdrLumaInvTonemap;
float3 perLuma = sdr.xyz / (luma + kEpsilon) * lumaInvTonemap;
float3 hdr = lerp(perLuma, perChannel, kLumaChannelRatio);
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.expandGamut > 0.0f)
if(global.expand_gamut > 0.0f)
{
rec2020 = mul( kExpanded709to2020, hdr);
}
float3 linearColour = rec2020 * (global.paperWhiteNits / kMaxNitsFor2084);
float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084);
float3 hdr10 = LinearToST2084(linearColour);
return float4(hdr10, sdr.w);

View file

@ -91,4 +91,100 @@ static INLINE uint32_t prev_pow2(uint32_t v)
return v - (v >> 1);
}
/**
* clamp:
* @v : initial value
*
* Get the clamped value based on initial value.
*
* Returns: clamped value (derived from @v).
**/
static INLINE float clamp_value(float v, float min, float max)
{
return v <= min ? min : v >= max ? max : v;
}
/**
* saturate_value:
* @v : initial value
*
* Get the clamped 0.0-1.0 value based on initial value.
*
* Returns: clamped 0.0-1.0 value (derived from @v).
**/
static INLINE float saturate_value(float v)
{
return clamp_value(v, 0.0f, 1.0f);
}
/**
* dot_product:
* @a : left hand vector value
* @b : right hand vector value
*
* Get the dot product of the two passed in vectors.
*
* Returns: dot product value (derived from @a and @b).
**/
static INLINE float dot_product(const float* a, const float* b)
{
return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}
/**
* retro_rgb_to_yxy:
* @rgb : in RGB colour space value
* @Yxy : out Yxy colour space value
*
* Convert from RGB colour space to Yxy colour space.
*
* Returns: Yxy colour space value (derived from @rgb).
**/
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
{
float inv;
float xyz[3];
float one[3] = {1.0, 1.0, 1.0};
float rgb_xyz[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
xyz[0] = dot_product(rgb_xyz[0], rgb);
xyz[1] = dot_product(rgb_xyz[1], rgb);
xyz[2] = dot_product(rgb_xyz[2], rgb);
inv = 1.0f / dot_product(xyz, one);
Yxy[0] = xyz[1];
Yxy[1] = xyz[0] * inv;
Yxy[2] = xyz[1] * inv;
}
/**
* yxy_to_rgb:
* @rgb : in Yxy colour space value
* @Yxy : out rgb colour space value
*
* Convert from Yxy colour space to rgb colour space.
*
* Returns: rgb colour space value (derived from @Yxy).
**/
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
{
float xyz[3];
float xyz_rgb[3][3] = {
{3.2404542, -1.5371385, -0.4985314},
{-0.9692660, 1.8760108, 0.0415560},
{0.0556434, -0.2040259, 1.0572252}
};
xyz[0] = Yxy[0] * Yxy[1] / Yxy[2];
xyz[1] = Yxy[0];
xyz[2] = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
rgb[0] = dot_product(xyz_rgb[0], xyz);
rgb[1] = dot_product(xyz_rgb[1], xyz);
rgb[2] = dot_product(xyz_rgb[2], xyz);
}
#endif

View file

@ -7738,9 +7738,9 @@ static void general_write_handler(rarch_setting_t *setting)
{
settings_t *settings = config_get_ptr();
settings->modified = true;
settings->floats.video_hdr_contrast = *setting->value.target.fraction;
settings->floats.video_hdr_display_contrast = *setting->value.target.fraction;
video_driver_set_hdr_contrast(settings->floats.video_hdr_contrast);
video_driver_set_hdr_contrast(settings->floats.video_hdr_display_contrast);
}
break;
case MENU_ENUM_LABEL_VIDEO_HDR_EXPAND_GAMUT:
@ -11924,7 +11924,7 @@ static bool setting_append_list(
CONFIG_FLOAT(
list, list_info,
&settings->floats.video_hdr_contrast,
&settings->floats.video_hdr_display_contrast,
MENU_ENUM_LABEL_VIDEO_HDR_CONTRAST,
MENU_ENUM_LABEL_VALUE_VIDEO_HDR_CONTRAST,
DEFAULT_VIDEO_HDR_CONTRAST,
@ -11935,7 +11935,7 @@ static bool setting_append_list(
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
menu_settings_list_current_add_range(list, list_info, 0.1, 3.0, 0.01, true, true);
menu_settings_list_current_add_range(list, list_info, 0.0, VIDEO_HDR_MAX_CONTRAST, 0.1, true, true);
CONFIG_BOOL(
list, list_info,

View file

@ -24868,53 +24868,147 @@ void *video_driver_read_frame_raw(unsigned *width,
unsigned *height, size_t *pitch)
{
struct rarch_state *p_rarch = &rarch_st;
if (!p_rarch->current_video || !p_rarch->current_video->read_frame_raw)
return NULL;
return p_rarch->current_video->read_frame_raw(
p_rarch->video_driver_data, width,
height, pitch);
if ( p_rarch->current_video
&& p_rarch->current_video->read_frame_raw)
return p_rarch->current_video->read_frame_raw(
p_rarch->video_driver_data, width,
height, pitch);
return NULL;
}
void video_driver_set_filtering(unsigned index, bool smooth, bool ctx_scaling)
void video_driver_set_filtering(unsigned index,
bool smooth, bool ctx_scaling)
{
struct rarch_state *p_rarch = &rarch_st;
if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_filtering)
p_rarch->video_driver_poke->set_filtering(p_rarch->video_driver_data,
if ( p_rarch->video_driver_poke
&& p_rarch->video_driver_poke->set_filtering)
p_rarch->video_driver_poke->set_filtering(
p_rarch->video_driver_data,
index, smooth, ctx_scaling);
}
void video_driver_set_hdr_max_nits(float max_nits)
{
struct rarch_state *p_rarch = &rarch_st;
if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_hdr_max_nits)
p_rarch->video_driver_poke->set_hdr_max_nits(p_rarch->video_driver_data,
if ( p_rarch->video_driver_poke
&& p_rarch->video_driver_poke->set_hdr_max_nits)
p_rarch->video_driver_poke->set_hdr_max_nits(
p_rarch->video_driver_data,
max_nits);
}
void video_driver_set_hdr_paper_white_nits(float paper_white_nits)
{
struct rarch_state *p_rarch = &rarch_st;
if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_hdr_paper_white_nits)
p_rarch->video_driver_poke->set_hdr_paper_white_nits(p_rarch->video_driver_data,
if ( p_rarch->video_driver_poke
&& p_rarch->video_driver_poke->set_hdr_paper_white_nits)
p_rarch->video_driver_poke->set_hdr_paper_white_nits(
p_rarch->video_driver_data,
paper_white_nits);
}
void video_driver_set_hdr_contrast(float contrast)
{
struct rarch_state *p_rarch = &rarch_st;
if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_hdr_contrast)
p_rarch->video_driver_poke->set_hdr_contrast(p_rarch->video_driver_data,
contrast);
if ( p_rarch->video_driver_poke
&& p_rarch->video_driver_poke->set_hdr_contrast)
p_rarch->video_driver_poke->set_hdr_contrast(
p_rarch->video_driver_data,
VIDEO_HDR_MAX_CONTRAST - contrast);
}
void video_driver_set_hdr_expand_gamut(bool expand_gamut)
{
struct rarch_state *p_rarch = &rarch_st;
if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_hdr_expand_gamut)
p_rarch->video_driver_poke->set_hdr_expand_gamut(p_rarch->video_driver_data,
if ( p_rarch->video_driver_poke
&& p_rarch->video_driver_poke->set_hdr_expand_gamut)
p_rarch->video_driver_poke->set_hdr_expand_gamut(
p_rarch->video_driver_data,
expand_gamut);
}
/* Use this value as a replacement for anywhere
* where a pure white colour value is used in the UI.
*
* When HDR is turned on 1,1,1,1 should never really
* be used as this is peak brightness and could cause
* damage to displays over long periods of time
* and be quite hard to look at on really bright displays.
*
* Use paper white instead which is always defined as
* 0.5, 0.5, 0.5, 1.0 or in other words is the top of
* the old SDR (Standard Dynamic Range) range
*/
unsigned video_driver_get_hdr_paper_white(void)
{
/* 0.5, 0.5, 0.5, 1 */
if ( video_driver_supports_hdr()
&& config_get_ptr()->bools.video_hdr_enable)
return 0x7f7f7fff;
return 0xffffffff;
}
/* Same as above but returns the white value in floats */
float *video_driver_get_hdr_paper_white_float(void)
{
static float paper_white[4] = { 0.5f, 0.5f, 0.5f, 1.0f};
static float sdr_white [4] = { 1.0f, 1.0f, 1.0f, 1.0f};
if( video_driver_supports_hdr()
&& config_get_ptr()->bools.video_hdr_enable)
return paper_white;
return sdr_white;
}
/* This is useful to create a HDR (High Dynamic Range) white
* based off of some passed in nit level - say you want a
* slightly brighter than paper white value for some parts
* of the UI
*/
float video_driver_get_hdr_luminace(float nits)
{
settings_t *settings = config_get_ptr();
if(video_driver_supports_hdr() && settings->bools.video_hdr_enable)
{
float luminance = nits /
settings->floats.video_hdr_paper_white_nits;
return luminance / (1.0f + luminance);
}
return nits;
}
/* Get reinhard tone mapped colour value for UI elements
* when using HDR and its inverse tonemapper - normally don't use
* but useful if you want a specific colour to look the same
* after inverse tonemapping has been applied */
unsigned video_driver_get_hdr_color(unsigned color)
{
if( video_driver_supports_hdr()
&& config_get_ptr()->bools.video_hdr_enable)
{
float luminance;
float rgb[3];
float yxy[3];
rgb[0] = (float)((color >> 24) & 0xFF) / 255.0f;
rgb[1] = (float)((color >> 16) & 0xFF) / 255.0f;
rgb[2] = (float)((color >> 8 ) & 0xFF) / 255.0f;
convert_rgb_to_yxy(rgb, yxy);
/* TODO: We should probably scale this by average luminance */
luminance = yxy[0];
yxy[0] = luminance / (1.0f + luminance);
convert_yxy_to_rgb(rgb, yxy);
return ( (unsigned)(saturate_value(rgb[0]) * 255.0f) << 24)
| ((unsigned)(saturate_value(rgb[1]) * 255.0f) << 16)
| ((unsigned)(saturate_value(rgb[2]) * 255.0f) << 8)
| (color & 0xFF);
}
return color;
}
void video_driver_cached_frame_set(const void *data, unsigned width,
unsigned height, size_t pitch)
{

View file

@ -806,6 +806,8 @@ void recording_driver_update_streaming_url(void);
#define VIDEO_SHADER_MENU_6 (GFX_MAX_SHADERS - 7)
#define VIDEO_SHADER_STOCK_HDR (GFX_MAX_SHADERS - 8)
#define VIDEO_HDR_MAX_CONTRAST 10.0f
#if defined(_XBOX360)
#define DEFAULT_SHADER_TYPE RARCH_SHADER_HLSL
#elif defined(__PSL1GHT__) || defined(HAVE_OPENGLES2) || defined(HAVE_GLSL)
@ -1598,6 +1600,14 @@ void video_driver_unset_hdr_support(void);
bool video_driver_supports_hdr(void);
unsigned video_driver_get_hdr_color(unsigned color);
float video_driver_get_hdr_luminace(float nits);
unsigned video_driver_get_hdr_paper_white(void);
float* video_driver_get_hdr_paper_white_float(void);
bool video_driver_get_next_video_out(void);
bool video_driver_get_prev_video_out(void);