Skip to content

Commit 620c9d1

Browse files
Deferred error reporting for debug commands (gfx-rs#7789)
1 parent cf83de3 commit 620c9d1

3 files changed

Lines changed: 129 additions & 62 deletions

File tree

deno_webgpu/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use wgpu_core::command::CommandEncoderError;
1919
use wgpu_core::command::ComputePassError;
2020
use wgpu_core::command::CopyError;
2121
use wgpu_core::command::CreateRenderBundleError;
22+
use wgpu_core::command::EncoderStateError;
2223
use wgpu_core::command::QueryError;
2324
use wgpu_core::command::RenderBundleError;
2425
use wgpu_core::command::RenderPassError;
@@ -198,6 +199,12 @@ fn fmt_err(err: &(dyn std::error::Error + 'static)) -> String {
198199
output
199200
}
200201

202+
impl From<EncoderStateError> for GPUError {
203+
fn from(err: EncoderStateError) -> Self {
204+
GPUError::Validation(fmt_err(&err))
205+
}
206+
}
207+
201208
impl From<CreateBufferError> for GPUError {
202209
fn from(err: CreateBufferError) -> Self {
203210
match err {

tests/tests/wgpu-gpu/encoder.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,15 @@ static DROP_ENCODER_AFTER_ERROR: GpuTestConfiguration = GpuTestConfiguration::ne
8080

8181
#[gpu_test]
8282
static ENCODER_OPERATIONS_FAIL_WHILE_PASS_ALIVE: GpuTestConfiguration = GpuTestConfiguration::new()
83-
.parameters(TestParameters::default().features(
84-
wgpu::Features::CLEAR_TEXTURE
85-
| wgpu::Features::TIMESTAMP_QUERY
86-
| wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS,
87-
))
83+
.parameters(
84+
TestParameters::default()
85+
.features(
86+
wgpu::Features::CLEAR_TEXTURE
87+
| wgpu::Features::TIMESTAMP_QUERY
88+
| wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS,
89+
)
90+
.expect_fail(FailureCase::always()), // temporary, until https://github.com/gfx-rs/wgpu/issues/7391 is completed
91+
)
8892
.run_sync(encoder_operations_fail_while_pass_alive);
8993

9094
fn encoder_operations_fail_while_pass_alive(ctx: TestingContext) {

wgpu-core/src/command/mod.rs

Lines changed: 113 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,53 @@ impl CommandEncoderStatus {
114114
}
115115
}
116116

117+
/// Record commands using the supplied closure.
118+
///
119+
/// If the encoder is in the [`Self::Recording`] state, calls the closure to
120+
/// record commands. If the closure returns an error, stores that error in
121+
/// the encoder for later reporting when `finish()` is called. Returns
122+
/// `Ok(())` even if the closure returned an error.
123+
///
124+
/// If the encoder is not in the [`Self::Recording`] state, the closure will
125+
/// not be called and nothing will be recorded. The encoder will be
126+
/// invalidated (if it is not already). If the error is a [validation error
127+
/// that should be raised immediately][ves], returns it in `Err`, otherwise,
128+
/// returns `Ok(())`.
129+
///
130+
/// [ves]: https://www.w3.org/TR/webgpu/#abstract-opdef-validate-the-encoder-state
131+
fn record_with<
132+
F: FnOnce(&mut CommandBufferMutable) -> Result<(), E>,
133+
E: Clone + Into<CommandEncoderError>,
134+
>(
135+
&mut self,
136+
f: F,
137+
) -> Result<(), EncoderStateError> {
138+
let err = match self.record() {
139+
Ok(guard) => {
140+
guard.record(f);
141+
return Ok(());
142+
}
143+
Err(err) => err,
144+
};
145+
match err {
146+
err @ EncoderStateError::Locked => {
147+
// Invalidate the encoder and do not record anything, but do not
148+
// return an immediate validation error.
149+
self.invalidate(err);
150+
Ok(())
151+
}
152+
err @ EncoderStateError::Ended => {
153+
// Invalidate the encoder, do not record anything, and return an
154+
// immediate validation error.
155+
Err(self.invalidate(err))
156+
}
157+
// Encoder is already invalid. Do not record anything, but do not
158+
// return an immediate validation error.
159+
EncoderStateError::Invalid => Ok(()),
160+
EncoderStateError::Unlocked | EncoderStateError::Submitted => unreachable!(),
161+
}
162+
}
163+
117164
#[cfg(feature = "trace")]
118165
fn get_inner(&mut self) -> &mut CommandBufferMutable {
119166
match self {
@@ -230,6 +277,21 @@ impl<'a> RecordingGuard<'a> {
230277
pub(crate) fn mark_successful(self) {
231278
mem::forget(self)
232279
}
280+
281+
fn record<
282+
F: FnOnce(&mut CommandBufferMutable) -> Result<(), E>,
283+
E: Clone + Into<CommandEncoderError>,
284+
>(
285+
mut self,
286+
f: F,
287+
) {
288+
match f(&mut self) {
289+
Ok(()) => self.mark_successful(),
290+
Err(err) => {
291+
self.inner.invalidate(err);
292+
}
293+
}
294+
}
233295
}
234296

235297
impl<'a> Drop for RecordingGuard<'a> {
@@ -859,104 +921,98 @@ impl Global {
859921
&self,
860922
encoder_id: id::CommandEncoderId,
861923
label: &str,
862-
) -> Result<(), CommandEncoderError> {
924+
) -> Result<(), EncoderStateError> {
863925
profiling::scope!("CommandEncoder::push_debug_group");
864926
api_log!("CommandEncoder::push_debug_group {label}");
865927

866928
let hub = &self.hub;
867929

868930
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
869931
let mut cmd_buf_data = cmd_buf.data.lock();
870-
let mut cmd_buf_data_guard = cmd_buf_data.record()?;
871-
let cmd_buf_data = &mut *cmd_buf_data_guard;
872-
873-
#[cfg(feature = "trace")]
874-
if let Some(ref mut list) = cmd_buf_data.commands {
875-
list.push(TraceCommand::PushDebugGroup(label.to_owned()));
876-
}
932+
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
933+
#[cfg(feature = "trace")]
934+
if let Some(ref mut list) = cmd_buf_data.commands {
935+
list.push(TraceCommand::PushDebugGroup(label.to_owned()));
936+
}
877937

878-
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
879-
if !cmd_buf
880-
.device
881-
.instance_flags
882-
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
883-
{
884-
unsafe {
885-
cmd_buf_raw.begin_debug_marker(label);
938+
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
939+
if !cmd_buf
940+
.device
941+
.instance_flags
942+
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
943+
{
944+
unsafe {
945+
cmd_buf_raw.begin_debug_marker(label);
946+
}
886947
}
887-
}
888948

889-
cmd_buf_data_guard.mark_successful();
890-
Ok(())
949+
Ok(())
950+
})
891951
}
892952

893953
pub fn command_encoder_insert_debug_marker(
894954
&self,
895955
encoder_id: id::CommandEncoderId,
896956
label: &str,
897-
) -> Result<(), CommandEncoderError> {
957+
) -> Result<(), EncoderStateError> {
898958
profiling::scope!("CommandEncoder::insert_debug_marker");
899959
api_log!("CommandEncoder::insert_debug_marker {label}");
900960

901961
let hub = &self.hub;
902962

903963
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
904964
let mut cmd_buf_data = cmd_buf.data.lock();
905-
let mut cmd_buf_data_guard = cmd_buf_data.record()?;
906-
let cmd_buf_data = &mut *cmd_buf_data_guard;
907-
908-
#[cfg(feature = "trace")]
909-
if let Some(ref mut list) = cmd_buf_data.commands {
910-
list.push(TraceCommand::InsertDebugMarker(label.to_owned()));
911-
}
965+
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
966+
#[cfg(feature = "trace")]
967+
if let Some(ref mut list) = cmd_buf_data.commands {
968+
list.push(TraceCommand::InsertDebugMarker(label.to_owned()));
969+
}
912970

913-
if !cmd_buf
914-
.device
915-
.instance_flags
916-
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
917-
{
918-
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
919-
unsafe {
920-
cmd_buf_raw.insert_debug_marker(label);
971+
if !cmd_buf
972+
.device
973+
.instance_flags
974+
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
975+
{
976+
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
977+
unsafe {
978+
cmd_buf_raw.insert_debug_marker(label);
979+
}
921980
}
922-
}
923981

924-
cmd_buf_data_guard.mark_successful();
925-
Ok(())
982+
Ok(())
983+
})
926984
}
927985

928986
pub fn command_encoder_pop_debug_group(
929987
&self,
930988
encoder_id: id::CommandEncoderId,
931-
) -> Result<(), CommandEncoderError> {
989+
) -> Result<(), EncoderStateError> {
932990
profiling::scope!("CommandEncoder::pop_debug_marker");
933991
api_log!("CommandEncoder::pop_debug_group");
934992

935993
let hub = &self.hub;
936994

937995
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
938996
let mut cmd_buf_data = cmd_buf.data.lock();
939-
let mut cmd_buf_data_guard = cmd_buf_data.record()?;
940-
let cmd_buf_data = &mut *cmd_buf_data_guard;
941-
942-
#[cfg(feature = "trace")]
943-
if let Some(ref mut list) = cmd_buf_data.commands {
944-
list.push(TraceCommand::PopDebugGroup);
945-
}
997+
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
998+
#[cfg(feature = "trace")]
999+
if let Some(ref mut list) = cmd_buf_data.commands {
1000+
list.push(TraceCommand::PopDebugGroup);
1001+
}
9461002

947-
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
948-
if !cmd_buf
949-
.device
950-
.instance_flags
951-
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
952-
{
953-
unsafe {
954-
cmd_buf_raw.end_debug_marker();
1003+
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
1004+
if !cmd_buf
1005+
.device
1006+
.instance_flags
1007+
.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
1008+
{
1009+
unsafe {
1010+
cmd_buf_raw.end_debug_marker();
1011+
}
9551012
}
956-
}
9571013

958-
cmd_buf_data_guard.mark_successful();
959-
Ok(())
1014+
Ok(())
1015+
})
9601016
}
9611017

9621018
fn validate_pass_timestamp_writes(

0 commit comments

Comments
 (0)