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: BindGroupLayoutDescriptor,
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 = BindGroupLayoutDescriptor::new(
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 pipeline_cache: &PipelineCache,
75 ) -> BindGroup {
76 render_device.create_bind_group(
77 None,
78 &pipeline_cache.get_bind_group_layout(&self.layout),
79 &BindGroupEntries::sequential((src_texture, &self.sampler)),
80 )
81 }
82}
83
84#[derive(PartialEq, Eq, Hash, Clone, Copy)]
85pub struct BlitPipelineKey {
86 pub texture_format: TextureFormat,
87 pub blend_state: Option<BlendState>,
88 pub samples: u32,
89}
90
91impl SpecializedRenderPipeline for BlitPipeline {
92 type Key = BlitPipelineKey;
93
94 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
95 RenderPipelineDescriptor {
96 label: Some("blit pipeline".into()),
97 layout: vec![self.layout.clone()],
98 vertex: self.fullscreen_shader.to_vertex_state(),
99 fragment: Some(FragmentState {
100 shader: self.fragment_shader.clone(),
101 targets: vec![Some(ColorTargetState {
102 format: key.texture_format,
103 blend: key.blend_state,
104 write_mask: ColorWrites::ALL,
105 })],
106 ..default()
107 }),
108 multisample: MultisampleState {
109 count: key.samples,
110 ..default()
111 },
112 ..default()
113 }
114 }
115}