Added support for HDR shaders - if we detect a shader that uses SLANG_FORMAT_A2B10G10R10_UNORM_PACK32 or SLANG_FORMAT_R16G16B16A16_SFLOAT as the format for the last render target in the shader chain AND hdr is switched on then this disables the internal HDR shader and allows the shader chain to define an inverse tonemapper and hdr10 shader. The first use of this is for my hdr shader crt\crt-sony-pvm-4k-hdr.slangp - submitted seperately (#13390)

This commit is contained in:
MajorPainTheCactus 2021-12-22 01:17:17 +00:00 committed by GitHub
parent b21f3964b6
commit 9151326b73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 27 deletions

View file

@ -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

View file

@ -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 =

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);
};
)