88
99use bevy:: {
1010 core_pipeline:: core_3d:: { Opaque3d , Opaque3dBatchSetKey , Opaque3dBinKey , CORE_3D_DEPTH_FORMAT } ,
11- ecs:: { component:: Tick , system :: StaticSystemParam } ,
11+ ecs:: component:: Tick ,
1212 math:: { vec3, vec4} ,
1313 pbr:: {
1414 DrawMesh , MeshPipeline , MeshPipelineKey , MeshPipelineViewLayoutKey , RenderMeshInstances ,
1515 SetMeshBindGroup , SetMeshViewBindGroup , SetMeshViewEmptyBindGroup ,
1616 } ,
1717 prelude:: * ,
1818 render:: {
19- batching:: {
20- gpu_preprocessing:: {
21- self , PhaseBatchedInstanceBuffers , PhaseIndirectParametersBuffers ,
22- PreprocessWorkItem , UntypedPhaseBatchedInstanceBuffers ,
23- } ,
24- GetBatchData , GetFullBatchData ,
25- } ,
26- experimental:: occlusion_culling:: OcclusionCulling ,
19+ batching:: gpu_preprocessing:: GpuPreprocessingSupport ,
2720 extract_component:: { ExtractComponent , ExtractComponentPlugin } ,
28- mesh:: { Indices , MeshVertexBufferLayoutRef , PrimitiveTopology , RenderMesh } ,
21+ mesh:: {
22+ allocator:: MeshAllocator , Indices , MeshVertexBufferLayoutRef , PrimitiveTopology ,
23+ RenderMesh ,
24+ } ,
2925 render_asset:: { RenderAssetUsages , RenderAssets } ,
3026 render_phase:: {
3127 AddRenderCommand , BinnedRenderPhaseType , DrawFunctions , SetItemPipeline ,
@@ -37,7 +33,6 @@ use bevy::{
3733 RenderPipelineDescriptor , SpecializedMeshPipeline , SpecializedMeshPipelineError ,
3834 SpecializedMeshPipelines , TextureFormat , VertexState ,
3935 } ,
40- view:: NoIndirectDrawing ,
4136 view:: { self , ExtractedView , RenderVisibleEntities , ViewTarget , VisibilityClass } ,
4237 Render , RenderApp , RenderStartup , RenderSystems ,
4338 } ,
@@ -262,7 +257,6 @@ impl SpecializedMeshPipeline for CustomMeshPipeline {
262257 count : mesh_key. msaa_samples ( ) ,
263258 ..default ( )
264259 } ,
265-
266260 ..default ( )
267261 } )
268262 }
@@ -278,75 +272,32 @@ fn queue_custom_mesh_pipeline(
278272 Res < DrawFunctions < Opaque3d > > ,
279273 ) ,
280274 mut specialized_mesh_pipelines : ResMut < SpecializedMeshPipelines < CustomMeshPipeline > > ,
281- views : Query < (
282- & RenderVisibleEntities ,
283- & ExtractedView ,
284- & Msaa ,
285- Has < NoIndirectDrawing > ,
286- Has < OcclusionCulling > ,
287- ) > ,
275+ views : Query < ( & RenderVisibleEntities , & ExtractedView , & Msaa ) > ,
288276 ( render_meshes, render_mesh_instances) : (
289277 Res < RenderAssets < RenderMesh > > ,
290278 Res < RenderMeshInstances > ,
291279 ) ,
292- param : StaticSystemParam < <MeshPipeline as GetBatchData >:: Param > ,
293- mut phase_batched_instance_buffers : ResMut <
294- PhaseBatchedInstanceBuffers < Opaque3d , <MeshPipeline as GetBatchData >:: BufferData > ,
295- > ,
296- mut phase_indirect_parameters_buffers : ResMut < PhaseIndirectParametersBuffers < Opaque3d > > ,
297280 mut change_tick : Local < Tick > ,
281+ mesh_allocator : Res < MeshAllocator > ,
282+ gpu_preprocessing_support : Res < GpuPreprocessingSupport > ,
298283) {
299- let system_param_item = param. into_inner ( ) ;
300-
301- let UntypedPhaseBatchedInstanceBuffers {
302- ref mut data_buffer,
303- ref mut work_item_buffers,
304- ref mut late_indexed_indirect_parameters_buffer,
305- ref mut late_non_indexed_indirect_parameters_buffer,
306- ..
307- } = phase_batched_instance_buffers. buffers ;
308-
309284 // Get the id for our custom draw function
310- let draw_function_id = opaque_draw_functions
285+ let draw_function = opaque_draw_functions
311286 . read ( )
312287 . id :: < DrawSpecializedPipelineCommands > ( ) ;
313288
314289 // Render phases are per-view, so we need to iterate over all views so that
315290 // the entity appears in them. (In this example, we have only one view, but
316291 // it's good practice to loop over all views anyway.)
317- for ( view_visible_entities, view, msaa, no_indirect_drawing, gpu_occlusion_culling) in
318- views. iter ( )
319- {
292+ for ( view_visible_entities, view, msaa) in views. iter ( ) {
320293 let Some ( opaque_phase) = opaque_render_phases. get_mut ( & view. retained_view_entity ) else {
321294 continue ;
322295 } ;
323296
324- // Create *work item buffers* if necessary. Work item buffers store the
325- // indices of meshes that are to be rendered when indirect drawing is
326- // enabled.
327- let work_item_buffer = gpu_preprocessing:: get_or_create_work_item_buffer :: < Opaque3d > (
328- work_item_buffers,
329- view. retained_view_entity ,
330- no_indirect_drawing,
331- gpu_occlusion_culling,
332- ) ;
333-
334- // Initialize those work item buffers in preparation for this new frame.
335- gpu_preprocessing:: init_work_item_buffers (
336- work_item_buffer,
337- late_indexed_indirect_parameters_buffer,
338- late_non_indexed_indirect_parameters_buffer,
339- ) ;
340-
341297 // Create the key based on the view. In this case we only care about MSAA and HDR
342298 let view_key = MeshPipelineKey :: from_msaa_samples ( msaa. samples ( ) )
343299 | MeshPipelineKey :: from_hdr ( view. hdr ) ;
344300
345- // Set up a slot to hold information about the batch set we're going to
346- // create. If there are any of our custom meshes in the scene, we'll
347- // need this information in order for Bevy to kick off the rendering.
348- let mut mesh_batch_set_info = None ;
349-
350301 // Find all the custom rendered entities that are visible from this
351302 // view.
352303 for & ( render_entity, visible_entity) in
@@ -363,34 +314,14 @@ fn queue_custom_mesh_pipeline(
363314 continue ;
364315 } ;
365316
317+ let ( vertex_slab, index_slab) = mesh_allocator. mesh_slabs ( & mesh_instance. mesh_asset_id ) ;
318+
366319 // Specialize the key for the current mesh entity
367320 // For this example we only specialize based on the mesh topology
368321 // but you could have more complex keys and that's where you'd need to create those keys
369322 let mut mesh_key = view_key;
370323 mesh_key |= MeshPipelineKey :: from_primitive_topology ( mesh. primitive_topology ( ) ) ;
371324
372- // Initialize the batch set information if this was the first custom
373- // mesh we saw. We'll need that information later to create the
374- // batch set.
375- if mesh_batch_set_info. is_none ( ) {
376- mesh_batch_set_info = Some ( MeshBatchSetInfo {
377- indirect_parameters_index : phase_indirect_parameters_buffers
378- . buffers
379- . allocate ( mesh. indexed ( ) , 1 ) ,
380- is_indexed : mesh. indexed ( ) ,
381- } ) ;
382- }
383- let mesh_info = mesh_batch_set_info. unwrap ( ) ;
384-
385- // Allocate some input and output indices. We'll need these to
386- // create the *work item* below.
387- let Some ( input_index) =
388- MeshPipeline :: get_binned_index ( & system_param_item, visible_entity)
389- else {
390- continue ;
391- } ;
392- let output_index = data_buffer. add ( ) as u32 ;
393-
394325 // Finally, we can specialize the pipeline based on the key
395326 let pipeline_id = specialized_mesh_pipelines
396327 . specialize (
@@ -399,8 +330,8 @@ fn queue_custom_mesh_pipeline(
399330 mesh_key,
400331 & mesh. layout ,
401332 )
402- // This should never with this example, but if your pipeline specialization
403- // can fail you need to handle the error here
333+ // This should never happen with this example, but if your pipeline
334+ // specialization can fail you need to handle the error here
404335 . expect ( "Failed to specialize mesh pipeline" ) ;
405336
406337 // Bump the change tick so that Bevy is forced to rebuild the bin.
@@ -410,59 +341,29 @@ fn queue_custom_mesh_pipeline(
410341 // Add the mesh with our specialized pipeline
411342 opaque_phase. add (
412343 Opaque3dBatchSetKey {
413- draw_function : draw_function_id ,
344+ draw_function,
414345 pipeline : pipeline_id,
415346 material_bind_group_index : None ,
416- vertex_slab : default ( ) ,
417- index_slab : None ,
347+ vertex_slab : vertex_slab . unwrap_or_default ( ) ,
348+ index_slab,
418349 lightmap_slab : None ,
419350 } ,
420- // The asset ID is arbitrary; we simply use [`AssetId::invalid`],
421- // but you can use anything you like. Note that the asset ID need
422- // not be the ID of a [`Mesh`].
351+ // For this example we can use the mesh asset id as the bin key,
352+ // but you can use any asset_id as a key
423353 Opaque3dBinKey {
424- asset_id : AssetId :: < Mesh > :: invalid ( ) . untyped ( ) ,
354+ asset_id : mesh_instance . mesh_asset_id . into ( ) ,
425355 } ,
426356 ( render_entity, visible_entity) ,
427357 mesh_instance. current_uniform_index ,
428- // This example supports batching, but if your pipeline doesn't
429- // support it you can use `BinnedRenderPhaseType::UnbatchableMesh`
430- BinnedRenderPhaseType :: BatchableMesh ,
358+ // This example supports batching and multi draw indirect,
359+ // but if your pipeline doesn't support it you can use
360+ // `BinnedRenderPhaseType::UnbatchableMesh`
361+ BinnedRenderPhaseType :: mesh (
362+ mesh_instance. should_batch ( ) ,
363+ & gpu_preprocessing_support,
364+ ) ,
431365 * change_tick,
432366 ) ;
433-
434- // Create a *work item*. A work item tells the Bevy renderer to
435- // transform the mesh on GPU.
436- work_item_buffer. push (
437- mesh. indexed ( ) ,
438- PreprocessWorkItem {
439- input_index : input_index. into ( ) ,
440- output_or_indirect_parameters_index : if no_indirect_drawing {
441- output_index
442- } else {
443- mesh_info. indirect_parameters_index
444- } ,
445- } ,
446- ) ;
447- }
448-
449- // Now if there were any meshes, we need to add a command to the
450- // indirect parameters buffer, so that the renderer will end up
451- // enqueuing a command to draw the mesh.
452- if let Some ( mesh_info) = mesh_batch_set_info {
453- phase_indirect_parameters_buffers
454- . buffers
455- . add_batch_set ( mesh_info. is_indexed , mesh_info. indirect_parameters_index ) ;
456367 }
457368 }
458369}
459-
460- // If we end up having any custom meshes to draw, this contains information
461- // needed to create the batch set.
462- #[ derive( Clone , Copy ) ]
463- struct MeshBatchSetInfo {
464- /// The first index of the mesh batch in the indirect parameters buffer.
465- indirect_parameters_index : u32 ,
466- /// Whether the mesh is indexed (has an index buffer).
467- is_indexed : bool ,
468- }
0 commit comments