Skip to content

Commit 6a6ad8d

Browse files
mvaligurskyMartin Valigursky
andauthored
Skip CAS HDR conversions for LDR input and use half-precision in WGSL (#8509)
When the scene texture is already LDR (RGBA8), the toSDR/toHDR tone mapping in the CAS shader is unnecessary. This adds a CAS_HDR define that is only set for HDR scenes, with identity functions for the LDR path. Also uses half-precision types for the CAS computation in WGSL. Made-with: Cursor Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent b319ef8 commit 6a6ad8d

File tree

4 files changed

+45
-18
lines changed

4 files changed

+45
-18
lines changed

src/extras/render-passes/render-pass-camera-frame.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ class RenderPassCameraFrame extends RenderPass {
455455
// create a compose pass, which combines the results of the scene and other passes
456456
this.composePass = new RenderPassCompose(this.device);
457457
this.composePass.bloomTexture = this.bloomPass?.bloomTexture;
458+
this.composePass.hdrScene = this.hdrFormat !== PIXELFORMAT_RGBA8;
458459
this.composePass.taaEnabled = options.taaEnabled;
459460
this.composePass.cocTexture = this.dofPass?.cocTexture;
460461
this.composePass.blurTexture = this.dofPass?.blurTexture;

src/extras/render-passes/render-pass-compose.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class RenderPassCompose extends RenderPassShaderQuad {
8181

8282
_taaEnabled = false;
8383

84+
_hdrScene = true;
85+
8486
_sharpness = 0.5;
8587

8688
_gammaCorrection = GAMMA_SRGB;
@@ -268,6 +270,17 @@ class RenderPassCompose extends RenderPassShaderQuad {
268270
return this._sharpness > 0;
269271
}
270272

273+
set hdrScene(value) {
274+
if (this._hdrScene !== value) {
275+
this._hdrScene = value;
276+
this._shaderDirty = true;
277+
}
278+
}
279+
280+
get hdrScene() {
281+
return this._hdrScene;
282+
}
283+
271284
postInit() {
272285
// clear all buffers to avoid them being loaded from memory
273286
this.setClearColor(Color.BLACK);
@@ -322,7 +335,7 @@ class RenderPassCompose extends RenderPassShaderQuad {
322335
`-${this.vignetteEnabled ? 'vignette' : 'novignette'}` +
323336
`-${this.fringingEnabled ? 'fringing' : 'nofringing'}` +
324337
`-${this.taaEnabled ? 'taa' : 'notaa'}` +
325-
`-${this.isSharpnessEnabled ? 'cas' : 'nocas'}` +
338+
`-${this.isSharpnessEnabled ? (this._hdrScene ? 'cashdr' : 'cas') : 'nocas'}` +
326339
`-${this._debug ?? ''}` +
327340
`-decl${declHash}-start${startHash}-end${endHash}`;
328341

@@ -342,7 +355,10 @@ class RenderPassCompose extends RenderPassShaderQuad {
342355
if (this.vignetteEnabled) defines.set('VIGNETTE', true);
343356
if (this.fringingEnabled) defines.set('FRINGING', true);
344357
if (this.taaEnabled) defines.set('TAA', true);
345-
if (this.isSharpnessEnabled) defines.set('CAS', true);
358+
if (this.isSharpnessEnabled) {
359+
defines.set('CAS', true);
360+
if (this._hdrScene) defines.set('CAS_HDR', true);
361+
}
346362
if (this._debug) defines.set('DEBUG_COMPOSE', this._debug);
347363

348364
const includes = new Map(shaderChunks);

src/scene/shader-lib/glsl/chunks/render-pass/frag/compose/compose-cas.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ export default /* glsl */`
88
uniform float sharpness;
99
1010
// reversible LDR <-> HDR tone mapping, as CAS needs LDR input
11-
float maxComponent(float x, float y, float z) { return max(x, max(y, z)); }
12-
vec3 toSDR(vec3 c) { return c / (1.0 + maxComponent(c.r, c.g, c.b)); }
13-
vec3 toHDR(vec3 c) { return c / (1.0 - maxComponent(c.r, c.g, c.b)); }
11+
#ifdef CAS_HDR
12+
float maxComponent(float x, float y, float z) { return max(x, max(y, z)); }
13+
vec3 toSDR(vec3 c) { return c / (1.0 + maxComponent(c.r, c.g, c.b)); }
14+
vec3 toHDR(vec3 c) { return c / (1.0 - maxComponent(c.r, c.g, c.b)); }
15+
#else
16+
vec3 toSDR(vec3 c) { return c; }
17+
vec3 toHDR(vec3 c) { return c; }
18+
#endif
1419
1520
vec3 applyCas(vec3 color, vec2 uv, float sharpness) {
1621
float x = sceneTextureInvRes.x;

src/scene/shader-lib/wgsl/chunks/render-pass/frag/compose/compose-cas.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,38 @@ export default /* wgsl */`
88
uniform sharpness: f32;
99
1010
// reversible LDR <-> HDR tone mapping, as CAS needs LDR input
11-
fn maxComponent(x: f32, y: f32, z: f32) -> f32 { return max(x, max(y, z)); }
12-
fn toSDR(c: vec3f) -> vec3f { return c / (1.0 + maxComponent(c.r, c.g, c.b)); }
13-
fn toHDR(c: vec3f) -> vec3f { return c / (1.0 - maxComponent(c.r, c.g, c.b)); }
11+
#ifdef CAS_HDR
12+
fn maxComponent(x: f32, y: f32, z: f32) -> f32 { return max(x, max(y, z)); }
13+
fn toSDR(c: vec3f) -> vec3f { return c / (1.0 + maxComponent(c.r, c.g, c.b)); }
14+
fn toHDR(c: vec3f) -> vec3f { return c / (1.0 - maxComponent(c.r, c.g, c.b)); }
15+
#else
16+
fn toSDR(c: vec3f) -> vec3f { return c; }
17+
fn toHDR(c: vec3f) -> vec3f { return c; }
18+
#endif
1419
1520
fn applyCas(color: vec3f, uv: vec2f, sharpness: f32) -> vec3f {
1621
let x = uniform.sceneTextureInvRes.x;
1722
let y = uniform.sceneTextureInvRes.y;
1823
1924
// sample 4 neighbors around the already sampled pixel, and convert it to SDR
20-
let a = toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(0.0, -y), 0.0).rgb);
21-
let b = toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(-x, 0.0), 0.0).rgb);
22-
let c = toSDR(color.rgb);
23-
let d = toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(x, 0.0), 0.0).rgb);
24-
let e = toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(0.0, y), 0.0).rgb);
25+
let a: half3 = half3(toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(0.0, -y), 0.0).rgb));
26+
let b: half3 = half3(toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(-x, 0.0), 0.0).rgb));
27+
let c: half3 = half3(toSDR(color.rgb));
28+
let d: half3 = half3(toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(x, 0.0), 0.0).rgb));
29+
let e: half3 = half3(toSDR(textureSampleLevel(sceneTexture, sceneTextureSampler, uv + vec2f(0.0, y), 0.0).rgb));
2530
2631
// apply the sharpening
2732
let min_g = min(a.g, min(b.g, min(c.g, min(d.g, e.g))));
2833
let max_g = max(a.g, max(b.g, max(c.g, max(d.g, e.g))));
29-
let sharpening_amount = sqrt(min(1.0 - max_g, min_g) / max_g);
30-
let w = sharpening_amount * uniform.sharpness;
31-
var res = (w * (a + b + d + e) + c) / (4.0 * w + 1.0);
34+
let sharpening_amount = sqrt(min(half(1.0) - max_g, min_g) / max_g);
35+
let w = sharpening_amount * half(uniform.sharpness);
36+
var res = (w * (a + b + d + e) + c) / (half(4.0) * w + half(1.0));
3237
3338
// remove negative colors
34-
res = max(res, vec3f(0.0));
39+
res = max(res, half3(0.0));
3540
3641
// convert back to HDR
37-
return toHDR(res);
42+
return toHDR(vec3f(res));
3843
}
3944
#endif
4045
`;

0 commit comments

Comments
 (0)