bevy_ui_render/
pipeline.rs

1use bevy_asset::{load_embedded_asset, AssetServer, Handle};
2use bevy_ecs::prelude::*;
3use bevy_image::BevyDefault as _;
4use bevy_mesh::VertexBufferLayout;
5use bevy_render::{
6    render_resource::{
7        binding_types::{sampler, texture_2d, uniform_buffer},
8        *,
9    },
10    renderer::RenderDevice,
11    view::{ViewTarget, ViewUniform},
12};
13use bevy_shader::Shader;
14use bevy_utils::default;
15
16#[derive(Resource)]
17pub struct UiPipeline {
18    pub view_layout: BindGroupLayout,
19    pub image_layout: BindGroupLayout,
20    pub shader: Handle<Shader>,
21}
22
23pub fn init_ui_pipeline(
24    mut commands: Commands,
25    render_device: Res<RenderDevice>,
26    asset_server: Res<AssetServer>,
27) {
28    let view_layout = render_device.create_bind_group_layout(
29        "ui_view_layout",
30        &BindGroupLayoutEntries::single(
31            ShaderStages::VERTEX_FRAGMENT,
32            uniform_buffer::<ViewUniform>(true),
33        ),
34    );
35
36    let image_layout = render_device.create_bind_group_layout(
37        "ui_image_layout",
38        &BindGroupLayoutEntries::sequential(
39            ShaderStages::FRAGMENT,
40            (
41                texture_2d(TextureSampleType::Float { filterable: true }),
42                sampler(SamplerBindingType::Filtering),
43            ),
44        ),
45    );
46
47    commands.insert_resource(UiPipeline {
48        view_layout,
49        image_layout,
50        shader: load_embedded_asset!(asset_server.as_ref(), "ui.wgsl"),
51    });
52}
53
54#[derive(Clone, Copy, Hash, PartialEq, Eq)]
55pub struct UiPipelineKey {
56    pub hdr: bool,
57    pub anti_alias: bool,
58}
59
60impl SpecializedRenderPipeline for UiPipeline {
61    type Key = UiPipelineKey;
62
63    fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
64        let vertex_layout = VertexBufferLayout::from_vertex_formats(
65            VertexStepMode::Vertex,
66            vec![
67                // position
68                VertexFormat::Float32x3,
69                // uv
70                VertexFormat::Float32x2,
71                // color
72                VertexFormat::Float32x4,
73                // mode
74                VertexFormat::Uint32,
75                // border radius
76                VertexFormat::Float32x4,
77                // border thickness
78                VertexFormat::Float32x4,
79                // border size
80                VertexFormat::Float32x2,
81                // position relative to the center
82                VertexFormat::Float32x2,
83            ],
84        );
85        let shader_defs = if key.anti_alias {
86            vec!["ANTI_ALIAS".into()]
87        } else {
88            Vec::new()
89        };
90
91        RenderPipelineDescriptor {
92            vertex: VertexState {
93                shader: self.shader.clone(),
94                shader_defs: shader_defs.clone(),
95                buffers: vec![vertex_layout],
96                ..default()
97            },
98            fragment: Some(FragmentState {
99                shader: self.shader.clone(),
100                shader_defs,
101                targets: vec![Some(ColorTargetState {
102                    format: if key.hdr {
103                        ViewTarget::TEXTURE_FORMAT_HDR
104                    } else {
105                        TextureFormat::bevy_default()
106                    },
107                    blend: Some(BlendState::ALPHA_BLENDING),
108                    write_mask: ColorWrites::ALL,
109                })],
110                ..default()
111            }),
112            layout: vec![self.view_layout.clone(), self.image_layout.clone()],
113            label: Some("ui_pipeline".into()),
114            ..default()
115        }
116    }
117}