Skip to content

Commit

Permalink
create bind group in tonemapping/upscaling node to enable customization
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobhellermann committed Dec 30, 2021
1 parent cea4fe8 commit 0de50d8
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 61 deletions.
32 changes: 32 additions & 0 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ impl Plugin for CorePipelinePlugin {
TonemappingNode::IN_VIEW,
)
.unwrap();
draw_2d_graph
.add_slot_edge(
draw_2d_graph::node::MAIN_PASS,
MainPass2dNode::OUT_TEXTURE,
draw_2d_graph::node::TONEMAPPING,
TonemappingNode::IN_TEXTURE,
)
.unwrap();

draw_2d_graph
.add_node_edge(
Expand All @@ -170,6 +178,14 @@ impl Plugin for CorePipelinePlugin {
UpscalingNode::IN_VIEW,
)
.unwrap();
draw_2d_graph
.add_slot_edge(
draw_2d_graph::node::TONEMAPPING,
TonemappingNode::OUT_TEXTURE,
draw_2d_graph::node::UPSCALING,
UpscalingNode::IN_TEXTURE,
)
.unwrap();

graph.add_sub_graph(draw_2d_graph::NAME, draw_2d_graph);

Expand Down Expand Up @@ -206,6 +222,14 @@ impl Plugin for CorePipelinePlugin {
TonemappingNode::IN_VIEW,
)
.unwrap();
draw_3d_graph
.add_slot_edge(
draw_3d_graph::node::MAIN_PASS,
MainPass3dNode::OUT_TEXTURE,
draw_3d_graph::node::TONEMAPPING,
TonemappingNode::IN_TEXTURE,
)
.unwrap();

draw_3d_graph
.add_node_edge(
Expand All @@ -221,6 +245,14 @@ impl Plugin for CorePipelinePlugin {
UpscalingNode::IN_VIEW,
)
.unwrap();
draw_3d_graph
.add_slot_edge(
draw_3d_graph::node::TONEMAPPING,
TonemappingNode::OUT_TEXTURE,
draw_3d_graph::node::UPSCALING,
UpscalingNode::IN_TEXTURE,
)
.unwrap();

graph.add_sub_graph(draw_3d_graph::NAME, draw_3d_graph);

Expand Down
32 changes: 6 additions & 26 deletions crates/bevy_core_pipeline/src/tonemapping/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy_asset::{Assets, HandleUntyped};
use bevy_ecs::prelude::*;
use bevy_render::renderer::RenderDevice;
use bevy_render::texture::BevyDefault;
use bevy_render::view::ViewTarget;
use bevy_render::view::ExtractedView;
use bevy_render::{render_resource::*, RenderApp, RenderStage};

use bevy_reflect::TypeUuid;
Expand Down Expand Up @@ -101,41 +101,21 @@ impl SpecializedPipeline for TonemappingPipeline {

#[derive(Component)]
pub struct TonemappingTarget {
pub hdr_texture_bind_group: BindGroup,
pub pipeline: CachedPipelineId,
}

fn queue_tonemapping_bind_groups(
mut commands: Commands,
render_device: Res<RenderDevice>,
mut render_pipeline_cache: ResMut<RenderPipelineCache>,
mut pipelines: ResMut<SpecializedPipelines<TonemappingPipeline>>,
tonemapping_pipeline: Res<TonemappingPipeline>,
view_targets: Query<(Entity, &ViewTarget)>,
views: Query<Entity, With<ExtractedView>>,
) {
for (entity, target) in view_targets.iter() {
for entity in views.iter() {
let pipeline = pipelines.specialize(&mut render_pipeline_cache, &tonemapping_pipeline, ());

let sampler = render_device.create_sampler(&SamplerDescriptor::default());

let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &tonemapping_pipeline.hdr_texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(&target.hdr_texture),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});

commands.entity(entity).insert(TonemappingTarget {
hdr_texture_bind_group: bind_group,
pipeline,
});
commands
.entity(entity)
.insert(TonemappingTarget { pipeline });
}
}
68 changes: 63 additions & 5 deletions crates/bevy_core_pipeline/src/tonemapping/node.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,51 @@
use std::sync::Mutex;

use bevy_ecs::prelude::*;
use bevy_ecs::query::QueryState;
use bevy_render::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType, SlotValue},
render_resource::{
LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineCache,
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, LoadOp, Operations,
RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineCache, SamplerDescriptor,
TextureViewId,
},
renderer::RenderContext,
view::{ExtractedView, ViewTarget},
};

use super::TonemappingTarget;
use super::{TonemappingPipeline, TonemappingTarget};

pub struct TonemappingNode {
query: QueryState<(&'static ViewTarget, &'static TonemappingTarget), With<ExtractedView>>,
cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
}

impl TonemappingNode {
pub const IN_VIEW: &'static str = "view";
pub const IN_TEXTURE: &'static str = "in_texture";
pub const OUT_TEXTURE: &'static str = "out_texture";

pub fn new(world: &mut World) -> Self {
Self {
query: QueryState::new(world),
cached_texture_bind_group: Mutex::new(None),
}
}
}

impl Node for TonemappingNode {
fn input(&self) -> Vec<SlotInfo> {
vec![SlotInfo::new(TonemappingNode::IN_VIEW, SlotType::Entity)]
vec![
SlotInfo::new(TonemappingNode::IN_TEXTURE, SlotType::TextureView),
SlotInfo::new(TonemappingNode::IN_VIEW, SlotType::Entity),
]
}

fn output(&self) -> Vec<SlotInfo> {
vec![SlotInfo::new(
TonemappingNode::OUT_TEXTURE,
SlotType::TextureView,
)]
}

fn update(&mut self, world: &mut World) {
Expand All @@ -41,8 +59,41 @@ impl Node for TonemappingNode {
world: &World,
) -> Result<(), NodeRunError> {
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let in_texture = graph.get_input_texture(Self::IN_TEXTURE)?;

let render_pipeline_cache = world.get_resource::<RenderPipelineCache>().unwrap();
let tonemapping_pipeline = world.get_resource::<TonemappingPipeline>().unwrap();

let mut cached_bind_group = self.cached_texture_bind_group.lock().unwrap();
let bind_group = match &mut *cached_bind_group {
Some((id, bind_group)) if in_texture.id() == *id => bind_group,
cached_bind_group => {
let sampler = render_context
.render_device
.create_sampler(&SamplerDescriptor::default());

let bind_group =
render_context
.render_device
.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &tonemapping_pipeline.hdr_texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(&in_texture),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});

let (_, bind_group) = cached_bind_group.insert((in_texture.id(), bind_group));
bind_group
}
};

let (target, tonemapping_target) = match self.query.get_manual(world, view_entity) {
Ok(query) => query,
Expand Down Expand Up @@ -72,9 +123,16 @@ impl Node for TonemappingNode {
.begin_render_pass(&pass_descriptor);

render_pass.set_pipeline(pipeline);
render_pass.set_bind_group(0, &tonemapping_target.hdr_texture_bind_group, &[]);
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.draw(0..3, 0..1);

graph
.set_output(
TonemappingNode::OUT_TEXTURE,
SlotValue::TextureView(target.ldr_texture.clone()),
)
.unwrap();

Ok(())
}
}
30 changes: 4 additions & 26 deletions crates/bevy_core_pipeline/src/upscaling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy_asset::{Assets, HandleUntyped};
use bevy_ecs::prelude::*;
use bevy_render::renderer::RenderDevice;
use bevy_render::texture::BevyDefault;
use bevy_render::view::ViewTarget;
use bevy_render::view::ExtractedView;
use bevy_render::{render_resource::*, RenderApp, RenderStage};

use bevy_reflect::TypeUuid;
Expand Down Expand Up @@ -101,41 +101,19 @@ impl SpecializedPipeline for UpscalingPipeline {

#[derive(Component)]
pub struct UpscalingTarget {
pub ldr_texture_bind_group: BindGroup,
pub pipeline: CachedPipelineId,
}

fn queue_upscaling_bind_groups(
mut commands: Commands,
render_device: Res<RenderDevice>,
mut render_pipeline_cache: ResMut<RenderPipelineCache>,
mut pipelines: ResMut<SpecializedPipelines<UpscalingPipeline>>,
upscaling_pipeline: Res<UpscalingPipeline>,
view_targets: Query<(Entity, &ViewTarget)>,
view_targets: Query<Entity, With<ExtractedView>>,
) {
for (entity, target) in view_targets.iter() {
for entity in view_targets.iter() {
let pipeline = pipelines.specialize(&mut render_pipeline_cache, &upscaling_pipeline, ());

let sampler = render_device.create_sampler(&SamplerDescriptor::default());

let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &upscaling_pipeline.ldr_texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(&target.ldr_texture),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});

commands.entity(entity).insert(UpscalingTarget {
ldr_texture_bind_group: bind_group,
pipeline,
});
commands.entity(entity).insert(UpscalingTarget { pipeline });
}
}
51 changes: 47 additions & 4 deletions crates/bevy_core_pipeline/src/upscaling/node.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
use std::sync::Mutex;

use bevy_ecs::prelude::*;
use bevy_ecs::query::QueryState;
use bevy_render::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_resource::{
LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineCache,
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, LoadOp, Operations,
RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineCache, SamplerDescriptor,
TextureViewId,
},
renderer::RenderContext,
view::{ExtractedView, ViewTarget},
};

use super::UpscalingTarget;
use super::{UpscalingPipeline, UpscalingTarget};

pub struct UpscalingNode {
query: QueryState<(&'static ViewTarget, &'static UpscalingTarget), With<ExtractedView>>,
cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
}

impl UpscalingNode {
pub const IN_VIEW: &'static str = "view";
pub const IN_TEXTURE: &'static str = "in_texture";

pub fn new(world: &mut World) -> Self {
Self {
query: QueryState::new(world),
cached_texture_bind_group: Mutex::new(None),
}
}
}

impl Node for UpscalingNode {
fn input(&self) -> Vec<SlotInfo> {
vec![SlotInfo::new(UpscalingNode::IN_VIEW, SlotType::Entity)]
vec![
SlotInfo::new(UpscalingNode::IN_TEXTURE, SlotType::TextureView),
SlotInfo::new(UpscalingNode::IN_VIEW, SlotType::Entity),
]
}

fn update(&mut self, world: &mut World) {
Expand All @@ -41,8 +51,41 @@ impl Node for UpscalingNode {
world: &World,
) -> Result<(), NodeRunError> {
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let in_texture = graph.get_input_texture(Self::IN_TEXTURE)?;

let render_pipeline_cache = world.get_resource::<RenderPipelineCache>().unwrap();
let upscaling_pipeline = world.get_resource::<UpscalingPipeline>().unwrap();

let mut cached_bind_group = self.cached_texture_bind_group.lock().unwrap();
let bind_group = match &mut *cached_bind_group {
Some((id, bind_group)) if in_texture.id() == *id => bind_group,
cached_bind_group => {
let sampler = render_context
.render_device
.create_sampler(&SamplerDescriptor::default());

let bind_group =
render_context
.render_device
.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &upscaling_pipeline.ldr_texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(&in_texture),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});

let (_, bind_group) = cached_bind_group.insert((in_texture.id(), bind_group));
bind_group
}
};

let (target, upscaling_target) = match self.query.get_manual(world, view_entity) {
Ok(query) => query,
Expand Down Expand Up @@ -72,7 +115,7 @@ impl Node for UpscalingNode {
.begin_render_pass(&pass_descriptor);

render_pass.set_pipeline(pipeline);
render_pass.set_bind_group(0, &upscaling_target.ldr_texture_bind_group, &[]);
render_pass.set_bind_group(0, bind_group, &[]);
render_pass.draw(0..3, 0..1);

Ok(())
Expand Down

0 comments on commit 0de50d8

Please sign in to comment.