mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
Don't ignore draw errors (#13240)
# Objective - It's possible to have errors in a draw command, but these errors are ignored ## Solution - Return a result with the error ## Changelog Renamed `RenderCommandResult::Failure` to `RenderCommandResult::Skip` Added a `reason` string parameter to `RenderCommandResult::Failure` ## Migration Guide If you were using `RenderCommandResult::Failure` to just ignore an error and retry later, use `RenderCommandResult::Skip` instead. This wasn't intentional, but this PR should also help with https://github.com/bevyengine/bevy/issues/12660 since we can turn a few unwraps into error messages now. --------- Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com>
This commit is contained in:
parent
ee88d79d88
commit
3faca1e549
19 changed files with 170 additions and 82 deletions
|
@ -58,7 +58,7 @@ impl ViewNode for MainTransparentPass2dNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !transparent_phase.items.is_empty() {
|
if !transparent_phase.items.is_empty() {
|
||||||
transparent_phase.render(&mut render_pass, world, view_entity);
|
transparent_phase.render(&mut render_pass, world, view_entity)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pass_span.end(&mut render_pass);
|
pass_span.end(&mut render_pass);
|
||||||
|
|
|
@ -12,6 +12,7 @@ use bevy_render::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ViewDepthTexture, ViewTarget, ViewUniformOffset},
|
view::{ViewDepthTexture, ViewTarget, ViewUniformOffset},
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
@ -95,14 +96,18 @@ impl ViewNode for MainOpaquePass3dNode {
|
||||||
if !opaque_phase.is_empty() {
|
if !opaque_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _opaque_main_pass_3d_span = info_span!("opaque_main_pass_3d").entered();
|
let _opaque_main_pass_3d_span = info_span!("opaque_main_pass_3d").entered();
|
||||||
opaque_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = opaque_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
error!("Error encountered while rendering the opaque phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alpha draws
|
// Alpha draws
|
||||||
if !alpha_mask_phase.is_empty() {
|
if !alpha_mask_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _alpha_mask_main_pass_3d_span = info_span!("alpha_mask_main_pass_3d").entered();
|
let _alpha_mask_main_pass_3d_span = info_span!("alpha_mask_main_pass_3d").entered();
|
||||||
alpha_mask_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = alpha_mask_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
error!("Error encountered while rendering the alpha mask phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skybox draw using a fullscreen triangle
|
// Skybox draw using a fullscreen triangle
|
||||||
|
|
|
@ -9,6 +9,7 @@ use bevy_render::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ViewDepthTexture, ViewTarget},
|
view::{ViewDepthTexture, ViewTarget},
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -98,7 +99,11 @@ impl ViewNode for MainTransmissivePass3dNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// render items in range
|
// render items in range
|
||||||
transmissive_phase.render_range(&mut render_pass, world, view_entity, range);
|
if let Err(err) =
|
||||||
|
transmissive_phase.render_range(&mut render_pass, world, view_entity, range)
|
||||||
|
{
|
||||||
|
error!("Error encountered while rendering the transmissive phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut render_pass =
|
let mut render_pass =
|
||||||
|
@ -108,7 +113,9 @@ impl ViewNode for MainTransmissivePass3dNode {
|
||||||
render_pass.set_camera_viewport(viewport);
|
render_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
transmissive_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = transmissive_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
error!("Error encountered while rendering the transmissive phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use bevy_render::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ViewDepthTexture, ViewTarget},
|
view::{ViewDepthTexture, ViewTarget},
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
@ -70,7 +71,9 @@ impl ViewNode for MainTransparentPass3dNode {
|
||||||
render_pass.set_camera_viewport(viewport);
|
render_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
transparent_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
error!("Error encountered while rendering the transparent phase {err:?}");
|
||||||
|
}
|
||||||
|
|
||||||
pass_span.end(&mut render_pass);
|
pass_span.end(&mut render_pass);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use bevy_render::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::ViewDepthTexture,
|
view::ViewDepthTexture,
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
@ -149,14 +150,23 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
||||||
{
|
{
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
|
let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
|
||||||
opaque_deferred_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = opaque_deferred_phase.render(&mut render_pass, world, view_entity)
|
||||||
|
{
|
||||||
|
error!("Error encountered while rendering the opaque deferred phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alpha masked draws
|
// Alpha masked draws
|
||||||
if !alpha_mask_deferred_phase.is_empty() {
|
if !alpha_mask_deferred_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
|
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
|
||||||
alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) =
|
||||||
|
alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity)
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"Error encountered while rendering the alpha mask deferred phase {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
|
|
|
@ -9,6 +9,7 @@ use bevy_render::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ViewDepthTexture, ViewUniformOffset},
|
view::{ViewDepthTexture, ViewUniformOffset},
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
@ -125,14 +126,23 @@ impl ViewNode for PrepassNode {
|
||||||
{
|
{
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _opaque_prepass_span = info_span!("opaque_prepass").entered();
|
let _opaque_prepass_span = info_span!("opaque_prepass").entered();
|
||||||
opaque_prepass_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = opaque_prepass_phase.render(&mut render_pass, world, view_entity)
|
||||||
|
{
|
||||||
|
error!("Error encountered while rendering the opaque prepass phase {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alpha masked draws
|
// Alpha masked draws
|
||||||
if !alpha_mask_prepass_phase.is_empty() {
|
if !alpha_mask_prepass_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _alpha_mask_prepass_span = info_span!("alpha_mask_prepass").entered();
|
let _alpha_mask_prepass_span = info_span!("alpha_mask_prepass").entered();
|
||||||
alpha_mask_prepass_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) =
|
||||||
|
alpha_mask_prepass_phase.render(&mut render_pass, world, view_entity)
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"Error encountered while rendering the alpha mask prepass phase {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skybox draw using a fullscreen triangle
|
// Skybox draw using a fullscreen triangle
|
||||||
|
|
|
@ -540,7 +540,7 @@ impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I>
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(uniform_index) = uniform_index else {
|
let Some(uniform_index) = uniform_index else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
pass.set_bind_group(
|
pass.set_bind_group(
|
||||||
I,
|
I,
|
||||||
|
@ -566,10 +566,10 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(handle) = handle else {
|
let Some(handle) = handle else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(line_gizmo) = line_gizmos.into_inner().get(handle) else {
|
let Some(line_gizmo) = line_gizmos.into_inner().get(handle) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
if line_gizmo.vertex_count < 2 {
|
if line_gizmo.vertex_count < 2 {
|
||||||
|
@ -612,10 +612,10 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(handle) = handle else {
|
let Some(handle) = handle else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(line_gizmo) = line_gizmos.into_inner().get(handle) else {
|
let Some(line_gizmo) = line_gizmos.into_inner().get(handle) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
if line_gizmo.vertex_count <= 2 || !line_gizmo.strip {
|
if line_gizmo.vertex_count <= 2 || !line_gizmo.strip {
|
||||||
|
|
|
@ -456,10 +456,10 @@ impl<P: PhaseItem, M: Material, const I: usize> RenderCommand<P> for SetMaterial
|
||||||
let material_instances = material_instances.into_inner();
|
let material_instances = material_instances.into_inner();
|
||||||
|
|
||||||
let Some(material_asset_id) = material_instances.get(&item.entity()) else {
|
let Some(material_asset_id) = material_instances.get(&item.entity()) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(material) = materials.get(*material_asset_id) else {
|
let Some(material) = materials.get(*material_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
pass.set_bind_group(I, &material.bind_group, &[]);
|
pass.set_bind_group(I, &material.bind_group, &[]);
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
|
|
|
@ -1445,7 +1445,11 @@ impl Node for ShadowPassNode {
|
||||||
let pass_span =
|
let pass_span =
|
||||||
diagnostics.pass_span(&mut render_pass, view_light.pass_name.clone());
|
diagnostics.pass_span(&mut render_pass, view_light.pass_name.clone());
|
||||||
|
|
||||||
shadow_phase.render(&mut render_pass, world, view_light_entity);
|
if let Err(err) =
|
||||||
|
shadow_phase.render(&mut render_pass, world, view_light_entity)
|
||||||
|
{
|
||||||
|
error!("Error encountered while rendering the shadow phase {err:?}");
|
||||||
|
}
|
||||||
|
|
||||||
pass_span.end(&mut render_pass);
|
pass_span.end(&mut render_pass);
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
|
|
|
@ -2261,12 +2261,11 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
|
||||||
is_morphed,
|
is_morphed,
|
||||||
has_motion_vector_prepass,
|
has_motion_vector_prepass,
|
||||||
) else {
|
) else {
|
||||||
error!(
|
return RenderCommandResult::Failure(
|
||||||
"The MeshBindGroups resource wasn't set in the render phase. \
|
"The MeshBindGroups resource wasn't set in the render phase. \
|
||||||
It should be set by the prepare_mesh_bind_group system.\n\
|
It should be set by the prepare_mesh_bind_group system.\n\
|
||||||
This is a bevy bug! Please open an issue."
|
This is a bevy bug! Please open an issue.",
|
||||||
);
|
);
|
||||||
return RenderCommandResult::Failure;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut dynamic_offsets: [u32; 3] = Default::default();
|
let mut dynamic_offsets: [u32; 3] = Default::default();
|
||||||
|
@ -2349,7 +2348,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
||||||
if !has_preprocess_bind_group
|
if !has_preprocess_bind_group
|
||||||
|| !preprocess_pipelines.pipelines_are_loaded(&pipeline_cache)
|
|| !preprocess_pipelines.pipelines_are_loaded(&pipeline_cache)
|
||||||
{
|
{
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2359,13 +2358,13 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
||||||
let mesh_allocator = mesh_allocator.into_inner();
|
let mesh_allocator = mesh_allocator.into_inner();
|
||||||
|
|
||||||
let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.entity()) else {
|
let Some(mesh_asset_id) = mesh_instances.mesh_asset_id(item.entity()) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
|
let Some(gpu_mesh) = meshes.get(mesh_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
|
let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(&mesh_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate the indirect offset, and look up the buffer.
|
// Calculate the indirect offset, and look up the buffer.
|
||||||
|
@ -2374,7 +2373,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
||||||
Some(index) => match indirect_parameters_buffer.buffer() {
|
Some(index) => match indirect_parameters_buffer.buffer() {
|
||||||
None => {
|
None => {
|
||||||
warn!("Not rendering mesh because indirect parameters buffer wasn't present");
|
warn!("Not rendering mesh because indirect parameters buffer wasn't present");
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
}
|
}
|
||||||
Some(buffer) => Some((
|
Some(buffer) => Some((
|
||||||
index as u64 * mem::size_of::<IndirectParameters>() as u64,
|
index as u64 * mem::size_of::<IndirectParameters>() as u64,
|
||||||
|
@ -2395,7 +2394,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
||||||
} => {
|
} => {
|
||||||
let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
|
let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(&mesh_asset_id)
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
||||||
Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError,
|
Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError,
|
||||||
RunSubGraphError, SlotInfo, SlotInfos,
|
RunSubGraphError, SlotInfo, SlotInfos,
|
||||||
},
|
},
|
||||||
|
render_phase::DrawError,
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
pub use bevy_ecs::label::DynEq;
|
pub use bevy_ecs::label::DynEq;
|
||||||
|
@ -97,6 +98,8 @@ pub enum NodeRunError {
|
||||||
OutputSlotError(#[from] OutputSlotError),
|
OutputSlotError(#[from] OutputSlotError),
|
||||||
#[error("encountered an error when running a sub-graph")]
|
#[error("encountered an error when running a sub-graph")]
|
||||||
RunSubGraphError(#[from] RunSubGraphError),
|
RunSubGraphError(#[from] RunSubGraphError),
|
||||||
|
#[error("encountered an error when executing draw command")]
|
||||||
|
DrawError(#[from] DrawError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of input and output [`Edges`](Edge) for a [`Node`].
|
/// A collection of input and output [`Edges`](Edge) for a [`Node`].
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::render_phase::{PhaseItem, TrackedRenderPass};
|
||||||
use bevy_app::{App, SubApp};
|
use bevy_app::{App, SubApp};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{QueryState, ROQueryItem, ReadOnlyQueryData},
|
query::{QueryEntityError, QueryState, ROQueryItem, ReadOnlyQueryData},
|
||||||
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ use std::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
/// A draw function used to draw [`PhaseItem`]s.
|
/// A draw function used to draw [`PhaseItem`]s.
|
||||||
///
|
///
|
||||||
|
@ -34,7 +35,17 @@ pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
item: &P,
|
item: &P,
|
||||||
);
|
) -> Result<(), DrawError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq, Eq)]
|
||||||
|
pub enum DrawError {
|
||||||
|
#[error("Failed to execute render command {0:?}")]
|
||||||
|
RenderCommandFailure(&'static str),
|
||||||
|
#[error("Failed to get execute view query")]
|
||||||
|
InvalidViewQuery,
|
||||||
|
#[error("View entity not found")]
|
||||||
|
ViewEntityNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this generic?
|
// TODO: make this generic?
|
||||||
|
@ -212,7 +223,8 @@ pub trait RenderCommand<P: PhaseItem> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RenderCommandResult {
|
pub enum RenderCommandResult {
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Skip,
|
||||||
|
Failure(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! render_command_tuple_impl {
|
macro_rules! render_command_tuple_impl {
|
||||||
|
@ -232,14 +244,22 @@ macro_rules! render_command_tuple_impl {
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
match maybe_entities {
|
match maybe_entities {
|
||||||
None => {
|
None => {
|
||||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, None, $name, _pass) {
|
$(
|
||||||
return RenderCommandResult::Failure;
|
match $name::render(_item, $view, None, $name, _pass) {
|
||||||
})*
|
RenderCommandResult::Skip => return RenderCommandResult::Skip,
|
||||||
|
RenderCommandResult::Failure(reason) => return RenderCommandResult::Failure(reason),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
Some(($($entity,)*)) => {
|
Some(($($entity,)*)) => {
|
||||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, Some($entity), $name, _pass) {
|
$(
|
||||||
return RenderCommandResult::Failure;
|
match $name::render(_item, $view, Some($entity), $name, _pass) {
|
||||||
})*
|
RenderCommandResult::Skip => return RenderCommandResult::Skip,
|
||||||
|
RenderCommandResult::Failure(reason) => return RenderCommandResult::Failure(reason),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
|
@ -290,12 +310,23 @@ where
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
item: &P,
|
item: &P,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
let param = self.state.get_manual(world);
|
let param = self.state.get_manual(world);
|
||||||
let view = self.view.get_manual(world, view).unwrap();
|
let view = match self.view.get_manual(world, view) {
|
||||||
|
Ok(view) => view,
|
||||||
|
Err(err) => match err {
|
||||||
|
QueryEntityError::NoSuchEntity(_) => return Err(DrawError::ViewEntityNotFound),
|
||||||
|
QueryEntityError::QueryDoesNotMatch(_) | QueryEntityError::AliasedMutability(_) => {
|
||||||
|
return Err(DrawError::InvalidViewQuery)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let entity = self.entity.get_manual(world, item.entity()).ok();
|
let entity = self.entity.get_manual(world, item.entity()).ok();
|
||||||
// TODO: handle/log `RenderCommand` failure
|
match C::render(item, view, entity, param, pass) {
|
||||||
C::render(item, view, entity, param, pass);
|
RenderCommandResult::Success | RenderCommandResult::Skip => Ok(()),
|
||||||
|
RenderCommandResult::Failure(reason) => Err(DrawError::RenderCommandFailure(reason)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,7 @@ where
|
||||||
render_pass: &mut TrackedRenderPass<'w>,
|
render_pass: &mut TrackedRenderPass<'w>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
{
|
{
|
||||||
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
||||||
let mut draw_functions = draw_functions.write();
|
let mut draw_functions = draw_functions.write();
|
||||||
|
@ -323,9 +323,11 @@ where
|
||||||
// locks.
|
// locks.
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_batchable_meshes(render_pass, world, view);
|
self.render_batchable_meshes(render_pass, world, view)?;
|
||||||
self.render_unbatchable_meshes(render_pass, world, view);
|
self.render_unbatchable_meshes(render_pass, world, view)?;
|
||||||
self.render_non_meshes(render_pass, world, view);
|
self.render_non_meshes(render_pass, world, view)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders all batchable meshes queued in this phase.
|
/// Renders all batchable meshes queued in this phase.
|
||||||
|
@ -334,7 +336,7 @@ where
|
||||||
render_pass: &mut TrackedRenderPass<'w>,
|
render_pass: &mut TrackedRenderPass<'w>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
||||||
let mut draw_functions = draw_functions.write();
|
let mut draw_functions = draw_functions.write();
|
||||||
|
|
||||||
|
@ -355,9 +357,11 @@ where
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
draw_function.draw(world, render_pass, view, &binned_phase_item);
|
draw_function.draw(world, render_pass, view, &binned_phase_item)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders all unbatchable meshes queued in this phase.
|
/// Renders all unbatchable meshes queued in this phase.
|
||||||
|
@ -366,7 +370,7 @@ where
|
||||||
render_pass: &mut TrackedRenderPass<'w>,
|
render_pass: &mut TrackedRenderPass<'w>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
||||||
let mut draw_functions = draw_functions.write();
|
let mut draw_functions = draw_functions.write();
|
||||||
|
|
||||||
|
@ -412,9 +416,10 @@ where
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
draw_function.draw(world, render_pass, view, &binned_phase_item);
|
draw_function.draw(world, render_pass, view, &binned_phase_item)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders all objects of type [`BinnedRenderPhaseType::NonMesh`].
|
/// Renders all objects of type [`BinnedRenderPhaseType::NonMesh`].
|
||||||
|
@ -425,7 +430,7 @@ where
|
||||||
render_pass: &mut TrackedRenderPass<'w>,
|
render_pass: &mut TrackedRenderPass<'w>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
let draw_functions = world.resource::<DrawFunctions<BPI>>();
|
||||||
let mut draw_functions = draw_functions.write();
|
let mut draw_functions = draw_functions.write();
|
||||||
|
|
||||||
|
@ -439,8 +444,10 @@ where
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
draw_function.draw(world, render_pass, view, &binned_phase_item);
|
draw_function.draw(world, render_pass, view, &binned_phase_item)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
@ -769,8 +776,8 @@ where
|
||||||
render_pass: &mut TrackedRenderPass<'w>,
|
render_pass: &mut TrackedRenderPass<'w>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
self.render_range(render_pass, world, view, ..);
|
self.render_range(render_pass, world, view, ..)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders all [`PhaseItem`]s in the provided `range` (based on their index in `self.items`) using their corresponding draw functions.
|
/// Renders all [`PhaseItem`]s in the provided `range` (based on their index in `self.items`) using their corresponding draw functions.
|
||||||
|
@ -780,7 +787,7 @@ where
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
view: Entity,
|
view: Entity,
|
||||||
range: impl SliceIndex<[I], Output = [I]>,
|
range: impl SliceIndex<[I], Output = [I]>,
|
||||||
) {
|
) -> Result<(), DrawError> {
|
||||||
let items = self
|
let items = self
|
||||||
.items
|
.items
|
||||||
.get(range)
|
.get(range)
|
||||||
|
@ -798,10 +805,11 @@ where
|
||||||
index += 1;
|
index += 1;
|
||||||
} else {
|
} else {
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
|
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
|
||||||
draw_function.draw(world, render_pass, view, item);
|
draw_function.draw(world, render_pass, view, item)?;
|
||||||
index += batch_range.len();
|
index += batch_range.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,7 +1089,7 @@ impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
|
||||||
pass.set_render_pipeline(pipeline);
|
pass.set_render_pipeline(pipeline);
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
} else {
|
} else {
|
||||||
RenderCommandResult::Failure
|
RenderCommandResult::Skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,10 +338,10 @@ impl<P: PhaseItem, M: Material2d, const I: usize> RenderCommand<P>
|
||||||
let materials = materials.into_inner();
|
let materials = materials.into_inner();
|
||||||
let material_instances = material_instances.into_inner();
|
let material_instances = material_instances.into_inner();
|
||||||
let Some(material_instance) = material_instances.get(&item.entity()) else {
|
let Some(material_instance) = material_instances.get(&item.entity()) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(material2d) = materials.get(*material_instance) else {
|
let Some(material2d) = materials.get(*material_instance) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
pass.set_bind_group(I, &material2d.bind_group, &[]);
|
pass.set_bind_group(I, &material2d.bind_group, &[]);
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
|
|
|
@ -718,13 +718,13 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh2d {
|
||||||
let Some(RenderMesh2dInstance { mesh_asset_id, .. }) =
|
let Some(RenderMesh2dInstance { mesh_asset_id, .. }) =
|
||||||
render_mesh2d_instances.get(&item.entity())
|
render_mesh2d_instances.get(&item.entity())
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(gpu_mesh) = meshes.get(*mesh_asset_id) else {
|
let Some(gpu_mesh) = meshes.get(*mesh_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(mesh_asset_id) else {
|
let Some(vertex_buffer_slice) = mesh_allocator.mesh_vertex_slice(mesh_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
|
pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
|
||||||
|
@ -737,7 +737,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh2d {
|
||||||
} => {
|
} => {
|
||||||
let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(mesh_asset_id)
|
let Some(index_buffer_slice) = mesh_allocator.mesh_index_slice(mesh_asset_id)
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
||||||
|
|
|
@ -804,7 +804,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteTextureBindGrou
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let image_bind_groups = image_bind_groups.into_inner();
|
let image_bind_groups = image_bind_groups.into_inner();
|
||||||
let Some(batch) = batch else {
|
let Some(batch) = batch else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_bind_group(
|
pass.set_bind_group(
|
||||||
|
@ -834,7 +834,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawSpriteBatch {
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let sprite_meta = sprite_meta.into_inner();
|
let sprite_meta = sprite_meta.into_inner();
|
||||||
let Some(batch) = batch else {
|
let Some(batch) = batch else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_index_buffer(
|
pass.set_index_buffer(
|
||||||
|
|
|
@ -15,6 +15,7 @@ use bevy_render::{
|
||||||
renderer::*,
|
renderer::*,
|
||||||
view::*,
|
view::*,
|
||||||
};
|
};
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
|
|
||||||
pub struct UiPassNode {
|
pub struct UiPassNode {
|
||||||
ui_view_query: QueryState<(&'static ViewTarget, &'static ExtractedCamera), With<ExtractedView>>,
|
ui_view_query: QueryState<(&'static ViewTarget, &'static ExtractedCamera), With<ExtractedView>>,
|
||||||
|
@ -80,7 +81,9 @@ impl Node for UiPassNode {
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
render_pass.set_camera_viewport(viewport);
|
render_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
transparent_phase.render(&mut render_pass, world, view_entity);
|
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
error!("Error encountered while rendering the ui phase {err:?}");
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -168,11 +171,10 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
|
||||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
pass.set_bind_group(
|
let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {
|
||||||
I,
|
return RenderCommandResult::Failure("view_bind_group not available");
|
||||||
ui_meta.into_inner().view_bind_group.as_ref().unwrap(),
|
};
|
||||||
&[view_uniform.offset],
|
pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);
|
||||||
);
|
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +194,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I>
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let image_bind_groups = image_bind_groups.into_inner();
|
let image_bind_groups = image_bind_groups.into_inner();
|
||||||
let Some(batch) = batch else {
|
let Some(batch) = batch else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
|
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
|
||||||
|
@ -214,15 +216,21 @@ impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(batch) = batch else {
|
let Some(batch) = batch else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
|
};
|
||||||
|
let ui_meta = ui_meta.into_inner();
|
||||||
|
let Some(vertices) = ui_meta.vertices.buffer() else {
|
||||||
|
return RenderCommandResult::Failure("missing vertices to draw ui");
|
||||||
|
};
|
||||||
|
let Some(indices) = ui_meta.indices.buffer() else {
|
||||||
|
return RenderCommandResult::Failure("missing indices to draw ui");
|
||||||
};
|
};
|
||||||
|
|
||||||
let ui_meta = ui_meta.into_inner();
|
|
||||||
// Store the vertices
|
// Store the vertices
|
||||||
pass.set_vertex_buffer(0, ui_meta.vertices.buffer().unwrap().slice(..));
|
pass.set_vertex_buffer(0, vertices.slice(..));
|
||||||
// Define how to "connect" the vertices
|
// Define how to "connect" the vertices
|
||||||
pass.set_index_buffer(
|
pass.set_index_buffer(
|
||||||
ui_meta.indices.buffer().unwrap().slice(..),
|
indices.slice(..),
|
||||||
0,
|
0,
|
||||||
bevy_render::render_resource::IndexFormat::Uint32,
|
bevy_render::render_resource::IndexFormat::Uint32,
|
||||||
);
|
);
|
||||||
|
|
|
@ -292,10 +292,10 @@ impl<P: PhaseItem, M: UiMaterial, const I: usize> RenderCommand<P>
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(material_handle) = material_handle else {
|
let Some(material_handle) = material_handle else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(material) = materials.into_inner().get(material_handle.material) else {
|
let Some(material) = materials.into_inner().get(material_handle.material) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
pass.set_bind_group(I, &material.bind_group, &[]);
|
pass.set_bind_group(I, &material.bind_group, &[]);
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
|
@ -317,7 +317,7 @@ impl<P: PhaseItem, M: UiMaterial> RenderCommand<P> for DrawUiMaterialNode<M> {
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let Some(batch) = batch else {
|
let Some(batch) = batch else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
|
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
|
||||||
|
|
|
@ -263,18 +263,18 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
|
||||||
|
|
||||||
let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(item.entity())
|
let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(item.entity())
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id) else {
|
let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id) else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(instance_buffer) = instance_buffer else {
|
let Some(instance_buffer) = instance_buffer else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
let Some(vertex_buffer_slice) =
|
let Some(vertex_buffer_slice) =
|
||||||
mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id)
|
mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id)
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
|
pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
|
||||||
|
@ -288,7 +288,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
|
||||||
let Some(index_buffer_slice) =
|
let Some(index_buffer_slice) =
|
||||||
mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id)
|
mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id)
|
||||||
else {
|
else {
|
||||||
return RenderCommandResult::Failure;
|
return RenderCommandResult::Skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
pass.set_index_buffer(index_buffer_slice.buffer.slice(..), 0, *index_format);
|
||||||
|
|
Loading…
Reference in a new issue