feat(render3d): HDR calibration; fix the HDR toggle crash and yellow reading as red
r3d_hdr_calibrate(peak, paper, black) feeds the tonemap's and the overlay's HDR10 variants and the display's HDR metadata; ov_hdr_nits draws a calibration patch at a number of nits. gpu_caps_probe asks the running Vulkan renderer's instance instead of making and destroying a second one under Streamline's interposer, which left the next swapchain rebuild calling address 0. The overlay gets an HDR10 variant, and the tonemap brightens HDR highlights by one factor rather than per channel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d80786e99a
commit
65c1b9ca5c
10 changed files with 124 additions and 19 deletions
|
|
@ -7,8 +7,11 @@ uniform sampler2D u_tex;
|
|||
uniform sampler2D u_font;
|
||||
out vec4 o_color;
|
||||
#ifdef HDR10
|
||||
// the interface is sRGB: drawn into an HDR10 frame it sits at paper white, as the picture's white does
|
||||
const float HDR_PAPER = 200.0;
|
||||
// the interface is sRGB: drawn into an HDR10 frame its white sits at the player's paper white, as the
|
||||
// picture's white does. u_hdr_scale multiplies that for one batch (ov_hdr_nits): a calibration
|
||||
// screen's test patches, which have to reach past paper white to the display's peak.
|
||||
uniform float u_hdr_paper;
|
||||
uniform float u_hdr_scale;
|
||||
vec3 bt709_to_2020(vec3 c) {
|
||||
return mat3(0.6274, 0.0691, 0.0164, 0.3293, 0.9195, 0.0880, 0.0433, 0.0114, 0.8956) * c;
|
||||
}
|
||||
|
|
@ -30,6 +33,7 @@ void main() {
|
|||
o_color = vec4(v_col.rgb * t.rgb, v_col.a * t.a);
|
||||
}
|
||||
#ifdef HDR10
|
||||
o_color.rgb = pq_encode(bt709_to_2020(pow(max(o_color.rgb, vec3(0.0)), vec3(2.2))) * HDR_PAPER);
|
||||
float nits = max(u_hdr_paper, 80.0) * max(u_hdr_scale, 0.0);
|
||||
o_color.rgb = pq_encode(bt709_to_2020(pow(max(o_color.rgb, vec3(0.0)), vec3(2.2))) * nits);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -578,7 +578,7 @@ T 725523d9 u_shadow 9
|
|||
T 725523d9 u_tershadow 10
|
||||
T 725523d9 u_ts_height 11
|
||||
P a4683767 fullscreen.vert tonemap.frag #define HDR10;
|
||||
B a4683767 frag 1 852
|
||||
B a4683767 frag 1 864
|
||||
U a4683767 frag u_cascade_vp 0 mat4 5 64
|
||||
U a4683767 frag u_cascade_split 320 float 5 16
|
||||
U a4683767 frag u_cascade_range 400 float 5 16
|
||||
|
|
@ -618,6 +618,9 @@ U a4683767 frag u_bloom_strength 836 float 1 0
|
|||
U a4683767 frag u_vignette 840 float 1 0
|
||||
U a4683767 frag u_saturation 844 float 1 0
|
||||
U a4683767 frag u_contrast 848 float 1 0
|
||||
U a4683767 frag u_hdr_paper 852 float 1 0
|
||||
U a4683767 frag u_hdr_peak 856 float 1 0
|
||||
U a4683767 frag u_hdr_black 860 float 1 0
|
||||
T a4683767 u_adapt 2
|
||||
T a4683767 u_ao 3
|
||||
T a4683767 u_bloom 4
|
||||
|
|
@ -1932,7 +1935,7 @@ U e86f78e8 vert u_screen 0 vec2 1 0
|
|||
I e86f78e8 a_pos 0 vec2
|
||||
I e86f78e8 a_uv 1 vec2
|
||||
I e86f78e8 a_col 2 vec4
|
||||
B e86f78e8 frag 0 764
|
||||
B e86f78e8 frag 1 772
|
||||
U e86f78e8 frag u_cascade_vp 0 mat4 5 64
|
||||
U e86f78e8 frag u_cascade_split 320 float 5 16
|
||||
U e86f78e8 frag u_cascade_range 400 float 5 16
|
||||
|
|
@ -1961,6 +1964,8 @@ U e86f78e8 frag u_ts_on 748 float 1 0
|
|||
U e86f78e8 frag u_force_cascade 752 int 1 0
|
||||
U e86f78e8 frag u_cloud_shadow 756 float 1 0
|
||||
U e86f78e8 frag u_time 760 float 1 0
|
||||
U e86f78e8 frag u_hdr_paper 764 float 1 0
|
||||
U e86f78e8 frag u_hdr_scale 768 float 1 0
|
||||
T e86f78e8 u_brdf 2
|
||||
T e86f78e8 u_font 3
|
||||
T e86f78e8 u_irradiance 4
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ vec3 aces(vec3 x) {
|
|||
}
|
||||
float hash(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }
|
||||
#ifdef HDR10
|
||||
// HDR10 output: nits in BT.2020 primaries, encoded with the SMPTE ST 2084 (PQ) curve
|
||||
const float HDR_PAPER = 200.0; // nits the SDR picture's white sits at
|
||||
const float HDR_PEAK = 1000.0; // nits the brightest highlight rolls on to
|
||||
// HDR10 output: nits in BT.2020 primaries, encoded with the SMPTE ST 2084 (PQ) curve. The three
|
||||
// numbers are the player's calibration of their display (r3d_hdr_calibrate).
|
||||
uniform float u_hdr_paper; // nits the SDR picture's white sits at
|
||||
uniform float u_hdr_peak; // nits the brightest highlight rolls on to: what the display reaches
|
||||
uniform float u_hdr_black; // nits the darkest shade is lifted to, fading out toward paper white
|
||||
vec3 bt709_to_2020(vec3 c) {
|
||||
return mat3(0.6274, 0.0691, 0.0164, 0.3293, 0.9195, 0.0880, 0.0433, 0.0114, 0.8956) * c;
|
||||
}
|
||||
|
|
@ -57,9 +59,16 @@ void main() {
|
|||
float vig = 1.0 - u_vignette * dot(q, q) * 0.5;
|
||||
c *= vig;
|
||||
#ifdef HDR10
|
||||
// up to paper white the SDR picture as it is; past it, what ACES clipped runs on to the peak
|
||||
vec3 hi = max(pre - 1.0, vec3(0.0));
|
||||
vec3 nits = (c + hi / (hi + 1.0) * (HDR_PEAK / HDR_PAPER - 1.0) * vig) * HDR_PAPER;
|
||||
// up to paper white the SDR picture as it is; past it, the whole graded colour is brightened by one
|
||||
// factor from its brightest channel. Extending each channel on its own boosted a bright yellow's red
|
||||
// far more than its green, and yellow read as red on an HDR display.
|
||||
float paper = max(u_hdr_paper, 80.0);
|
||||
float peak = max(u_hdr_peak, paper);
|
||||
float over = max(max(pre.r, max(pre.g, pre.b)) - 1.0, 0.0);
|
||||
float lift = 1.0 + over / (over + 1.0) * (peak / paper - 1.0);
|
||||
vec3 nits = c * lift * paper;
|
||||
// the black level: the shadows' floor raised for a display that crushes them, gone by paper white
|
||||
nits += max(u_hdr_black, 0.0) * (1.0 - clamp(nits / paper, 0.0, 1.0));
|
||||
vec3 e = pq_encode(bt709_to_2020(nits));
|
||||
e += (hash(gl_FragCoord.xy) - 0.5) / 1023.0;
|
||||
o_color = vec4(e, 1.0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue