Skip to content

Commit

Permalink
Split render pipleline
Browse files Browse the repository at this point in the history
  • Loading branch information
ManevilleF committed Dec 4, 2022
1 parent 6d3766a commit 9e93770
Show file tree
Hide file tree
Showing 6 changed files with 587 additions and 557 deletions.
8 changes: 4 additions & 4 deletions crates/bevy_sprite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ impl Plugin for SpritePlugin {
.add_render_command::<Transparent2d, DrawSprite>()
.add_system_to_stage(
RenderStage::Extract,
render::extract_sprites.label(SpriteSystem::ExtractSprites),
render::extract::extract_sprites.label(SpriteSystem::ExtractSprites),
)
.add_system_to_stage(RenderStage::Extract, render::extract_sprite_events)
.add_system_to_stage(RenderStage::Prepare, render::prepare_sprites)
.add_system_to_stage(RenderStage::Queue, queue_sprites);
.add_system_to_stage(RenderStage::Extract, render::extract::extract_sprite_events)
.add_system_to_stage(RenderStage::Prepare, render::prepare::prepare_sprites)
.add_system_to_stage(RenderStage::Queue, render::queue::queue_sprites);
};
}
}
87 changes: 87 additions & 0 deletions crates/bevy_sprite/src/render/draw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use super::{ImageBindGroups, SpriteBatch, SpriteMeta};
use bevy_asset::Handle;
use bevy_ecs::prelude::*;
use bevy_ecs::system::{
lifetimeless::{Read, SQuery, SRes},
SystemParamItem,
};
use bevy_render::{
render_phase::{
BatchedPhaseItem, EntityRenderCommand, RenderCommand, RenderCommandResult, SetItemPipeline,
TrackedRenderPass,
},
view::ViewUniformOffset,
};

pub type DrawSprite = (
SetItemPipeline,
SetSpriteViewBindGroup<0>,
SetSpriteTextureBindGroup<1>,
DrawSpriteBatch,
);

pub struct SetSpriteViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetSpriteViewBindGroup<I> {
type Param = (SRes<SpriteMeta>, SQuery<Read<ViewUniformOffset>>);

fn render<'w>(
view: Entity,
_item: Entity,
(sprite_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let view_uniform = view_query.get(view).unwrap();
pass.set_bind_group(
I,
sprite_meta.into_inner().view_bind_group.as_ref().unwrap(),
&[view_uniform.offset],
);
RenderCommandResult::Success
}
}
pub struct SetSpriteTextureBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> {
type Param = (SRes<ImageBindGroups>, SQuery<Read<SpriteBatch>>);

fn render<'w>(
_view: Entity,
item: Entity,
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let sprite_batch = query_batch.get(item).unwrap();
let image_bind_groups = image_bind_groups.into_inner();

pass.set_bind_group(
I,
image_bind_groups
.values
.get(&Handle::weak(sprite_batch.image_handle_id))
.unwrap(),
&[],
);
RenderCommandResult::Success
}
}

pub struct DrawSpriteBatch;
impl<P: BatchedPhaseItem> RenderCommand<P> for DrawSpriteBatch {
type Param = (SRes<SpriteMeta>, SQuery<Read<SpriteBatch>>);

fn render<'w>(
_view: Entity,
item: &P,
(sprite_meta, query_batch): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let sprite_batch = query_batch.get(item.entity()).unwrap();
let sprite_meta = sprite_meta.into_inner();
if sprite_batch.colored {
pass.set_vertex_buffer(0, sprite_meta.colored_vertices.buffer().unwrap().slice(..));
} else {
pass.set_vertex_buffer(0, sprite_meta.vertices.buffer().unwrap().slice(..));
}
pass.draw(item.batch_range().as_ref().unwrap().clone(), 0..1);
RenderCommandResult::Success
}
}
120 changes: 120 additions & 0 deletions crates/bevy_sprite/src/render/extract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use crate::{Sprite, TextureAtlas, TextureAtlasSprite};
use bevy_asset::{AssetEvent, Assets, Handle, HandleId};
use bevy_ecs::prelude::*;
use bevy_math::{Rect, Vec2};
use bevy_render::prelude::{Color, ComputedVisibility, Image};
use bevy_render::Extract;
use bevy_transform::prelude::GlobalTransform;

#[derive(Clone, Copy)]
pub struct ExtractedSprite {
pub entity: Entity,
pub transform: GlobalTransform,
pub color: Color,
/// Select an area of the texture
pub rect: Option<Rect>,
/// Change the on-screen size of the sprite
pub custom_size: Option<Vec2>,
/// Handle to the `Image` of this sprite
/// PERF: storing a `HandleId` instead of `Handle<Image>` enables some optimizations (`ExtractedSprite` becomes `Copy` and doesn't need to be dropped)
pub image_handle_id: HandleId,
pub flip_x: bool,
pub flip_y: bool,
pub anchor: Vec2,
}

#[derive(Resource, Default)]
pub struct ExtractedSprites {
pub sprites: Vec<ExtractedSprite>,
}

#[derive(Resource, Default)]
pub struct SpriteAssetEvents {
pub images: Vec<AssetEvent<Image>>,
}

pub fn extract_sprite_events(
mut events: ResMut<SpriteAssetEvents>,
mut image_events: Extract<EventReader<AssetEvent<Image>>>,
) {
let SpriteAssetEvents { ref mut images } = *events;
images.clear();

for image in image_events.iter() {
// AssetEvent: !Clone
images.push(match image {
AssetEvent::Created { handle } => AssetEvent::Created {
handle: handle.clone_weak(),
},
AssetEvent::Modified { handle } => AssetEvent::Modified {
handle: handle.clone_weak(),
},
AssetEvent::Removed { handle } => AssetEvent::Removed {
handle: handle.clone_weak(),
},
});
}
}

pub fn extract_sprites(
mut extracted_sprites: ResMut<ExtractedSprites>,
texture_atlases: Extract<Res<Assets<TextureAtlas>>>,
sprite_query: Extract<
Query<(
Entity,
&ComputedVisibility,
&Sprite,
&GlobalTransform,
&Handle<Image>,
)>,
>,
atlas_query: Extract<
Query<(
Entity,
&ComputedVisibility,
&TextureAtlasSprite,
&GlobalTransform,
&Handle<TextureAtlas>,
)>,
>,
) {
for (entity, visibility, sprite, transform, handle) in sprite_query.iter() {
if !visibility.is_visible() {
continue;
}
// PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive
extracted_sprites.sprites.push(ExtractedSprite {
entity,
color: sprite.color,
transform: *transform,
rect: sprite.rect,
// Pass the custom size
custom_size: sprite.custom_size,
flip_x: sprite.flip_x,
flip_y: sprite.flip_y,
image_handle_id: handle.id(),
anchor: sprite.anchor.as_vec(),
});
}
for (entity, visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() {
if !visibility.is_visible() {
continue;
}
if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) {
let rect = Some(texture_atlas.textures[atlas_sprite.index]);
extracted_sprites.sprites.push(ExtractedSprite {
entity,
color: atlas_sprite.color,
transform: *transform,
// Select the area in the texture atlas
rect,
// Pass the custom size
custom_size: atlas_sprite.custom_size,
flip_x: atlas_sprite.flip_x,
flip_y: atlas_sprite.flip_y,
image_handle_id: texture_atlas.texture.id(),
anchor: atlas_sprite.anchor.as_vec(),
});
}
}
}
Loading

0 comments on commit 9e93770

Please sign in to comment.