diff --git a/examples/shader_advanced/specialized_mesh_pipeline.rs b/examples/shader_advanced/specialized_mesh_pipeline.rs index 3b5d95f0b5915..86baf7afd8b54 100644 --- a/examples/shader_advanced/specialized_mesh_pipeline.rs +++ b/examples/shader_advanced/specialized_mesh_pipeline.rs @@ -8,7 +8,7 @@ use bevy::{ core_pipeline::core_3d::{Opaque3d, Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT}, - ecs::{component::Tick, system::StaticSystemParam}, + ecs::component::Tick, math::{vec3, vec4}, pbr::{ DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, RenderMeshInstances, @@ -16,16 +16,12 @@ use bevy::{ }, prelude::*, render::{ - batching::{ - gpu_preprocessing::{ - self, PhaseBatchedInstanceBuffers, PhaseIndirectParametersBuffers, - PreprocessWorkItem, UntypedPhaseBatchedInstanceBuffers, - }, - GetBatchData, GetFullBatchData, - }, - experimental::occlusion_culling::OcclusionCulling, + batching::gpu_preprocessing::GpuPreprocessingSupport, extract_component::{ExtractComponent, ExtractComponentPlugin}, - mesh::{Indices, MeshVertexBufferLayoutRef, PrimitiveTopology, RenderMesh}, + mesh::{ + allocator::MeshAllocator, Indices, MeshVertexBufferLayoutRef, PrimitiveTopology, + RenderMesh, + }, render_asset::{RenderAssetUsages, RenderAssets}, render_phase::{ AddRenderCommand, BinnedRenderPhaseType, DrawFunctions, SetItemPipeline, @@ -37,7 +33,6 @@ use bevy::{ RenderPipelineDescriptor, SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines, TextureFormat, VertexState, }, - view::NoIndirectDrawing, view::{self, ExtractedView, RenderVisibleEntities, ViewTarget, VisibilityClass}, Render, RenderApp, RenderStartup, RenderSystems, }, @@ -262,7 +257,6 @@ impl SpecializedMeshPipeline for CustomMeshPipeline { count: mesh_key.msaa_samples(), ..default() }, - ..default() }) } @@ -278,75 +272,32 @@ fn queue_custom_mesh_pipeline( Res>, ), mut specialized_mesh_pipelines: ResMut>, - views: Query<( - &RenderVisibleEntities, - &ExtractedView, - &Msaa, - Has, - Has, - )>, + views: Query<(&RenderVisibleEntities, &ExtractedView, &Msaa)>, (render_meshes, render_mesh_instances): ( Res>, Res, ), - param: StaticSystemParam<::Param>, - mut phase_batched_instance_buffers: ResMut< - PhaseBatchedInstanceBuffers::BufferData>, - >, - mut phase_indirect_parameters_buffers: ResMut>, mut change_tick: Local, + mesh_allocator: Res, + gpu_preprocessing_support: Res, ) { - let system_param_item = param.into_inner(); - - let UntypedPhaseBatchedInstanceBuffers { - ref mut data_buffer, - ref mut work_item_buffers, - ref mut late_indexed_indirect_parameters_buffer, - ref mut late_non_indexed_indirect_parameters_buffer, - .. - } = phase_batched_instance_buffers.buffers; - // Get the id for our custom draw function - let draw_function_id = opaque_draw_functions + let draw_function = opaque_draw_functions .read() .id::(); // Render phases are per-view, so we need to iterate over all views so that // the entity appears in them. (In this example, we have only one view, but // it's good practice to loop over all views anyway.) - for (view_visible_entities, view, msaa, no_indirect_drawing, gpu_occlusion_culling) in - views.iter() - { + for (view_visible_entities, view, msaa) in views.iter() { let Some(opaque_phase) = opaque_render_phases.get_mut(&view.retained_view_entity) else { continue; }; - // Create *work item buffers* if necessary. Work item buffers store the - // indices of meshes that are to be rendered when indirect drawing is - // enabled. - let work_item_buffer = gpu_preprocessing::get_or_create_work_item_buffer::( - work_item_buffers, - view.retained_view_entity, - no_indirect_drawing, - gpu_occlusion_culling, - ); - - // Initialize those work item buffers in preparation for this new frame. - gpu_preprocessing::init_work_item_buffers( - work_item_buffer, - late_indexed_indirect_parameters_buffer, - late_non_indexed_indirect_parameters_buffer, - ); - // Create the key based on the view. In this case we only care about MSAA and HDR let view_key = MeshPipelineKey::from_msaa_samples(msaa.samples()) | MeshPipelineKey::from_hdr(view.hdr); - // Set up a slot to hold information about the batch set we're going to - // create. If there are any of our custom meshes in the scene, we'll - // need this information in order for Bevy to kick off the rendering. - let mut mesh_batch_set_info = None; - // Find all the custom rendered entities that are visible from this // view. for &(render_entity, visible_entity) in @@ -363,34 +314,14 @@ fn queue_custom_mesh_pipeline( continue; }; + let (vertex_slab, index_slab) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id); + // Specialize the key for the current mesh entity // For this example we only specialize based on the mesh topology // but you could have more complex keys and that's where you'd need to create those keys let mut mesh_key = view_key; mesh_key |= MeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); - // Initialize the batch set information if this was the first custom - // mesh we saw. We'll need that information later to create the - // batch set. - if mesh_batch_set_info.is_none() { - mesh_batch_set_info = Some(MeshBatchSetInfo { - indirect_parameters_index: phase_indirect_parameters_buffers - .buffers - .allocate(mesh.indexed(), 1), - is_indexed: mesh.indexed(), - }); - } - let mesh_info = mesh_batch_set_info.unwrap(); - - // Allocate some input and output indices. We'll need these to - // create the *work item* below. - let Some(input_index) = - MeshPipeline::get_binned_index(&system_param_item, visible_entity) - else { - continue; - }; - let output_index = data_buffer.add() as u32; - // Finally, we can specialize the pipeline based on the key let pipeline_id = specialized_mesh_pipelines .specialize( @@ -399,8 +330,8 @@ fn queue_custom_mesh_pipeline( mesh_key, &mesh.layout, ) - // This should never with this example, but if your pipeline specialization - // can fail you need to handle the error here + // This should never happen with this example, but if your pipeline + // specialization can fail you need to handle the error here .expect("Failed to specialize mesh pipeline"); // Bump the change tick so that Bevy is forced to rebuild the bin. @@ -410,59 +341,29 @@ fn queue_custom_mesh_pipeline( // Add the mesh with our specialized pipeline opaque_phase.add( Opaque3dBatchSetKey { - draw_function: draw_function_id, + draw_function, pipeline: pipeline_id, material_bind_group_index: None, - vertex_slab: default(), - index_slab: None, + vertex_slab: vertex_slab.unwrap_or_default(), + index_slab, lightmap_slab: None, }, - // The asset ID is arbitrary; we simply use [`AssetId::invalid`], - // but you can use anything you like. Note that the asset ID need - // not be the ID of a [`Mesh`]. + // For this example we can use the mesh asset id as the bin key, + // but you can use any asset_id as a key Opaque3dBinKey { - asset_id: AssetId::::invalid().untyped(), + asset_id: mesh_instance.mesh_asset_id.into(), }, (render_entity, visible_entity), mesh_instance.current_uniform_index, - // This example supports batching, but if your pipeline doesn't - // support it you can use `BinnedRenderPhaseType::UnbatchableMesh` - BinnedRenderPhaseType::BatchableMesh, + // This example supports batching and multi draw indirect, + // but if your pipeline doesn't support it you can use + // `BinnedRenderPhaseType::UnbatchableMesh` + BinnedRenderPhaseType::mesh( + mesh_instance.should_batch(), + &gpu_preprocessing_support, + ), *change_tick, ); - - // Create a *work item*. A work item tells the Bevy renderer to - // transform the mesh on GPU. - work_item_buffer.push( - mesh.indexed(), - PreprocessWorkItem { - input_index: input_index.into(), - output_or_indirect_parameters_index: if no_indirect_drawing { - output_index - } else { - mesh_info.indirect_parameters_index - }, - }, - ); - } - - // Now if there were any meshes, we need to add a command to the - // indirect parameters buffer, so that the renderer will end up - // enqueuing a command to draw the mesh. - if let Some(mesh_info) = mesh_batch_set_info { - phase_indirect_parameters_buffers - .buffers - .add_batch_set(mesh_info.is_indexed, mesh_info.indirect_parameters_index); } } } - -// If we end up having any custom meshes to draw, this contains information -// needed to create the batch set. -#[derive(Clone, Copy)] -struct MeshBatchSetInfo { - /// The first index of the mesh batch in the indirect parameters buffer. - indirect_parameters_index: u32, - /// Whether the mesh is indexed (has an index buffer). - is_indexed: bool, -}