bevy/crates/bevy_ui/src/render/pipeline.rs
ickshonpe 78a80c5377 Only use physical coords internally in bevy_ui (#16375)
We switch back and forwards between logical and physical coordinates all
over the place. Systems have to query for cameras and the UiScale when
they shouldn't need to. It's confusing and fragile and new scale factor
bugs get found constantly.

* Use physical coordinates whereever possible in `bevy_ui`.
* Store physical coords in `ComputedNode` and tear out all the unneeded
scale factor calculations and queries.
* Add an `inverse_scale_factor` field to `ComputedNode` and set nodes
changed when their scale factor changes.

`ComputedNode`'s fields and methods now use physical coordinates.
`ComputedNode` has a new field `inverse_scale_factor`. Multiplying the
physical coordinates by the `inverse_scale_factor` will give the logical
values.

---------

Co-authored-by: atlv <email@atlasdostal.com>
2024-11-22 21:23:59 +01:00

128 lines
3.9 KiB
Rust

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,
}
impl FromWorld for UiPipeline {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
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),
),
),
);
UiPipeline {
view_layout,
image_layout,
}
}
}
#[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: super::UI_SHADER_HANDLE,
entry_point: "vertex".into(),
shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout],
},
fragment: Some(FragmentState {
shader: super::UI_SHADER_HANDLE,
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,
}
}
}