migrate blit

This commit is contained in:
Emerson Coskey 2025-07-17 10:35:41 -07:00
parent 88b3b5e71e
commit 9d41372966
No known key found for this signature in database
3 changed files with 63 additions and 47 deletions

View File

@ -1,6 +1,8 @@
use core::{ops::Deref, result::Result};
use crate::FullscreenShader;
use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer};
use bevy_ecs::prelude::*;
use bevy_render::{
render_resource::{
@ -24,8 +26,7 @@ impl Plugin for BlitPlugin {
};
render_app
.allow_ambiguous_resource::<SpecializedRenderPipelines<BlitPipeline>>()
.init_resource::<SpecializedRenderPipelines<BlitPipeline>>()
.allow_ambiguous_resource::<BlitPipeline>()
.add_systems(RenderStartup, init_blit_pipeline);
}
}
@ -34,8 +35,7 @@ impl Plugin for BlitPlugin {
pub struct BlitPipeline {
pub layout: BindGroupLayout,
pub sampler: Sampler,
pub fullscreen_shader: FullscreenShader,
pub fragment_shader: Handle<Shader>,
pub specialized_cache: SpecializedCache<RenderPipeline, BlitSpecializer>,
}
pub fn init_blit_pipeline(
@ -57,11 +57,23 @@ pub fn init_blit_pipeline(
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
let base_descriptor = RenderPipelineDescriptor {
label: Some("blit pipeline".into()),
layout: vec![layout.clone()],
vertex: fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: load_embedded_asset!(asset_server.deref(), "blit.wgsl"),
..default()
}),
..default()
};
let specialized_cache = SpecializedCache::new(BlitSpecializer, base_descriptor);
commands.insert_resource(BlitPipeline {
layout,
sampler,
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "blit.wgsl"),
specialized_cache,
});
}
@ -79,35 +91,34 @@ impl BlitPipeline {
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct BlitPipelineKey {
pub struct BlitSpecializer;
impl Specializer<RenderPipeline> for BlitSpecializer {
type Key = BlitKey;
fn specialize(
&self,
key: Self::Key,
descriptor: &mut <RenderPipeline as Specializable>::Descriptor,
) -> Result<Canonical<Self::Key>, BevyError> {
descriptor.multisample.count = key.samples;
descriptor.fragment_mut()?.set_target(
0,
ColorTargetState {
format: key.texture_format,
blend: key.blend_state,
write_mask: ColorWrites::ALL,
},
);
Ok(key)
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy, SpecializerKey)]
pub struct BlitKey {
pub texture_format: TextureFormat,
pub blend_state: Option<BlendState>,
pub samples: u32,
}
impl SpecializedRenderPipeline for BlitPipeline {
type Key = BlitPipelineKey;
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
RenderPipelineDescriptor {
label: Some("blit pipeline".into()),
layout: vec![self.layout.clone()],
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.fragment_shader.clone(),
targets: vec![Some(ColorTargetState {
format: key.texture_format,
blend: key.blend_state,
write_mask: ColorWrites::ALL,
})],
..default()
}),
multisample: MultisampleState {
count: key.samples,
..default()
},
..default()
}
}
}

View File

@ -1,5 +1,5 @@
use crate::{
blit::{BlitPipeline, BlitPipelineKey},
blit::{BlitKey, BlitPipeline},
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
};
@ -119,22 +119,23 @@ pub struct MsaaWritebackBlitPipeline(CachedRenderPipelineId);
fn prepare_msaa_writeback_pipelines(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<BlitPipeline>>,
blit_pipeline: Res<BlitPipeline>,
mut blit_pipeline: ResMut<BlitPipeline>,
view_targets: Query<(Entity, &ViewTarget, &ExtractedCamera, &Msaa)>,
) {
) -> Result<(), BevyError> {
for (entity, view_target, camera, msaa) in view_targets.iter() {
// only do writeback if writeback is enabled for the camera and this isn't the first camera in the target,
// as there is nothing to write back for the first camera.
if msaa.samples() > 1 && camera.msaa_writeback && camera.sorted_camera_index_for_target > 0
{
let key = BlitPipelineKey {
let key = BlitKey {
texture_format: view_target.main_texture_format(),
samples: msaa.samples(),
blend_state: None,
};
let pipeline = pipelines.specialize(&pipeline_cache, &blit_pipeline, key);
let pipeline = blit_pipeline
.specialized_cache
.specialize(&pipeline_cache, key)?;
commands
.entity(entity)
.insert(MsaaWritebackBlitPipeline(pipeline));
@ -146,4 +147,5 @@ fn prepare_msaa_writeback_pipelines(
.remove::<MsaaWritebackBlitPipeline>();
}
}
Ok(())
}

View File

@ -1,4 +1,4 @@
use crate::blit::{BlitPipeline, BlitPipelineKey};
use crate::blit::{BlitKey, BlitPipeline};
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_platform::collections::HashSet;
@ -39,10 +39,9 @@ pub struct ViewUpscalingPipeline(CachedRenderPipelineId);
fn prepare_view_upscaling_pipelines(
mut commands: Commands,
mut pipeline_cache: ResMut<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<BlitPipeline>>,
blit_pipeline: Res<BlitPipeline>,
mut blit_pipeline: ResMut<BlitPipeline>,
view_targets: Query<(Entity, &ViewTarget, Option<&ExtractedCamera>)>,
) {
) -> Result<(), BevyError> {
let mut output_textures = <HashSet<_>>::default();
for (entity, view_target, camera) in view_targets.iter() {
let out_texture_id = view_target.out_texture().id();
@ -73,12 +72,14 @@ fn prepare_view_upscaling_pipelines(
None
};
let key = BlitPipelineKey {
let key = BlitKey {
texture_format: view_target.out_texture_format(),
blend_state,
samples: 1,
};
let pipeline = pipelines.specialize(&pipeline_cache, &blit_pipeline, key);
let pipeline = blit_pipeline
.specialized_cache
.specialize(&pipeline_cache, key)?;
// Ensure the pipeline is loaded before continuing the frame to prevent frames without any GPU work submitted
pipeline_cache.block_on_render_pipeline(pipeline);
@ -87,4 +88,6 @@ fn prepare_view_upscaling_pipelines(
.entity(entity)
.insert(ViewUpscalingPipeline(pipeline));
}
Ok(())
}