use bevy_core_pipeline::FullscreenShader;
use super::{
downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT,
};
use bevy_asset::{load_embedded_asset, AssetServer, Handle};
use bevy_ecs::{
prelude::{Component, Entity},
resource::Resource,
system::{Commands, Query, Res, ResMut},
};
use bevy_render::{
render_resource::{
binding_types::{sampler, texture_2d, uniform_buffer},
*,
},
view::ViewTarget,
};
use bevy_shader::Shader;
use bevy_utils::default;
#[derive(Component)]
pub struct UpsamplingPipelineIds {
pub id_main: CachedRenderPipelineId,
pub id_final: CachedRenderPipelineId,
}
#[derive(Resource)]
pub struct BloomUpsamplingPipeline {
pub bind_group_layout: BindGroupLayoutDescriptor,
pub fullscreen_shader: FullscreenShader,
pub fragment_shader: Handle<Shader>,
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct BloomUpsamplingPipelineKeys {
composite_mode: BloomCompositeMode,
final_pipeline: bool,
}
pub fn init_bloom_upscaling_pipeline(
mut commands: Commands,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
) {
let bind_group_layout = BindGroupLayoutDescriptor::new(
"bloom_upsampling_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<BloomUniforms>(true),
),
),
);
commands.insert_resource(BloomUpsamplingPipeline {
bind_group_layout,
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "bloom.wgsl"),
});
}
impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
type Key = BloomUpsamplingPipelineKeys;
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let texture_format = if key.final_pipeline {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
BLOOM_TEXTURE_FORMAT
};
let color_blend = match key.composite_mode {
BloomCompositeMode::EnergyConserving => {
BlendComponent {
src_factor: BlendFactor::Constant,
dst_factor: BlendFactor::OneMinusConstant,
operation: BlendOperation::Add,
}
}
BloomCompositeMode::Additive => BlendComponent {
src_factor: BlendFactor::Constant,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
},
};
RenderPipelineDescriptor {
label: Some("bloom_upsampling_pipeline".into()),
layout: vec![self.bind_group_layout.clone()],
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.fragment_shader.clone(),
entry_point: Some("upsample".into()),
targets: vec![Some(ColorTargetState {
format: texture_format,
blend: Some(BlendState {
color: color_blend,
alpha: BlendComponent {
src_factor: BlendFactor::Zero,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
},
}),
write_mask: ColorWrites::ALL,
})],
..default()
}),
..default()
}
}
}
pub fn prepare_upsampling_pipeline(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<BloomUpsamplingPipeline>>,
pipeline: Res<BloomUpsamplingPipeline>,
views: Query<(Entity, &Bloom)>,
) {
for (entity, bloom) in &views {
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&pipeline,
BloomUpsamplingPipelineKeys {
composite_mode: bloom.composite_mode,
final_pipeline: false,
},
);
let pipeline_final_id = pipelines.specialize(
&pipeline_cache,
&pipeline,
BloomUpsamplingPipelineKeys {
composite_mode: bloom.composite_mode,
final_pipeline: true,
},
);
commands.entity(entity).insert(UpsamplingPipelineIds {
id_main: pipeline_id,
id_final: pipeline_final_id,
});
}
}