bevy_core_pipeline/fxaa/
node.rs

1use std::sync::Mutex;
2
3use crate::fxaa::{CameraFxaaPipeline, Fxaa, FxaaPipeline};
4use bevy_ecs::{prelude::*, query::QueryItem};
5use bevy_render::{
6    render_graph::{NodeRunError, RenderGraphContext, ViewNode},
7    render_resource::{
8        BindGroup, BindGroupEntries, Operations, PipelineCache, RenderPassColorAttachment,
9        RenderPassDescriptor, TextureViewId,
10    },
11    renderer::RenderContext,
12    view::ViewTarget,
13};
14
15#[derive(Default)]
16pub struct FxaaNode {
17    cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
18}
19
20impl ViewNode for FxaaNode {
21    type ViewQuery = (
22        &'static ViewTarget,
23        &'static CameraFxaaPipeline,
24        &'static Fxaa,
25    );
26
27    fn run(
28        &self,
29        _graph: &mut RenderGraphContext,
30        render_context: &mut RenderContext,
31        (target, pipeline, fxaa): QueryItem<Self::ViewQuery>,
32        world: &World,
33    ) -> Result<(), NodeRunError> {
34        let pipeline_cache = world.resource::<PipelineCache>();
35        let fxaa_pipeline = world.resource::<FxaaPipeline>();
36
37        if !fxaa.enabled {
38            return Ok(());
39        };
40
41        let Some(pipeline) = pipeline_cache.get_render_pipeline(pipeline.pipeline_id) else {
42            return Ok(());
43        };
44
45        let post_process = target.post_process_write();
46        let source = post_process.source;
47        let destination = post_process.destination;
48        let mut cached_bind_group = self.cached_texture_bind_group.lock().unwrap();
49        let bind_group = match &mut *cached_bind_group {
50            Some((id, bind_group)) if source.id() == *id => bind_group,
51            cached_bind_group => {
52                let bind_group = render_context.render_device().create_bind_group(
53                    None,
54                    &fxaa_pipeline.texture_bind_group,
55                    &BindGroupEntries::sequential((source, &fxaa_pipeline.sampler)),
56                );
57
58                let (_, bind_group) = cached_bind_group.insert((source.id(), bind_group));
59                bind_group
60            }
61        };
62
63        let pass_descriptor = RenderPassDescriptor {
64            label: Some("fxaa_pass"),
65            color_attachments: &[Some(RenderPassColorAttachment {
66                view: destination,
67                resolve_target: None,
68                ops: Operations::default(),
69            })],
70            depth_stencil_attachment: None,
71            timestamp_writes: None,
72            occlusion_query_set: None,
73        };
74
75        let mut render_pass = render_context
76            .command_encoder()
77            .begin_render_pass(&pass_descriptor);
78
79        render_pass.set_pipeline(pipeline);
80        render_pass.set_bind_group(0, bind_group, &[]);
81        render_pass.draw(0..3, 0..1);
82
83        Ok(())
84    }
85}