Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 67 additions & 62 deletions crates/bevy_core_pipeline/src/skybox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_camera::Exposure;
use bevy_ecs::{
error::BevyError,
prelude::{Component, Entity},
query::{QueryItem, With},
reflect::ReflectComponent,
Expand All @@ -27,7 +28,6 @@ use bevy_render::{
view::{ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniforms},
Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_shader::Shader;
use bevy_transform::components::Transform;
use bevy_utils::default;
use prepass::SkyboxPrepassPipeline;
Expand Down Expand Up @@ -55,7 +55,6 @@ impl Plugin for SkyboxPlugin {
return;
};
render_app
.init_resource::<SpecializedRenderPipelines<SkyboxPipeline>>()
.init_resource::<SpecializedRenderPipelines<SkyboxPrepassPipeline>>()
.init_resource::<PreviousViewUniforms>()
.add_systems(
Expand Down Expand Up @@ -150,55 +149,36 @@ pub struct SkyboxUniforms {
#[derive(Resource)]
struct SkyboxPipeline {
bind_group_layout: BindGroupLayoutDescriptor,
shader: Handle<Shader>,
variants: Variants<RenderPipeline, SkyboxPipelineSpecializer>,
}

impl SkyboxPipeline {
fn new(shader: Handle<Shader>) -> Self {
Self {
bind_group_layout: BindGroupLayoutDescriptor::new(
"skybox_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_cube(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<ViewUniform>(true)
.visibility(ShaderStages::VERTEX_FRAGMENT),
uniform_buffer::<SkyboxUniforms>(true),
),
),
fn init_skybox_pipeline(mut commands: Commands, asset_server: Res<AssetServer>) {
let bind_group_layout = BindGroupLayoutDescriptor::new(
"skybox_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_cube(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
uniform_buffer::<SkyboxUniforms>(true),
),
shader,
}
}
}
),
);

fn init_skybox_pipeline(mut commands: Commands, asset_server: Res<AssetServer>) {
let shader = load_embedded_asset!(asset_server.as_ref(), "skybox.wgsl");
commands.insert_resource(SkyboxPipeline::new(shader));
}

#[derive(PartialEq, Eq, Hash, Clone, Copy)]
struct SkyboxPipelineKey {
hdr: bool,
samples: u32,
depth_format: TextureFormat,
}

impl SpecializedRenderPipeline for SkyboxPipeline {
type Key = SkyboxPipelineKey;

fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let variants = Variants::new(
SkyboxPipelineSpecializer,
RenderPipelineDescriptor {
label: Some("skybox_pipeline".into()),
layout: vec![self.bind_group_layout.clone()],
layout: vec![bind_group_layout.clone()],
vertex: VertexState {
shader: self.shader.clone(),
shader: shader.clone(),
..default()
},
depth_stencil: Some(DepthStencilState {
format: key.depth_format,
format: TextureFormat::R8Unorm, // placeholder.
depth_write_enabled: false,
depth_compare: CompareFunction::GreaterEqual,
stencil: StencilState {
Expand All @@ -213,27 +193,53 @@ impl SpecializedRenderPipeline for SkyboxPipeline {
clamp: 0.0,
},
}),
multisample: MultisampleState {
count: key.samples,
mask: !0,
alpha_to_coverage_enabled: false,
},
fragment: Some(FragmentState {
shader: self.shader.clone(),
targets: vec![Some(ColorTargetState {
format: if key.hdr {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
},
// BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases.
blend: None,
write_mask: ColorWrites::ALL,
})],
shader,
..default()
}),
..default()
}
},
);

commands.insert_resource(SkyboxPipeline {
bind_group_layout,
variants,
});
}

#[derive(PartialEq, Eq, Hash, Clone, Copy, SpecializerKey)]
struct SkyboxPipelineKey {
hdr: bool,
samples: u32,
depth_format: TextureFormat,
}

struct SkyboxPipelineSpecializer;

impl Specializer<RenderPipeline> for SkyboxPipelineSpecializer {
type Key = SkyboxPipelineKey;

fn specialize(
&self,
key: Self::Key,
descriptor: &mut RenderPipelineDescriptor,
) -> Result<Canonical<Self::Key>, BevyError> {
descriptor.depth_stencil_mut()?.format = key.depth_format;
descriptor.multisample.count = key.samples;
descriptor.fragment_mut()?.set_target(
0,
ColorTargetState {
format: if key.hdr {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
},
blend: None,
write_mask: ColorWrites::ALL,
},
);

Ok(key)
}
}

Expand All @@ -243,25 +249,24 @@ pub struct SkyboxPipelineId(pub CachedRenderPipelineId);
fn prepare_skybox_pipelines(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<SkyboxPipeline>>,
pipeline: Res<SkyboxPipeline>,
mut pipeline: ResMut<SkyboxPipeline>,
views: Query<(Entity, &ExtractedView, &Msaa), With<Skybox>>,
) {
) -> Result<(), BevyError> {
for (entity, view, msaa) in &views {
let pipeline_id = pipelines.specialize(
let pipeline_id = pipeline.variants.specialize(
&pipeline_cache,
&pipeline,
SkyboxPipelineKey {
hdr: view.hdr,
samples: msaa.samples(),
depth_format: CORE_3D_DEPTH_FORMAT,
},
);
)?;

commands
.entity(entity)
.insert(SkyboxPipelineId(pipeline_id));
}
Ok(())
}

#[derive(Component)]
Expand Down
10 changes: 10 additions & 0 deletions crates/bevy_render/src/render_resource/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,21 @@ pub struct RenderPipelineDescriptor {
#[error("RenderPipelineDescriptor has no FragmentState configured")]
pub struct NoFragmentStateError;

#[derive(Copy, Clone, Debug, Error)]
#[error("RenderPipelineDescriptor has no DepthStencilState configured")]
pub struct NoDepthStencilStateError;

impl RenderPipelineDescriptor {
pub fn fragment_mut(&mut self) -> Result<&mut FragmentState, NoFragmentStateError> {
self.fragment.as_mut().ok_or(NoFragmentStateError)
}

pub fn depth_stencil_mut(
&mut self,
) -> Result<&mut DepthStencilState, NoDepthStencilStateError> {
self.depth_stencil.as_mut().ok_or(NoDepthStencilStateError)
}

pub fn set_layout(&mut self, index: usize, layout: BindGroupLayoutDescriptor) {
filling_set_at(&mut self.layout, index, bevy_utils::default(), layout);
}
Expand Down