bevy_core_pipeline/blit/
mod.rs

1use bevy_app::{App, Plugin};
2use bevy_asset::{load_internal_asset, Handle};
3use bevy_ecs::prelude::*;
4use bevy_render::{
5    render_resource::{
6        binding_types::{sampler, texture_2d},
7        *,
8    },
9    renderer::RenderDevice,
10    RenderApp,
11};
12
13use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
14
15pub const BLIT_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(2312396983770133547);
16
17/// Adds support for specialized "blit pipelines", which can be used to write one texture to another.
18pub struct BlitPlugin;
19
20impl Plugin for BlitPlugin {
21    fn build(&self, app: &mut App) {
22        load_internal_asset!(app, BLIT_SHADER_HANDLE, "blit.wgsl", Shader::from_wgsl);
23
24        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
25            render_app.allow_ambiguous_resource::<SpecializedRenderPipelines<BlitPipeline>>();
26        }
27    }
28
29    fn finish(&self, app: &mut App) {
30        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
31            return;
32        };
33        render_app
34            .init_resource::<BlitPipeline>()
35            .init_resource::<SpecializedRenderPipelines<BlitPipeline>>();
36    }
37}
38
39#[derive(Resource)]
40pub struct BlitPipeline {
41    pub texture_bind_group: BindGroupLayout,
42    pub sampler: Sampler,
43}
44
45impl FromWorld for BlitPipeline {
46    fn from_world(render_world: &mut World) -> Self {
47        let render_device = render_world.resource::<RenderDevice>();
48
49        let texture_bind_group = render_device.create_bind_group_layout(
50            "blit_bind_group_layout",
51            &BindGroupLayoutEntries::sequential(
52                ShaderStages::FRAGMENT,
53                (
54                    texture_2d(TextureSampleType::Float { filterable: false }),
55                    sampler(SamplerBindingType::NonFiltering),
56                ),
57            ),
58        );
59
60        let sampler = render_device.create_sampler(&SamplerDescriptor::default());
61
62        BlitPipeline {
63            texture_bind_group,
64            sampler,
65        }
66    }
67}
68
69#[derive(PartialEq, Eq, Hash, Clone, Copy)]
70pub struct BlitPipelineKey {
71    pub texture_format: TextureFormat,
72    pub blend_state: Option<BlendState>,
73    pub samples: u32,
74}
75
76impl SpecializedRenderPipeline for BlitPipeline {
77    type Key = BlitPipelineKey;
78
79    fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
80        RenderPipelineDescriptor {
81            label: Some("blit pipeline".into()),
82            layout: vec![self.texture_bind_group.clone()],
83            vertex: fullscreen_shader_vertex_state(),
84            fragment: Some(FragmentState {
85                shader: BLIT_SHADER_HANDLE,
86                shader_defs: vec![],
87                entry_point: "fs_main".into(),
88                targets: vec![Some(ColorTargetState {
89                    format: key.texture_format,
90                    blend: key.blend_state,
91                    write_mask: ColorWrites::ALL,
92                })],
93            }),
94            primitive: PrimitiveState::default(),
95            depth_stencil: None,
96            multisample: MultisampleState {
97                count: key.samples,
98                ..Default::default()
99            },
100            push_constant_ranges: Vec::new(),
101            zero_initialize_workgroup_memory: false,
102        }
103    }
104}