Remove Shader weak_handles from bevy_ui. (#19393)

# Objective

- Related to #19024

## Solution

- Use the new `load_shader_library` macro for the shader libraries and
`embedded_asset`/`load_embedded_asset` for the "shader binaries" in
`bevy_ui`.

## Testing

- `box_shadow` example still works.
- `gradient` example is broken at head (see #19384) - but otherwise
gives the same result in the console.
- `ui_materials` example still works.
- `ui_texture_slice` example still works.

P.S. I don't think this needs a migration guide. Technically users could
be using the `pub` weak handles, but there's no actual good use for
them, so omitting it seems fine. Alternatively, we could mix this in
with the migration guide notes for #19137.
This commit is contained in:
andriyDev 2025-05-27 15:32:40 -07:00 committed by GitHub
parent 846cec9ed2
commit e8c2a5af66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 77 deletions

View File

@ -34,20 +34,12 @@ use bytemuck::{Pod, Zeroable};
use super::{stack_z_offsets, UiCameraMap, UiCameraView, QUAD_INDICES, QUAD_VERTEX_POSITIONS}; use super::{stack_z_offsets, UiCameraMap, UiCameraView, QUAD_INDICES, QUAD_VERTEX_POSITIONS};
pub const BOX_SHADOW_SHADER_HANDLE: Handle<Shader> =
weak_handle!("d2991ecd-134f-4f82-adf5-0fcc86f02227");
/// A plugin that enables the rendering of box shadows. /// A plugin that enables the rendering of box shadows.
pub struct BoxShadowPlugin; pub struct BoxShadowPlugin;
impl Plugin for BoxShadowPlugin { impl Plugin for BoxShadowPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!( embedded_asset!(app, "box_shadow.wgsl");
app,
BOX_SHADOW_SHADER_HANDLE,
"box_shadow.wgsl",
Shader::from_wgsl
);
if let Some(render_app) = app.get_sub_app_mut(RenderApp) { if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app render_app
@ -115,6 +107,7 @@ impl Default for BoxShadowMeta {
#[derive(Resource)] #[derive(Resource)]
pub struct BoxShadowPipeline { pub struct BoxShadowPipeline {
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub shader: Handle<Shader>,
} }
impl FromWorld for BoxShadowPipeline { impl FromWorld for BoxShadowPipeline {
@ -129,7 +122,10 @@ impl FromWorld for BoxShadowPipeline {
), ),
); );
BoxShadowPipeline { view_layout } BoxShadowPipeline {
view_layout,
shader: load_embedded_asset!(world, "box_shadow.wgsl"),
}
} }
} }
@ -170,13 +166,13 @@ impl SpecializedRenderPipeline for BoxShadowPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: BOX_SHADOW_SHADER_HANDLE, shader: self.shader.clone(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout], buffers: vec![vertex_layout],
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: BOX_SHADOW_SHADER_HANDLE, shader: self.shader.clone(),
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -34,19 +34,11 @@ use bytemuck::{Pod, Zeroable};
use super::shader_flags::BORDER_ALL; use super::shader_flags::BORDER_ALL;
pub const UI_GRADIENT_SHADER_HANDLE: Handle<Shader> =
weak_handle!("10116113-aac4-47fa-91c8-35cbe80dddcb");
pub struct GradientPlugin; pub struct GradientPlugin;
impl Plugin for GradientPlugin { impl Plugin for GradientPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!( embedded_asset!(app, "gradient.wgsl");
app,
UI_GRADIENT_SHADER_HANDLE,
"gradient.wgsl",
Shader::from_wgsl
);
if let Some(render_app) = app.get_sub_app_mut(RenderApp) { if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app render_app
@ -103,6 +95,7 @@ impl Default for GradientMeta {
#[derive(Resource)] #[derive(Resource)]
pub struct GradientPipeline { pub struct GradientPipeline {
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub shader: Handle<Shader>,
} }
impl FromWorld for GradientPipeline { impl FromWorld for GradientPipeline {
@ -117,7 +110,10 @@ impl FromWorld for GradientPipeline {
), ),
); );
GradientPipeline { view_layout } GradientPipeline {
view_layout,
shader: load_embedded_asset!(world, "gradient.wgsl"),
}
} }
} }
@ -192,13 +188,13 @@ impl SpecializedRenderPipeline for GradientPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: UI_GRADIENT_SHADER_HANDLE, shader: self.shader.clone(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout], buffers: vec![vertex_layout],
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: UI_GRADIENT_SHADER_HANDLE, shader: self.shader.clone(),
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -14,7 +14,7 @@ use crate::{
ComputedNodeTarget, Outline, ResolvedBorderRadius, TextShadow, UiAntiAlias, ComputedNodeTarget, Outline, ResolvedBorderRadius, TextShadow, UiAntiAlias,
}; };
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_asset::{load_internal_asset, weak_handle, AssetEvent, AssetId, Assets, Handle}; use bevy_asset::{AssetEvent, AssetId, Assets};
use bevy_color::{Alpha, ColorToComponents, LinearRgba}; use bevy_color::{Alpha, ColorToComponents, LinearRgba};
use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d};
use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
@ -23,6 +23,7 @@ use bevy_ecs::prelude::*;
use bevy_ecs::system::SystemParam; use bevy_ecs::system::SystemParam;
use bevy_image::prelude::*; use bevy_image::prelude::*;
use bevy_math::{FloatOrd, Mat4, Rect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4Swizzles}; use bevy_math::{FloatOrd, Mat4, Rect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4Swizzles};
use bevy_render::load_shader_library;
use bevy_render::render_graph::{NodeRunError, RenderGraphContext}; use bevy_render::render_graph::{NodeRunError, RenderGraphContext};
use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::render_phase::ViewSortedRenderPhases;
use bevy_render::renderer::RenderContext; use bevy_render::renderer::RenderContext;
@ -100,8 +101,6 @@ pub mod stack_z_offsets {
pub const MATERIAL: f32 = 0.18267; pub const MATERIAL: f32 = 0.18267;
} }
pub const UI_SHADER_HANDLE: Handle<Shader> = weak_handle!("7d190d05-545b-42f5-bd85-22a0da85b0f6");
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub enum RenderUiSystems { pub enum RenderUiSystems {
ExtractCameraViews, ExtractCameraViews,
@ -123,7 +122,7 @@ pub enum RenderUiSystems {
pub type RenderUiSystem = RenderUiSystems; pub type RenderUiSystem = RenderUiSystems;
pub fn build_ui_render(app: &mut App) { pub fn build_ui_render(app: &mut App) {
load_internal_asset!(app, UI_SHADER_HANDLE, "ui.wgsl", Shader::from_wgsl); load_shader_library!(app, "ui.wgsl");
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return; return;

View File

@ -1,3 +1,4 @@
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_image::BevyDefault as _; use bevy_image::BevyDefault as _;
use bevy_render::{ use bevy_render::{
@ -13,6 +14,7 @@ use bevy_render::{
pub struct UiPipeline { pub struct UiPipeline {
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub image_layout: BindGroupLayout, pub image_layout: BindGroupLayout,
pub shader: Handle<Shader>,
} }
impl FromWorld for UiPipeline { impl FromWorld for UiPipeline {
@ -41,6 +43,7 @@ impl FromWorld for UiPipeline {
UiPipeline { UiPipeline {
view_layout, view_layout,
image_layout, image_layout,
shader: load_embedded_asset!(world, "ui.wgsl"),
} }
} }
} }
@ -84,13 +87,13 @@ impl SpecializedRenderPipeline for UiPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: super::UI_SHADER_HANDLE, shader: self.shader.clone(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout], buffers: vec![vertex_layout],
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: super::UI_SHADER_HANDLE, shader: self.shader.clone(),
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -12,7 +12,6 @@ use bevy_ecs::{
}; };
use bevy_image::BevyDefault as _; use bevy_image::BevyDefault as _;
use bevy_math::{FloatOrd, Mat4, Rect, Vec2, Vec4Swizzles}; use bevy_math::{FloatOrd, Mat4, Rect, Vec2, Vec4Swizzles};
use bevy_render::sync_world::{MainEntity, TemporaryRenderEntity};
use bevy_render::{ use bevy_render::{
extract_component::ExtractComponentPlugin, extract_component::ExtractComponentPlugin,
globals::{GlobalsBuffer, GlobalsUniform}, globals::{GlobalsBuffer, GlobalsUniform},
@ -23,16 +22,14 @@ use bevy_render::{
view::*, view::*,
Extract, ExtractSchedule, Render, RenderSystems, Extract, ExtractSchedule, Render, RenderSystems,
}; };
use bevy_render::{
load_shader_library,
sync_world::{MainEntity, TemporaryRenderEntity},
};
use bevy_sprite::BorderRect; use bevy_sprite::BorderRect;
use bevy_transform::prelude::GlobalTransform; use bevy_transform::prelude::GlobalTransform;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
pub const UI_MATERIAL_SHADER_HANDLE: Handle<Shader> =
weak_handle!("b5612b7b-aed5-41b4-a930-1d1588239fcd");
const UI_VERTEX_OUTPUT_SHADER_HANDLE: Handle<Shader> =
weak_handle!("1d97ca3e-eaa8-4bc5-a676-e8e9568c472e");
/// Adds the necessary ECS resources and render logic to enable rendering entities using the given /// Adds the necessary ECS resources and render logic to enable rendering entities using the given
/// [`UiMaterial`] asset type (which includes [`UiMaterial`] types). /// [`UiMaterial`] asset type (which includes [`UiMaterial`] types).
pub struct UiMaterialPlugin<M: UiMaterial>(PhantomData<M>); pub struct UiMaterialPlugin<M: UiMaterial>(PhantomData<M>);
@ -48,18 +45,10 @@ where
M::Data: PartialEq + Eq + Hash + Clone, M::Data: PartialEq + Eq + Hash + Clone,
{ {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!( load_shader_library!(app, "ui_vertex_output.wgsl");
app,
UI_VERTEX_OUTPUT_SHADER_HANDLE, embedded_asset!(app, "ui_material.wgsl");
"ui_vertex_output.wgsl",
Shader::from_wgsl
);
load_internal_asset!(
app,
UI_MATERIAL_SHADER_HANDLE,
"ui_material.wgsl",
Shader::from_wgsl
);
app.init_asset::<M>() app.init_asset::<M>()
.register_type::<MaterialNode<M>>() .register_type::<MaterialNode<M>>()
.add_plugins(( .add_plugins((
@ -135,8 +124,8 @@ pub struct UiMaterialBatch<M: UiMaterial> {
pub struct UiMaterialPipeline<M: UiMaterial> { pub struct UiMaterialPipeline<M: UiMaterial> {
pub ui_layout: BindGroupLayout, pub ui_layout: BindGroupLayout,
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub vertex_shader: Option<Handle<Shader>>, pub vertex_shader: Handle<Shader>,
pub fragment_shader: Option<Handle<Shader>>, pub fragment_shader: Handle<Shader>,
marker: PhantomData<M>, marker: PhantomData<M>,
} }
@ -166,13 +155,13 @@ where
let mut descriptor = RenderPipelineDescriptor { let mut descriptor = RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: UI_MATERIAL_SHADER_HANDLE, shader: self.vertex_shader.clone(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout], buffers: vec![vertex_layout],
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: UI_MATERIAL_SHADER_HANDLE, shader: self.fragment_shader.clone(),
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {
@ -205,13 +194,6 @@ where
label: Some("ui_material_pipeline".into()), label: Some("ui_material_pipeline".into()),
zero_initialize_workgroup_memory: false, zero_initialize_workgroup_memory: false,
}; };
if let Some(vertex_shader) = &self.vertex_shader {
descriptor.vertex.shader = vertex_shader.clone();
}
if let Some(fragment_shader) = &self.fragment_shader {
descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone();
}
descriptor.layout = vec![self.view_layout.clone(), self.ui_layout.clone()]; descriptor.layout = vec![self.view_layout.clone(), self.ui_layout.clone()];
@ -238,18 +220,20 @@ impl<M: UiMaterial> FromWorld for UiMaterialPipeline<M> {
), ),
); );
let load_default = || load_embedded_asset!(asset_server, "ui_material.wgsl");
UiMaterialPipeline { UiMaterialPipeline {
ui_layout, ui_layout,
view_layout, view_layout,
vertex_shader: match M::vertex_shader() { vertex_shader: match M::vertex_shader() {
ShaderRef::Default => None, ShaderRef::Default => load_default(),
ShaderRef::Handle(handle) => Some(handle), ShaderRef::Handle(handle) => handle,
ShaderRef::Path(path) => Some(asset_server.load(path)), ShaderRef::Path(path) => asset_server.load(path),
}, },
fragment_shader: match M::fragment_shader() { fragment_shader: match M::fragment_shader() {
ShaderRef::Default => None, ShaderRef::Default => load_default(),
ShaderRef::Handle(handle) => Some(handle), ShaderRef::Handle(handle) => handle,
ShaderRef::Path(path) => Some(asset_server.load(path)), ShaderRef::Path(path) => asset_server.load(path),
}, },
marker: PhantomData, marker: PhantomData,
} }

View File

@ -30,19 +30,11 @@ use binding_types::{sampler, texture_2d};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use widget::ImageNode; use widget::ImageNode;
pub const UI_SLICER_SHADER_HANDLE: Handle<Shader> =
weak_handle!("10cd61e3-bbf7-47fa-91c8-16cbe806378c");
pub struct UiTextureSlicerPlugin; pub struct UiTextureSlicerPlugin;
impl Plugin for UiTextureSlicerPlugin { impl Plugin for UiTextureSlicerPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!( embedded_asset!(app, "ui_texture_slice.wgsl");
app,
UI_SLICER_SHADER_HANDLE,
"ui_texture_slice.wgsl",
Shader::from_wgsl
);
if let Some(render_app) = app.get_sub_app_mut(RenderApp) { if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app render_app
@ -116,6 +108,7 @@ pub struct UiTextureSliceImageBindGroups {
pub struct UiTextureSlicePipeline { pub struct UiTextureSlicePipeline {
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub image_layout: BindGroupLayout, pub image_layout: BindGroupLayout,
pub shader: Handle<Shader>,
} }
impl FromWorld for UiTextureSlicePipeline { impl FromWorld for UiTextureSlicePipeline {
@ -144,6 +137,7 @@ impl FromWorld for UiTextureSlicePipeline {
UiTextureSlicePipeline { UiTextureSlicePipeline {
view_layout, view_layout,
image_layout, image_layout,
shader: load_embedded_asset!(world, "ui_texture_slice.wgsl"),
} }
} }
} }
@ -180,13 +174,13 @@ impl SpecializedRenderPipeline for UiTextureSlicePipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: UI_SLICER_SHADER_HANDLE, shader: self.shader.clone(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: shader_defs.clone(),
buffers: vec![vertex_layout], buffers: vec![vertex_layout],
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: UI_SLICER_SHADER_HANDLE, shader: self.shader.clone(),
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {