mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Stop extracting mesh entities to the render world. (#11803)
This fixes a `FIXME` in `extract_meshes` and results in a performance improvement. As a result of this change, meshes in the render world might not be attached to entities anymore. Therefore, the `entity` parameter to `RenderCommand::render()` is now wrapped in an `Option`. Most applications that use the render app's ECS can simply unwrap the `Option`. Note that for now sprites, gizmos, and UI elements still use the render world as usual. ## Migration guide * For efficiency reasons, some meshes in the render world may not have corresponding `Entity` IDs anymore. As a result, the `entity` parameter to `RenderCommand::render()` is now wrapped in an `Option`. Custom rendering code may need to be updated to handle the case in which no `Entity` exists for an object that is to be rendered.
This commit is contained in:
parent
55ada617cb
commit
3af8526786
12 changed files with 73 additions and 39 deletions
|
@ -383,10 +383,13 @@ impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I>
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: ROQueryItem<'w, Self::ViewQuery>,
|
||||
uniform_index: ROQueryItem<'w, Self::ItemQuery>,
|
||||
uniform_index: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
||||
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(uniform_index) = uniform_index else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&bind_group.into_inner().bindgroup,
|
||||
|
@ -406,10 +409,13 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: ROQueryItem<'w, Self::ViewQuery>,
|
||||
handle: ROQueryItem<'w, Self::ItemQuery>,
|
||||
handle: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
||||
line_gizmos: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(handle) = handle else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
let Some(line_gizmo) = line_gizmos.into_inner().get(handle) else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
|
|
@ -388,7 +388,7 @@ impl<P: PhaseItem, M: Material, const I: usize> RenderCommand<P> for SetMaterial
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
(materials, material_instances): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -912,7 +912,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
|
|||
&'_ ViewUniformOffset,
|
||||
Option<&'_ PreviousViewProjectionUniformOffset>,
|
||||
),
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -256,12 +256,7 @@ pub struct RenderMeshInstance {
|
|||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct RenderMeshInstances(EntityHashMap<Entity, RenderMeshInstance>);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Mesh3d;
|
||||
|
||||
pub fn extract_meshes(
|
||||
mut commands: Commands,
|
||||
mut previous_len: Local<usize>,
|
||||
mut render_mesh_instances: ResMut<RenderMeshInstances>,
|
||||
mut thread_local_queues: Local<ThreadLocal<Cell<Vec<(Entity, RenderMeshInstance)>>>>,
|
||||
meshes_query: Extract<
|
||||
|
@ -328,15 +323,9 @@ pub fn extract_meshes(
|
|||
);
|
||||
|
||||
render_mesh_instances.clear();
|
||||
let mut entities = Vec::with_capacity(*previous_len);
|
||||
for queue in thread_local_queues.iter_mut() {
|
||||
// FIXME: Remove this - it is just a workaround to enable rendering to work as
|
||||
// render commands require an entity to exist at the moment.
|
||||
entities.extend(queue.get_mut().iter().map(|(e, _)| (*e, Mesh3d)));
|
||||
render_mesh_instances.extend(queue.get_mut().drain(..));
|
||||
}
|
||||
*previous_len = entities.len();
|
||||
commands.insert_or_spawn_batch(entities);
|
||||
}
|
||||
|
||||
#[derive(Resource, Clone)]
|
||||
|
@ -1050,7 +1039,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I>
|
|||
'w,
|
||||
Self::ViewQuery,
|
||||
>,
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
_: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -1085,7 +1074,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
(bind_groups, mesh_instances, skin_indices, morph_indices, lightmaps): SystemParamItem<
|
||||
'w,
|
||||
'_,
|
||||
|
@ -1154,7 +1143,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
(meshes, mesh_instances): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -190,6 +190,11 @@ pub trait RenderCommand<P: PhaseItem> {
|
|||
///
|
||||
/// The item is the entity that will be rendered for the corresponding view.
|
||||
/// All components have to be accessed read only.
|
||||
///
|
||||
/// For efficiency reasons, Bevy doesn't always extract entities to the
|
||||
/// render world; for instance, entities that simply consist of meshes are
|
||||
/// often not extracted. If the entity doesn't exist in the render world,
|
||||
/// the supplied query data will be `None`.
|
||||
type ItemQuery: ReadOnlyQueryData;
|
||||
|
||||
/// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups,
|
||||
|
@ -197,7 +202,7 @@ pub trait RenderCommand<P: PhaseItem> {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
view: ROQueryItem<'w, Self::ViewQuery>,
|
||||
entity: ROQueryItem<'w, Self::ItemQuery>,
|
||||
entity: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
||||
param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult;
|
||||
|
@ -220,13 +225,22 @@ macro_rules! render_command_tuple_impl {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
($($view,)*): ROQueryItem<'w, Self::ViewQuery>,
|
||||
($($entity,)*): ROQueryItem<'w, Self::ItemQuery>,
|
||||
maybe_entities: Option<ROQueryItem<'w, Self::ItemQuery>>,
|
||||
($($name,)*): SystemParamItem<'w, '_, Self::Param>,
|
||||
_pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, $entity, $name, _pass) {
|
||||
return RenderCommandResult::Failure;
|
||||
})*
|
||||
match maybe_entities {
|
||||
None => {
|
||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, None, $name, _pass) {
|
||||
return RenderCommandResult::Failure;
|
||||
})*
|
||||
}
|
||||
Some(($($entity,)*)) => {
|
||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, Some($entity), $name, _pass) {
|
||||
return RenderCommandResult::Failure;
|
||||
})*
|
||||
}
|
||||
}
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +292,7 @@ where
|
|||
) {
|
||||
let param = self.state.get_manual(world);
|
||||
let view = self.view.get_manual(world, view).unwrap();
|
||||
let entity = self.entity.get_manual(world, item.entity()).unwrap();
|
||||
let entity = self.entity.get_manual(world, item.entity()).ok();
|
||||
// TODO: handle/log `RenderCommand` failure
|
||||
C::render(item, view, entity, param, pass);
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -337,7 +337,7 @@ impl<P: PhaseItem, M: Material2d, const I: usize> RenderCommand<P>
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
(materials, material_instances): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -624,7 +624,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dViewBindGroup<I
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
(view_uniform, mesh2d_view_bind_group): ROQueryItem<'w, Self::ViewQuery>,
|
||||
_view: (),
|
||||
_view: Option<()>,
|
||||
_param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -644,7 +644,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dBindGroup<I> {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
mesh2d_bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -673,7 +673,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh2d {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
_item_query: (),
|
||||
_item_query: Option<()>,
|
||||
(meshes, render_mesh2d_instances): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
|
@ -752,7 +752,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteViewBindGroup<I
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
view_uniform: &'_ ViewUniformOffset,
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -773,11 +773,14 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteTextureBindGrou
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'_ SpriteBatch,
|
||||
batch: Option<&'_ SpriteBatch>,
|
||||
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let image_bind_groups = image_bind_groups.into_inner();
|
||||
let Some(batch) = batch else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
|
@ -800,11 +803,15 @@ impl<P: PhaseItem> RenderCommand<P> for DrawSpriteBatch {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'_ SpriteBatch,
|
||||
batch: Option<&'_ SpriteBatch>,
|
||||
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let sprite_meta = sprite_meta.into_inner();
|
||||
let Some(batch) = batch else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_index_buffer(
|
||||
sprite_meta.sprite_index_buffer.buffer().unwrap().slice(..),
|
||||
0,
|
||||
|
|
|
@ -161,7 +161,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
view_uniform: &'w ViewUniformOffset,
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -183,11 +183,15 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I>
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'w UiBatch,
|
||||
batch: Option<&'w UiBatch>,
|
||||
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let image_bind_groups = image_bind_groups.into_inner();
|
||||
let Some(batch) = batch else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
|
@ -202,10 +206,14 @@ impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'w UiBatch,
|
||||
batch: Option<&'w UiBatch>,
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(batch) = batch else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
|
||||
pass.draw(batch.range.clone(), 0..1);
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -272,7 +272,7 @@ impl<P: PhaseItem, M: UiMaterial, const I: usize> RenderCommand<P> for SetMatUiV
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
view_uniform: &'w ViewUniformOffset,
|
||||
_entity: (),
|
||||
_entity: Option<()>,
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -296,10 +296,13 @@ impl<P: PhaseItem, M: UiMaterial, const I: usize> RenderCommand<P>
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
material_handle: ROQueryItem<'_, Self::ItemQuery>,
|
||||
material_handle: Option<ROQueryItem<'_, Self::ItemQuery>>,
|
||||
materials: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(material_handle) = material_handle else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
let Some(material) = materials.into_inner().get(&material_handle.material) else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
@ -318,10 +321,14 @@ impl<P: PhaseItem, M: UiMaterial> RenderCommand<P> for DrawUiMaterialNode<M> {
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'w UiMaterialBatch<M>,
|
||||
batch: Option<&'w UiMaterialBatch<M>>,
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(batch) = batch else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
|
||||
pass.draw(batch.range.clone(), 0..1);
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -244,7 +244,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
|
|||
fn render<'w>(
|
||||
item: &P,
|
||||
_view: (),
|
||||
instance_buffer: &'w InstanceBuffer,
|
||||
instance_buffer: Option<&'w InstanceBuffer>,
|
||||
(meshes, render_mesh_instances): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -254,6 +254,9 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
|
|||
let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id) else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
let Some(instance_buffer) = instance_buffer else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
pass.set_vertex_buffer(1, instance_buffer.buffer.slice(..));
|
||||
|
|
Loading…
Reference in a new issue