From b4c7987aa70990147268575ea2d2975fa0d5ba91 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 25 Jun 2024 09:37:29 +0200 Subject: [PATCH] Separate renderpass arc resolve & renderpass consume on end (#5794) --- deno_webgpu/render_pass.rs | 102 +-- player/src/lib.rs | 4 +- wgpu-core/src/command/bundle.rs | 34 +- wgpu-core/src/command/compute_command.rs | 2 +- wgpu-core/src/command/draw.rs | 239 +------ wgpu-core/src/command/mod.rs | 52 +- wgpu-core/src/command/render.rs | 784 +++++++++++++++-------- wgpu-core/src/command/render_command.rs | 668 +++++++++++++++++++ wgpu/src/backend/wgpu_core.rs | 339 ++++++++-- 9 files changed, 1557 insertions(+), 667 deletions(-) create mode 100644 wgpu-core/src/command/render_command.rs diff --git a/deno_webgpu/render_pass.rs b/deno_webgpu/render_pass.rs index 39dd0f2a68..5b08925803 100644 --- a/deno_webgpu/render_pass.rs +++ b/deno_webgpu/render_pass.rs @@ -9,6 +9,7 @@ use deno_core::ResourceId; use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; +use wgpu_core::global::Global; use super::error::WebGpuResult; @@ -41,7 +42,7 @@ pub fn op_webgpu_render_pass_set_viewport( .resource_table .get::(args.render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_set_viewport( + state.borrow::().render_pass_set_viewport( &mut render_pass_resource.0.borrow_mut(), args.x, args.y, @@ -49,7 +50,7 @@ pub fn op_webgpu_render_pass_set_viewport( args.height, args.min_depth, args.max_depth, - ); + )?; Ok(WebGpuResult::empty()) } @@ -68,13 +69,13 @@ pub fn op_webgpu_render_pass_set_scissor_rect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_set_scissor_rect( + state.borrow::().render_pass_set_scissor_rect( &mut render_pass_resource.0.borrow_mut(), x, y, width, height, - ); + )?; Ok(WebGpuResult::empty()) } @@ -90,10 +91,9 @@ pub fn op_webgpu_render_pass_set_blend_constant( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_set_blend_constant( - &mut render_pass_resource.0.borrow_mut(), - &color, - ); + state + .borrow::() + .render_pass_set_blend_constant(&mut render_pass_resource.0.borrow_mut(), &color)?; Ok(WebGpuResult::empty()) } @@ -109,10 +109,9 @@ pub fn op_webgpu_render_pass_set_stencil_reference( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_set_stencil_reference( - &mut render_pass_resource.0.borrow_mut(), - reference, - ); + state + .borrow::() + .render_pass_set_stencil_reference(&mut render_pass_resource.0.borrow_mut(), reference)?; Ok(WebGpuResult::empty()) } @@ -128,10 +127,9 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_begin_occlusion_query( - &mut render_pass_resource.0.borrow_mut(), - query_index, - ); + state + .borrow::() + .render_pass_begin_occlusion_query(&mut render_pass_resource.0.borrow_mut(), query_index)?; Ok(WebGpuResult::empty()) } @@ -146,9 +144,9 @@ pub fn op_webgpu_render_pass_end_occlusion_query( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_end_occlusion_query( - &mut render_pass_resource.0.borrow_mut(), - ); + state + .borrow::() + .render_pass_end_occlusion_query(&mut render_pass_resource.0.borrow_mut())?; Ok(WebGpuResult::empty()) } @@ -174,10 +172,9 @@ pub fn op_webgpu_render_pass_execute_bundles( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_execute_bundles( - &mut render_pass_resource.0.borrow_mut(), - &bundles, - ); + state + .borrow::() + .render_pass_execute_bundles(&mut render_pass_resource.0.borrow_mut(), &bundles)?; Ok(WebGpuResult::empty()) } @@ -191,11 +188,15 @@ pub fn op_webgpu_render_pass_end( let render_pass_resource = state .resource_table .take::(render_pass_rid)?; - let render_pass = &render_pass_resource.0.borrow(); - let command_encoder = render_pass.parent_id(); - let instance = state.borrow::(); - gfx_ok!(command_encoder => instance.render_pass_end(render_pass)) + // TODO: Just like parent_id ComputePass, there's going to be DynComputePass soon which will eliminate the need of doing gfx_select here. + let instance = state.borrow::(); + let parent_id = render_pass_resource.0.borrow().parent_id(); + gfx_select!(parent_id => instance.render_pass_end( + &mut render_pass_resource.0.borrow_mut() + ))?; + + Ok(WebGpuResult::empty()) } #[op2] @@ -225,12 +226,12 @@ pub fn op_webgpu_render_pass_set_bind_group( let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - wgpu_core::command::render_commands::wgpu_render_pass_set_bind_group( + state.borrow::().render_pass_set_bind_group( &mut render_pass_resource.0.borrow_mut(), index, bind_group_resource.1, dynamic_offsets_data, - ); + )?; Ok(WebGpuResult::empty()) } @@ -246,11 +247,11 @@ pub fn op_webgpu_render_pass_push_debug_group( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_push_debug_group( + state.borrow::().render_pass_push_debug_group( &mut render_pass_resource.0.borrow_mut(), group_label, 0, // wgpu#975 - ); + )?; Ok(WebGpuResult::empty()) } @@ -265,9 +266,9 @@ pub fn op_webgpu_render_pass_pop_debug_group( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_pop_debug_group( - &mut render_pass_resource.0.borrow_mut(), - ); + state + .borrow::() + .render_pass_pop_debug_group(&mut render_pass_resource.0.borrow_mut())?; Ok(WebGpuResult::empty()) } @@ -283,11 +284,11 @@ pub fn op_webgpu_render_pass_insert_debug_marker( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_insert_debug_marker( + state.borrow::().render_pass_insert_debug_marker( &mut render_pass_resource.0.borrow_mut(), marker_label, 0, // wgpu#975 - ); + )?; Ok(WebGpuResult::empty()) } @@ -306,10 +307,10 @@ pub fn op_webgpu_render_pass_set_pipeline( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_set_pipeline( + state.borrow::().render_pass_set_pipeline( &mut render_pass_resource.0.borrow_mut(), render_pipeline_resource.1, - ); + )?; Ok(WebGpuResult::empty()) } @@ -340,12 +341,13 @@ pub fn op_webgpu_render_pass_set_index_buffer( None }; - render_pass_resource.0.borrow_mut().set_index_buffer( + state.borrow::().render_pass_set_index_buffer( + &mut render_pass_resource.0.borrow_mut(), buffer_resource.1, index_format, offset, size, - ); + )?; Ok(WebGpuResult::empty()) } @@ -376,13 +378,13 @@ pub fn op_webgpu_render_pass_set_vertex_buffer( None }; - wgpu_core::command::render_commands::wgpu_render_pass_set_vertex_buffer( + state.borrow::().render_pass_set_vertex_buffer( &mut render_pass_resource.0.borrow_mut(), slot, buffer_resource.1, offset, size, - ); + )?; Ok(WebGpuResult::empty()) } @@ -401,13 +403,13 @@ pub fn op_webgpu_render_pass_draw( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_draw( + state.borrow::().render_pass_draw( &mut render_pass_resource.0.borrow_mut(), vertex_count, instance_count, first_vertex, first_instance, - ); + )?; Ok(WebGpuResult::empty()) } @@ -427,14 +429,14 @@ pub fn op_webgpu_render_pass_draw_indexed( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_draw_indexed( + state.borrow::().render_pass_draw_indexed( &mut render_pass_resource.0.borrow_mut(), index_count, instance_count, first_index, base_vertex, first_instance, - ); + )?; Ok(WebGpuResult::empty()) } @@ -454,11 +456,11 @@ pub fn op_webgpu_render_pass_draw_indirect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_draw_indirect( + state.borrow::().render_pass_draw_indirect( &mut render_pass_resource.0.borrow_mut(), buffer_resource.1, indirect_offset, - ); + )?; Ok(WebGpuResult::empty()) } @@ -478,11 +480,11 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_commands::wgpu_render_pass_draw_indexed_indirect( + state.borrow::().render_pass_draw_indexed_indirect( &mut render_pass_resource.0.borrow_mut(), buffer_resource.1, indirect_offset, - ); + )?; Ok(WebGpuResult::empty()) } diff --git a/player/src/lib.rs b/player/src/lib.rs index 2edfc2755c..9ba9cfef45 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -113,9 +113,9 @@ impl GlobalPlay for wgc::global::Global { timestamp_writes, occlusion_query_set_id, } => { - self.render_pass_end_impl::( + self.render_pass_end_with_unresolved_commands::( encoder, - base.as_ref(), + base, &target_colors, target_depth_stencil.as_ref(), timestamp_writes.as_ref(), diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 2a0c5354d7..c5b74b7997 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -48,7 +48,7 @@ To create a render bundle: 3) Call [`Global::render_bundle_encoder_finish`][Grbef], which analyzes and cleans up the command stream and returns a `RenderBundleId`. -4) Then, any number of times, call [`wgpu_render_pass_execute_bundles`][wrpeb] to +4) Then, any number of times, call [`render_pass_execute_bundles`][wrpeb] to execute the bundle as part of some render pass. ## Implementation @@ -73,7 +73,7 @@ index format changes. [Gdcrbe]: crate::global::Global::device_create_render_bundle_encoder [Grbef]: crate::global::Global::render_bundle_encoder_finish -[wrpeb]: crate::command::render::render_commands::wgpu_render_pass_execute_bundles +[wrpeb]: crate::global::Global::render_pass_execute_bundles !*/ #![allow(clippy::reversed_empty_ranges)] @@ -84,7 +84,7 @@ use crate::{ binding_model::{buffer_binding_type_alignment, BindGroup, BindGroupLayout, PipelineLayout}, command::{ BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr, - PassErrorScope, RenderCommand, RenderCommandError, StateChange, + PassErrorScope, RenderCommandError, StateChange, }, conv, device::{ @@ -112,7 +112,10 @@ use thiserror::Error; use hal::CommandEncoder as _; -use super::ArcRenderCommand; +use super::{ + render_command::{ArcRenderCommand, RenderCommand}, + DrawKind, +}; /// fn validate_draw( @@ -327,7 +330,7 @@ impl RenderBundleEncoder { #[cfg(feature = "trace")] pub(crate) fn to_base_pass(&self) -> BasePass { - BasePass::from_ref(self.base.as_ref()) + self.base.clone() } pub fn parent(&self) -> id::DeviceId { @@ -398,10 +401,11 @@ impl RenderBundleEncoder { let mut buffer_memory_init_actions = Vec::new(); let mut texture_memory_init_actions = Vec::new(); - let base = self.base.as_ref(); let mut next_dynamic_offset = 0; - for &command in base.commands { + let base = &self.base; + + for &command in &base.commands { match command { RenderCommand::SetBindGroup { index, @@ -621,8 +625,8 @@ impl RenderBundleEncoder { first_instance, } => { let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, indexed: false, - indirect: false, pipeline: state.pipeline_id(), }; let pipeline = state.pipeline(scope)?; @@ -639,7 +643,7 @@ impl RenderBundleEncoder { if instance_count > 0 && vertex_count > 0 { commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.extend(state.flush_binds(used_bind_groups, &base.dynamic_offsets)); commands.push(ArcRenderCommand::Draw { vertex_count, instance_count, @@ -656,8 +660,8 @@ impl RenderBundleEncoder { first_instance, } => { let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, indexed: true, - indirect: false, pipeline: state.pipeline_id(), }; let pipeline = state.pipeline(scope)?; @@ -680,7 +684,7 @@ impl RenderBundleEncoder { if instance_count > 0 && index_count > 0 { commands.extend(state.flush_index()); commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.extend(state.flush_binds(used_bind_groups, &base.dynamic_offsets)); commands.push(ArcRenderCommand::DrawIndexed { index_count, instance_count, first_index, base_vertex, first_instance }); } } @@ -691,8 +695,8 @@ impl RenderBundleEncoder { indexed: false, } => { let scope = PassErrorScope::Draw { + kind: DrawKind::DrawIndirect, indexed: false, - indirect: true, pipeline: state.pipeline_id(), }; device @@ -724,7 +728,7 @@ impl RenderBundleEncoder { )); commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.extend(state.flush_binds(used_bind_groups, &base.dynamic_offsets)); commands.push(ArcRenderCommand::MultiDrawIndirect { buffer: buffer.clone(), offset, count: None, indexed: false }); } RenderCommand::MultiDrawIndirect { @@ -734,8 +738,8 @@ impl RenderBundleEncoder { indexed: true, } => { let scope = PassErrorScope::Draw { + kind: DrawKind::DrawIndirect, indexed: true, - indirect: true, pipeline: state.pipeline_id(), }; device @@ -773,7 +777,7 @@ impl RenderBundleEncoder { commands.extend(index.flush()); commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.extend(state.flush_binds(used_bind_groups, &base.dynamic_offsets)); commands.push(ArcRenderCommand::MultiDrawIndirect { buffer: buffer.clone(), offset, count: None, indexed: true }); } RenderCommand::MultiDrawIndirect { .. } diff --git a/wgpu-core/src/command/compute_command.rs b/wgpu-core/src/command/compute_command.rs index 8d3c07825c..bd98bda157 100644 --- a/wgpu-core/src/command/compute_command.rs +++ b/wgpu-core/src/command/compute_command.rs @@ -72,7 +72,7 @@ pub enum ComputeCommand { impl ComputeCommand { /// Resolves all ids in a list of commands into the corresponding resource Arc. - /// + // // TODO: Once resolving is done on-the-fly during recording, this function should be only needed with the replay feature: // #[cfg(feature = "replay")] pub fn resolve_compute_command_ids( diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 125fbdf8ee..d9745acc0b 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -1,24 +1,14 @@ -/*! Draw structures - shared between render passes and bundles. -!*/ - use crate::{ - binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PushConstantUploadError}, + binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, error::ErrorFormatter, - hal_api::HalApi, id, - pipeline::RenderPipeline, - resource::{ - Buffer, DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError, QuerySet, - }, + resource::{DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError}, track::ResourceUsageCompatibilityError, }; -use wgt::{BufferAddress, BufferSize, Color, VertexStepMode}; +use wgt::VertexStepMode; -use std::{num::NonZeroU32, sync::Arc}; use thiserror::Error; -use super::RenderBundle; - /// Error validating a draw call. #[derive(Clone, Debug, Error, Eq, PartialEq)] #[non_exhaustive] @@ -134,226 +124,3 @@ pub struct Rect { pub w: T, pub h: T, } - -#[doc(hidden)] -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum RenderCommand { - SetBindGroup { - index: u32, - num_dynamic_offsets: usize, - bind_group_id: id::BindGroupId, - }, - SetPipeline(id::RenderPipelineId), - SetIndexBuffer { - buffer_id: id::BufferId, - index_format: wgt::IndexFormat, - offset: BufferAddress, - size: Option, - }, - SetVertexBuffer { - slot: u32, - buffer_id: id::BufferId, - offset: BufferAddress, - size: Option, - }, - SetBlendConstant(Color), - SetStencilReference(u32), - SetViewport { - rect: Rect, - //TODO: use half-float to reduce the size? - depth_min: f32, - depth_max: f32, - }, - SetScissor(Rect), - - /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. - /// - /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation - /// of the restrictions these commands must satisfy. - SetPushConstant { - /// Which stages we are setting push constant values for. - stages: wgt::ShaderStages, - - /// The byte offset within the push constant storage to write to. This - /// must be a multiple of four. - offset: u32, - - /// The number of bytes to write. This must be a multiple of four. - size_bytes: u32, - - /// Index in [`BasePass::push_constant_data`] of the start of the data - /// to be written. - /// - /// Note: this is not a byte offset like `offset`. Rather, it is the - /// index of the first `u32` element in `push_constant_data` to read. - /// - /// `None` means zeros should be written to the destination range, and - /// there is no corresponding data in `push_constant_data`. This is used - /// by render bundles, which explicitly clear out any state that - /// post-bundle code might see. - values_offset: Option, - }, - Draw { - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, - }, - DrawIndexed { - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, - }, - MultiDrawIndirect { - buffer_id: id::BufferId, - offset: BufferAddress, - /// Count of `None` represents a non-multi call. - count: Option, - indexed: bool, - }, - MultiDrawIndirectCount { - buffer_id: id::BufferId, - offset: BufferAddress, - count_buffer_id: id::BufferId, - count_buffer_offset: BufferAddress, - max_count: u32, - indexed: bool, - }, - PushDebugGroup { - color: u32, - len: usize, - }, - PopDebugGroup, - InsertDebugMarker { - color: u32, - len: usize, - }, - WriteTimestamp { - query_set_id: id::QuerySetId, - query_index: u32, - }, - BeginOcclusionQuery { - query_index: u32, - }, - EndOcclusionQuery, - BeginPipelineStatisticsQuery { - query_set_id: id::QuerySetId, - query_index: u32, - }, - EndPipelineStatisticsQuery, - ExecuteBundle(id::RenderBundleId), -} - -/// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs. -#[doc(hidden)] -#[derive(Clone, Debug)] -pub enum ArcRenderCommand { - SetBindGroup { - index: u32, - num_dynamic_offsets: usize, - bind_group: Arc>, - }, - SetPipeline(Arc>), - SetIndexBuffer { - buffer: Arc>, - index_format: wgt::IndexFormat, - offset: BufferAddress, - size: Option, - }, - SetVertexBuffer { - slot: u32, - buffer: Arc>, - offset: BufferAddress, - size: Option, - }, - SetBlendConstant(Color), - SetStencilReference(u32), - SetViewport { - rect: Rect, - depth_min: f32, - depth_max: f32, - }, - SetScissor(Rect), - - /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. - /// - /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation - /// of the restrictions these commands must satisfy. - SetPushConstant { - /// Which stages we are setting push constant values for. - stages: wgt::ShaderStages, - - /// The byte offset within the push constant storage to write to. This - /// must be a multiple of four. - offset: u32, - - /// The number of bytes to write. This must be a multiple of four. - size_bytes: u32, - - /// Index in [`BasePass::push_constant_data`] of the start of the data - /// to be written. - /// - /// Note: this is not a byte offset like `offset`. Rather, it is the - /// index of the first `u32` element in `push_constant_data` to read. - /// - /// `None` means zeros should be written to the destination range, and - /// there is no corresponding data in `push_constant_data`. This is used - /// by render bundles, which explicitly clear out any state that - /// post-bundle code might see. - values_offset: Option, - }, - Draw { - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, - }, - DrawIndexed { - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, - }, - MultiDrawIndirect { - buffer: Arc>, - offset: BufferAddress, - /// Count of `None` represents a non-multi call. - count: Option, - indexed: bool, - }, - MultiDrawIndirectCount { - buffer: Arc>, - offset: BufferAddress, - count_buffer: Arc>, - count_buffer_offset: BufferAddress, - max_count: u32, - indexed: bool, - }, - PushDebugGroup { - color: u32, - len: usize, - }, - PopDebugGroup, - InsertDebugMarker { - color: u32, - len: usize, - }, - WriteTimestamp { - query_set: Arc>, - query_index: u32, - }, - BeginOcclusionQuery { - query_index: u32, - }, - EndOcclusionQuery, - BeginPipelineStatisticsQuery { - query_set: Arc>, - query_index: u32, - }, - EndPipelineStatisticsQuery, - ExecuteBundle(Arc>), -} diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 997da708f6..cd79ea31c0 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -9,6 +9,7 @@ mod dyn_compute_pass; mod memory_init; mod query; mod render; +mod render_command; mod transfer; use std::sync::Arc; @@ -16,7 +17,8 @@ use std::sync::Arc; pub(crate) use self::clear::clear_texture; pub use self::{ bundle::*, clear::ClearError, compute::*, compute_command::ComputeCommand, draw::*, - dyn_compute_pass::DynComputePass, query::*, render::*, transfer::*, + dyn_compute_pass::DynComputePass, query::*, render::*, render_command::RenderCommand, + transfer::*, }; pub(crate) use allocator::CommandAllocator; @@ -544,15 +546,6 @@ impl ParentDevice for CommandBuffer { } } -#[derive(Copy, Clone, Debug)] -pub struct BasePassRef<'a, C> { - pub label: Option<&'a str>, - pub commands: &'a [C], - pub dynamic_offsets: &'a [wgt::DynamicOffset], - pub string_data: &'a [u8], - pub push_constant_data: &'a [u32], -} - /// A stream of commands for a render pass or compute pass. /// /// This also contains side tables referred to by certain commands, @@ -565,7 +558,7 @@ pub struct BasePassRef<'a, C> { /// [`SetBindGroup`]: RenderCommand::SetBindGroup /// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker #[doc(hidden)] -#[derive(Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BasePass { pub label: Option, @@ -602,27 +595,6 @@ impl BasePass { push_constant_data: Vec::new(), } } - - #[cfg(feature = "trace")] - fn from_ref(base: BasePassRef) -> Self { - Self { - label: base.label.map(str::to_string), - commands: base.commands.to_vec(), - dynamic_offsets: base.dynamic_offsets.to_vec(), - string_data: base.string_data.to_vec(), - push_constant_data: base.push_constant_data.to_vec(), - } - } - - pub fn as_ref(&self) -> BasePassRef { - BasePassRef { - label: self.label.as_deref(), - commands: &self.commands, - dynamic_offsets: &self.dynamic_offsets, - string_data: &self.string_data, - push_constant_data: &self.push_constant_data, - } - } } #[derive(Clone, Debug, Error)] @@ -879,6 +851,14 @@ trait MapPassErr { fn map_pass_err(self, scope: PassErrorScope) -> Result; } +#[derive(Clone, Copy, Debug)] +pub enum DrawKind { + Draw, + DrawIndirect, + MultiDrawIndirect, + MultiDrawIndirectCount, +} + #[derive(Clone, Copy, Debug, Error)] pub enum PassErrorScope { #[error("In a bundle parameter")] @@ -902,14 +882,18 @@ pub enum PassErrorScope { SetVertexBuffer(id::BufferId), #[error("In a set_index_buffer command")] SetIndexBuffer(id::BufferId), + #[error("In a set_blend_constant command")] + SetBlendConstant, + #[error("In a set_stencil_reference command")] + SetStencilReference, #[error("In a set_viewport command")] SetViewport, #[error("In a set_scissor_rect command")] SetScissorRect, - #[error("In a draw command, indexed:{indexed} indirect:{indirect}")] + #[error("In a draw command, kind: {kind:?}")] Draw { + kind: DrawKind, indexed: bool, - indirect: bool, pipeline: Option, }, #[error("While resetting queries after the renderpass was ran")] diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 8b2bcc9974..8a04656ae0 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -10,9 +10,9 @@ use crate::{ bind::Binder, end_occlusion_query, end_pipeline_statistics_query, memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState}, - BasePass, BasePassRef, BindGroupStateChange, CommandBuffer, CommandEncoderError, - CommandEncoderStatus, DrawError, ExecutionError, MapPassErr, PassErrorScope, QueryUseError, - RenderCommand, RenderCommandError, StateChange, + BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError, CommandEncoderStatus, + DrawError, ExecutionError, MapPassErr, PassErrorScope, QueryUseError, RenderCommandError, + StateChange, }, device::{ AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures, @@ -49,10 +49,12 @@ use serde::Serialize; use std::sync::Arc; use std::{borrow::Cow, fmt, iter, marker::PhantomData, mem, num::NonZeroU32, ops::Range, str}; +use super::render_command::{ArcRenderCommand, RenderCommand}; use super::{ memory_init::TextureSurfaceDiscard, CommandBufferTextureMemoryActions, CommandEncoder, QueryResetMap, }; +use super::{DrawKind, Rect}; /// Operation to perform to the output attachment at the start of a renderpass. #[repr(C)] @@ -220,7 +222,13 @@ pub struct RenderPassDescriptor<'a> { #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RenderPass { - base: BasePass, + /// All pass data & records is stored here. + /// + /// If this is `None`, the pass is in the 'ended' state and can no longer be used. + /// Any attempt to record more commands will result in a validation error. + // TODO: this is soon to become `ArcRenderCommand` + base: Option>, + parent_id: id::CommandEncoderId, color_targets: ArrayVec, { hal::MAX_COLOR_ATTACHMENTS }>, depth_stencil_target: Option, @@ -237,7 +245,7 @@ pub struct RenderPass { impl RenderPass { pub fn new(parent_id: id::CommandEncoderId, desc: &RenderPassDescriptor) -> Self { Self { - base: BasePass::new(&desc.label), + base: Some(BasePass::new(&desc.label)), parent_id, color_targets: desc.color_attachments.iter().cloned().collect(), depth_stencil_target: desc.depth_stencil_attachment.cloned(), @@ -256,33 +264,17 @@ impl RenderPass { #[inline] pub fn label(&self) -> Option<&str> { - self.base.label.as_deref() - } - - #[cfg(feature = "trace")] - pub fn into_command(self) -> crate::device::trace::Command { - crate::device::trace::Command::RunRenderPass { - base: self.base, - target_colors: self.color_targets.into_iter().collect(), - target_depth_stencil: self.depth_stencil_target, - timestamp_writes: self.timestamp_writes, - occlusion_query_set_id: self.occlusion_query_set_id, - } + self.base.as_ref().and_then(|base| base.label.as_deref()) } - pub fn set_index_buffer( - &mut self, - buffer_id: id::BufferId, - index_format: IndexFormat, - offset: BufferAddress, - size: Option, - ) { - self.base.commands.push(RenderCommand::SetIndexBuffer { - buffer_id, - index_format, - offset, - size, - }); + fn base_mut<'a>( + &'a mut self, + scope: PassErrorScope, + ) -> Result<&'a mut BasePass, RenderPassError> { + self.base + .as_mut() + .ok_or(RenderPassErrorInner::PassEnded) + .map_pass_err(scope) } } @@ -292,11 +284,23 @@ impl fmt::Debug for RenderPass { .field("encoder_id", &self.parent_id) .field("color_targets", &self.color_targets) .field("depth_stencil_target", &self.depth_stencil_target) - .field("command count", &self.base.commands.len()) - .field("dynamic offset count", &self.base.dynamic_offsets.len()) + .field( + "command count", + &self.base.as_ref().map_or(0, |base| base.commands.len()), + ) + .field( + "dynamic offset count", + &self + .base + .as_ref() + .map_or(0, |base| base.dynamic_offsets.len()), + ) .field( "push constant u32 count", - &self.base.push_constant_data.len(), + &self + .base + .as_ref() + .map_or(0, |base| base.push_constant_data.len()), ) .finish() } @@ -601,6 +605,8 @@ pub enum RenderPassErrorInner { SurfaceTextureDropped, #[error("Not enough memory left for render pass")] OutOfMemory, + #[error("The bind group at index {0:?} is invalid")] + InvalidBindGroup(u32), #[error("Unable to clear non-present/read-only depth")] InvalidDepthOps, #[error("Unable to clear non-present/read-only stencil")] @@ -649,6 +655,12 @@ pub enum RenderPassErrorInner { Draw(#[from] DrawError), #[error(transparent)] Bind(#[from] BindError), + #[error("Push constant offset must be aligned to 4 bytes")] + PushConstantOffsetAlignment, + #[error("Push constant size must be aligned to 4 bytes")] + PushConstantSizeAlignment, + #[error("Ran out of push constant space. Don't set 4gb of push constants per ComputePass.")] + PushConstantOutOfMemory, #[error(transparent)] QueryUse(#[from] QueryUseError), #[error("Multiview layer count must match")] @@ -663,6 +675,8 @@ pub enum RenderPassErrorInner { MissingOcclusionQuerySet, #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), + #[error("The compute pass has already been ended and no further commands can be recorded")] + PassEnded, } impl PrettyError for RenderPassErrorInner { @@ -703,7 +717,7 @@ impl From for RenderPassErrorInner { pub struct RenderPassError { pub scope: PassErrorScope, #[source] - inner: RenderPassErrorInner, + pub(super) inner: RenderPassErrorInner, } impl PrettyError for RenderPassError { fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { @@ -1309,13 +1323,18 @@ impl<'a, 'd, A: HalApi> RenderPassInfo<'a, 'd, A> { } } -// Common routines between render/compute - impl Global { - pub fn render_pass_end(&self, pass: &RenderPass) -> Result<(), RenderPassError> { - self.render_pass_end_impl::( - pass.parent_id(), - pass.base.as_ref(), + pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), RenderPassError> { + let scope = PassErrorScope::PassEncoder(pass.parent_id); + let base = pass + .base + .take() + .ok_or(RenderPassErrorInner::PassEnded) + .map_pass_err(scope)?; + + self.render_pass_end_with_unresolved_commands::( + pass.parent_id, + base, &pass.color_targets, pass.depth_stencil_target.as_ref(), pass.timestamp_writes.as_ref(), @@ -1323,11 +1342,39 @@ impl Global { ) } + #[doc(hidden)] + pub fn render_pass_end_with_unresolved_commands( + &self, + encoder_id: id::CommandEncoderId, + base: BasePass, + color_attachments: &[Option], + depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, + timestamp_writes: Option<&RenderPassTimestampWrites>, + occlusion_query_set_id: Option, + ) -> Result<(), RenderPassError> { + let commands = RenderCommand::resolve_render_command_ids(A::hub(self), &base.commands)?; + + self.render_pass_end_impl::( + encoder_id, + BasePass { + label: base.label, + commands, + dynamic_offsets: base.dynamic_offsets, + string_data: base.string_data, + push_constant_data: base.push_constant_data, + }, + color_attachments, + depth_stencil_attachment, + timestamp_writes, + occlusion_query_set_id, + ) + } + #[doc(hidden)] pub fn render_pass_end_impl( &self, encoder_id: id::CommandEncoderId, - base: BasePassRef, + base: BasePass>, color_attachments: &[Option], depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, timestamp_writes: Option<&RenderPassTimestampWrites>, @@ -1342,7 +1389,7 @@ impl Global { .instance .flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS); - let label = hal_label(base.label, self.instance.flags); + let label = hal_label(base.label.as_deref(), self.instance.flags); let pass_scope = PassErrorScope::PassEncoder(encoder_id); @@ -1360,7 +1407,13 @@ impl Global { #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf_data.commands { list.push(crate::device::trace::Command::RunRenderPass { - base: BasePass::from_ref(base), + base: BasePass { + label: base.label.clone(), + commands: base.commands.iter().map(Into::into).collect(), + dynamic_offsets: base.dynamic_offsets.to_vec(), + string_data: base.string_data.to_vec(), + push_constant_data: base.push_constant_data.to_vec(), + }, target_colors: color_attachments.to_vec(), target_depth_stencil: depth_stencil_attachment.cloned(), timestamp_writes: timestamp_writes.cloned(), @@ -1385,11 +1438,7 @@ impl Global { *status = CommandEncoderStatus::Error; encoder.open_pass(label).map_pass_err(pass_scope)?; - let bundle_guard = hub.render_bundles.read(); - let bind_group_guard = hub.bind_groups.read(); - let render_pipeline_guard = hub.render_pipelines.read(); let query_set_guard = hub.query_sets.read(); - let buffer_guard = hub.buffers.read(); let view_guard = hub.texture_views.read(); log::trace!( @@ -1443,12 +1492,13 @@ impl Global { let mut active_query = None; for command in base.commands { - match *command { - RenderCommand::SetBindGroup { + match command { + ArcRenderCommand::SetBindGroup { index, num_dynamic_offsets, - bind_group_id, + bind_group, } => { + let bind_group_id = bind_group.as_info().id(); api_log!("RenderPass::set_bind_group {index} {bind_group_id:?}"); let scope = PassErrorScope::SetBindGroup(bind_group_id); @@ -1468,12 +1518,7 @@ impl Global { ); dynamic_offset_count += num_dynamic_offsets; - let bind_group = bind_group_guard - .get(bind_group_id) - .map_err(|_| RenderCommandError::InvalidBindGroupId(bind_group_id)) - .map_pass_err(scope)?; - - tracker.bind_groups.add_single(bind_group); + let bind_group = tracker.bind_groups.insert_single(bind_group); bind_group .same_device_as(cmd_buf.as_ref()) @@ -1529,18 +1574,14 @@ impl Global { } } } - RenderCommand::SetPipeline(pipeline_id) => { + ArcRenderCommand::SetPipeline(pipeline) => { + let pipeline_id = pipeline.as_info().id(); api_log!("RenderPass::set_pipeline {pipeline_id:?}"); let scope = PassErrorScope::SetPipelineRender(pipeline_id); state.pipeline = Some(pipeline_id); - let pipeline = render_pipeline_guard - .get(pipeline_id) - .map_err(|_| RenderCommandError::InvalidPipeline(pipeline_id)) - .map_pass_err(scope)?; - - tracker.render_pipelines.add_single(pipeline); + let pipeline = tracker.render_pipelines.insert_single(pipeline); pipeline .same_device_as(cmd_buf.as_ref()) @@ -1654,24 +1695,20 @@ impl Global { // Update vertex buffer limits. state.vertex.update_limits(); } - RenderCommand::SetIndexBuffer { - buffer_id, + ArcRenderCommand::SetIndexBuffer { + buffer, index_format, offset, size, } => { + let buffer_id = buffer.as_info().id(); api_log!("RenderPass::set_index_buffer {buffer_id:?}"); let scope = PassErrorScope::SetIndexBuffer(buffer_id); - let buffer = buffer_guard - .get(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id)) - .map_pass_err(scope)?; - info.usage_scope .buffers - .merge_single(buffer, hal::BufferUses::INDEX) + .merge_single(&buffer, hal::BufferUses::INDEX) .map_pass_err(scope)?; buffer @@ -1694,7 +1731,7 @@ impl Global { buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( - buffer, + &buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, ), @@ -1709,24 +1746,20 @@ impl Global { raw.set_index_buffer(bb, index_format); } } - RenderCommand::SetVertexBuffer { + ArcRenderCommand::SetVertexBuffer { slot, - buffer_id, + buffer, offset, size, } => { + let buffer_id = buffer.as_info().id(); api_log!("RenderPass::set_vertex_buffer {slot} {buffer_id:?}"); let scope = PassErrorScope::SetVertexBuffer(buffer_id); - let buffer = buffer_guard - .get(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id)) - .map_pass_err(scope)?; - info.usage_scope .buffers - .merge_single(buffer, hal::BufferUses::VERTEX) + .merge_single(&buffer, hal::BufferUses::VERTEX) .map_pass_err(scope)?; buffer @@ -1763,7 +1796,7 @@ impl Global { buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( - buffer, + &buffer, offset..(offset + vertex_state.total_size), MemoryInitKind::NeedsInitializedMemory, ), @@ -1779,7 +1812,7 @@ impl Global { } state.vertex.update_limits(); } - RenderCommand::SetBlendConstant(ref color) => { + ArcRenderCommand::SetBlendConstant(ref color) => { api_log!("RenderPass::set_blend_constant"); state.blend_constant = OptionalState::Set; @@ -1793,7 +1826,7 @@ impl Global { raw.set_blend_constants(&array); } } - RenderCommand::SetStencilReference(value) => { + ArcRenderCommand::SetStencilReference(value) => { api_log!("RenderPass::set_stencil_reference {value}"); state.stencil_reference = value; @@ -1806,7 +1839,7 @@ impl Global { } } } - RenderCommand::SetViewport { + ArcRenderCommand::SetViewport { ref rect, depth_min, depth_max, @@ -1843,7 +1876,7 @@ impl Global { raw.set_viewport(&r, depth_min..depth_max); } } - RenderCommand::SetPushConstant { + ArcRenderCommand::SetPushConstant { stages, offset, size_bytes, @@ -1883,7 +1916,7 @@ impl Global { ) } } - RenderCommand::SetScissor(ref rect) => { + ArcRenderCommand::SetScissor(ref rect) => { api_log!("RenderPass::set_scissor_rect {rect:?}"); let scope = PassErrorScope::SetScissorRect; @@ -1903,7 +1936,7 @@ impl Global { raw.set_scissor_rect(&r); } } - RenderCommand::Draw { + ArcRenderCommand::Draw { vertex_count, instance_count, first_vertex, @@ -1915,8 +1948,8 @@ impl Global { let indexed = false; let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, indexed, - indirect: false, pipeline: state.pipeline, }; state.is_ready(indexed).map_pass_err(scope)?; @@ -1953,7 +1986,7 @@ impl Global { } } } - RenderCommand::DrawIndexed { + ArcRenderCommand::DrawIndexed { index_count, instance_count, first_index, @@ -1964,8 +1997,8 @@ impl Global { let indexed = true; let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, indexed, - indirect: false, pipeline: state.pipeline, }; state.is_ready(indexed).map_pass_err(scope)?; @@ -2002,17 +2035,22 @@ impl Global { } } } - RenderCommand::MultiDrawIndirect { - buffer_id, + ArcRenderCommand::MultiDrawIndirect { + buffer: indirect_buffer, offset, count, indexed, } => { - api_log!("RenderPass::draw_indirect (indexed:{indexed}) {buffer_id:?} {offset} {count:?}"); + let indirect_buffer_id = indirect_buffer.as_info().id(); + api_log!("RenderPass::draw_indirect (indexed:{indexed}) {indirect_buffer_id:?} {offset} {count:?}"); let scope = PassErrorScope::Draw { + kind: if count.is_some() { + DrawKind::MultiDrawIndirect + } else { + DrawKind::DrawIndirect + }, indexed, - indirect: true, pipeline: state.pipeline, }; state.is_ready(indexed).map_pass_err(scope)?; @@ -2031,14 +2069,9 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer = buffer_guard - .get(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id)) - .map_pass_err(scope)?; - info.usage_scope .buffers - .merge_single(indirect_buffer, hal::BufferUses::INDIRECT) + .merge_single(&indirect_buffer, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; indirect_buffer @@ -2062,7 +2095,7 @@ impl Global { buffer_memory_init_actions.extend( indirect_buffer.initialization_status.read().create_action( - indirect_buffer, + &indirect_buffer, offset..end_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -2077,19 +2110,21 @@ impl Global { }, } } - RenderCommand::MultiDrawIndirectCount { - buffer_id, + ArcRenderCommand::MultiDrawIndirectCount { + buffer: indirect_buffer, offset, - count_buffer_id, + count_buffer, count_buffer_offset, max_count, indexed, } => { - api_log!("RenderPass::multi_draw_indirect_count (indexed:{indexed}) {buffer_id:?} {offset} {count_buffer_id:?} {count_buffer_offset:?} {max_count:?}"); + let indirect_buffer_id = indirect_buffer.as_info().id(); + let count_buffer_id = count_buffer.as_info().id(); + api_log!("RenderPass::multi_draw_indirect_count (indexed:{indexed}) {indirect_buffer_id:?} {offset} {count_buffer_id:?} {count_buffer_offset:?} {max_count:?}"); let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirectCount, indexed, - indirect: true, pipeline: state.pipeline, }; state.is_ready(indexed).map_pass_err(scope)?; @@ -2106,14 +2141,9 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer = buffer_guard - .get(buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id)) - .map_pass_err(scope)?; - info.usage_scope .buffers - .merge_single(indirect_buffer, hal::BufferUses::INDIRECT) + .merge_single(&indirect_buffer, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; indirect_buffer @@ -2122,14 +2152,9 @@ impl Global { let indirect_raw = indirect_buffer.try_raw(&snatch_guard).map_pass_err(scope)?; - let count_buffer = buffer_guard - .get(count_buffer_id) - .map_err(|_| RenderCommandError::InvalidBufferId(count_buffer_id)) - .map_pass_err(scope)?; - info.usage_scope .buffers - .merge_single(count_buffer, hal::BufferUses::INDIRECT) + .merge_single(&count_buffer, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; count_buffer @@ -2149,7 +2174,7 @@ impl Global { } buffer_memory_init_actions.extend( indirect_buffer.initialization_status.read().create_action( - indirect_buffer, + &indirect_buffer, offset..end_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -2167,7 +2192,7 @@ impl Global { } buffer_memory_init_actions.extend( count_buffer.initialization_status.read().create_action( - count_buffer, + &count_buffer, count_buffer_offset..end_count_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -2194,7 +2219,7 @@ impl Global { }, } } - RenderCommand::PushDebugGroup { color: _, len } => { + ArcRenderCommand::PushDebugGroup { color: _, len } => { state.debug_scope_depth += 1; if !discard_hal_labels { let label = str::from_utf8( @@ -2209,7 +2234,7 @@ impl Global { } string_offset += len; } - RenderCommand::PopDebugGroup => { + ArcRenderCommand::PopDebugGroup => { api_log!("RenderPass::pop_debug_group"); let scope = PassErrorScope::PopDebugGroup; @@ -2224,7 +2249,7 @@ impl Global { } } } - RenderCommand::InsertDebugMarker { color: _, len } => { + ArcRenderCommand::InsertDebugMarker { color: _, len } => { if !discard_hal_labels { let label = str::from_utf8( &base.string_data[string_offset..string_offset + len], @@ -2237,10 +2262,11 @@ impl Global { } string_offset += len; } - RenderCommand::WriteTimestamp { - query_set_id, + ArcRenderCommand::WriteTimestamp { + query_set, query_index, } => { + let query_set_id = query_set.as_info().id(); api_log!("RenderPass::write_timestamps {query_set_id:?} {query_index}"); let scope = PassErrorScope::WriteTimestamp; @@ -2248,12 +2274,7 @@ impl Global { .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES) .map_pass_err(scope)?; - let query_set = query_set_guard - .get(query_set_id) - .map_err(|_| RenderPassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; - - tracker.query_sets.add_single(query_set); + let query_set = tracker.query_sets.insert_single(query_set); query_set .validate_and_write_timestamp( @@ -2263,7 +2284,7 @@ impl Global { ) .map_pass_err(scope)?; } - RenderCommand::BeginOcclusionQuery { query_index } => { + ArcRenderCommand::BeginOcclusionQuery { query_index } => { api_log!("RenderPass::begin_occlusion_query {query_index}"); let scope = PassErrorScope::BeginOcclusionQuery; @@ -2287,25 +2308,21 @@ impl Global { ) .map_pass_err(scope)?; } - RenderCommand::EndOcclusionQuery => { + ArcRenderCommand::EndOcclusionQuery => { api_log!("RenderPass::end_occlusion_query"); let scope = PassErrorScope::EndOcclusionQuery; end_occlusion_query(raw, &mut active_query).map_pass_err(scope)?; } - RenderCommand::BeginPipelineStatisticsQuery { - query_set_id, + ArcRenderCommand::BeginPipelineStatisticsQuery { + query_set, query_index, } => { + let query_set_id = query_set.as_info().id(); api_log!("RenderPass::begin_pipeline_statistics_query {query_set_id:?} {query_index}"); let scope = PassErrorScope::BeginPipelineStatisticsQuery; - let query_set = query_set_guard - .get(query_set_id) - .map_err(|_| RenderPassErrorInner::InvalidQuerySet(query_set_id)) - .map_pass_err(scope)?; - - tracker.query_sets.add_single(query_set); + let query_set = tracker.query_sets.insert_single(query_set); validate_and_begin_pipeline_statistics_query( query_set.clone(), @@ -2316,23 +2333,21 @@ impl Global { ) .map_pass_err(scope)?; } - RenderCommand::EndPipelineStatisticsQuery => { + ArcRenderCommand::EndPipelineStatisticsQuery => { api_log!("RenderPass::end_pipeline_statistics_query"); let scope = PassErrorScope::EndPipelineStatisticsQuery; end_pipeline_statistics_query(raw, &mut active_query) .map_pass_err(scope)?; } - RenderCommand::ExecuteBundle(bundle_id) => { + ArcRenderCommand::ExecuteBundle(bundle) => { + let bundle_id = bundle.as_info().id(); api_log!("RenderPass::execute_bundle {bundle_id:?}"); let scope = PassErrorScope::ExecuteBundle; - let bundle = bundle_guard - .get(bundle_id) - .map_err(|_| RenderCommandError::InvalidRenderBundle(bundle_id)) - .map_pass_err(scope)?; - - tracker.bundles.add_single(bundle); + // Have to clone the bundle arc, otherwise we keep a mutable reference to the bundle + // while later trying to add the bundle's resources to the tracker. + let bundle = tracker.bundles.insert_single(bundle).clone(); bundle .same_device_as(cmd_buf.as_ref()) @@ -2449,87 +2464,131 @@ impl Global { } } -pub mod render_commands { - use super::{ - super::{Rect, RenderCommand}, - RenderPass, - }; - use crate::id; - use std::{convert::TryInto, num::NonZeroU32}; - use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat}; - - pub fn wgpu_render_pass_set_bind_group( +impl Global { + pub fn render_pass_set_bind_group( + &self, pass: &mut RenderPass, index: u32, bind_group_id: id::BindGroupId, - offsets: &[DynamicOffset], - ) { - let redundant = pass.current_bind_groups.set_and_check_redundant( + offsets: &[wgt::DynamicOffset], + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetBindGroup(bind_group_id); + let base = pass + .base + .as_mut() + .ok_or(RenderPassErrorInner::PassEnded) + .map_pass_err(scope)?; + + if pass.current_bind_groups.set_and_check_redundant( bind_group_id, index, - &mut pass.base.dynamic_offsets, + &mut base.dynamic_offsets, offsets, - ); - - if redundant { - return; + ) { + // Do redundant early-out **after** checking whether the pass is ended or not. + return Ok(()); } - pass.base.commands.push(RenderCommand::SetBindGroup { + base.commands.push(RenderCommand::SetBindGroup { index, num_dynamic_offsets: offsets.len(), bind_group_id, }); + + Ok(()) } - pub fn wgpu_render_pass_set_pipeline(pass: &mut RenderPass, pipeline_id: id::RenderPipelineId) { - if pass.current_pipeline.set_and_check_redundant(pipeline_id) { - return; + pub fn render_pass_set_pipeline( + &self, + pass: &mut RenderPass, + pipeline_id: id::RenderPipelineId, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetPipelineRender(pipeline_id); + + let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id); + let base = pass.base_mut(scope)?; + + if redundant { + // Do redundant early-out **after** checking whether the pass is ended or not. + return Ok(()); } - pass.base - .commands - .push(RenderCommand::SetPipeline(pipeline_id)); + base.commands.push(RenderCommand::SetPipeline(pipeline_id)); + + Ok(()) } - pub fn wgpu_render_pass_set_vertex_buffer( + pub fn render_pass_set_index_buffer( + &self, pass: &mut RenderPass, - slot: u32, buffer_id: id::BufferId, + index_format: IndexFormat, offset: BufferAddress, size: Option, - ) { - pass.base.commands.push(RenderCommand::SetVertexBuffer { - slot, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetIndexBuffer(buffer_id); + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::SetIndexBuffer { buffer_id, + index_format, offset, size, }); + + Ok(()) } - pub fn wgpu_render_pass_set_index_buffer( + pub fn render_pass_set_vertex_buffer( + &self, pass: &mut RenderPass, - buffer: id::BufferId, - index_format: IndexFormat, + slot: u32, + buffer_id: id::BufferId, offset: BufferAddress, size: Option, - ) { - pass.set_index_buffer(buffer, index_format, offset, size); + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetVertexBuffer(buffer_id); + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + }); + + Ok(()) } - pub fn wgpu_render_pass_set_blend_constant(pass: &mut RenderPass, color: &Color) { - pass.base - .commands - .push(RenderCommand::SetBlendConstant(*color)); + pub fn render_pass_set_blend_constant( + &self, + pass: &mut RenderPass, + color: &Color, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetBlendConstant; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::SetBlendConstant(*color)); + + Ok(()) } - pub fn wgpu_render_pass_set_stencil_reference(pass: &mut RenderPass, value: u32) { - pass.base - .commands + pub fn render_pass_set_stencil_reference( + &self, + pass: &mut RenderPass, + value: u32, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetStencilReference; + let base = pass.base_mut(scope)?; + + base.commands .push(RenderCommand::SetStencilReference(value)); + + Ok(()) } - pub fn wgpu_render_pass_set_viewport( + pub fn render_pass_set_viewport( + &self, pass: &mut RenderPass, x: f32, y: f32, @@ -2537,259 +2596,414 @@ pub mod render_commands { h: f32, depth_min: f32, depth_max: f32, - ) { - pass.base.commands.push(RenderCommand::SetViewport { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetViewport; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::SetViewport { rect: Rect { x, y, w, h }, depth_min, depth_max, }); + + Ok(()) } - pub fn wgpu_render_pass_set_scissor_rect( + pub fn render_pass_set_scissor_rect( + &self, pass: &mut RenderPass, x: u32, y: u32, w: u32, h: u32, - ) { - pass.base - .commands + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetScissorRect; + let base = pass.base_mut(scope)?; + + base.commands .push(RenderCommand::SetScissor(Rect { x, y, w, h })); + + Ok(()) } - pub fn wgpu_render_pass_set_push_constants( + pub fn render_pass_set_push_constants( + &self, pass: &mut RenderPass, stages: wgt::ShaderStages, offset: u32, data: &[u8], - ) { - assert_eq!( - offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), - 0, - "Push constant offset must be aligned to 4 bytes." - ); - assert_eq!( - data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1), - 0, - "Push constant size must be aligned to 4 bytes." - ); - let value_offset = pass.base.push_constant_data.len().try_into().expect( - "Ran out of push constant space. Don't set 4gb of push constants per RenderPass.", - ); + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::SetPushConstant; + let base = pass.base_mut(scope)?; + + if offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 { + return Err(RenderPassErrorInner::PushConstantOffsetAlignment).map_pass_err(scope); + } + if data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 { + return Err(RenderPassErrorInner::PushConstantSizeAlignment).map_pass_err(scope); + } + + let value_offset = base + .push_constant_data + .len() + .try_into() + .map_err(|_| RenderPassErrorInner::PushConstantOutOfMemory) + .map_pass_err(scope)?; - pass.base.push_constant_data.extend( + base.push_constant_data.extend( data.chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize) .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])), ); - pass.base.commands.push(RenderCommand::SetPushConstant { + base.commands.push(RenderCommand::SetPushConstant { stages, offset, size_bytes: data.len() as u32, values_offset: Some(value_offset), }); + + Ok(()) } - pub fn wgpu_render_pass_draw( + pub fn render_pass_draw( + &self, pass: &mut RenderPass, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, - ) { - pass.base.commands.push(RenderCommand::Draw { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, + indexed: false, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::Draw { vertex_count, instance_count, first_vertex, first_instance, }); + + Ok(()) } - pub fn wgpu_render_pass_draw_indexed( + pub fn render_pass_draw_indexed( + &self, pass: &mut RenderPass, index_count: u32, instance_count: u32, first_index: u32, base_vertex: i32, first_instance: u32, - ) { - pass.base.commands.push(RenderCommand::DrawIndexed { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::Draw, + indexed: true, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::DrawIndexed { index_count, instance_count, first_index, base_vertex, first_instance, }); + + Ok(()) } - pub fn wgpu_render_pass_draw_indirect( + pub fn render_pass_draw_indirect( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, - ) { - pass.base.commands.push(RenderCommand::MultiDrawIndirect { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::DrawIndirect, + indexed: false, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirect { buffer_id, offset, count: None, indexed: false, }); + + Ok(()) } - pub fn wgpu_render_pass_draw_indexed_indirect( + pub fn render_pass_draw_indexed_indirect( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, - ) { - pass.base.commands.push(RenderCommand::MultiDrawIndirect { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::DrawIndirect, + indexed: true, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirect { buffer_id, offset, count: None, indexed: true, }); + + Ok(()) } - pub fn wgpu_render_pass_multi_draw_indirect( + pub fn render_pass_multi_draw_indirect( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, count: u32, - ) { - pass.base.commands.push(RenderCommand::MultiDrawIndirect { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirect, + indexed: false, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirect { buffer_id, offset, count: NonZeroU32::new(count), indexed: false, }); + + Ok(()) } - pub fn wgpu_render_pass_multi_draw_indexed_indirect( + pub fn render_pass_multi_draw_indexed_indirect( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, count: u32, - ) { - pass.base.commands.push(RenderCommand::MultiDrawIndirect { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirect, + indexed: true, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirect { buffer_id, offset, count: NonZeroU32::new(count), indexed: true, }); + + Ok(()) } - pub fn wgpu_render_pass_multi_draw_indirect_count( + pub fn render_pass_multi_draw_indirect_count( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, count_buffer_id: id::BufferId, count_buffer_offset: BufferAddress, max_count: u32, - ) { - pass.base - .commands - .push(RenderCommand::MultiDrawIndirectCount { - buffer_id, - offset, - count_buffer_id, - count_buffer_offset, - max_count, - indexed: false, - }); + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirectCount, + indexed: false, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: false, + }); + + Ok(()) } - pub fn wgpu_render_pass_multi_draw_indexed_indirect_count( + pub fn render_pass_multi_draw_indexed_indirect_count( + &self, pass: &mut RenderPass, buffer_id: id::BufferId, offset: BufferAddress, count_buffer_id: id::BufferId, count_buffer_offset: BufferAddress, max_count: u32, - ) { - pass.base - .commands - .push(RenderCommand::MultiDrawIndirectCount { - buffer_id, - offset, - count_buffer_id, - count_buffer_offset, - max_count, - indexed: true, - }); + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirectCount, + indexed: true, + pipeline: pass.current_pipeline.last_state, + }; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: true, + }); + + Ok(()) } - pub fn wgpu_render_pass_push_debug_group(pass: &mut RenderPass, label: &str, color: u32) { + pub fn render_pass_push_debug_group( + &self, + pass: &mut RenderPass, + label: &str, + color: u32, + ) -> Result<(), RenderPassError> { + let base = pass.base_mut(PassErrorScope::PushDebugGroup)?; + let bytes = label.as_bytes(); - pass.base.string_data.extend_from_slice(bytes); + base.string_data.extend_from_slice(bytes); - pass.base.commands.push(RenderCommand::PushDebugGroup { + base.commands.push(RenderCommand::PushDebugGroup { color, len: bytes.len(), }); + + Ok(()) } - pub fn wgpu_render_pass_pop_debug_group(pass: &mut RenderPass) { - pass.base.commands.push(RenderCommand::PopDebugGroup); + pub fn render_pass_pop_debug_group( + &self, + pass: &mut RenderPass, + ) -> Result<(), RenderPassError> { + let base = pass.base_mut(PassErrorScope::PopDebugGroup)?; + + base.commands.push(RenderCommand::PopDebugGroup); + + Ok(()) } - pub fn wgpu_render_pass_insert_debug_marker(pass: &mut RenderPass, label: &str, color: u32) { + pub fn render_pass_insert_debug_marker( + &self, + pass: &mut RenderPass, + label: &str, + color: u32, + ) -> Result<(), RenderPassError> { + let base = pass.base_mut(PassErrorScope::InsertDebugMarker)?; + let bytes = label.as_bytes(); - pass.base.string_data.extend_from_slice(bytes); + base.string_data.extend_from_slice(bytes); - pass.base.commands.push(RenderCommand::InsertDebugMarker { + base.commands.push(RenderCommand::InsertDebugMarker { color, len: bytes.len(), }); + + Ok(()) } - pub fn wgpu_render_pass_write_timestamp( + pub fn render_pass_write_timestamp( + &self, pass: &mut RenderPass, query_set_id: id::QuerySetId, query_index: u32, - ) { - pass.base.commands.push(RenderCommand::WriteTimestamp { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::WriteTimestamp; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::WriteTimestamp { query_set_id, query_index, }); + + Ok(()) } - pub fn wgpu_render_pass_begin_occlusion_query(pass: &mut RenderPass, query_index: u32) { - pass.base - .commands + pub fn render_pass_begin_occlusion_query( + &self, + pass: &mut RenderPass, + query_index: u32, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::BeginOcclusionQuery; + let base = pass.base_mut(scope)?; + + base.commands .push(RenderCommand::BeginOcclusionQuery { query_index }); + + Ok(()) } - pub fn wgpu_render_pass_end_occlusion_query(pass: &mut RenderPass) { - pass.base.commands.push(RenderCommand::EndOcclusionQuery); + pub fn render_pass_end_occlusion_query( + &self, + pass: &mut RenderPass, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::EndOcclusionQuery; + let base = pass.base_mut(scope)?; + + base.commands.push(RenderCommand::EndOcclusionQuery); + + Ok(()) } - pub fn wgpu_render_pass_begin_pipeline_statistics_query( + pub fn render_pass_begin_pipeline_statistics_query( + &self, pass: &mut RenderPass, query_set_id: id::QuerySetId, query_index: u32, - ) { - pass.base - .commands + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::BeginPipelineStatisticsQuery; + let base = pass.base_mut(scope)?; + + base.commands .push(RenderCommand::BeginPipelineStatisticsQuery { query_set_id, query_index, }); + + Ok(()) } - pub fn wgpu_render_pass_end_pipeline_statistics_query(pass: &mut RenderPass) { - pass.base - .commands + pub fn render_pass_end_pipeline_statistics_query( + &self, + pass: &mut RenderPass, + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::EndPipelineStatisticsQuery; + let base = pass.base_mut(scope)?; + + base.commands .push(RenderCommand::EndPipelineStatisticsQuery); + + Ok(()) } - pub fn wgpu_render_pass_execute_bundles( + pub fn render_pass_execute_bundles( + &self, pass: &mut RenderPass, render_bundle_ids: &[id::RenderBundleId], - ) { + ) -> Result<(), RenderPassError> { + let scope = PassErrorScope::ExecuteBundle; + let base = pass.base_mut(scope)?; + for &bundle_id in render_bundle_ids { - pass.base - .commands - .push(RenderCommand::ExecuteBundle(bundle_id)); + base.commands.push(RenderCommand::ExecuteBundle(bundle_id)); } pass.current_pipeline.reset(); pass.current_bind_groups.reset(); + + Ok(()) } } diff --git a/wgpu-core/src/command/render_command.rs b/wgpu-core/src/command/render_command.rs new file mode 100644 index 0000000000..22072bfc6e --- /dev/null +++ b/wgpu-core/src/command/render_command.rs @@ -0,0 +1,668 @@ +use crate::{ + binding_model::BindGroup, + hal_api::HalApi, + id, + pipeline::RenderPipeline, + resource::{Buffer, QuerySet}, +}; +use wgt::{BufferAddress, BufferSize, Color}; + +use std::{num::NonZeroU32, sync::Arc}; + +use super::{ + DrawKind, PassErrorScope, Rect, RenderBundle, RenderCommandError, RenderPassError, + RenderPassErrorInner, +}; + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum RenderCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::RenderPipelineId), + SetIndexBuffer { + buffer_id: id::BufferId, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option, + }, + SetVertexBuffer { + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + rect: Rect, + //TODO: use half-float to reduce the size? + depth_min: f32, + depth_max: f32, + }, + SetScissor(Rect), + + /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. + /// + /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation + /// of the restrictions these commands must satisfy. + SetPushConstant { + /// Which stages we are setting push constant values for. + stages: wgt::ShaderStages, + + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in [`BasePass::push_constant_data`] of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + /// + /// `None` means zeros should be written to the destination range, and + /// there is no corresponding data in `push_constant_data`. This is used + /// by render bundles, which explicitly clear out any state that + /// post-bundle code might see. + values_offset: Option, + }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(id::RenderBundleId), +} + +impl RenderCommand { + /// Resolves all ids in a list of commands into the corresponding resource Arc. + // + // TODO: Once resolving is done on-the-fly during recording, this function should be only needed with the replay feature: + // #[cfg(feature = "replay")] + pub fn resolve_render_command_ids( + hub: &crate::hub::Hub, + commands: &[RenderCommand], + ) -> Result>, RenderPassError> { + let buffers_guard = hub.buffers.read(); + let bind_group_guard = hub.bind_groups.read(); + let query_set_guard = hub.query_sets.read(); + let pipelines_guard = hub.render_pipelines.read(); + + let resolved_commands: Vec> = commands + .iter() + .map(|c| -> Result, RenderPassError> { + Ok(match *c { + RenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group_guard.get_owned(bind_group_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::SetBindGroup(bind_group_id), + inner: RenderPassErrorInner::InvalidBindGroup(index), + } + })?, + }, + + RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline( + pipelines_guard + .get_owned(pipeline_id) + .map_err(|_| RenderPassError { + scope: PassErrorScope::SetPipelineRender(pipeline_id), + inner: RenderCommandError::InvalidPipeline(pipeline_id).into(), + })?, + ), + + RenderCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + stages, + } => ArcRenderCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + stages, + }, + + RenderCommand::PushDebugGroup { color, len } => { + ArcRenderCommand::PushDebugGroup { color, len } + } + + RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup, + + RenderCommand::InsertDebugMarker { color, len } => { + ArcRenderCommand::InsertDebugMarker { color, len } + } + + RenderCommand::WriteTimestamp { + query_set_id, + query_index, + } => ArcRenderCommand::WriteTimestamp { + query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::WriteTimestamp, + inner: RenderPassErrorInner::InvalidQuerySet(query_set_id), + } + })?, + query_index, + }, + + RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => ArcRenderCommand::BeginPipelineStatisticsQuery { + query_set: query_set_guard.get_owned(query_set_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::BeginPipelineStatisticsQuery, + inner: RenderPassErrorInner::InvalidQuerySet(query_set_id), + } + })?, + query_index, + }, + + RenderCommand::EndPipelineStatisticsQuery => { + ArcRenderCommand::EndPipelineStatisticsQuery + } + + RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + } => ArcRenderCommand::SetIndexBuffer { + buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::SetIndexBuffer(buffer_id), + inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + } + })?, + index_format, + offset, + size, + }, + + RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + } => ArcRenderCommand::SetVertexBuffer { + slot, + buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::SetVertexBuffer(buffer_id), + inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + } + })?, + offset, + size, + }, + + RenderCommand::SetBlendConstant(color) => { + ArcRenderCommand::SetBlendConstant(color) + } + + RenderCommand::SetStencilReference(reference) => { + ArcRenderCommand::SetStencilReference(reference) + } + + RenderCommand::SetViewport { + rect, + depth_min, + depth_max, + } => ArcRenderCommand::SetViewport { + rect, + depth_min, + depth_max, + }, + + RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor), + + RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => ArcRenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }, + + RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => ArcRenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }, + + RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count, + indexed, + } => ArcRenderCommand::MultiDrawIndirect { + buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + RenderPassError { + scope: PassErrorScope::Draw { + kind: if count.is_some() { + DrawKind::MultiDrawIndirect + } else { + DrawKind::DrawIndirect + }, + indexed, + pipeline: None, + }, + inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + } + })?, + offset, + count, + indexed, + }, + + RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed, + } => { + let scope = PassErrorScope::Draw { + kind: DrawKind::MultiDrawIndirectCount, + indexed, + pipeline: None, + }; + ArcRenderCommand::MultiDrawIndirectCount { + buffer: buffers_guard.get_owned(buffer_id).map_err(|_| { + RenderPassError { + scope, + inner: RenderCommandError::InvalidBufferId(buffer_id).into(), + } + })?, + offset, + count_buffer: buffers_guard.get_owned(count_buffer_id).map_err( + |_| RenderPassError { + scope, + inner: RenderCommandError::InvalidBufferId(count_buffer_id) + .into(), + }, + )?, + count_buffer_offset, + max_count, + indexed, + } + } + + RenderCommand::BeginOcclusionQuery { query_index } => { + ArcRenderCommand::BeginOcclusionQuery { query_index } + } + + RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery, + + RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle( + hub.render_bundles.read().get_owned(bundle).map_err(|_| { + RenderPassError { + scope: PassErrorScope::ExecuteBundle, + inner: RenderCommandError::InvalidRenderBundle(bundle).into(), + } + })?, + ), + }) + }) + .collect::, RenderPassError>>()?; + Ok(resolved_commands) + } +} + +/// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs. +#[doc(hidden)] +#[derive(Clone, Debug)] +pub enum ArcRenderCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group: Arc>, + }, + SetPipeline(Arc>), + SetIndexBuffer { + buffer: Arc>, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option, + }, + SetVertexBuffer { + slot: u32, + buffer: Arc>, + offset: BufferAddress, + size: Option, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + rect: Rect, + depth_min: f32, + depth_max: f32, + }, + SetScissor(Rect), + + /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. + /// + /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation + /// of the restrictions these commands must satisfy. + SetPushConstant { + /// Which stages we are setting push constant values for. + stages: wgt::ShaderStages, + + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in [`BasePass::push_constant_data`] of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + /// + /// `None` means zeros should be written to the destination range, and + /// there is no corresponding data in `push_constant_data`. This is used + /// by render bundles, which explicitly clear out any state that + /// post-bundle code might see. + values_offset: Option, + }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer: Arc>, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer: Arc>, + offset: BufferAddress, + count_buffer: Arc>, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set: Arc>, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set: Arc>, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(Arc>), +} + +#[cfg(feature = "trace")] +impl From<&ArcRenderCommand> for RenderCommand { + fn from(value: &ArcRenderCommand) -> Self { + use crate::resource::Resource as _; + + match value { + ArcRenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => RenderCommand::SetBindGroup { + index: *index, + num_dynamic_offsets: *num_dynamic_offsets, + bind_group_id: bind_group.as_info().id(), + }, + + ArcRenderCommand::SetPipeline(pipeline) => { + RenderCommand::SetPipeline(pipeline.as_info().id()) + } + + ArcRenderCommand::SetPushConstant { + offset, + size_bytes, + values_offset, + stages, + } => RenderCommand::SetPushConstant { + offset: *offset, + size_bytes: *size_bytes, + values_offset: *values_offset, + stages: *stages, + }, + + ArcRenderCommand::PushDebugGroup { color, len } => RenderCommand::PushDebugGroup { + color: *color, + len: *len, + }, + + ArcRenderCommand::PopDebugGroup => RenderCommand::PopDebugGroup, + + ArcRenderCommand::InsertDebugMarker { color, len } => { + RenderCommand::InsertDebugMarker { + color: *color, + len: *len, + } + } + + ArcRenderCommand::WriteTimestamp { + query_set, + query_index, + } => RenderCommand::WriteTimestamp { + query_set_id: query_set.as_info().id(), + query_index: *query_index, + }, + + ArcRenderCommand::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => RenderCommand::BeginPipelineStatisticsQuery { + query_set_id: query_set.as_info().id(), + query_index: *query_index, + }, + + ArcRenderCommand::EndPipelineStatisticsQuery => { + RenderCommand::EndPipelineStatisticsQuery + } + ArcRenderCommand::SetIndexBuffer { + buffer, + index_format, + offset, + size, + } => RenderCommand::SetIndexBuffer { + buffer_id: buffer.as_info().id(), + index_format: *index_format, + offset: *offset, + size: *size, + }, + + ArcRenderCommand::SetVertexBuffer { + slot, + buffer, + offset, + size, + } => RenderCommand::SetVertexBuffer { + slot: *slot, + buffer_id: buffer.as_info().id(), + offset: *offset, + size: *size, + }, + + ArcRenderCommand::SetBlendConstant(color) => RenderCommand::SetBlendConstant(*color), + + ArcRenderCommand::SetStencilReference(reference) => { + RenderCommand::SetStencilReference(*reference) + } + + ArcRenderCommand::SetViewport { + rect, + depth_min, + depth_max, + } => RenderCommand::SetViewport { + rect: *rect, + depth_min: *depth_min, + depth_max: *depth_max, + }, + + ArcRenderCommand::SetScissor(scissor) => RenderCommand::SetScissor(*scissor), + + ArcRenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => RenderCommand::Draw { + vertex_count: *vertex_count, + instance_count: *instance_count, + first_vertex: *first_vertex, + first_instance: *first_instance, + }, + + ArcRenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => RenderCommand::DrawIndexed { + index_count: *index_count, + instance_count: *instance_count, + first_index: *first_index, + base_vertex: *base_vertex, + first_instance: *first_instance, + }, + + ArcRenderCommand::MultiDrawIndirect { + buffer, + offset, + count, + indexed, + } => RenderCommand::MultiDrawIndirect { + buffer_id: buffer.as_info().id(), + offset: *offset, + count: *count, + indexed: *indexed, + }, + + ArcRenderCommand::MultiDrawIndirectCount { + buffer, + offset, + count_buffer, + count_buffer_offset, + max_count, + indexed, + } => RenderCommand::MultiDrawIndirectCount { + buffer_id: buffer.as_info().id(), + offset: *offset, + count_buffer_id: count_buffer.as_info().id(), + count_buffer_offset: *count_buffer_offset, + max_count: *max_count, + indexed: *indexed, + }, + + ArcRenderCommand::BeginOcclusionQuery { query_index } => { + RenderCommand::BeginOcclusionQuery { + query_index: *query_index, + } + } + + ArcRenderCommand::EndOcclusionQuery => RenderCommand::EndOcclusionQuery, + + ArcRenderCommand::ExecuteBundle(bundle) => { + RenderCommand::ExecuteBundle(bundle.as_info().id()) + } + } + } +} diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 1f63f766b3..57574d8abb 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -24,12 +24,8 @@ use std::{ sync::Arc, }; use wgc::{ - command::{bundle_ffi::*, render_commands::*}, - device::DeviceLostClosure, - gfx_select, - id::CommandEncoderId, - id::TextureViewId, - pipeline::CreateShaderModuleError, + command::bundle_ffi::*, device::DeviceLostClosure, gfx_select, id::CommandEncoderId, + id::TextureViewId, pipeline::CreateShaderModuleError, }; use wgt::WasmNotSendSync; @@ -2814,7 +2810,18 @@ impl crate::Context for ContextWgpuCore { pipeline: &Self::RenderPipelineId, _pipeline_data: &Self::RenderPipelineData, ) { - wgpu_render_pass_set_pipeline(&mut pass_data.pass, *pipeline) + if let Err(cause) = self + .0 + .render_pass_set_pipeline(&mut pass_data.pass, *pipeline) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_pipeline", + ); + } } fn render_pass_set_bind_group( @@ -2826,7 +2833,18 @@ impl crate::Context for ContextWgpuCore { _bind_group_data: &Self::BindGroupData, offsets: &[wgt::DynamicOffset], ) { - wgpu_render_pass_set_bind_group(&mut pass_data.pass, index, *bind_group, offsets) + if let Err(cause) = + self.0 + .render_pass_set_bind_group(&mut pass_data.pass, index, *bind_group, offsets) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_bind_group", + ); + } } fn render_pass_set_index_buffer( @@ -2839,9 +2857,21 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, size: Option, ) { - pass_data - .pass - .set_index_buffer(*buffer, index_format, offset, size) + if let Err(cause) = self.0.render_pass_set_index_buffer( + &mut pass_data.pass, + *buffer, + index_format, + offset, + size, + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_index_buffer", + ); + } } fn render_pass_set_vertex_buffer( @@ -2854,7 +2884,18 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, size: Option, ) { - wgpu_render_pass_set_vertex_buffer(&mut pass_data.pass, slot, *buffer, offset, size) + if let Err(cause) = + self.0 + .render_pass_set_vertex_buffer(&mut pass_data.pass, slot, *buffer, offset, size) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_vertex_buffer", + ); + } } fn render_pass_set_push_constants( @@ -2865,7 +2906,18 @@ impl crate::Context for ContextWgpuCore { offset: u32, data: &[u8], ) { - wgpu_render_pass_set_push_constants(&mut pass_data.pass, stages, offset, data) + if let Err(cause) = + self.0 + .render_pass_set_push_constants(&mut pass_data.pass, stages, offset, data) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_push_constants", + ); + } } fn render_pass_draw( @@ -2875,13 +2927,21 @@ impl crate::Context for ContextWgpuCore { vertices: Range, instances: Range, ) { - wgpu_render_pass_draw( + if let Err(cause) = self.0.render_pass_draw( &mut pass_data.pass, vertices.end - vertices.start, instances.end - instances.start, vertices.start, instances.start, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::draw", + ); + } } fn render_pass_draw_indexed( @@ -2892,14 +2952,22 @@ impl crate::Context for ContextWgpuCore { base_vertex: i32, instances: Range, ) { - wgpu_render_pass_draw_indexed( + if let Err(cause) = self.0.render_pass_draw_indexed( &mut pass_data.pass, indices.end - indices.start, instances.end - instances.start, indices.start, base_vertex, instances.start, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::draw_indexed", + ); + } } fn render_pass_draw_indirect( @@ -2910,7 +2978,18 @@ impl crate::Context for ContextWgpuCore { _indirect_buffer_data: &Self::BufferData, indirect_offset: wgt::BufferAddress, ) { - wgpu_render_pass_draw_indirect(&mut pass_data.pass, *indirect_buffer, indirect_offset) + if let Err(cause) = + self.0 + .render_pass_draw_indirect(&mut pass_data.pass, *indirect_buffer, indirect_offset) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::draw_indirect", + ); + } } fn render_pass_draw_indexed_indirect( @@ -2921,11 +3000,19 @@ impl crate::Context for ContextWgpuCore { _indirect_buffer_data: &Self::BufferData, indirect_offset: wgt::BufferAddress, ) { - wgpu_render_pass_draw_indexed_indirect( + if let Err(cause) = self.0.render_pass_draw_indexed_indirect( &mut pass_data.pass, *indirect_buffer, indirect_offset, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::draw_indexed_indirect", + ); + } } fn render_pass_multi_draw_indirect( @@ -2937,12 +3024,20 @@ impl crate::Context for ContextWgpuCore { indirect_offset: wgt::BufferAddress, count: u32, ) { - wgpu_render_pass_multi_draw_indirect( + if let Err(cause) = self.0.render_pass_multi_draw_indirect( &mut pass_data.pass, *indirect_buffer, indirect_offset, count, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::multi_draw_indirect", + ); + } } fn render_pass_multi_draw_indexed_indirect( @@ -2954,12 +3049,20 @@ impl crate::Context for ContextWgpuCore { indirect_offset: wgt::BufferAddress, count: u32, ) { - wgpu_render_pass_multi_draw_indexed_indirect( + if let Err(cause) = self.0.render_pass_multi_draw_indexed_indirect( &mut pass_data.pass, *indirect_buffer, indirect_offset, count, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::multi_draw_indexed_indirect", + ); + } } fn render_pass_multi_draw_indirect_count( @@ -2974,14 +3077,22 @@ impl crate::Context for ContextWgpuCore { count_buffer_offset: wgt::BufferAddress, max_count: u32, ) { - wgpu_render_pass_multi_draw_indirect_count( + if let Err(cause) = self.0.render_pass_multi_draw_indirect_count( &mut pass_data.pass, *indirect_buffer, indirect_offset, *count_buffer, count_buffer_offset, max_count, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::multi_draw_indirect_count", + ); + } } fn render_pass_multi_draw_indexed_indirect_count( @@ -2996,14 +3107,22 @@ impl crate::Context for ContextWgpuCore { count_buffer_offset: wgt::BufferAddress, max_count: u32, ) { - wgpu_render_pass_multi_draw_indexed_indirect_count( + if let Err(cause) = self.0.render_pass_multi_draw_indexed_indirect_count( &mut pass_data.pass, *indirect_buffer, indirect_offset, *count_buffer, count_buffer_offset, max_count, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::multi_draw_indexed_indirect_count", + ); + } } fn render_pass_set_blend_constant( @@ -3012,7 +3131,18 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, color: wgt::Color, ) { - wgpu_render_pass_set_blend_constant(&mut pass_data.pass, &color) + if let Err(cause) = self + .0 + .render_pass_set_blend_constant(&mut pass_data.pass, &color) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_blend_constant", + ); + } } fn render_pass_set_scissor_rect( @@ -3024,7 +3154,18 @@ impl crate::Context for ContextWgpuCore { width: u32, height: u32, ) { - wgpu_render_pass_set_scissor_rect(&mut pass_data.pass, x, y, width, height) + if let Err(cause) = + self.0 + .render_pass_set_scissor_rect(&mut pass_data.pass, x, y, width, height) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_scissor_rect", + ); + } } fn render_pass_set_viewport( @@ -3038,7 +3179,7 @@ impl crate::Context for ContextWgpuCore { min_depth: f32, max_depth: f32, ) { - wgpu_render_pass_set_viewport( + if let Err(cause) = self.0.render_pass_set_viewport( &mut pass_data.pass, x, y, @@ -3046,7 +3187,15 @@ impl crate::Context for ContextWgpuCore { height, min_depth, max_depth, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_viewport", + ); + } } fn render_pass_set_stencil_reference( @@ -3055,7 +3204,18 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, reference: u32, ) { - wgpu_render_pass_set_stencil_reference(&mut pass_data.pass, reference) + if let Err(cause) = self + .0 + .render_pass_set_stencil_reference(&mut pass_data.pass, reference) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::set_stencil_reference", + ); + } } fn render_pass_insert_debug_marker( @@ -3064,7 +3224,18 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, label: &str, ) { - wgpu_render_pass_insert_debug_marker(&mut pass_data.pass, label, 0); + if let Err(cause) = self + .0 + .render_pass_insert_debug_marker(&mut pass_data.pass, label, 0) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::insert_debug_marker", + ); + } } fn render_pass_push_debug_group( @@ -3073,7 +3244,18 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, group_label: &str, ) { - wgpu_render_pass_push_debug_group(&mut pass_data.pass, group_label, 0); + if let Err(cause) = self + .0 + .render_pass_push_debug_group(&mut pass_data.pass, group_label, 0) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::push_debug_group", + ); + } } fn render_pass_pop_debug_group( @@ -3081,7 +3263,15 @@ impl crate::Context for ContextWgpuCore { _pass: &mut Self::RenderPassId, pass_data: &mut Self::RenderPassData, ) { - wgpu_render_pass_pop_debug_group(&mut pass_data.pass); + if let Err(cause) = self.0.render_pass_pop_debug_group(&mut pass_data.pass) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::pop_debug_group", + ); + } } fn render_pass_write_timestamp( @@ -3092,7 +3282,18 @@ impl crate::Context for ContextWgpuCore { _query_set_data: &Self::QuerySetData, query_index: u32, ) { - wgpu_render_pass_write_timestamp(&mut pass_data.pass, *query_set, query_index) + if let Err(cause) = + self.0 + .render_pass_write_timestamp(&mut pass_data.pass, *query_set, query_index) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::write_timestamp", + ); + } } fn render_pass_begin_occlusion_query( @@ -3101,7 +3302,18 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, query_index: u32, ) { - wgpu_render_pass_begin_occlusion_query(&mut pass_data.pass, query_index) + if let Err(cause) = self + .0 + .render_pass_begin_occlusion_query(&mut pass_data.pass, query_index) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::begin_occlusion_query", + ); + } } fn render_pass_end_occlusion_query( @@ -3109,7 +3321,15 @@ impl crate::Context for ContextWgpuCore { _pass: &mut Self::RenderPassId, pass_data: &mut Self::RenderPassData, ) { - wgpu_render_pass_end_occlusion_query(&mut pass_data.pass) + if let Err(cause) = self.0.render_pass_end_occlusion_query(&mut pass_data.pass) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::end_occlusion_query", + ); + } } fn render_pass_begin_pipeline_statistics_query( @@ -3120,11 +3340,19 @@ impl crate::Context for ContextWgpuCore { _query_set_data: &Self::QuerySetData, query_index: u32, ) { - wgpu_render_pass_begin_pipeline_statistics_query( + if let Err(cause) = self.0.render_pass_begin_pipeline_statistics_query( &mut pass_data.pass, *query_set, query_index, - ) + ) { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::begin_pipeline_statistics_query", + ); + } } fn render_pass_end_pipeline_statistics_query( @@ -3132,7 +3360,18 @@ impl crate::Context for ContextWgpuCore { _pass: &mut Self::RenderPassId, pass_data: &mut Self::RenderPassData, ) { - wgpu_render_pass_end_pipeline_statistics_query(&mut pass_data.pass) + if let Err(cause) = self + .0 + .render_pass_end_pipeline_statistics_query(&mut pass_data.pass) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::end_pipeline_statistics_query", + ); + } } fn render_pass_execute_bundles( @@ -3142,7 +3381,18 @@ impl crate::Context for ContextWgpuCore { render_bundles: &mut dyn Iterator, ) { let temp_render_bundles = render_bundles.map(|(i, _)| i).collect::>(); - wgpu_render_pass_execute_bundles(&mut pass_data.pass, &temp_render_bundles) + if let Err(cause) = self + .0 + .render_pass_execute_bundles(&mut pass_data.pass, &temp_render_bundles) + { + self.handle_error( + &pass_data.error_sink, + cause, + LABEL, + pass_data.pass.label(), + "RenderPass::execute_bundles", + ); + } } fn render_pass_end( @@ -3151,7 +3401,8 @@ impl crate::Context for ContextWgpuCore { pass_data: &mut Self::RenderPassData, ) { let encoder = pass_data.pass.parent_id(); - if let Err(cause) = wgc::gfx_select!(encoder => self.0.render_pass_end(&pass_data.pass)) { + if let Err(cause) = wgc::gfx_select!(encoder => self.0.render_pass_end(&mut pass_data.pass)) + { self.handle_error( &pass_data.error_sink, cause,