bevy_core_pipeline/blit/
mod.rs1use crate::FullscreenShader;
2use bevy_app::{App, Plugin};
3use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
4use bevy_ecs::prelude::*;
5use bevy_render::{
6 render_resource::{
7 binding_types::{sampler, texture_2d},
8 *,
9 },
10 renderer::RenderDevice,
11 RenderApp, RenderStartup,
12};
13use bevy_shader::Shader;
14use bevy_utils::default;
15
16pub struct BlitPlugin;
18
19impl Plugin for BlitPlugin {
20 fn build(&self, app: &mut App) {
21 embedded_asset!(app, "blit.wgsl");
22
23 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
24 return;
25 };
26
27 render_app
28 .allow_ambiguous_resource::<SpecializedRenderPipelines<BlitPipeline>>()
29 .init_resource::<SpecializedRenderPipelines<BlitPipeline>>()
30 .add_systems(RenderStartup, init_blit_pipeline);
31 }
32}
33
34#[derive(Resource)]
35pub struct BlitPipeline {
36 pub layout: BindGroupLayout,
37 pub sampler: Sampler,
38 pub fullscreen_shader: FullscreenShader,
39 pub fragment_shader: Handle<Shader>,
40}
41
42pub fn init_blit_pipeline(
43 mut commands: Commands,
44 render_device: Res<RenderDevice>,
45 fullscreen_shader: Res<FullscreenShader>,
46 asset_server: Res<AssetServer>,
47) {
48 let layout = render_device.create_bind_group_layout(
49 "blit_bind_group_layout",
50 &BindGroupLayoutEntries::sequential(
51 ShaderStages::FRAGMENT,
52 (
53 texture_2d(TextureSampleType::Float { filterable: false }),
54 sampler(SamplerBindingType::NonFiltering),
55 ),
56 ),
57 );
58
59 let sampler = render_device.create_sampler(&SamplerDescriptor::default());
60
61 commands.insert_resource(BlitPipeline {
62 layout,
63 sampler,
64 fullscreen_shader: fullscreen_shader.clone(),
65 fragment_shader: load_embedded_asset!(asset_server.as_ref(), "blit.wgsl"),
66 });
67}
68
69impl BlitPipeline {
70 pub fn create_bind_group(
71 &self,
72 render_device: &RenderDevice,
73 src_texture: &TextureView,
74 ) -> BindGroup {
75 render_device.create_bind_group(
76 None,
77 &self.layout,
78 &BindGroupEntries::sequential((src_texture, &self.sampler)),
79 )
80 }
81}
82
83#[derive(PartialEq, Eq, Hash, Clone, Copy)]
84pub struct BlitPipelineKey {
85 pub texture_format: TextureFormat,
86 pub blend_state: Option<BlendState>,
87 pub samples: u32,
88}
89
90impl SpecializedRenderPipeline for BlitPipeline {
91 type Key = BlitPipelineKey;
92
93 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
94 RenderPipelineDescriptor {
95 label: Some("blit pipeline".into()),
96 layout: vec![self.layout.clone()],
97 vertex: self.fullscreen_shader.to_vertex_state(),
98 fragment: Some(FragmentState {
99 shader: self.fragment_shader.clone(),
100 targets: vec![Some(ColorTargetState {
101 format: key.texture_format,
102 blend: key.blend_state,
103 write_mask: ColorWrites::ALL,
104 })],
105 ..default()
106 }),
107 multisample: MultisampleState {
108 count: key.samples,
109 ..default()
110 },
111 ..default()
112 }
113 }
114}