From f5ab3e211eb6da24a8c74c9e4abd8fb00588d6bf Mon Sep 17 00:00:00 2001 From: James Bell Date: Sun, 7 Jan 2024 13:46:35 -0500 Subject: [PATCH] Added batch saving --- Cargo.lock | 37 ++++++++++++++++++ Cargo.toml | 1 + crates/bevy_tiles_render/Cargo.toml | 1 + .../bevy_tiles_render/examples/hello_tile.rs | 12 +++++- .../bevy_tiles_render/src/chunk/internal.rs | 10 ++++- crates/bevy_tiles_render/src/cleanup.rs | 38 +++++++++++++++++++ crates/bevy_tiles_render/src/extract.rs | 28 +++++++++++--- crates/bevy_tiles_render/src/lib.rs | 11 +++++- crates/bevy_tiles_render/src/maps/internal.rs | 10 ++++- crates/bevy_tiles_render/src/queue.rs | 24 ++++++------ crates/bevy_tiles_render/src/tiles_render.rs | 6 --- 11 files changed, 148 insertions(+), 30 deletions(-) create mode 100644 crates/bevy_tiles_render/src/cleanup.rs delete mode 100644 crates/bevy_tiles_render/src/tiles_render.rs diff --git a/Cargo.lock b/Cargo.lock index e7f0449..9ca2fca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1000,6 +1000,7 @@ dependencies = [ "aery", "bevy", "bevy_tiles", + "rand", "rstest", ] @@ -2881,6 +2882,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -2945,6 +2952,36 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17fd96390ed3feda12e1dfe2645ed587e0bea749e319333f104a33ff62f77a0b" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "range-alloc" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index 4def0ad..6257fbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ aery = "0.5.1" bevy = {version = "0.12.1", default-features = false} rstest = "0.18.2" bimap = "0.6.3" +rand = "0.8.5" [workspace.lints.clippy] type_complexity = "allow" diff --git a/crates/bevy_tiles_render/Cargo.toml b/crates/bevy_tiles_render/Cargo.toml index a0f0d02..3f5016b 100644 --- a/crates/bevy_tiles_render/Cargo.toml +++ b/crates/bevy_tiles_render/Cargo.toml @@ -31,6 +31,7 @@ bevy_tiles = {path = "../bevy_tiles"} [dev-dependencies] rstest = {workspace = true} bevy = {workspace = true, default-features = true} +rand = {workspace = true} [lints] workspace = true \ No newline at end of file diff --git a/crates/bevy_tiles_render/examples/hello_tile.rs b/crates/bevy_tiles_render/examples/hello_tile.rs index be06bd5..9ba17af 100644 --- a/crates/bevy_tiles_render/examples/hello_tile.rs +++ b/crates/bevy_tiles_render/examples/hello_tile.rs @@ -4,6 +4,7 @@ use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, ecs::system::Commands, math::{Quat, Vec3}, + render::camera::OrthographicProjection, transform::{ components::{GlobalTransform, Transform}, TransformBundle, @@ -33,7 +34,7 @@ fn main() { struct GameLayer; impl TileMapLabel for GameLayer { - const CHUNK_SIZE: usize = 8; + const CHUNK_SIZE: usize = 32; } fn spawn(mut commands: Commands) { @@ -41,12 +42,19 @@ fn spawn(mut commands: Commands) { tile_commands.spawn_map(TileMapRenderingBundle { tile_size: TileSize(16.0), grid_size: TileGridSize(18.0), + tile_map_renderer: TileMapRenderer { batch_size: 512 }, ..Default::default() }); - tile_commands.spawn_tile_batch(CoordIterator::new([-100, -100], [100, 100]), move |_| ()); + tile_commands.spawn_tile_batch(CoordIterator::new([-200, -200], [200, 200]), move |_| ()); commands.spawn(Camera2dBundle { + projection: OrthographicProjection { + scale: 5.0, + far: 1000.0, + near: -1000.0, + ..Default::default() + }, ..Default::default() }); } diff --git a/crates/bevy_tiles_render/src/chunk/internal.rs b/crates/bevy_tiles_render/src/chunk/internal.rs index a092d32..fe16b26 100644 --- a/crates/bevy_tiles_render/src/chunk/internal.rs +++ b/crates/bevy_tiles_render/src/chunk/internal.rs @@ -1,9 +1,15 @@ use bevy::{ - ecs::{component::Component, entity::Entity}, - prelude::Deref, + ecs::{component::Component, entity::Entity, system::Resource}, + prelude::{Deref, DerefMut}, + utils::HashMap, }; use bevy_tiles::chunks::ChunkCoord; +use crate::bindings::ChunkBuffer; + +#[derive(Default, Resource, Deref, DerefMut)] +pub struct SavedChunks(HashMap); + #[derive(Component, Deref)] pub struct BatchSize(pub u32); diff --git a/crates/bevy_tiles_render/src/cleanup.rs b/crates/bevy_tiles_render/src/cleanup.rs new file mode 100644 index 0000000..7dd5900 --- /dev/null +++ b/crates/bevy_tiles_render/src/cleanup.rs @@ -0,0 +1,38 @@ +use bevy::ecs::{entity::Entity, query::With, system::ResMut, world::World}; + +use crate::{ + bindings::ChunkBuffer, + chunk::internal::SavedChunks, + maps::internal::{MapInfo, SavedMaps}, +}; + +pub fn save_chunks(mut world: &mut World) { + // Get the map id's we need + let map_ids: Vec = world + .query_filtered::>() + .iter(world) + .collect(); + + // Get the chunk id's we need + let chunk_ids: Vec = world + .query_filtered::>() + .iter(world) + .collect(); + + // Remove the map entities and put them into our hashmap + let mut saved_maps = SavedMaps::default(); + for map_id in map_ids.into_iter() { + let mut map = world.entity_mut(map_id); + saved_maps.insert(map_id, map.take::().unwrap()); + } + + // Remove the chunk entities and put them into our hashmap + let mut saved_chunks = SavedChunks::default(); + for chunk_id in chunk_ids.into_iter() { + let mut chunk = world.entity_mut(chunk_id); + saved_chunks.insert(chunk_id, chunk.take::().unwrap()); + } + + world.insert_resource(saved_maps); + world.insert_resource(saved_chunks); +} diff --git a/crates/bevy_tiles_render/src/extract.rs b/crates/bevy_tiles_render/src/extract.rs index b8ca17c..c7a1dcd 100644 --- a/crates/bevy_tiles_render/src/extract.rs +++ b/crates/bevy_tiles_render/src/extract.rs @@ -3,7 +3,7 @@ use bevy::{ ecs::{ entity::Entity, query::With, - system::{Commands, Query}, + system::{Commands, Query, Res, ResMut}, }, log::debug, render::Extract, @@ -16,12 +16,17 @@ use bevy_tiles::{ }; use crate::{ - chunk::internal::ChunkUniforms, - maps::{internal::MapInfo, TileGridSize, TileMapRenderer, TileSize}, + chunk::internal::{ChunkUniforms, SavedChunks}, + maps::{ + internal::{MapInfo, SavedMaps}, + TileGridSize, TileMapRenderer, TileSize, + }, }; pub fn extract_chunks( mut commands: Commands, + mut saved_maps: ResMut, + mut saved_chunks: ResMut, maps: Extract< Query<( Entity, @@ -37,6 +42,11 @@ pub fn extract_chunks( ) { let mut extracted_maps = Vec::with_capacity(maps.iter().len()); for (map_id, map, renderer, transform, tile_size, grid_size) in maps.iter() { + // TODO: Check if it's changed + if let Some(map_info) = saved_maps.remove(&map_id) { + extracted_maps.push((map_id, map_info)); + continue; + } let transform = transform.cloned().unwrap_or_default(); let tile_size = tile_size.cloned().unwrap_or_default(); let grid_size = grid_size.cloned().unwrap_or_default(); @@ -54,6 +64,7 @@ pub fn extract_chunks( commands.insert_or_spawn_batch(extracted_maps); let mut extracted_chunks = Vec::with_capacity(chunks.iter().len()); + let mut extracted_saved_chunks = Vec::new(); let mut chunk_edges = Vec::with_capacity(chunks.iter().len()); for (chunk_id, edges, chunk, chunk_coord) in chunks.iter() { @@ -61,6 +72,14 @@ pub fn extract_chunks( panic!("Missing map reference on chunk!"); }; + chunk_edges.push((chunk_id, *map_id)); + + // TODO: Check if it's changed + if let Some(chunk_info) = saved_chunks.remove(&chunk_id) { + extracted_saved_chunks.push((chunk_id, chunk_info)); + continue; + } + let mut extracted_tile_instances = Vec::with_capacity(chunk.total_size()); for tile in chunk.get_tiles() { @@ -71,8 +90,6 @@ pub fn extract_chunks( } } - chunk_edges.push((chunk_id, *map_id)); - extracted_chunks.push(( chunk_id, ChunkUniforms { @@ -82,6 +99,7 @@ pub fn extract_chunks( )); } + commands.insert_or_spawn_batch(extracted_saved_chunks); commands.insert_or_spawn_batch(extracted_chunks); for (chunk_id, map_id) in chunk_edges.into_iter() { diff --git a/crates/bevy_tiles_render/src/lib.rs b/crates/bevy_tiles_render/src/lib.rs index 43b154d..092fb87 100644 --- a/crates/bevy_tiles_render/src/lib.rs +++ b/crates/bevy_tiles_render/src/lib.rs @@ -11,7 +11,10 @@ use bevy::{ }, }; +use chunk::internal::SavedChunks; +use cleanup::save_chunks; use extract::extract_chunks; +use maps::internal::SavedMaps; use prepare::{create_bind_groups, prepare_chunk_batch, prepare_chunks}; use queue::{create_chunk_batches, queue_chunks}; @@ -20,6 +23,7 @@ use crate::{draw::DrawChunks, pipeline::TilesChunkPipeline}; mod bindings; mod buffer_helpers; pub mod chunk; +mod cleanup; mod draw; mod extract; pub mod maps; @@ -27,7 +31,6 @@ mod pipeline; mod prepare; mod queue; pub mod tiles; -mod tiles_render; const TILES_VERT: Handle = Handle::weak_from_u128(163058266501073814892310220797241232500); const TILES_FRAG: Handle = Handle::weak_from_u128(163058266501073814892310220797241232501); @@ -37,7 +40,10 @@ pub struct TilesRenderPlugin; impl Plugin for TilesRenderPlugin { fn build(&self, app: &mut bevy::prelude::App) { let render_app = app.get_sub_app_mut(RenderApp).expect("No RenderApp found!"); + render_app.add_plugins(Aery); + render_app.init_resource::(); + render_app.init_resource::(); // Respawn chunks that we saved from the last frame // Copy over tile data @@ -60,7 +66,8 @@ impl Plugin for TilesRenderPlugin { ) .chain() .in_set(RenderSet::Prepare), - ); + ) + .add_systems(Render, (save_chunks).in_set(RenderSet::Cleanup)); } fn finish(&self, app: &mut bevy::prelude::App) { diff --git a/crates/bevy_tiles_render/src/maps/internal.rs b/crates/bevy_tiles_render/src/maps/internal.rs index d44c440..aed3891 100644 --- a/crates/bevy_tiles_render/src/maps/internal.rs +++ b/crates/bevy_tiles_render/src/maps/internal.rs @@ -1,7 +1,15 @@ -use bevy::{ecs::component::Component, prelude::Deref, transform::components::GlobalTransform}; +use bevy::{ + ecs::{component::Component, entity::Entity, system::Resource}, + prelude::{Deref, DerefMut}, + transform::components::GlobalTransform, + utils::HashMap, +}; use super::{TileGridSize, TileMapRenderer, TileSize}; +#[derive(Default, Resource, Deref, DerefMut)] +pub struct SavedMaps(HashMap); + #[derive(Clone, Component)] pub struct MapInfo { pub chunk_size: u32, diff --git a/crates/bevy_tiles_render/src/queue.rs b/crates/bevy_tiles_render/src/queue.rs index 310cb2a..15f62b1 100644 --- a/crates/bevy_tiles_render/src/queue.rs +++ b/crates/bevy_tiles_render/src/queue.rs @@ -6,6 +6,7 @@ use bevy::{ core_pipeline::core_2d::Transparent2d, ecs::{ entity::Entity, + query::{Or, With}, system::{Commands, Query, Res, ResMut}, }, log::debug, @@ -21,6 +22,7 @@ use bevy::{ use bevy_tiles::chunks::InMap; use crate::{ + bindings::ChunkBuffer, chunk::internal::{BatchSize, ChunkBatch, ChunkUniforms}, draw::DrawChunks, maps::internal::MapInfo, @@ -30,7 +32,7 @@ use crate::{ pub fn create_chunk_batches( mut commands: Commands, maps: Query<((Entity, &MapInfo), Relations)>, - chunks: Query<(Entity, &ChunkUniforms)>, + chunks: Query, With)>>, ) { for ((map_id, map_info), edges) in maps.iter() { let max_batch_size = map_info.tile_map_renderer.batch_size; @@ -52,17 +54,15 @@ pub fn create_chunk_batches( let mut batch_size = 0; let mut current_batch = ChunkBatch(commands.spawn_empty().id()); - edges - .join::(&chunks) - .for_each(|(chunk_id, extracted_tiles)| { - if batch_size == max_batch_size { - batches.push((*current_batch, (BatchSize(batch_size), map_info.clone()))); - batch_size = 0; - current_batch = ChunkBatch(commands.spawn_empty().id()); - } - batched_chunks.push((chunk_id, current_batch.clone())); - batch_size += 1; - }); + edges.join::(&chunks).for_each(|chunk_id| { + if batch_size == max_batch_size { + batches.push((*current_batch, (BatchSize(batch_size), map_info.clone()))); + batch_size = 0; + current_batch = ChunkBatch(commands.spawn_empty().id()); + } + batched_chunks.push((chunk_id, current_batch.clone())); + batch_size += 1; + }); if batch_size > 0 { batches.push((*current_batch, (BatchSize(batch_size), map_info.clone()))); diff --git a/crates/bevy_tiles_render/src/tiles_render.rs b/crates/bevy_tiles_render/src/tiles_render.rs deleted file mode 100644 index 5e58173..0000000 --- a/crates/bevy_tiles_render/src/tiles_render.rs +++ /dev/null @@ -1,6 +0,0 @@ -use bevy::{ecs::component::Component, render::render_resource::BindGroup}; - -#[derive(Component)] -pub struct TriThingBindGroups { - pub transform_bind_group: BindGroup, -}