-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
node.rs
127 lines (109 loc) · 4.38 KB
/
node.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::sync::Mutex;
use crate::tonemapping::{Tonemapping, TonemappingPipeline};
use bevy_ecs::prelude::*;
use bevy_ecs::query::QueryState;
use bevy_render::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, LoadOp, Operations,
PipelineCache, RenderPassColorAttachment, RenderPassDescriptor, SamplerDescriptor,
TextureViewId,
},
renderer::RenderContext,
view::{ExtractedView, ViewTarget},
};
pub struct TonemappingNode {
query: QueryState<(&'static ViewTarget, Option<&'static Tonemapping>), With<ExtractedView>>,
cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
}
impl TonemappingNode {
pub const IN_VIEW: &'static str = "view";
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)]
}
fn update(&mut self, world: &mut World) {
self.query.update_archetypes(world);
}
fn run(
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let pipeline_cache = world.resource::<PipelineCache>();
let tonemapping_pipeline = world.resource::<TonemappingPipeline>();
let (target, tonemapping) = match self.query.get_manual(world, view_entity) {
Ok(result) => result,
Err(_) => return Ok(()),
};
let tonemapping_enabled = tonemapping.map_or(false, |t| t.is_enabled());
if !tonemapping_enabled || !target.is_hdr() {
return Ok(());
}
let pipeline = match pipeline_cache
.get_render_pipeline(tonemapping_pipeline.tonemapping_pipeline_id)
{
Some(pipeline) => pipeline,
None => return Ok(()),
};
let post_process = target.post_process_write();
let source = post_process.source;
let destination = post_process.destination;
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 source.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.texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(source),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});
let (_, bind_group) = cached_bind_group.insert((source.id(), bind_group));
bind_group
}
};
let pass_descriptor = RenderPassDescriptor {
label: Some("tonemapping_pass"),
color_attachments: &[Some(RenderPassColorAttachment {
view: destination,
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(Default::default()), // TODO shouldn't need to be cleared
store: true,
},
})],
depth_stencil_attachment: None,
};
let mut render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
render_pass.set_pipeline(pipeline);
render_pass.set_bind_group(0, bind_group, &[]);
render_pass.draw(0..3, 0..1);
Ok(())
}
}