From d52b0171f6fb37298ab62bd32ab16bda242969c4 Mon Sep 17 00:00:00 2001 From: James Bell Date: Wed, 3 Jan 2024 17:28:56 -0500 Subject: [PATCH] Thing --- Cargo.lock | 5 +- Cargo.toml | 1 - crates/bevy_tiles_render/Cargo.toml | 1 - .../bevy_tiles_render/examples/hello_tile.rs | 2 +- crates/bevy_tiles_render/src/bindings.rs | 24 ++-- .../gpu_storage_buffer.rs | 25 +++- .../src/buffer_helpers/mod.rs | 3 + .../bevy_tiles_render/src/chunk/internal.rs | 7 ++ crates/bevy_tiles_render/src/chunk/mod.rs | 4 + crates/bevy_tiles_render/src/draw.rs | 118 ++++-------------- crates/bevy_tiles_render/src/extract.rs | 4 +- crates/bevy_tiles_render/src/lib.rs | 37 ++++-- crates/bevy_tiles_render/src/pipeline.rs | 2 +- crates/bevy_tiles_render/src/prepare.rs | 113 +++++++++++++++-- crates/bevy_tiles_render/src/queue.rs | 107 ++++++++-------- 15 files changed, 261 insertions(+), 192 deletions(-) rename crates/bevy_tiles_render/src/{ => buffer_helpers}/gpu_storage_buffer.rs (72%) create mode 100644 crates/bevy_tiles_render/src/buffer_helpers/mod.rs create mode 100644 crates/bevy_tiles_render/src/chunk/internal.rs create mode 100644 crates/bevy_tiles_render/src/chunk/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e80e471..e7f0449 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1000,7 +1000,6 @@ dependencies = [ "aery", "bevy", "bevy_tiles", - "regex", "rstest", ] @@ -1512,9 +1511,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] diff --git a/Cargo.toml b/Cargo.toml index 676a010..4def0ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ opt-level = 3 aery = "0.5.1" bevy = {version = "0.12.1", default-features = false} rstest = "0.18.2" -regex = "1.10.2" bimap = "0.6.3" [workspace.lints.clippy] diff --git a/crates/bevy_tiles_render/Cargo.toml b/crates/bevy_tiles_render/Cargo.toml index ce8e8e3..a0f0d02 100644 --- a/crates/bevy_tiles_render/Cargo.toml +++ b/crates/bevy_tiles_render/Cargo.toml @@ -27,7 +27,6 @@ bevy = { workspace = true, features = [ "bevy_sprite", ] } bevy_tiles = {path = "../bevy_tiles"} -regex = { workspace = true } [dev-dependencies] rstest = {workspace = true} diff --git a/crates/bevy_tiles_render/examples/hello_tile.rs b/crates/bevy_tiles_render/examples/hello_tile.rs index 588c1a9..7f8b7a5 100644 --- a/crates/bevy_tiles_render/examples/hello_tile.rs +++ b/crates/bevy_tiles_render/examples/hello_tile.rs @@ -7,7 +7,7 @@ use bevy::{ DefaultPlugins, }; use bevy_tiles::TilesPlugin; -use bevy_tiles_render::{tiles::TriThing, TilesRenderPlugin}; +use bevy_tiles_render::{settings::ChunkRenderSettings, tiles::TriThing, TilesRenderPlugin}; fn main() { App::new() diff --git a/crates/bevy_tiles_render/src/bindings.rs b/crates/bevy_tiles_render/src/bindings.rs index 7668fd3..280af79 100644 --- a/crates/bevy_tiles_render/src/bindings.rs +++ b/crates/bevy_tiles_render/src/bindings.rs @@ -1,24 +1,16 @@ -use std::{mem::size_of, num::NonZeroU64, ops::Deref}; - use bevy::{ - ecs::{system::Resource, world::FromWorld}, - log::info, - math::{Affine3, Mat3A, Mat4, Vec2, Vec4}, + ecs::world::FromWorld, + math::{Affine3, Vec4}, render::{ - mesh::{Mesh, MeshVertexAttribute}, - render_resource::{ - self, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, - Buffer, BufferInitDescriptor, BufferUsages, PrimitiveTopology, ShaderDefVal, - ShaderStages, ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, - }, + render_resource::{BindGroupLayout, BindGroupLayoutDescriptor, ShaderStages, ShaderType}, renderer::RenderDevice, }, transform::components::GlobalTransform, }; -use crate::gpu_storage_buffer::GpuStorageBuffer; +use crate::buffer_helpers::*; -#[derive(ShaderType, Clone)] +#[derive(ShaderType, Clone, Default)] pub struct TilesChunkModelUniform { // Affine 4x3 matrix transposed to 3x4 pub transform: [Vec4; 3], @@ -43,7 +35,7 @@ impl From<&GlobalTransform> for TilesChunkModelUniform { } pub struct TilesChunkBindGroupLayouts { - pub mesh_layout: BindGroupLayout, + pub model_layout: BindGroupLayout, } impl FromWorld for TilesChunkBindGroupLayouts { @@ -61,6 +53,8 @@ impl FromWorld for TilesChunkBindGroupLayouts { )], }); - Self { mesh_layout } + Self { + model_layout: mesh_layout, + } } } diff --git a/crates/bevy_tiles_render/src/gpu_storage_buffer.rs b/crates/bevy_tiles_render/src/buffer_helpers/gpu_storage_buffer.rs similarity index 72% rename from crates/bevy_tiles_render/src/gpu_storage_buffer.rs rename to crates/bevy_tiles_render/src/buffer_helpers/gpu_storage_buffer.rs index 2c783b4..5da21bb 100644 --- a/crates/bevy_tiles_render/src/gpu_storage_buffer.rs +++ b/crates/bevy_tiles_render/src/buffer_helpers/gpu_storage_buffer.rs @@ -1,7 +1,7 @@ use std::{marker::PhantomData, mem}; use bevy::{ - ecs::{system::Resource, world::FromWorld}, + ecs::{component::Component, system::Resource, world::FromWorld}, render::{ render_resource::{ BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, @@ -14,7 +14,7 @@ use bevy::{ /// Stores an array of elements to be transferred to the GPU and made accessible to shaders as a read-only array. /// This is modified from bevy's GpuArrayBuffer -#[derive(Resource)] +#[derive(Resource, Component)] pub struct GpuStorageBuffer { gpu_buffer: StorageBuffer>, buffer: Vec, @@ -69,4 +69,25 @@ impl GpuStorageBuffer { pub fn batch_size(device: &RenderDevice) -> Option { None } + + // Fails if used on the wrong size buffer + /// SAFETY: Use carefully, this is to allow for parallel writes to sections of a buffer. + pub unsafe fn raw_insert(&self, index: usize, value: T) { + let spot: *const T = self.buffer.get(index).unwrap(); + let spot: *mut T = spot as *mut T; + unsafe { *spot = value }; + } +} + +impl GpuStorageBuffer +where + T: Default, +{ + /// Creates a buffer of the given size filled with default values + pub fn with_size(size: usize) -> Self { + Self { + buffer: vec![T::default(); size], + gpu_buffer: Default::default(), + } + } } diff --git a/crates/bevy_tiles_render/src/buffer_helpers/mod.rs b/crates/bevy_tiles_render/src/buffer_helpers/mod.rs new file mode 100644 index 0000000..0ad7685 --- /dev/null +++ b/crates/bevy_tiles_render/src/buffer_helpers/mod.rs @@ -0,0 +1,3 @@ +pub mod gpu_storage_buffer; + +pub use gpu_storage_buffer::*; diff --git a/crates/bevy_tiles_render/src/chunk/internal.rs b/crates/bevy_tiles_render/src/chunk/internal.rs new file mode 100644 index 0000000..35fbdbb --- /dev/null +++ b/crates/bevy_tiles_render/src/chunk/internal.rs @@ -0,0 +1,7 @@ +use bevy::{ecs::component::Component, prelude::Deref}; + +#[derive(Component)] +pub struct TileInstances(Vec); + +#[derive(Component, Deref)] +pub struct BatchSize(pub usize); diff --git a/crates/bevy_tiles_render/src/chunk/mod.rs b/crates/bevy_tiles_render/src/chunk/mod.rs new file mode 100644 index 0000000..de803c5 --- /dev/null +++ b/crates/bevy_tiles_render/src/chunk/mod.rs @@ -0,0 +1,4 @@ +//! Components that can effect chunk rendering + +/// Components used by rendering pipeline +pub(crate) mod internal; diff --git a/crates/bevy_tiles_render/src/draw.rs b/crates/bevy_tiles_render/src/draw.rs index 13b7e73..2f215d6 100644 --- a/crates/bevy_tiles_render/src/draw.rs +++ b/crates/bevy_tiles_render/src/draw.rs @@ -1,121 +1,45 @@ +//! Contains commands given to the Transparent2D render step +//! to draw tiles. +//! +//! In order to batch draw calls of batched chunk draws (used for larger scenes if for lower memory situations) +//! the draw commands consist of copying individual chunk buffers to the various instance buffers before +//! issuing a draw call for a given batch of chunks. use bevy::{ core_pipeline::core_2d::Transparent2d, ecs::{ query::ROQueryItem, - system::{ - lifetimeless::{Read, SRes, SResMut}, - SystemParamItem, - }, + system::{lifetimeless::Read, SystemParamItem}, }, - log::info, - render::{ - render_phase::{ - PhaseItem, RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass, - }, - render_resource::{BindGroupEntries, PipelineCache}, - renderer::{RenderDevice, RenderQueue}, + log::debug, + render::render_phase::{ + PhaseItem, RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass, }, - sprite::{DrawMesh2d, SetMesh2dViewBindGroup}, - transform::components::GlobalTransform, + sprite::SetMesh2dViewBindGroup, }; -use crate::{ - bindings::TilesChunkModelUniform, gpu_storage_buffer::GpuStorageBuffer, - pipeline::TilesChunkPipeline, prepare::TilesChunkMeshBindGroup, - tiles_render::TriThingBindGroups, -}; - -pub type LoadChunk = AddTransform; +use crate::queue::ChunkBatchBindGroups; pub type DrawChunks = ( - // Set the pipeline SetItemPipeline, - // Set the view uniform as bind group 0 SetMesh2dViewBindGroup<0>, - // Set the mesh uniform as bind group 1 SetChunkBindGroup<1>, - // Draw the mesh DrawChunkBatch, ); -pub struct AddTransform; -impl RenderCommand for AddTransform { - type Param = SResMut>; - - type ViewWorldQuery = (); - - type ItemWorldQuery = Read; - - #[inline] - fn render<'w>( - item: &Transparent2d, - _view: (), - uniforms: ROQueryItem<'w, Self::ItemWorldQuery>, - mut chunk_uniforms: SystemParamItem<'w, '_, Self::Param>, - pass: &mut TrackedRenderPass<'w>, - ) -> RenderCommandResult { - chunk_uniforms.push(uniforms.into()); - RenderCommandResult::Success - } -} -pub struct CreateUniformBindGroups; -impl RenderCommand for CreateUniformBindGroups { - type Param = ( - SRes, - SRes, - SRes, - SRes>, - SResMut, - ); - - type ViewWorldQuery = (); - - type ItemWorldQuery = (); - - #[inline] - fn render<'w>( - item: &Transparent2d, - _view: (), - _item_query: (), - (device, queue, base_pipeline, mut model_buffer, mut bind_groups): SystemParamItem< - 'w, - '_, - Self::Param, - >, - pass: &mut TrackedRenderPass<'w>, - ) -> RenderCommandResult { - model_buffer.write_buffer(&device, &queue); - - let Some(binding) = model_buffer.binding() else { - return RenderCommandResult::Failure; - }; - - let bind_group = device.create_bind_group( - "tiles_bind_group", - &base_pipeline.tiles_bind_groups.mesh_layout, - &BindGroupEntries::single(binding), - ); - - bind_groups.value = Some(bind_group); - - RenderCommandResult::Success - } -} - pub struct SetChunkBindGroup; impl RenderCommand for SetChunkBindGroup { - type Param = SRes; + type Param = (); type ViewWorldQuery = (); - type ItemWorldQuery = (); + type ItemWorldQuery = Read; #[inline] fn render<'w>( item: &Transparent2d, _view: (), - _item_query: (), - mesh2d_bind_group: SystemParamItem<'w, '_, Self::Param>, + bind_groups: ROQueryItem<'w, Self::ItemWorldQuery>, + _: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { let mut dynamic_offsets: [u32; 1] = Default::default(); @@ -125,11 +49,11 @@ impl RenderCommand for SetChunkBindGroup { offset_count += 1; } - let Some(model_bindgroup) = mesh2d_bind_group.value else { - return RenderCommandResult::Failure; - }; - - pass.set_bind_group(I, &model_bindgroup, &dynamic_offsets[..offset_count]); + pass.set_bind_group( + I, + &bind_groups.model_bind_group, + &dynamic_offsets[..offset_count], + ); RenderCommandResult::Success } } diff --git a/crates/bevy_tiles_render/src/extract.rs b/crates/bevy_tiles_render/src/extract.rs index 96c12dc..6f33e75 100644 --- a/crates/bevy_tiles_render/src/extract.rs +++ b/crates/bevy_tiles_render/src/extract.rs @@ -3,7 +3,7 @@ use bevy::{ entity::Entity, system::{Commands, Query, ResMut}, }, - log::info, + log::{debug, info}, prelude::SpatialBundle, render::Extract, sprite::{Mesh2d, RenderMesh2dInstance, RenderMesh2dInstances}, @@ -17,6 +17,6 @@ pub fn extract_chunks( tri_things: Extract>, ) { let tri_things = Vec::from_iter(tri_things.iter().map(|(e, gt, tt)| (e, (*gt, *tt)))); - info!("Extracting! {:?}", tri_things.len()); + debug!("Extracted {:?} Chunks", tri_things.len()); commands.insert_or_spawn_batch(tri_things); } diff --git a/crates/bevy_tiles_render/src/lib.rs b/crates/bevy_tiles_render/src/lib.rs index 52a60c3..1d8509f 100644 --- a/crates/bevy_tiles_render/src/lib.rs +++ b/crates/bevy_tiles_render/src/lib.rs @@ -2,7 +2,7 @@ use bevy::{ app::Plugin, asset::{load_internal_asset, Handle}, core_pipeline::core_2d::Transparent2d, - ecs::schedule::IntoSystemConfigs, + ecs::schedule::{apply_deferred, IntoSystemConfigs}, render::{ render_phase::AddRenderCommand, render_resource::{Shader, SpecializedRenderPipelines}, @@ -12,20 +12,22 @@ use bevy::{ }; use extract::extract_chunks; -use queue::queue_chunks; +use prepare::{create_bind_groups, prepare_chunk_batch}; +use queue::{create_chunk_batches, queue_chunks}; use crate::{ bindings::TilesChunkModelUniform, - draw::{DrawChunkBatch, LoadChunk}, - gpu_storage_buffer::GpuStorageBuffer, + buffer_helpers::gpu_storage_buffer::GpuStorageBuffer, + draw::{DrawChunkBatch, DrawChunks}, pipeline::TilesChunkPipeline, - prepare::TilesChunkMeshBindGroup, + settings::ChunkRenderSettings, }; mod bindings; +mod buffer_helpers; +mod chunk; mod draw; mod extract; -mod gpu_storage_buffer; mod pipeline; mod prepare; mod queue; @@ -44,8 +46,20 @@ impl Plugin for TilesRenderPlugin { // Respawn chunks that we saved from the last frame // Copy over tile data - render_app.add_systems(ExtractSchedule, extract_chunks); - render_app.add_systems(Render, queue_chunks.in_set(RenderSet::Queue)); + render_app + .add_systems(ExtractSchedule, extract_chunks) + .add_systems( + Render, + (create_chunk_batches, apply_deferred, queue_chunks) + .chain() + .in_set(RenderSet::Queue), + ) + .add_systems( + Render, + (prepare_chunk_batch, apply_deferred, create_bind_groups) + .chain() + .in_set(RenderSet::Prepare), + ); /* render_app.add_systems( ExtractSchedule, @@ -64,10 +78,11 @@ impl Plugin for TilesRenderPlugin { fn finish(&self, app: &mut bevy::prelude::App) { let render_app = app.get_sub_app_mut(RenderApp).expect("No RenderApp found!"); - render_app.add_render_command::(); - render_app.add_render_command::(); + render_app.add_render_command::(); + render_app.insert_resource(ChunkRenderSettings { + max_chunk_batch_size: 64, + }); render_app - .init_resource::() .init_resource::>() .init_resource::() .init_resource::>(); diff --git a/crates/bevy_tiles_render/src/pipeline.rs b/crates/bevy_tiles_render/src/pipeline.rs index 32e66ad..fc81e65 100644 --- a/crates/bevy_tiles_render/src/pipeline.rs +++ b/crates/bevy_tiles_render/src/pipeline.rs @@ -75,7 +75,7 @@ impl SpecializedRenderPipeline for TilesChunkPipeline { // Bind group 0 is the view uniform self.mesh2d_pipeline.view_layout.clone(), // Bind group 1 is the mesh uniforms for all the chunks - self.tiles_bind_groups.mesh_layout.clone(), + self.tiles_bind_groups.model_layout.clone(), ], push_constant_ranges: Vec::new(), primitive: PrimitiveState { diff --git a/crates/bevy_tiles_render/src/prepare.rs b/crates/bevy_tiles_render/src/prepare.rs index 91f0978..9fb1922 100644 --- a/crates/bevy_tiles_render/src/prepare.rs +++ b/crates/bevy_tiles_render/src/prepare.rs @@ -1,26 +1,123 @@ use std::{ + iter::{once, repeat_with}, mem::size_of, num::{NonZeroU32, NonZeroU64}, + sync::atomic::{AtomicUsize, Ordering}, }; use bevy::{ ecs::{ - query::With, - system::{Commands, Query, Res, ResMut, Resource}, + entity::Entity, + system::{Commands, ParallelCommands, Query, Res, Resource}, }, + log::{debug, info}, render::{ - render_resource::{BindGroup, BindGroupEntries}, + render_resource::{BindGroup, BindGroupEntries, GpuArrayBuffer}, renderer::{RenderDevice, RenderQueue}, }, transform::components::GlobalTransform, }; use crate::{ - bindings::TilesChunkModelUniform, gpu_storage_buffer::GpuStorageBuffer, - pipeline::TilesChunkPipeline, tiles::TriThing, tiles_render::TriThingBindGroups, + bindings::TilesChunkModelUniform, + buffer_helpers::GpuStorageBuffer, + chunk::internal::{BatchSize, TileInstances}, + pipeline::TilesChunkPipeline, + queue::ChunkBatchBindGroups, + settings::ChunkRenderSettings, + tiles::TriThing, }; -#[derive(Resource, Default)] -pub struct TilesChunkMeshBindGroup { - pub value: Option, +pub type ChunkQueryItems<'w> = (&'w GlobalTransform, &'w TriThing); + +pub type ChunkBatchQueryItems<'w> = (&'w BatchSize, &'w GpuStorageBuffer); + +pub fn prepare_chunk_batch( + mut commands: Commands, + render_settings: Res, + device: Res, + queue: Res, + chunks: Query, + chunk_batches: Query<(Entity, &BatchSize)>, +) { + let max_batch_size = render_settings.max_chunk_batch_size as usize; + let chunk_count = chunks.iter().len(); + let batch_count = chunk_count / max_batch_size; + // Create all our instance buffers before we start iterating over chunks + let mut transform_buffers: Vec> = + repeat_with(|| GpuStorageBuffer::::with_size(max_batch_size)) + .take(batch_count) + .collect(); + + if (chunk_count % max_batch_size) > 0 { + transform_buffers.push(GpuStorageBuffer::::with_size( + chunk_count % max_batch_size, + )); + } + + let chunk_index = AtomicUsize::new(0); + chunks.par_iter().for_each(|chunk| { + let chunk_index = chunk_index.fetch_add(1, Ordering::Acquire); + + let batch = chunk_index / max_batch_size; + let batch_index = chunk_index % max_batch_size; + + prepare_chunk( + batch, + batch_index, + &render_settings, + &device, + &queue, + &transform_buffers, + chunk, + ) + }); + + for buffer in transform_buffers.iter_mut() { + buffer.write_buffer(&device, &queue) + } + + for ((batch_id, _), buffer) in chunk_batches.iter().zip(transform_buffers.into_iter()) { + commands.entity(batch_id).insert(buffer); + } +} + +#[inline] +fn prepare_chunk( + batch: usize, + batch_index: usize, + render_settings: &ChunkRenderSettings, + device: &RenderDevice, + queue: &RenderQueue, + transform_buffers: &[GpuStorageBuffer], + (transform, instances): ChunkQueryItems, +) { + // SAFETY: Each chunk can only write to one place because math + unsafe { transform_buffers[batch].raw_insert(batch_index, transform.into()) }; +} + +pub fn create_bind_groups( + mut commands: Commands, + device: Res, + chunk_pipeline: Res, + chunk_batches: Query<(Entity, ChunkBatchQueryItems)>, +) { + // Create bind groups + debug!( + "Creating bind group for {} batches", + chunk_batches.iter().len() + ); + for (batch_id, (_, model_buffer)) in chunk_batches.iter() { + let binding = model_buffer.binding().expect("No model buffer found!"); + + let model_bind_group = device.create_bind_group( + "tiles_bind_group", + &chunk_pipeline.tiles_bind_groups.model_layout, + &BindGroupEntries::single(binding), + ); + + commands + .entity(batch_id) + .insert(ChunkBatchBindGroups { model_bind_group }); + } } diff --git a/crates/bevy_tiles_render/src/queue.rs b/crates/bevy_tiles_render/src/queue.rs index 9906b9d..abe9241 100644 --- a/crates/bevy_tiles_render/src/queue.rs +++ b/crates/bevy_tiles_render/src/queue.rs @@ -1,87 +1,94 @@ +use std::ops::Deref; + use bevy::{ core_pipeline::core_2d::Transparent2d, ecs::{ + component::Component, entity::Entity, - query::With, - system::{Query, Res, ResMut}, + system::{Commands, Query, Res, ResMut}, }, log::{debug, info}, render::{ - mesh::Mesh, - render_asset::RenderAssets, render_phase::{DrawFunctions, RenderPhase}, - render_resource::{PipelineCache, PrimitiveTopology, SpecializedRenderPipelines}, - view::{ExtractedView, Msaa, VisibleEntities}, + render_resource::{ + BindGroup, BindGroupEntries, DynamicStorageBuffer, PipelineCache, PrimitiveTopology, + SpecializedRenderPipelines, + }, + renderer::RenderDevice, + view::{ExtractedView, Msaa}, }, - sprite::{DrawMesh2d, Mesh2dPipelineKey, RenderMesh2dInstances}, + sprite::Mesh2dPipelineKey, utils::FloatOrd, }; use crate::{ - draw::{DrawChunkBatch, LoadChunk}, + chunk::internal::BatchSize, + draw::{DrawChunkBatch, DrawChunks}, pipeline::TilesChunkPipeline, + prepare::{ChunkBatchQueryItems, ChunkQueryItems}, settings::ChunkRenderSettings, - tiles::TriThing, }; +#[derive(Component)] +pub struct ChunkBatchBindGroups { + pub model_bind_group: BindGroup, +} + +pub fn create_chunk_batches( + mut commands: Commands, + render_settings: Res, + chunks: Query, +) { + let max_batch_size = render_settings.max_chunk_batch_size as usize; + let chunk_count = chunks.iter().len(); + let batch_count = chunk_count / max_batch_size; + + let mut batch_sizes = Vec::new(); + for _ in 0..batch_count { + batch_sizes.push(BatchSize(max_batch_size)); + } + if (chunk_count % max_batch_size) > 0 { + batch_sizes.push(BatchSize(chunk_count % max_batch_size)); + } + + commands.spawn_batch(batch_sizes); +} + pub fn queue_chunks( + mut commands: Commands, mut pipelines: ResMut>, - colored_mesh2d_pipeline: Res, + device: Res, + chunk_pipeline: Res, transparent_draw_functions: Res>, pipeline_cache: Res, msaa: Res, - mut views: Query<(Entity, &mut RenderPhase, &ExtractedView)>, - chunks: Query>, - chunk_render_settings: Res, + render_settings: Res, + mut views: Query<(&mut RenderPhase, &ExtractedView)>, + chunk_batches: Query<(Entity, &BatchSize)>, ) { - for (view_id, mut transparent_phase, view) in &mut views { + for (mut transparent_phase, view) in &mut views { let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples()) | Mesh2dPipelineKey::from_hdr(view.hdr) | Mesh2dPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList); - let pipeline_id = pipelines.specialize(&pipeline_cache, &colored_mesh2d_pipeline, mesh_key); - - let load_chunk = transparent_draw_functions.read().id::(); - let draw_chunks = transparent_draw_functions.read().id::(); + let pipeline_id = pipelines.specialize(&pipeline_cache, &chunk_pipeline, mesh_key); - let mut batch_size = 0; - - // Queue all entities visible to that view - for chunk_id in chunks.iter() { - batch_size += 1; + let draw_chunks = transparent_draw_functions.read().id::(); + for (batch_id, batch_size) in chunk_batches.iter() { transparent_phase.add(Transparent2d { - entity: chunk_id, - draw_function: load_chunk, - pipeline: pipeline_id, - sort_key: FloatOrd(0.0), - batch_range: 0..1, - dynamic_offset: None, - }); - - if batch_size == chunk_render_settings.max_chunk_batch_size { - transparent_phase.add(Transparent2d { - entity: view_id, - draw_function: draw_chunks, - pipeline: pipeline_id, - sort_key: FloatOrd(0.0), - batch_range: 0..batch_size, - dynamic_offset: None, - }); - - batch_size = 0; - } - } - - // Add one more draw call at the end - if batch_size > 0 { - transparent_phase.add(Transparent2d { - entity: view_id, + entity: batch_id, draw_function: draw_chunks, pipeline: pipeline_id, sort_key: FloatOrd(0.0), - batch_range: 0..batch_size, + // We ignore this + batch_range: 0..(*batch_size.deref() as u32), dynamic_offset: None, }); } + + debug!( + "Queued {:?} Chunk Batches for Drawing", + chunk_batches.iter().len() + ); } }