diff --git a/config.def.h b/config.def.h index d1090ad0e4..cab443509a 100644 --- a/config.def.h +++ b/config.def.h @@ -425,10 +425,10 @@ #define DEFAULT_VIDEO_HDR_ENABLE false /* The maximum nunmber of nits the actual display can show - needs to be calibrated */ -#define DEFAULT_VIDEO_HDR_MAX_NITS 1000.0f +#define DEFAULT_VIDEO_HDR_MAX_NITS 700.0f /* The number of nits that paper white is at */ -#define DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS 200.0f +#define DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS 400.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 diff --git a/gfx/common/d3d12_common.c b/gfx/common/d3d12_common.c index 8ed6a1e747..a6667272de 100644 --- a/gfx/common/d3d12_common.c +++ b/gfx/common/d3d12_common.c @@ -405,7 +405,7 @@ bool d3d12_init_swapchain(d3d12_video_t* d3d12, d3d12->chain.back_buffer.desc.Width = width; d3d12->chain.back_buffer.desc.Height = height; d3d12->chain.back_buffer.desc.Format = - DXGI_FORMAT_R8G8B8A8_UNORM; + d3d12->shader_preset && d3d12->shader_preset->passes ? glslang_format_to_dxgi(d3d12->pass[d3d12->shader_preset->passes - 1].semantics.format) : DXGI_FORMAT_R8G8B8A8_UNORM; d3d12->chain.back_buffer.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; d3d12->chain.back_buffer.srv_heap = diff --git a/gfx/common/dxgi_common.h b/gfx/common/dxgi_common.h index c5532da959..acda79beba 100644 --- a/gfx/common/dxgi_common.h +++ b/gfx/common/dxgi_common.h @@ -25,7 +25,8 @@ typedef struct ALIGN(16) float paper_white_nits; /* 200.0f */ float max_nits; /* 1000.0f */ float expand_gamut; /* 1.0f */ - float inverse_tonemap; /* 1.0f */ + float inverse_tonemap; /* 1.0f */ + float hdr10; /* 1.0f */ } dxgi_hdr_uniform_t; enum dxgi_swapchain_bit_depth diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 68d309b229..df4c78cde8 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -326,7 +326,33 @@ 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.expand_gamut = expand_gamut; + d3d11->hdr.ubo_values.expand_gamut = expand_gamut ? 1.0f : 0.0f; + + D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo); + ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData; + *ubo = d3d11->hdr.ubo_values; + D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0); +} + +static void d3d11_set_hdr_inverse_tonemap(d3d11_video_t* d3d11, bool inverse_tonemap) +{ + D3D11_MAPPED_SUBRESOURCE mapped_ubo; + dxgi_hdr_uniform_t *ubo = NULL; + + d3d11->hdr.ubo_values.inverse_tonemap = inverse_tonemap ? 1.0f : 0.0f; + + D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo); + ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData; + *ubo = d3d11->hdr.ubo_values; + D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0); +} + +static void d3d11_set_hdr10(d3d11_video_t* d3d11, bool hdr10) +{ + D3D11_MAPPED_SUBRESOURCE mapped_ubo; + dxgi_hdr_uniform_t *ubo = NULL; + + d3d11->hdr.ubo_values.hdr10 = hdr10 ? 1.0f : 0.0f; D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo); ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData; @@ -614,6 +640,29 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const } } + if (d3d11->hdr.enable) + { + if(d3d11->shader_preset && d3d11->shader_preset->passes && (d3d11->pass[d3d11->shader_preset->passes - 1].semantics.format == SLANG_FORMAT_A2B10G10R10_UNORM_PACK32)) + { + /* If the last shader pass uses a RGB10A2 back buffer and hdr has been enabled assume we want to skip the inverse tonemapper and hdr10 conversion */ + d3d11_set_hdr_inverse_tonemap(d3d11, false); + d3d11_set_hdr10(d3d11, false); + d3d11->resize_chain = true; + } + else if(d3d11->shader_preset && d3d11->shader_preset->passes && (d3d11->pass[d3d11->shader_preset->passes - 1].semantics.format == SLANG_FORMAT_R16G16B16A16_SFLOAT)) + { + /* If the last shader pass uses a RGBA16 back buffer and hdr has been enabled assume we want to skip the inverse tonemapper */ + d3d11_set_hdr_inverse_tonemap(d3d11, false); + d3d11_set_hdr10(d3d11, true); + d3d11->resize_chain = true; + } + else + { + d3d11_set_hdr_inverse_tonemap(d3d11, true); + d3d11_set_hdr10(d3d11, true); + } + } + for (i = 0; i < d3d11->shader_preset->luts; i++) { struct texture_image image = { 0 }; @@ -1000,7 +1049,7 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11, memset(&d3d11->back_buffer, 0, sizeof(d3d11->back_buffer)); d3d11->back_buffer.desc.Width = width; d3d11->back_buffer.desc.Height = height; - d3d11->back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + d3d11->back_buffer.desc.Format = d3d11->shader_preset && d3d11->shader_preset->passes ? glslang_format_to_dxgi(d3d11->pass[d3d11->shader_preset->passes - 1].semantics.format) : DXGI_FORMAT_R8G8B8A8_UNORM; d3d11->back_buffer.desc.BindFlags = D3D11_BIND_RENDER_TARGET; d3d11_init_texture(d3d11->device, &d3d11->back_buffer); #endif @@ -1162,6 +1211,7 @@ static void *d3d11_gfx_init(const video_info_t* video, 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 */ + d3d11->hdr.ubo_values.hdr10 = 1.0f; /* Use this to turn on/off the hdr10 */ desc.ByteWidth = sizeof(dxgi_hdr_uniform_t); desc.Usage = D3D11_USAGE_DYNAMIC; @@ -1743,7 +1793,7 @@ static bool d3d11_gfx_frame( memset(&d3d11->back_buffer, 0, sizeof(d3d11->back_buffer)); d3d11->back_buffer.desc.Width = video_width; d3d11->back_buffer.desc.Height = video_height; - d3d11->back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + d3d11->back_buffer.desc.Format = d3d11->shader_preset && d3d11->shader_preset->passes ? glslang_format_to_dxgi(d3d11->pass[d3d11->shader_preset->passes - 1].semantics.format) : DXGI_FORMAT_R8G8B8A8_UNORM; d3d11->back_buffer.desc.BindFlags = D3D11_BIND_RENDER_TARGET; d3d11_init_texture(d3d11->device, &d3d11->back_buffer); diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 37c8d87cb9..9c2efa443f 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -302,7 +302,32 @@ 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.expand_gamut = expand_gamut; + d3d12->hdr.ubo_values.expand_gamut = expand_gamut ? 1.0f : 0.0f; + + D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo); + *mapped_ubo = d3d12->hdr.ubo_values; + D3D12Unmap(d3d12->hdr.ubo, 0, NULL); +} + +static void d3d12_set_hdr_inverse_tonemap(d3d12_video_t* d3d12, bool inverse_tonemap) +{ + D3D12_RANGE read_range = { 0, 0 }; + dxgi_hdr_uniform_t *mapped_ubo = NULL; + + d3d12->hdr.ubo_values.inverse_tonemap = inverse_tonemap ? 1.0f : 0.0f; + + D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo); + *mapped_ubo = d3d12->hdr.ubo_values; + D3D12Unmap(d3d12->hdr.ubo, 0, NULL); +} + +static void d3d12_set_hdr10(d3d12_video_t* d3d12, bool hdr10) +{ + D3D12_RANGE read_range = { 0, 0 }; + dxgi_hdr_uniform_t *mapped_ubo = NULL; + + d3d12->hdr.ubo_values.hdr10 = hdr10 ? 1.0f : 0.0f; + D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo); *mapped_ubo = d3d12->hdr.ubo_values; D3D12Unmap(d3d12->hdr.ubo, 0, NULL); @@ -597,6 +622,29 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const } } + if (d3d12->hdr.enable) + { + if(d3d12->shader_preset && d3d12->shader_preset->passes && (d3d12->pass[d3d12->shader_preset->passes - 1].semantics.format == SLANG_FORMAT_A2B10G10R10_UNORM_PACK32)) + { + /* If the last shader pass uses a RGB10A2 back buffer and hdr has been enabled assume we want to skip the inverse tonemapper and hdr10 conversion */ + d3d12_set_hdr_inverse_tonemap(d3d12, false); + d3d12_set_hdr10(d3d12, false); + d3d12->resize_chain = true; + } + else if(d3d12->shader_preset && d3d12->shader_preset->passes && (d3d12->pass[d3d12->shader_preset->passes - 1].semantics.format == SLANG_FORMAT_R16G16B16A16_SFLOAT)) + { + /* If the last shader pass uses a RGBA16 back buffer and hdr has been enabled assume we want to skip the inverse tonemapper */ + d3d12_set_hdr_inverse_tonemap(d3d12, false); + d3d12_set_hdr10(d3d12, true); + d3d12->resize_chain = true; + } + else + { + d3d12_set_hdr_inverse_tonemap(d3d12, true); + d3d12_set_hdr10(d3d12, true); + } + } + for (i = 0; i < d3d12->shader_preset->luts; i++) { struct texture_image image = { 0 }; @@ -1157,6 +1205,7 @@ static void *d3d12_gfx_init(const video_info_t* video, 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 */ + d3d12->hdr.ubo_values.hdr10 = 1.0f; /* Use this to turn on/off the hdr10 */ { dxgi_hdr_uniform_t* mapped_ubo; @@ -1430,7 +1479,7 @@ static bool d3d12_gfx_frame( 0, sizeof(d3d12->chain.back_buffer)); d3d12->chain.back_buffer.desc.Width = video_width; d3d12->chain.back_buffer.desc.Height = video_height; - d3d12->chain.back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + d3d12->chain.back_buffer.desc.Format = d3d12->shader_preset && d3d12->shader_preset->passes ? glslang_format_to_dxgi(d3d12->pass[d3d12->shader_preset->passes - 1].semantics.format) : DXGI_FORMAT_R8G8B8A8_UNORM; d3d12->chain.back_buffer.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; d3d12->chain.back_buffer.srv_heap = &d3d12->desc.srv_heap; diff --git a/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h b/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h index d11207bc63..07b281432b 100644 --- a/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h +++ b/gfx/drivers/d3d_shaders/hdr_sm5.hlsl.h @@ -9,6 +9,7 @@ SRC( float max_nits; /* 1000.0f; */ float expand_gamut; /* 1.0f; */ float inverse_tonemap; + float hdr10; }; uniform UBO global; @@ -72,29 +73,29 @@ SRC( color.z < 0.04045f ? scale.z : gamma.z); } - float4 Hdr(float4 sdr) + float3 Hdr(float3 sdr) { float3 hdr; if(global.inverse_tonemap) { - sdr.xyz = pow(abs(sdr.xyz), global.contrast / 2.2f ); /* Display Gamma - needs to be determined by calibration screen */ + sdr = pow(abs(sdr), global.contrast / 2.2f ); /* 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) */ + float luma = dot(sdr, 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.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 elbow = maxValue / (maxValue - 1.0f); + float offset = 1.0f - ((0.5f * elbow) / (elbow - 0.5f)); 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 */ float lumaInvTonemap = (luma > 0.5f) ? hdrLumaInvTonemap : sdrLumaInvTonemap; - float3 perLuma = sdr.xyz / (luma + kEpsilon) * lumaInvTonemap; + float3 perLuma = sdr / (luma + kEpsilon) * lumaInvTonemap; - 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 hdrInvTonemap = offset + ((sdr * elbow) / (elbow - sdr)); + float3 sdrInvTonemap = sdr / ((1.0f + kEpsilon) - sdr); /* 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, @@ -104,27 +105,37 @@ SRC( } else { - hdr = SRGBToLinear(sdr.xyz); + hdr = sdr; } - /* Now convert into HDR10 */ - float3 rec2020 = mul(k709to2020, hdr); + float3 hdr10; - if(global.expand_gamut > 0.0f) + if(global.hdr10) { - rec2020 = mul( kExpanded709to2020, hdr); + /* Now convert into HDR10 */ + float3 rec2020 = mul(k709to2020, hdr); + + if(global.expand_gamut > 0.0f) + { + rec2020 = mul( kExpanded709to2020, hdr); + } + + float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084); + + hdr10 = LinearToST2084(linearColour); + } + else + { + hdr10 = hdr; } - float3 linearColour = rec2020 * (global.paper_white_nits / kMaxNitsFor2084); - float3 hdr10 = LinearToST2084(linearColour); - - return float4(hdr10, sdr.w); + return hdr10; } float4 PSMain(PSInput input) : SV_TARGET { float4 sdr = input.color * t0.Sample(s0, input.texcoord); - return Hdr(sdr); + return float4(Hdr(sdr.rgb), sdr.a); }; )