From 2ab94a2a1722f1e1eda1031e732d76bdaec46f83 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Thu, 10 Nov 2022 12:11:58 -0800 Subject: [PATCH] Specialize on deband dither key --- .../bevy_core_pipeline/src/core_2d/camera_2d.rs | 2 +- .../bevy_core_pipeline/src/core_3d/camera_3d.rs | 4 +++- .../bevy_core_pipeline/src/tonemapping/mod.rs | 14 ++++++++++++-- .../bevy_core_pipeline/src/tonemapping/node.rs | 2 +- .../src/tonemapping/tonemapping.wgsl | 4 ++++ crates/bevy_pbr/src/material.rs | 11 +++++++++-- crates/bevy_pbr/src/render/mesh.rs | 6 ++++++ crates/bevy_pbr/src/render/pbr.wgsl | 2 ++ crates/bevy_pbr/src/render/pbr_functions.wgsl | 2 ++ crates/bevy_sprite/src/mesh2d/material.rs | 11 +++++++++-- crates/bevy_sprite/src/mesh2d/mesh.rs | 6 ++++++ crates/bevy_sprite/src/render/mod.rs | 17 +++++++++++++++-- 12 files changed, 70 insertions(+), 11 deletions(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs index 711fda3a57a2a..86906240b467c 100644 --- a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs +++ b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs @@ -75,7 +75,7 @@ impl Camera2dBundle { global_transform: Default::default(), camera: Camera::default(), camera_2d: Camera2d::default(), - tonemapping: Tonemapping { is_enabled: false }, + tonemapping: Tonemapping::Disabled, } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index 20a0001457a9f..5278ca5488b70 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -74,7 +74,9 @@ impl Default for Camera3dBundle { fn default() -> Self { Self { camera_render_graph: CameraRenderGraph::new(crate::core_3d::graph::NAME), - tonemapping: Tonemapping { is_enabled: true }, + tonemapping: Tonemapping::Enabled { + is_deband_dither_enabled: true, + }, camera: Default::default(), projection: Default::default(), visible_entities: Default::default(), diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index 3af2ecedccb18..cf587c508740b 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -108,8 +108,18 @@ impl FromWorld for TonemappingPipeline { #[derive(Component, Clone, Reflect, Default)] #[reflect(Component)] -pub struct Tonemapping { - pub is_enabled: bool, +pub enum Tonemapping { + #[default] + Disabled, + Enabled { + is_deband_dither_enabled: bool, + }, +} + +impl Tonemapping { + pub fn is_enabled(&self) -> bool { + matches!(self, Tonemapping::Enabled { .. }) + } } impl ExtractComponent for Tonemapping { diff --git a/crates/bevy_core_pipeline/src/tonemapping/node.rs b/crates/bevy_core_pipeline/src/tonemapping/node.rs index 3a41a22025f12..a300303c5c8ae 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/node.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/node.rs @@ -54,7 +54,7 @@ impl Node for TonemappingNode { Err(_) => return Ok(()), }; - let tonemapping_enabled = tonemapping.map_or(false, |t| t.is_enabled); + let tonemapping_enabled = tonemapping.map_or(false, |t| t.is_enabled()); if !tonemapping_enabled || !target.is_hdr() { return Ok(()); } diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl index a920670318480..3415f9da21dce 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl @@ -11,10 +11,14 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { let hdr_color = textureSample(hdr_texture, hdr_sampler, in.uv); var output_rgb = vec3(reinhard_luminance(hdr_color.rgb)); + +#ifdef DEBAND_DITHER output_rgb = pow(output_rgb.rgb, vec3(1.0 / 2.2)); output_rgb = output_rgb + screen_space_dither(in.position.xy); // This conversion back to linear space is required because our output texture format is // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. output_rgb = pow(output_rgb.rgb, vec3(2.2)); +#endif + return vec4(output_rgb, hdr_color.a); } diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index d294b7eeb386a..c7c5a93a6e9b2 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -363,9 +363,16 @@ pub fn queue_material_meshes( let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples) | MeshPipelineKey::from_hdr(view.hdr); - if let Some(tonemapping) = tonemapping { - if tonemapping.is_enabled && !view.hdr { + if let Some(Tonemapping::Enabled { + is_deband_dither_enabled, + }) = tonemapping + { + if !view.hdr { view_key |= MeshPipelineKey::TONEMAP_IN_SHADER; + + if *is_deband_dither_enabled { + view_key |= MeshPipelineKey::DEBAND_DITHER; + } } } let rangefinder = view.rangefinder3d(); diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index b89e521eff824..73e7eea7b0c5f 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -518,6 +518,7 @@ bitflags::bitflags! { const TRANSPARENT_MAIN_PASS = (1 << 0); const HDR = (1 << 1); const TONEMAP_IN_SHADER = (1 << 2); + const DEBAND_DITHER = (1 << 3); const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; const PRIMITIVE_TOPOLOGY_RESERVED_BITS = Self::PRIMITIVE_TOPOLOGY_MASK_BITS << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS; } @@ -636,6 +637,11 @@ impl SpecializedMeshPipeline for MeshPipeline { if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) { shader_defs.push("TONEMAP_IN_SHADER".to_string()); + + // Debanding is tied to tonemapping in the shader, cannot run without it. + if key.contains(MeshPipelineKey::DEBAND_DITHER) { + shader_defs.push("DEBAND_DITHER".to_string()); + } } let format = match key.contains(MeshPipelineKey::HDR) { diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index 4835c1897c426..6f5d94edfbaf3 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -97,6 +97,8 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { #ifdef TONEMAP_IN_SHADER output_color = tone_mapping(output_color); +#endif +#ifdef DEBAND_DITHER output_color = dither(output_color, in.frag_coord.xy); #endif return output_color; diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 44fd2c97c609b..de2e83e4a4681 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -260,7 +260,9 @@ fn tone_mapping(in: vec4) -> vec4 { // Not needed with sRGB buffer // output_color.rgb = pow(output_color.rgb, vec3(1.0 / 2.2)); } +#endif +#ifdef DEBAND_DITHER fn dither(color: vec4, pos: vec2) -> vec4 { return vec4(color.rgb + screen_space_dither(pos.xy), color.a); } diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 2e4e03179b216..9b088e9fc906b 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -328,9 +328,16 @@ pub fn queue_material2d_meshes( let mut view_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples) | Mesh2dPipelineKey::from_hdr(view.hdr); - if let Some(tonemapping) = tonemapping { - if tonemapping.is_enabled && !view.hdr { + if let Some(Tonemapping::Enabled { + is_deband_dither_enabled, + }) = tonemapping + { + if !view.hdr { view_key |= Mesh2dPipelineKey::TONEMAP_IN_SHADER; + + if *is_deband_dither_enabled { + view_key |= Mesh2dPipelineKey::DEBAND_DITHER; + } } } diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 43a932f53d565..5483c2b98d972 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -288,6 +288,7 @@ bitflags::bitflags! { const NONE = 0; const HDR = (1 << 0); const TONEMAP_IN_SHADER = (1 << 1); + const DEBAND_DITHER = (1 << 2); const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; const PRIMITIVE_TOPOLOGY_RESERVED_BITS = Self::PRIMITIVE_TOPOLOGY_MASK_BITS << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS; } @@ -376,6 +377,11 @@ impl SpecializedMeshPipeline for Mesh2dPipeline { if key.contains(Mesh2dPipelineKey::TONEMAP_IN_SHADER) { shader_defs.push("TONEMAP_IN_SHADER".to_string()); + + // Debanding is tied to tonemapping in the shader, cannot run without it. + if key.contains(Mesh2dPipelineKey::DEBAND_DITHER) { + shader_defs.push("DEBAND_DITHER".to_string()); + } } let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?; diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 931f99ac6c97b..f9bc957351e05 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -151,6 +151,7 @@ bitflags::bitflags! { const COLORED = (1 << 0); const HDR = (1 << 1); const TONEMAP_IN_SHADER = (1 << 2); + const DEBAND_DITHER = (1 << 3); const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; } } @@ -212,6 +213,11 @@ impl SpecializedRenderPipeline for SpritePipeline { if key.contains(SpritePipelineKey::TONEMAP_IN_SHADER) { shader_defs.push("TONEMAP_IN_SHADER".to_string()); + + // Debanding is tied to tonemapping in the shader, cannot run without it. + if key.contains(SpritePipelineKey::DEBAND_DITHER) { + shader_defs.push("DEBAND_DITHER".to_string()); + } } let format = match key.contains(SpritePipelineKey::HDR) { @@ -508,9 +514,16 @@ pub fn queue_sprites( for (mut transparent_phase, visible_entities, view, tonemapping) in &mut views { let mut view_key = SpritePipelineKey::from_hdr(view.hdr) | msaa_key; - if let Some(tonemapping) = tonemapping { - if tonemapping.is_enabled && !view.hdr { + if let Some(Tonemapping::Enabled { + is_deband_dither_enabled, + }) = tonemapping + { + if !view.hdr { view_key |= SpritePipelineKey::TONEMAP_IN_SHADER; + + if *is_deband_dither_enabled { + view_key |= SpritePipelineKey::DEBAND_DITHER; + } } } let pipeline = pipelines.specialize(