use bevy_asset::{load_embedded_asset, Handle}; use bevy_ecs::prelude::*; use bevy_image::BevyDefault as _; use bevy_render::{ render_resource::{ binding_types::{sampler, texture_2d, uniform_buffer}, *, }, renderer::RenderDevice, view::{ViewTarget, ViewUniform}, }; #[derive(Resource)] pub struct UiPipeline { pub view_layout: BindGroupLayout, pub image_layout: BindGroupLayout, pub shader: Handle, } impl FromWorld for UiPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); let view_layout = render_device.create_bind_group_layout( "ui_view_layout", &BindGroupLayoutEntries::single( ShaderStages::VERTEX_FRAGMENT, uniform_buffer::(true), ), ); let image_layout = render_device.create_bind_group_layout( "ui_image_layout", &BindGroupLayoutEntries::sequential( ShaderStages::FRAGMENT, ( texture_2d(TextureSampleType::Float { filterable: true }), sampler(SamplerBindingType::Filtering), ), ), ); UiPipeline { view_layout, image_layout, shader: load_embedded_asset!(world, "ui.wgsl"), } } } #[derive(Clone, Copy, Hash, PartialEq, Eq)] pub struct UiPipelineKey { pub hdr: bool, pub anti_alias: bool, } impl SpecializedRenderPipeline for UiPipeline { type Key = UiPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { let vertex_layout = VertexBufferLayout::from_vertex_formats( VertexStepMode::Vertex, vec![ // position VertexFormat::Float32x3, // uv VertexFormat::Float32x2, // color VertexFormat::Float32x4, // mode VertexFormat::Uint32, // border radius VertexFormat::Float32x4, // border thickness VertexFormat::Float32x4, // border size VertexFormat::Float32x2, // position relative to the center VertexFormat::Float32x2, ], ); let shader_defs = if key.anti_alias { vec!["ANTI_ALIAS".into()] } else { Vec::new() }; RenderPipelineDescriptor { vertex: VertexState { shader: self.shader.clone(), entry_point: "vertex".into(), shader_defs: shader_defs.clone(), buffers: vec![vertex_layout], }, fragment: Some(FragmentState { shader: self.shader.clone(), shader_defs, entry_point: "fragment".into(), targets: vec![Some(ColorTargetState { format: if key.hdr { ViewTarget::TEXTURE_FORMAT_HDR } else { TextureFormat::bevy_default() }, blend: Some(BlendState::ALPHA_BLENDING), write_mask: ColorWrites::ALL, })], }), layout: vec![self.view_layout.clone(), self.image_layout.clone()], push_constant_ranges: Vec::new(), primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode: None, unclipped_depth: false, polygon_mode: PolygonMode::Fill, conservative: false, topology: PrimitiveTopology::TriangleList, strip_index_format: None, }, depth_stencil: None, multisample: MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, label: Some("ui_pipeline".into()), zero_initialize_workgroup_memory: false, } } }