Replace FULLSCREEN_SHADER_HANDLE with a FullscreenShader resource. (#19426)

# Objective

- Related to #19024.

## Solution

- Remove the `FULLSCREEN_SHADER_HANDLE` `weak_handle` with a resource
holding the shader handle.
- This also changes us from using `load_internal_asset` to
`embedded_asset`/`load_embedded_asset`.
- All uses have been migrated to clone the `FullscreenShader` resource
and use its `to_vertex_state` method.

## Testing

- `anti_aliasing` example still works.
- `bloom_3d` example still works.

---------

Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
This commit is contained in:
andriyDev 2025-06-23 17:02:23 -07:00 committed by GitHub
parent 9f376e2537
commit a7fdd6fc6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 255 additions and 120 deletions

View File

@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{ use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d}, core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d}, core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state, FullscreenShader,
}; };
use bevy_ecs::{prelude::*, query::QueryItem}; use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_image::BevyDefault as _; use bevy_image::BevyDefault as _;
@ -163,7 +163,8 @@ impl Plugin for CasPlugin {
pub struct CasPipeline { pub struct CasPipeline {
texture_bind_group: BindGroupLayout, texture_bind_group: BindGroupLayout,
sampler: Sampler, sampler: Sampler,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
impl FromWorld for CasPipeline { impl FromWorld for CasPipeline {
@ -187,7 +188,11 @@ impl FromWorld for CasPipeline {
CasPipeline { CasPipeline {
texture_bind_group, texture_bind_group,
sampler, sampler,
shader: load_embedded_asset!(render_world, "robust_contrast_adaptive_sharpening.wgsl"), fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(
render_world,
"robust_contrast_adaptive_sharpening.wgsl"
),
} }
} }
} }
@ -209,9 +214,9 @@ impl SpecializedRenderPipeline for CasPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("contrast_adaptive_sharpening".into()), label: Some("contrast_adaptive_sharpening".into()),
layout: vec![self.texture_bind_group.clone()], layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), 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 {

View File

@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{ use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d}, core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d}, core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state, FullscreenShader,
}; };
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_image::BevyDefault as _; use bevy_image::BevyDefault as _;
@ -130,7 +130,8 @@ impl Plugin for FxaaPlugin {
pub struct FxaaPipeline { pub struct FxaaPipeline {
texture_bind_group: BindGroupLayout, texture_bind_group: BindGroupLayout,
sampler: Sampler, sampler: Sampler,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
impl FromWorld for FxaaPipeline { impl FromWorld for FxaaPipeline {
@ -157,7 +158,8 @@ impl FromWorld for FxaaPipeline {
FxaaPipeline { FxaaPipeline {
texture_bind_group, texture_bind_group,
sampler, sampler,
shader: load_embedded_asset!(render_world, "fxaa.wgsl"), fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
} }
} }
} }
@ -181,9 +183,9 @@ impl SpecializedRenderPipeline for FxaaPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("fxaa".into()), label: Some("fxaa".into()),
layout: vec![self.texture_bind_group.clone()], layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs: vec![ shader_defs: vec![
format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(), format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(),
format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(), format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(),

View File

@ -2,9 +2,9 @@ use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, Handle}; use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{ use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d}, core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prelude::Camera3d, prelude::Camera3d,
prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures}, prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
FullscreenShader,
}; };
use bevy_diagnostic::FrameCount; use bevy_diagnostic::FrameCount;
use bevy_ecs::{ use bevy_ecs::{
@ -238,7 +238,8 @@ struct TaaPipeline {
taa_bind_group_layout: BindGroupLayout, taa_bind_group_layout: BindGroupLayout,
nearest_sampler: Sampler, nearest_sampler: Sampler,
linear_sampler: Sampler, linear_sampler: Sampler,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
impl FromWorld for TaaPipeline { impl FromWorld for TaaPipeline {
@ -283,7 +284,8 @@ impl FromWorld for TaaPipeline {
taa_bind_group_layout, taa_bind_group_layout,
nearest_sampler, nearest_sampler,
linear_sampler, linear_sampler,
shader: load_embedded_asset!(world, "taa.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "taa.wgsl"),
} }
} }
} }
@ -314,9 +316,9 @@ impl SpecializedRenderPipeline for TaaPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("taa_pipeline".into()), label: Some("taa_pipeline".into()),
layout: vec![self.taa_bind_group_layout.clone()], layout: vec![self.taa_bind_group_layout.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs, shader_defs,
entry_point: "taa".into(), entry_point: "taa".into(),
targets: vec![ targets: vec![

View File

@ -10,7 +10,7 @@ use bevy_render::{
RenderApp, RenderApp,
}; };
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state; use crate::FullscreenShader;
/// Adds support for specialized "blit pipelines", which can be used to write one texture to another. /// Adds support for specialized "blit pipelines", which can be used to write one texture to another.
pub struct BlitPlugin; pub struct BlitPlugin;
@ -38,7 +38,8 @@ impl Plugin for BlitPlugin {
pub struct BlitPipeline { pub struct BlitPipeline {
pub texture_bind_group: BindGroupLayout, pub texture_bind_group: BindGroupLayout,
pub sampler: Sampler, pub sampler: Sampler,
pub shader: Handle<Shader>, pub fullscreen_shader: FullscreenShader,
pub fragment_shader: Handle<Shader>,
} }
impl FromWorld for BlitPipeline { impl FromWorld for BlitPipeline {
@ -61,7 +62,8 @@ impl FromWorld for BlitPipeline {
BlitPipeline { BlitPipeline {
texture_bind_group, texture_bind_group,
sampler, sampler,
shader: load_embedded_asset!(render_world, "blit.wgsl"), fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "blit.wgsl"),
} }
} }
} }
@ -80,9 +82,9 @@ impl SpecializedRenderPipeline for BlitPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("blit pipeline".into()), label: Some("blit pipeline".into()),
layout: vec![self.texture_bind_group.clone()], layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs: vec![], shader_defs: vec![],
entry_point: "fs_main".into(), entry_point: "fs_main".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -1,5 +1,6 @@
use crate::FullscreenShader;
use super::{Bloom, BLOOM_TEXTURE_FORMAT}; use super::{Bloom, BLOOM_TEXTURE_FORMAT};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle}; use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{ use bevy_ecs::{
prelude::{Component, Entity}, prelude::{Component, Entity},
@ -27,8 +28,10 @@ pub struct BloomDownsamplingPipeline {
/// Layout with a texture, a sampler, and uniforms /// Layout with a texture, a sampler, and uniforms
pub bind_group_layout: BindGroupLayout, pub bind_group_layout: BindGroupLayout,
pub sampler: Sampler, pub sampler: Sampler,
/// The shader asset handle. /// The asset handle for the fullscreen vertex shader.
pub shader: Handle<Shader>, pub fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
pub fragment_shader: Handle<Shader>,
} }
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
@ -81,7 +84,8 @@ impl FromWorld for BloomDownsamplingPipeline {
BloomDownsamplingPipeline { BloomDownsamplingPipeline {
bind_group_layout, bind_group_layout,
sampler, sampler,
shader: load_embedded_asset!(world, "bloom.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
} }
} }
} }
@ -122,9 +126,9 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
.into(), .into(),
), ),
layout, layout,
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs, shader_defs,
entry_point, entry_point,
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -1,7 +1,8 @@
use crate::FullscreenShader;
use super::{ use super::{
downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT, downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT,
}; };
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle}; use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{ use bevy_ecs::{
prelude::{Component, Entity}, prelude::{Component, Entity},
@ -27,8 +28,10 @@ pub struct UpsamplingPipelineIds {
#[derive(Resource)] #[derive(Resource)]
pub struct BloomUpsamplingPipeline { pub struct BloomUpsamplingPipeline {
pub bind_group_layout: BindGroupLayout, pub bind_group_layout: BindGroupLayout,
/// The shader asset handle. /// The asset handle for the fullscreen vertex shader.
pub shader: Handle<Shader>, pub fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
pub fragment_shader: Handle<Shader>,
} }
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
@ -58,7 +61,8 @@ impl FromWorld for BloomUpsamplingPipeline {
BloomUpsamplingPipeline { BloomUpsamplingPipeline {
bind_group_layout, bind_group_layout,
shader: load_embedded_asset!(world, "bloom.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
} }
} }
} }
@ -108,9 +112,9 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("bloom_upsampling_pipeline".into()), label: Some("bloom_upsampling_pipeline".into()),
layout: vec![self.bind_group_layout.clone()], layout: vec![self.bind_group_layout.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs: vec![], shader_defs: vec![],
entry_point: "upsample".into(), entry_point: "upsample".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prepass::{DeferredPrepass, ViewPrepassTextures}, prepass::{DeferredPrepass, ViewPrepassTextures},
FullscreenShader,
}; };
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset}; use bevy_asset::{embedded_asset, load_embedded_asset};
@ -130,6 +130,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
), ),
); );
let vertex_state = world.resource::<FullscreenShader>().to_vertex_state();
let shader = load_embedded_asset!(world, "copy_deferred_lighting_id.wgsl"); let shader = load_embedded_asset!(world, "copy_deferred_lighting_id.wgsl");
let pipeline_id = let pipeline_id =
@ -138,7 +139,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
.queue_render_pipeline(RenderPipelineDescriptor { .queue_render_pipeline(RenderPipelineDescriptor {
label: Some("copy_deferred_lighting_id_pipeline".into()), label: Some("copy_deferred_lighting_id_pipeline".into()),
layout: vec![layout.clone()], layout: vec![layout.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: vertex_state,
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader, shader,
shader_defs: vec![], shader_defs: vec![],

View File

@ -66,7 +66,7 @@ use crate::{
graph::{Core3d, Node3d}, graph::{Core3d, Node3d},
Camera3d, DEPTH_TEXTURE_SAMPLING_SUPPORTED, Camera3d, DEPTH_TEXTURE_SAMPLING_SUPPORTED,
}, },
fullscreen_vertex_shader::fullscreen_shader_vertex_state, FullscreenShader,
}; };
/// A plugin that adds support for the depth of field effect to Bevy. /// A plugin that adds support for the depth of field effect to Bevy.
@ -325,8 +325,10 @@ pub struct DepthOfFieldPipeline {
/// The bind group layout shared among all invocations of the depth of field /// The bind group layout shared among all invocations of the depth of field
/// shader. /// shader.
global_bind_group_layout: BindGroupLayout, global_bind_group_layout: BindGroupLayout,
/// The shader asset handle. /// The asset handle for the fullscreen vertex shader.
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
fragment_shader: Handle<Shader>,
} }
impl ViewNode for DepthOfFieldNode { impl ViewNode for DepthOfFieldNode {
@ -678,13 +680,15 @@ pub fn prepare_depth_of_field_pipelines(
&ViewDepthOfFieldBindGroupLayouts, &ViewDepthOfFieldBindGroupLayouts,
&Msaa, &Msaa,
)>, )>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
) { ) {
for (entity, view, depth_of_field, view_bind_group_layouts, msaa) in view_targets.iter() { for (entity, view, depth_of_field, view_bind_group_layouts, msaa) in view_targets.iter() {
let dof_pipeline = DepthOfFieldPipeline { let dof_pipeline = DepthOfFieldPipeline {
view_bind_group_layouts: view_bind_group_layouts.clone(), view_bind_group_layouts: view_bind_group_layouts.clone(),
global_bind_group_layout: global_bind_group_layout.layout.clone(), global_bind_group_layout: global_bind_group_layout.layout.clone(),
shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"), fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
}; };
// We'll need these two flags to create the `DepthOfFieldPipelineKey`s. // We'll need these two flags to create the `DepthOfFieldPipelineKey`s.
@ -797,12 +801,12 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline {
label: Some("depth of field pipeline".into()), label: Some("depth of field pipeline".into()),
layout, layout,
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
primitive: default(), primitive: default(),
depth_stencil: None, depth_stencil: None,
multisample: default(), multisample: default(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs, shader_defs,
entry_point: match key.pass { entry_point: match key.pass {
DofPass::GaussianHorizontal => "gaussian_horizontal".into(), DofPass::GaussianHorizontal => "gaussian_horizontal".into(),

View File

@ -1,25 +1,40 @@
use bevy_asset::{weak_handle, Handle}; use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{resource::Resource, world::FromWorld};
use bevy_render::{prelude::Shader, render_resource::VertexState}; use bevy_render::{prelude::Shader, render_resource::VertexState};
pub const FULLSCREEN_SHADER_HANDLE: Handle<Shader> = /// A shader that renders to the whole screen. Useful for post-processing.
weak_handle!("481fb759-d0b1-4175-8319-c439acde30a2"); #[derive(Resource, Clone)]
pub struct FullscreenShader(Handle<Shader>);
/// uses the [`FULLSCREEN_SHADER_HANDLE`] to output a impl FromWorld for FullscreenShader {
/// ```wgsl fn from_world(world: &mut bevy_ecs::world::World) -> Self {
/// struct FullscreenVertexOutput { Self(load_embedded_asset!(world, "fullscreen.wgsl"))
/// [[builtin(position)]] }
/// position: vec4<f32>; }
/// [[location(0)]]
/// uv: vec2<f32>; impl FullscreenShader {
/// }; /// Gets the raw shader handle.
/// ``` pub fn shader(&self) -> Handle<Shader> {
/// from the vertex shader. self.0.clone()
/// The draw call should render one triangle: `render_pass.draw(0..3, 0..1);` }
pub fn fullscreen_shader_vertex_state() -> VertexState {
VertexState { /// Creates a [`VertexState`] that uses the [`FullscreenShader`] to output a
shader: FULLSCREEN_SHADER_HANDLE, /// ```wgsl
shader_defs: Vec::new(), /// struct FullscreenVertexOutput {
entry_point: "fullscreen_vertex_shader".into(), /// @builtin(position)
buffers: Vec::new(), /// position: vec4<f32>;
/// @location(0)
/// uv: vec2<f32>;
/// };
/// ```
/// from the vertex shader.
/// The draw call should render one triangle: `render_pass.draw(0..3, 0..1);`
pub fn to_vertex_state(&self) -> VertexState {
VertexState {
shader: self.0.clone(),
shader_defs: Vec::new(),
entry_point: "fullscreen_vertex_shader".into(),
buffers: Vec::new(),
}
} }
} }

View File

@ -14,18 +14,20 @@ pub mod core_3d;
pub mod deferred; pub mod deferred;
pub mod dof; pub mod dof;
pub mod experimental; pub mod experimental;
pub mod fullscreen_vertex_shader;
pub mod motion_blur; pub mod motion_blur;
pub mod msaa_writeback; pub mod msaa_writeback;
pub mod oit; pub mod oit;
pub mod post_process; pub mod post_process;
pub mod prepass; pub mod prepass;
mod skybox;
pub mod tonemapping; pub mod tonemapping;
pub mod upscaling; pub mod upscaling;
pub use fullscreen_vertex_shader::FullscreenShader;
pub use skybox::Skybox; pub use skybox::Skybox;
mod fullscreen_vertex_shader;
mod skybox;
/// The core pipeline prelude. /// The core pipeline prelude.
/// ///
/// This includes the most common types in this crate, re-exported for your convenience. /// This includes the most common types in this crate, re-exported for your convenience.
@ -42,7 +44,6 @@ use crate::{
deferred::copy_lighting_id::CopyDeferredLightingIdPlugin, deferred::copy_lighting_id::CopyDeferredLightingIdPlugin,
dof::DepthOfFieldPlugin, dof::DepthOfFieldPlugin,
experimental::mip_generation::MipGenerationPlugin, experimental::mip_generation::MipGenerationPlugin,
fullscreen_vertex_shader::FULLSCREEN_SHADER_HANDLE,
motion_blur::MotionBlurPlugin, motion_blur::MotionBlurPlugin,
msaa_writeback::MsaaWritebackPlugin, msaa_writeback::MsaaWritebackPlugin,
post_process::PostProcessingPlugin, post_process::PostProcessingPlugin,
@ -51,8 +52,8 @@ use crate::{
upscaling::UpscalingPlugin, upscaling::UpscalingPlugin,
}; };
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
use bevy_asset::load_internal_asset; use bevy_asset::embedded_asset;
use bevy_render::prelude::Shader; use bevy_render::RenderApp;
use oit::OrderIndependentTransparencyPlugin; use oit::OrderIndependentTransparencyPlugin;
#[derive(Default)] #[derive(Default)]
@ -60,17 +61,13 @@ pub struct CorePipelinePlugin;
impl Plugin for CorePipelinePlugin { impl Plugin for CorePipelinePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!( embedded_asset!(app, "fullscreen_vertex_shader/fullscreen.wgsl");
app,
FULLSCREEN_SHADER_HANDLE,
"fullscreen_vertex_shader/fullscreen.wgsl",
Shader::from_wgsl
);
app.register_type::<DepthPrepass>() app.register_type::<DepthPrepass>()
.register_type::<NormalPrepass>() .register_type::<NormalPrepass>()
.register_type::<MotionVectorPrepass>() .register_type::<MotionVectorPrepass>()
.register_type::<DeferredPrepass>() .register_type::<DeferredPrepass>()
.init_resource::<FullscreenShader>()
.add_plugins((Core2dPlugin, Core3dPlugin, CopyDeferredLightingIdPlugin)) .add_plugins((Core2dPlugin, Core3dPlugin, CopyDeferredLightingIdPlugin))
.add_plugins(( .add_plugins((
BlitPlugin, BlitPlugin,
@ -85,4 +82,11 @@ impl Plugin for CorePipelinePlugin {
MipGenerationPlugin, MipGenerationPlugin,
)); ));
} }
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app.init_resource::<FullscreenShader>();
}
} }

View File

@ -25,7 +25,7 @@ use bevy_render::{
view::{ExtractedView, Msaa, ViewTarget}, view::{ExtractedView, Msaa, ViewTarget},
}; };
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state; use crate::FullscreenShader;
use super::MotionBlurUniform; use super::MotionBlurUniform;
@ -34,11 +34,16 @@ pub struct MotionBlurPipeline {
pub(crate) sampler: Sampler, pub(crate) sampler: Sampler,
pub(crate) layout: BindGroupLayout, pub(crate) layout: BindGroupLayout,
pub(crate) layout_msaa: BindGroupLayout, pub(crate) layout_msaa: BindGroupLayout,
pub(crate) shader: Handle<Shader>, pub(crate) fullscreen_shader: FullscreenShader,
pub(crate) fragment_shader: Handle<Shader>,
} }
impl MotionBlurPipeline { impl MotionBlurPipeline {
pub(crate) fn new(render_device: &RenderDevice, shader: Handle<Shader>) -> Self { pub(crate) fn new(
render_device: &RenderDevice,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
) -> Self {
let mb_layout = &BindGroupLayoutEntries::sequential( let mb_layout = &BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT, ShaderStages::FRAGMENT,
( (
@ -84,7 +89,8 @@ impl MotionBlurPipeline {
sampler, sampler,
layout, layout,
layout_msaa, layout_msaa,
shader, fullscreen_shader,
fragment_shader,
} }
} }
} }
@ -93,8 +99,9 @@ impl FromWorld for MotionBlurPipeline {
fn from_world(render_world: &mut bevy_ecs::world::World) -> Self { fn from_world(render_world: &mut bevy_ecs::world::World) -> Self {
let render_device = render_world.resource::<RenderDevice>().clone(); let render_device = render_world.resource::<RenderDevice>().clone();
let shader = load_embedded_asset!(render_world, "motion_blur.wgsl"); let fullscreen_shader = render_world.resource::<FullscreenShader>().clone();
MotionBlurPipeline::new(&render_device, shader) let fragment_shader = load_embedded_asset!(render_world, "motion_blur.wgsl");
MotionBlurPipeline::new(&render_device, fullscreen_shader, fragment_shader)
} }
} }
@ -128,9 +135,9 @@ impl SpecializedRenderPipeline for MotionBlurPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("motion_blur_pipeline".into()), label: Some("motion_blur_pipeline".into()),
layout, layout,
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), 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 {

View File

@ -1,7 +1,4 @@
use crate::{ use crate::{oit::OrderIndependentTransparencySettings, FullscreenShader};
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
oit::OrderIndependentTransparencySettings,
};
use bevy_app::Plugin; use bevy_app::Plugin;
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer}; use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer};
use bevy_derive::Deref; use bevy_derive::Deref;
@ -156,6 +153,7 @@ pub fn queue_oit_resolve_pipeline(
), ),
With<OrderIndependentTransparencySettings>, With<OrderIndependentTransparencySettings>,
>, >,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
// Store the key with the id to make the clean up logic easier. // Store the key with the id to make the clean up logic easier.
// This also means it will always replace the entry if the key changes so nothing to clean up. // This also means it will always replace the entry if the key changes so nothing to clean up.
@ -176,7 +174,12 @@ pub fn queue_oit_resolve_pipeline(
} }
} }
let desc = specialize_oit_resolve_pipeline(key, &resolve_pipeline, &asset_server); let desc = specialize_oit_resolve_pipeline(
key,
&resolve_pipeline,
&fullscreen_shader,
&asset_server,
);
let pipeline_id = pipeline_cache.queue_render_pipeline(desc); let pipeline_id = pipeline_cache.queue_render_pipeline(desc);
commands.entity(e).insert(OitResolvePipelineId(pipeline_id)); commands.entity(e).insert(OitResolvePipelineId(pipeline_id));
@ -194,6 +197,7 @@ pub fn queue_oit_resolve_pipeline(
fn specialize_oit_resolve_pipeline( fn specialize_oit_resolve_pipeline(
key: OitResolvePipelineKey, key: OitResolvePipelineKey,
resolve_pipeline: &OitResolvePipeline, resolve_pipeline: &OitResolvePipeline,
fullscreen_shader: &FullscreenShader,
asset_server: &AssetServer, asset_server: &AssetServer,
) -> RenderPipelineDescriptor { ) -> RenderPipelineDescriptor {
let format = if key.hdr { let format = if key.hdr {
@ -224,7 +228,7 @@ fn specialize_oit_resolve_pipeline(
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})], })],
}), }),
vertex: fullscreen_shader_vertex_state(), vertex: fullscreen_shader.to_vertex_state(),
primitive: PrimitiveState::default(), primitive: PrimitiveState::default(),
depth_stencil: None, depth_stencil: None,
multisample: MultisampleState::default(), multisample: MultisampleState::default(),

View File

@ -44,7 +44,7 @@ use bevy_utils::prelude::default;
use crate::{ use crate::{
core_2d::graph::{Core2d, Node2d}, core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d}, core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader, FullscreenShader,
}; };
/// The handle to the default chromatic aberration lookup texture. /// The handle to the default chromatic aberration lookup texture.
@ -130,8 +130,10 @@ pub struct PostProcessingPipeline {
source_sampler: Sampler, source_sampler: Sampler,
/// Specifies how to sample the chromatic aberration gradient. /// Specifies how to sample the chromatic aberration gradient.
chromatic_aberration_lut_sampler: Sampler, chromatic_aberration_lut_sampler: Sampler,
/// The shader asset handle. /// The asset handle for the fullscreen vertex shader.
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
fragment_shader: Handle<Shader>,
} }
/// A key that uniquely identifies a built-in postprocessing pipeline. /// A key that uniquely identifies a built-in postprocessing pipeline.
@ -308,7 +310,8 @@ impl FromWorld for PostProcessingPipeline {
bind_group_layout, bind_group_layout,
source_sampler, source_sampler,
chromatic_aberration_lut_sampler, chromatic_aberration_lut_sampler,
shader: load_embedded_asset!(world, "post_process.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "post_process.wgsl"),
} }
} }
} }
@ -320,9 +323,9 @@ impl SpecializedRenderPipeline for PostProcessingPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("postprocessing".into()), label: Some("postprocessing".into()),
layout: vec![self.bind_group_layout.clone()], layout: vec![self.bind_group_layout.clone()],
vertex: fullscreen_vertex_shader::fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs: vec![], shader_defs: vec![],
entry_point: "fragment_main".into(), entry_point: "fragment_main".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -27,7 +27,7 @@ use crate::{
prepass_target_descriptors, MotionVectorPrepass, NormalPrepass, PreviousViewData, prepass_target_descriptors, MotionVectorPrepass, NormalPrepass, PreviousViewData,
PreviousViewUniforms, PreviousViewUniforms,
}, },
Skybox, FullscreenShader, Skybox,
}; };
/// This pipeline writes motion vectors to the prepass for all [`Skybox`]es. /// This pipeline writes motion vectors to the prepass for all [`Skybox`]es.
@ -38,7 +38,8 @@ use crate::{
#[derive(Resource)] #[derive(Resource)]
pub struct SkyboxPrepassPipeline { pub struct SkyboxPrepassPipeline {
bind_group_layout: BindGroupLayout, bind_group_layout: BindGroupLayout,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
/// Used to specialize the [`SkyboxPrepassPipeline`]. /// Used to specialize the [`SkyboxPrepassPipeline`].
@ -73,7 +74,8 @@ impl FromWorld for SkyboxPrepassPipeline {
), ),
), ),
), ),
shader: load_embedded_asset!(world, "skybox_prepass.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "skybox_prepass.wgsl"),
} }
} }
} }
@ -86,7 +88,7 @@ impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
label: Some("skybox_prepass_pipeline".into()), label: Some("skybox_prepass_pipeline".into()),
layout: vec![self.bind_group_layout.clone()], layout: vec![self.bind_group_layout.clone()],
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
primitive: default(), primitive: default(),
depth_stencil: Some(DepthStencilState { depth_stencil: Some(DepthStencilState {
format: CORE_3D_DEPTH_FORMAT, format: CORE_3D_DEPTH_FORMAT,
@ -101,7 +103,7 @@ impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
alpha_to_coverage_enabled: false, alpha_to_coverage_enabled: false,
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs: vec![], shader_defs: vec![],
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: prepass_target_descriptors(key.normal_prepass, true, false), targets: prepass_target_descriptors(key.normal_prepass, true, false),

View File

@ -1,4 +1,3 @@
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset, Assets, Handle}; use bevy_asset::{embedded_asset, load_embedded_asset, Assets, Handle};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
@ -28,6 +27,8 @@ mod node;
use bevy_utils::default; use bevy_utils::default;
pub use node::TonemappingNode; pub use node::TonemappingNode;
use crate::FullscreenShader;
/// 3D LUT (look up table) textures used for tonemapping /// 3D LUT (look up table) textures used for tonemapping
#[derive(Resource, Clone, ExtractResource)] #[derive(Resource, Clone, ExtractResource)]
pub struct TonemappingLuts { pub struct TonemappingLuts {
@ -112,7 +113,8 @@ impl Plugin for TonemappingPlugin {
pub struct TonemappingPipeline { pub struct TonemappingPipeline {
texture_bind_group: BindGroupLayout, texture_bind_group: BindGroupLayout,
sampler: Sampler, sampler: Sampler,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
/// Optionally enables a tonemapping shader that attempts to map linear input stimulus into a perceptually uniform image for a given [`Camera`] entity. /// Optionally enables a tonemapping shader that attempts to map linear input stimulus into a perceptually uniform image for a given [`Camera`] entity.
@ -273,9 +275,9 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("tonemapping pipeline".into()), label: Some("tonemapping pipeline".into()),
layout: vec![self.texture_bind_group.clone()], layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), 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 {
@ -319,7 +321,8 @@ impl FromWorld for TonemappingPipeline {
TonemappingPipeline { TonemappingPipeline {
texture_bind_group: tonemap_texture_bind_group, texture_bind_group: tonemap_texture_bind_group,
sampler, sampler,
shader: load_embedded_asset!(render_world, "tonemapping.wgsl"), fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "tonemapping.wgsl"),
} }
} }
} }

View File

@ -1,7 +1,5 @@
use bevy_asset::{load_embedded_asset, Handle}; use bevy_asset::{load_embedded_asset, Handle};
use bevy_core_pipeline::{ use bevy_core_pipeline::{core_3d::Camera3d, FullscreenShader};
core_3d::Camera3d, fullscreen_vertex_shader::fullscreen_shader_vertex_state,
};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
entity::Entity, entity::Entity,
@ -36,7 +34,8 @@ pub(crate) struct AtmosphereBindGroupLayouts {
pub(crate) struct RenderSkyBindGroupLayouts { pub(crate) struct RenderSkyBindGroupLayouts {
pub render_sky: BindGroupLayout, pub render_sky: BindGroupLayout,
pub render_sky_msaa: BindGroupLayout, pub render_sky_msaa: BindGroupLayout,
pub shader: Handle<Shader>, pub fullscreen_shader: FullscreenShader,
pub fragment_shader: Handle<Shader>,
} }
impl FromWorld for AtmosphereBindGroupLayouts { impl FromWorld for AtmosphereBindGroupLayouts {
@ -205,7 +204,8 @@ impl FromWorld for RenderSkyBindGroupLayouts {
Self { Self {
render_sky, render_sky,
render_sky_msaa, render_sky_msaa,
shader: load_embedded_asset!(world, "render_sky.wgsl"), fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"),
} }
} }
} }
@ -358,7 +358,7 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts {
self.render_sky_msaa.clone() self.render_sky_msaa.clone()
}], }],
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
primitive: PrimitiveState::default(), primitive: PrimitiveState::default(),
depth_stencil: None, depth_stencil: None,
multisample: MultisampleState { multisample: MultisampleState {
@ -368,7 +368,7 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts {
}, },
zero_initialize_workgroup_memory: false, zero_initialize_workgroup_memory: false,
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), shader: self.fragment_shader.clone(),
shader_defs, shader_defs,
entry_point: "main".into(), entry_point: "main".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {

View File

@ -2,7 +2,7 @@ use super::resource_manager::ResourceManager;
use bevy_asset::{weak_handle, Handle}; use bevy_asset::{weak_handle, Handle};
use bevy_core_pipeline::{ use bevy_core_pipeline::{
core_3d::CORE_3D_DEPTH_FORMAT, experimental::mip_generation::DOWNSAMPLE_DEPTH_SHADER_HANDLE, core_3d::CORE_3D_DEPTH_FORMAT, experimental::mip_generation::DOWNSAMPLE_DEPTH_SHADER_HANDLE,
fullscreen_vertex_shader::fullscreen_shader_vertex_state, FullscreenShader,
}; };
use bevy_ecs::{ use bevy_ecs::{
resource::Resource, resource::Resource,
@ -80,6 +80,8 @@ impl FromWorld for MeshletPipelines {
let remap_1d_to_2d_dispatch_layout = resource_manager let remap_1d_to_2d_dispatch_layout = resource_manager
.remap_1d_to_2d_dispatch_bind_group_layout .remap_1d_to_2d_dispatch_bind_group_layout
.clone(); .clone();
let vertex_state = world.resource::<FullscreenShader>().to_vertex_state();
let pipeline_cache = world.resource_mut::<PipelineCache>(); let pipeline_cache = world.resource_mut::<PipelineCache>();
Self { Self {
@ -400,7 +402,7 @@ impl FromWorld for MeshletPipelines {
label: Some("meshlet_resolve_depth_pipeline".into()), label: Some("meshlet_resolve_depth_pipeline".into()),
layout: vec![resolve_depth_layout], layout: vec![resolve_depth_layout],
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(), vertex: vertex_state.clone(),
primitive: PrimitiveState::default(), primitive: PrimitiveState::default(),
depth_stencil: Some(DepthStencilState { depth_stencil: Some(DepthStencilState {
format: CORE_3D_DEPTH_FORMAT, format: CORE_3D_DEPTH_FORMAT,
@ -424,7 +426,7 @@ impl FromWorld for MeshletPipelines {
label: Some("meshlet_resolve_depth_pipeline".into()), label: Some("meshlet_resolve_depth_pipeline".into()),
layout: vec![resolve_depth_shadow_view_layout], layout: vec![resolve_depth_shadow_view_layout],
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(), vertex: vertex_state.clone(),
primitive: PrimitiveState::default(), primitive: PrimitiveState::default(),
depth_stencil: Some(DepthStencilState { depth_stencil: Some(DepthStencilState {
format: CORE_3D_DEPTH_FORMAT, format: CORE_3D_DEPTH_FORMAT,
@ -449,7 +451,7 @@ impl FromWorld for MeshletPipelines {
label: Some("meshlet_resolve_material_depth_pipeline".into()), label: Some("meshlet_resolve_material_depth_pipeline".into()),
layout: vec![resolve_material_depth_layout], layout: vec![resolve_material_depth_layout],
push_constant_ranges: vec![], push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(), vertex: vertex_state,
primitive: PrimitiveState::default(), primitive: PrimitiveState::default(),
depth_stencil: Some(DepthStencilState { depth_stencil: Some(DepthStencilState {
format: TextureFormat::Depth16Unorm, format: TextureFormat::Depth16Unorm,

View File

@ -7,8 +7,8 @@ use bevy_core_pipeline::{
graph::{Core3d, Node3d}, graph::{Core3d, Node3d},
DEPTH_TEXTURE_SAMPLING_SUPPORTED, DEPTH_TEXTURE_SAMPLING_SUPPORTED,
}, },
fullscreen_vertex_shader,
prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},
FullscreenShader,
}; };
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{ use bevy_ecs::{
@ -155,7 +155,8 @@ pub struct ScreenSpaceReflectionsPipeline {
depth_nearest_sampler: Sampler, depth_nearest_sampler: Sampler,
bind_group_layout: BindGroupLayout, bind_group_layout: BindGroupLayout,
binding_arrays_are_usable: bool, binding_arrays_are_usable: bool,
shader: Handle<Shader>, fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
} }
/// A GPU buffer that stores the screen space reflection settings for each view. /// A GPU buffer that stores the screen space reflection settings for each view.
@ -397,9 +398,10 @@ impl FromWorld for ScreenSpaceReflectionsPipeline {
depth_nearest_sampler, depth_nearest_sampler,
bind_group_layout, bind_group_layout,
binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter), binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
// Even though ssr was loaded using load_shader_library, we can still access it like a // Even though ssr was loaded using load_shader_library, we can still access it like a
// normal embedded asset (so we can use it as both a library or a kernel). // normal embedded asset (so we can use it as both a library or a kernel).
shader: load_embedded_asset!(world, "ssr.wgsl"), fragment_shader: load_embedded_asset!(world, "ssr.wgsl"),
} }
} }
} }
@ -536,9 +538,9 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline {
RenderPipelineDescriptor { RenderPipelineDescriptor {
label: Some("SSR pipeline".into()), label: Some("SSR pipeline".into()),
layout: vec![mesh_view_layout.clone(), self.bind_group_layout.clone()], layout: vec![mesh_view_layout.clone(), self.bind_group_layout.clone()],
vertex: fullscreen_vertex_shader::fullscreen_shader_vertex_state(), vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: self.shader.clone(), 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 {

View File

@ -9,7 +9,7 @@
use bevy::{ use bevy::{
core_pipeline::{ core_pipeline::{
core_3d::graph::{Core3d, Node3d}, core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state, FullscreenShader,
}, },
ecs::query::QueryItem, ecs::query::QueryItem,
prelude::*, prelude::*,
@ -259,6 +259,8 @@ impl FromWorld for PostProcessPipeline {
// Get the shader handle // Get the shader handle
let shader = world.load_asset(SHADER_ASSET_PATH); let shader = world.load_asset(SHADER_ASSET_PATH);
// This will setup a fullscreen triangle for the vertex state.
let vertex_state = world.resource::<FullscreenShader>().to_vertex_state();
let pipeline_id = world let pipeline_id = world
.resource_mut::<PipelineCache>() .resource_mut::<PipelineCache>()
@ -266,8 +268,7 @@ impl FromWorld for PostProcessPipeline {
.queue_render_pipeline(RenderPipelineDescriptor { .queue_render_pipeline(RenderPipelineDescriptor {
label: Some("post_process_pipeline".into()), label: Some("post_process_pipeline".into()),
layout: vec![layout.clone()], layout: vec![layout.clone()],
// This will setup a fullscreen triangle for the vertex state vertex: vertex_state,
vertex: fullscreen_shader_vertex_state(),
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader, shader,
shader_defs: vec![], shader_defs: vec![],

View File

@ -0,0 +1,68 @@
---
title: `FULLSCREEN_SHADER_HANDLE` replaced with `FullscreenShader`
pull_requests: [19426]
---
`FULLSCREEN_SHADER_HANDLE` and `fullscreen_shader_vertex_state` have been replaced by the
`FullscreenShader` resource. Users of either of these will need to call `FullscreenShader::shader`
or `FullscreenShader::to_vertex_state` respectively. You may need to clone `FullscreenShader` out of
the render world to store an instance that you can use later (e.g., if you are attempting to use the
fullscreen shader inside a `SpecializedRenderPipeline` implementation).
For example, if your previous code looked like this:
```rust
struct MyPipeline {
some_bind_group: BindGroupLayout,
}
impl FromWorld for MyPipeline {
fn from_world(render_world: &mut World) -> Self {
let some_bind_group = /* ... RenderDevice stuff */;
Self {
some_bind_group,
}
}
}
impl SpecializedRenderPipeline for MyPipeline {
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
RenderPipelineDescriptor {
vertex: fullscreen_shader_vertex_state(),
// ... other stuff
}
}
}
```
You can migrate your code to:
```rust
struct MyPipeline {
some_bind_group: BindGroupLayout,
fullscreen_shader: FullscreenShader,
}
impl FromWorld for MyPipeline {
fn from_world(render_world: &mut World) -> Self {
let some_bind_group = /* ... RenderDevice stuff */;
Self {
some_bind_group,
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
}
}
}
impl SpecializedRenderPipeline for MyPipeline {
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
RenderPipelineDescriptor {
vertex: self.fullscreen_shader.to_vertex_state(),
// ... other stuff
}
}
}
```
This is just one example. Pipelines may be initialized in different ways, but the primary strategy
is clone out the `FullscreenShader` resource from the render world, and call `to_vertex_state` to
use it as the vertex shader.