migrate auto_exposure

This commit is contained in:
Emerson Coskey 2025-07-13 20:04:19 -07:00
parent 498b1099a9
commit f9f0451a86
No known key found for this signature in database
3 changed files with 65 additions and 46 deletions

View File

@ -5,9 +5,7 @@ use bevy_render::{
extract_component::ExtractComponentPlugin, extract_component::ExtractComponentPlugin,
render_asset::RenderAssetPlugin, render_asset::RenderAssetPlugin,
render_graph::RenderGraphExt, render_graph::RenderGraphExt,
render_resource::{ render_resource::{Buffer, BufferDescriptor, BufferUsages, PipelineCache},
Buffer, BufferDescriptor, BufferUsages, PipelineCache, SpecializedComputePipelines,
},
renderer::RenderDevice, renderer::RenderDevice,
ExtractSchedule, Render, RenderApp, RenderSystems, ExtractSchedule, Render, RenderApp, RenderSystems,
}; };
@ -59,7 +57,6 @@ impl Plugin for AutoExposurePlugin {
}; };
render_app render_app
.init_resource::<SpecializedComputePipelines<AutoExposurePipeline>>()
.init_resource::<AutoExposureBuffers>() .init_resource::<AutoExposureBuffers>()
.add_systems(ExtractSchedule, extract_buffers) .add_systems(ExtractSchedule, extract_buffers)
.add_systems( .add_systems(
@ -104,15 +101,16 @@ impl FromWorld for AutoExposureResources {
fn queue_view_auto_exposure_pipelines( fn queue_view_auto_exposure_pipelines(
mut commands: Commands, mut commands: Commands,
pipeline_cache: Res<PipelineCache>, pipeline_cache: Res<PipelineCache>,
mut compute_pipelines: ResMut<SpecializedComputePipelines<AutoExposurePipeline>>, mut auto_exposure_pipeline: ResMut<AutoExposurePipeline>,
pipeline: Res<AutoExposurePipeline>,
view_targets: Query<(Entity, &AutoExposure)>, view_targets: Query<(Entity, &AutoExposure)>,
) { ) -> Result<(), BevyError> {
for (entity, auto_exposure) in view_targets.iter() { for (entity, auto_exposure) in view_targets.iter() {
let histogram_pipeline = let histogram_pipeline = auto_exposure_pipeline
compute_pipelines.specialize(&pipeline_cache, &pipeline, AutoExposurePass::Histogram); .variants
let average_pipeline = .specialize(&pipeline_cache, AutoExposurePass::Histogram)?;
compute_pipelines.specialize(&pipeline_cache, &pipeline, AutoExposurePass::Average); let average_pipeline = auto_exposure_pipeline
.variants
.specialize(&pipeline_cache, AutoExposurePass::Average)?;
commands.entity(entity).insert(ViewAutoExposurePipeline { commands.entity(entity).insert(ViewAutoExposurePipeline {
histogram_pipeline, histogram_pipeline,
@ -121,4 +119,5 @@ fn queue_view_auto_exposure_pipelines(
metering_mask: auto_exposure.metering_mask.clone(), metering_mask: auto_exposure.metering_mask.clone(),
}); });
} }
Ok(())
} }

View File

@ -100,7 +100,7 @@ impl Node for AutoExposureNode {
let compute_bind_group = render_context.render_device().create_bind_group( let compute_bind_group = render_context.render_device().create_bind_group(
None, None,
&pipeline.histogram_layout, &pipeline.layout,
&BindGroupEntries::sequential(( &BindGroupEntries::sequential((
&globals_buffer.buffer, &globals_buffer.buffer,
&auto_exposure_buffers.settings, &auto_exposure_buffers.settings,

View File

@ -12,13 +12,16 @@ use bevy_render::{
}; };
use bevy_utils::default; use bevy_utils::default;
use core::num::NonZero; use core::num::NonZero;
use std::result::Result;
#[derive(Resource)] #[derive(Resource)]
pub struct AutoExposurePipeline { pub struct AutoExposurePipeline {
pub histogram_layout: BindGroupLayout, pub layout: BindGroupLayout,
pub histogram_shader: Handle<Shader>, pub variants: SpecializedCache<ComputePipeline, AutoExposureSpecializer>,
} }
pub struct AutoExposureSpecializer;
#[derive(Component)] #[derive(Component)]
pub struct ViewAutoExposurePipeline { pub struct ViewAutoExposurePipeline {
pub histogram_pipeline: CachedComputePipelineId, pub histogram_pipeline: CachedComputePipelineId,
@ -39,7 +42,7 @@ pub struct AutoExposureUniform {
pub(super) exponential_transition_distance: f32, pub(super) exponential_transition_distance: f32,
} }
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone, SpecializerKey)]
pub enum AutoExposurePass { pub enum AutoExposurePass {
Histogram, Histogram,
Average, Average,
@ -51,43 +54,60 @@ impl FromWorld for AutoExposurePipeline {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>(); let render_device = world.resource::<RenderDevice>();
Self { let layout = render_device.create_bind_group_layout(
histogram_layout: render_device.create_bind_group_layout( "compute histogram bind group",
"compute histogram bind group", &BindGroupLayoutEntries::sequential(
&BindGroupLayoutEntries::sequential( ShaderStages::COMPUTE,
ShaderStages::COMPUTE, (
( uniform_buffer::<GlobalsUniform>(false),
uniform_buffer::<GlobalsUniform>(false), uniform_buffer::<AutoExposureUniform>(false),
uniform_buffer::<AutoExposureUniform>(false), texture_2d(TextureSampleType::Float { filterable: false }),
texture_2d(TextureSampleType::Float { filterable: false }), texture_2d(TextureSampleType::Float { filterable: false }),
texture_2d(TextureSampleType::Float { filterable: false }), texture_1d(TextureSampleType::Float { filterable: false }),
texture_1d(TextureSampleType::Float { filterable: false }), uniform_buffer::<AutoExposureCompensationCurveUniform>(false),
uniform_buffer::<AutoExposureCompensationCurveUniform>(false), storage_buffer_sized(false, NonZero::<u64>::new(HISTOGRAM_BIN_COUNT * 4)),
storage_buffer_sized(false, NonZero::<u64>::new(HISTOGRAM_BIN_COUNT * 4)), storage_buffer_sized(false, NonZero::<u64>::new(4)),
storage_buffer_sized(false, NonZero::<u64>::new(4)), storage_buffer::<ViewUniform>(true),
storage_buffer::<ViewUniform>(true),
),
), ),
), ),
histogram_shader: load_embedded_asset!(world, "auto_exposure.wgsl"), );
}
let shader = load_embedded_asset!(world, "auto_exposure.wgsl");
let base_descriptor = ComputePipelineDescriptor {
layout: vec![layout.clone()],
shader,
..default()
};
let variants = SpecializedCache::new(AutoExposureSpecializer, None, base_descriptor);
Self { layout, variants }
} }
} }
impl SpecializedComputePipeline for AutoExposurePipeline { impl Specializer<ComputePipeline> for AutoExposureSpecializer {
type Key = AutoExposurePass; type Key = AutoExposurePass;
fn specialize(&self, pass: AutoExposurePass) -> ComputePipelineDescriptor { fn specialize(
ComputePipelineDescriptor { &self,
label: Some("luminance compute pipeline".into()), key: Self::Key,
layout: vec![self.histogram_layout.clone()], descriptor: &mut ComputePipelineDescriptor,
shader: self.histogram_shader.clone(), ) -> Result<Canonical<Self::Key>, BevyError> {
shader_defs: vec![], let (label, entry_point) = match key {
entry_point: Some(match pass { AutoExposurePass::Histogram => (
AutoExposurePass::Histogram => "compute_histogram".into(), "auto_exposure_compute_histogram".into(),
AutoExposurePass::Average => "compute_average".into(), "compute_histogram".into(),
}), ),
..default() AutoExposurePass::Average => (
} "auto_exposure_compute_average".into(),
"compute_average".into(),
),
};
descriptor.label = Some(label);
descriptor.entry_point = Some(entry_point);
Ok(key)
} }
} }