use super::{
downsampling_pipeline::BloomUniforms, BloomCompositeMode, BloomSettings, BLOOM_SHADER_HANDLE,
BLOOM_TEXTURE_FORMAT,
};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_ecs::{
prelude::{Component, Entity},
system::{Commands, Query, Res, ResMut, Resource},
world::{FromWorld, World},
};
use bevy_render::{
render_resource::{
binding_types::{sampler, texture_2d, uniform_buffer},
*,
},
renderer::RenderDevice,
view::ViewTarget,
};
#[derive(Component)]
pub struct UpsamplingPipelineIds {
pub id_main: CachedRenderPipelineId,
pub id_final: CachedRenderPipelineId,
}
#[derive(Resource)]
pub struct BloomUpsamplingPipeline {
pub bind_group_layout: BindGroupLayout,
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct BloomUpsamplingPipelineKeys {
composite_mode: BloomCompositeMode,
final_pipeline: bool,
}
impl FromWorld for BloomUpsamplingPipeline {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
let bind_group_layout = render_device.create_bind_group_layout(
"bloom_upsampling_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<BloomUniforms>(true),
),
),
);
BloomUpsamplingPipeline { bind_group_layout }
}
}
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: fullscreen_shader_vertex_state(),
fragment: Some(FragmentState {
shader: BLOOM_SHADER_HANDLE,
shader_defs: vec![],
entry_point: "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,
})],
}),
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState::default(),
push_constant_ranges: Vec::new(),
}
}
}
pub fn prepare_upsampling_pipeline(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<BloomUpsamplingPipeline>>,
pipeline: Res<BloomUpsamplingPipeline>,
views: Query<(Entity, &BloomSettings)>,
) {
for (entity, settings) in &views {
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&pipeline,
BloomUpsamplingPipelineKeys {
composite_mode: settings.composite_mode,
final_pipeline: false,
},
);
let pipeline_final_id = pipelines.specialize(
&pipeline_cache,
&pipeline,
BloomUpsamplingPipelineKeys {
composite_mode: settings.composite_mode,
final_pipeline: true,
},
);
commands.entity(entity).insert(UpsamplingPipelineIds {
id_main: pipeline_id,
id_final: pipeline_final_id,
});
}
}