diff --git a/config.def.h b/config.def.h index 7b50f5cb49..7b6d55d20c 100644 --- a/config.def.h +++ b/config.def.h @@ -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 diff --git a/configuration.c b/configuration.c index 10c0a17163..ae072067c6 100644 --- a/configuration.c +++ b/configuration.c @@ -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; diff --git a/configuration.h b/configuration.h index d2db2ed49c..cee78b6469 100644 --- a/configuration.h +++ b/configuration.h @@ -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; diff --git a/gfx/common/dxgi_common.h b/gfx/common/dxgi_common.h index d9c64db6f4..2672e87ba0 100644 --- a/gfx/common/dxgi_common.h +++ b/gfx/common/dxgi_common.h @@ -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 diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 5003ae1fba..879c8a43b6 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -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 diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 879a9c221e..9039697032 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -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, diff --git a/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h b/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h index 97f31456a8..d11207bc63 100644 --- a/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h +++ b/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h @@ -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); diff --git a/libretro-common/include/retro_math.h b/libretro-common/include/retro_math.h index b426698bb0..af0b6c5f43 100644 --- a/libretro-common/include/retro_math.h +++ b/libretro-common/include/retro_math.h @@ -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 diff --git a/menu/menu_setting.c b/menu/menu_setting.c index f10eef8851..0033624776 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -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, diff --git a/retroarch.c b/retroarch.c index 9402e88210..bd89db6b5d 100644 --- a/retroarch.c +++ b/retroarch.c @@ -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) { diff --git a/retroarch.h b/retroarch.h index 19f0924781..0e18e1a3f8 100644 --- a/retroarch.h +++ b/retroarch.h @@ -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);