
# Objective - Progress towards #19887. ## Solution - Convert `FromWorld` impls into systems that run in `RenderStartup`. - Move `UiPipeline` init to `build_ui_render` instead of doing it separately in `finish`. Note: I am making several of these systems pub so that users could order their systems relative to them. This is to match the fact that these types previously were FromWorld so users could initialize them. ## Testing - Ran `ui_material`, `ui_texture_slice`, `box_shadow`, and `gradients` examples and it still worked.
116 lines
3.4 KiB
Rust
116 lines
3.4 KiB
Rust
use bevy_asset::{load_embedded_asset, AssetServer, 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},
|
|
};
|
|
use bevy_utils::default;
|
|
|
|
#[derive(Resource)]
|
|
pub struct UiPipeline {
|
|
pub view_layout: BindGroupLayout,
|
|
pub image_layout: BindGroupLayout,
|
|
pub shader: Handle<Shader>,
|
|
}
|
|
|
|
pub fn init_ui_pipeline(
|
|
mut commands: Commands,
|
|
render_device: Res<RenderDevice>,
|
|
asset_server: Res<AssetServer>,
|
|
) {
|
|
let view_layout = render_device.create_bind_group_layout(
|
|
"ui_view_layout",
|
|
&BindGroupLayoutEntries::single(
|
|
ShaderStages::VERTEX_FRAGMENT,
|
|
uniform_buffer::<ViewUniform>(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),
|
|
),
|
|
),
|
|
);
|
|
|
|
commands.insert_resource(UiPipeline {
|
|
view_layout,
|
|
image_layout,
|
|
shader: load_embedded_asset!(asset_server.as_ref(), "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(),
|
|
shader_defs: shader_defs.clone(),
|
|
buffers: vec![vertex_layout],
|
|
..default()
|
|
},
|
|
fragment: Some(FragmentState {
|
|
shader: self.shader.clone(),
|
|
shader_defs,
|
|
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,
|
|
})],
|
|
..default()
|
|
}),
|
|
layout: vec![self.view_layout.clone(), self.image_layout.clone()],
|
|
label: Some("ui_pipeline".into()),
|
|
..default()
|
|
}
|
|
}
|
|
}
|