From eb47449eb96a1dab52e3b771d74aa701c3569057 Mon Sep 17 00:00:00 2001 From: teoxoy <28601907+teoxoy@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:51:26 +0200 Subject: [PATCH] invalidate the device when we encounter driver-induced device loss or on unexpected errors --- wgpu-core/src/command/clear.rs | 4 +- wgpu-core/src/command/compute.rs | 12 +-- wgpu-core/src/command/mod.rs | 32 ++++---- wgpu-core/src/command/query.rs | 4 +- wgpu-core/src/command/render.rs | 14 ++-- wgpu-core/src/command/transfer.rs | 10 +-- wgpu-core/src/device/global.rs | 38 +++++----- wgpu-core/src/device/mod.rs | 17 +++-- wgpu-core/src/device/queue.rs | 55 +++++++------- wgpu-core/src/device/resource.rs | 118 +++++++++++++++--------------- wgpu-core/src/instance.rs | 32 +++----- wgpu-core/src/pipeline.rs | 10 --- wgpu-core/src/present.rs | 8 +- wgpu-core/src/resource.rs | 8 +- 14 files changed, 176 insertions(+), 186 deletions(-) diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 944dd40af..7a16f6db3 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -163,7 +163,7 @@ impl Global { // actual hal barrier & operation let dst_barrier = dst_pending.map(|pending| pending.into_hal(&dst_buffer, &snatch_guard)); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_buffers(dst_barrier.as_slice()); cmd_buf_raw.clear_buffer(dst_raw, offset..end_offset); @@ -249,7 +249,7 @@ impl Global { let device = &cmd_buf.device; device.check_is_valid()?; - let (encoder, tracker) = cmd_buf_data.open_encoder_and_tracker()?; + let (encoder, tracker) = cmd_buf_data.open_encoder_and_tracker(&cmd_buf.device)?; let snatch_guard = device.snatchable_lock.read(); clear_texture( diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 2a258f1ef..8dbd6efa1 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -433,10 +433,10 @@ impl Global { // We automatically keep extending command buffers over time, and because // we want to insert a command buffer _before_ what we're about to record, // we need to make sure to close the previous one. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // will be reset to true if recording is done without errors *status = CommandEncoderStatus::Error; - let raw_encoder = encoder.open().map_pass_err(pass_scope)?; + let raw_encoder = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; let mut state = State { binder: Binder::new(), @@ -617,12 +617,12 @@ impl Global { } = state; // Stop the current command buffer. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // Create a new command buffer, which we will insert _before_ the body of the compute pass. // // Use that buffer to insert barriers and clear discarded images. - let transit = encoder.open().map_pass_err(pass_scope)?; + let transit = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), transit, @@ -637,7 +637,9 @@ impl Global { &snatch_guard, ); // Close the command buffer, and swap it with the previous. - encoder.close_and_swap().map_pass_err(pass_scope)?; + encoder + .close_and_swap(&cmd_buf.device) + .map_pass_err(pass_scope)?; Ok(()) } diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 14b7892d0..91af31662 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -172,10 +172,10 @@ impl CommandEncoder { /// [l]: CommandEncoder::list /// [`transition_buffers`]: hal::CommandEncoder::transition_buffers /// [`transition_textures`]: hal::CommandEncoder::transition_textures - fn close_and_swap(&mut self) -> Result<(), DeviceError> { + fn close_and_swap(&mut self, device: &Device) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; - let new = unsafe { self.raw.end_encoding()? }; + let new = unsafe { self.raw.end_encoding() }.map_err(|e| device.handle_hal_error(e))?; self.list.insert(self.list.len() - 1, new); } @@ -192,10 +192,11 @@ impl CommandEncoder { /// On return, the underlying hal encoder is closed. /// /// [l]: CommandEncoder::list - fn close(&mut self) -> Result<(), DeviceError> { + fn close(&mut self, device: &Device) -> Result<(), DeviceError> { if self.is_open { self.is_open = false; - let cmd_buf = unsafe { self.raw.end_encoding()? }; + let cmd_buf = + unsafe { self.raw.end_encoding() }.map_err(|e| device.handle_hal_error(e))?; self.list.push(cmd_buf); } @@ -215,11 +216,15 @@ impl CommandEncoder { /// Begin recording a new command buffer, if we haven't already. /// /// The underlying hal encoder is put in the "recording" state. - pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> { + pub(crate) fn open( + &mut self, + device: &Device, + ) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> { if !self.is_open { self.is_open = true; let hal_label = self.hal_label.as_deref(); - unsafe { self.raw.begin_encoding(hal_label)? }; + unsafe { self.raw.begin_encoding(hal_label) } + .map_err(|e| device.handle_hal_error(e))?; } Ok(self.raw.as_mut()) @@ -229,9 +234,9 @@ impl CommandEncoder { /// its own label. /// /// The underlying hal encoder is put in the "recording" state. - fn open_pass(&mut self, hal_label: Option<&str>) -> Result<(), DeviceError> { + fn open_pass(&mut self, hal_label: Option<&str>, device: &Device) -> Result<(), DeviceError> { self.is_open = true; - unsafe { self.raw.begin_encoding(hal_label)? }; + unsafe { self.raw.begin_encoding(hal_label) }.map_err(|e| device.handle_hal_error(e))?; Ok(()) } @@ -276,8 +281,9 @@ pub struct CommandBufferMutable { impl CommandBufferMutable { pub(crate) fn open_encoder_and_tracker( &mut self, + device: &Device, ) -> Result<(&mut dyn hal::DynCommandEncoder, &mut Tracker), DeviceError> { - let encoder = self.encoder.open()?; + let encoder = self.encoder.open(device)?; let tracker = &mut self.trackers; Ok((encoder, tracker)) @@ -621,7 +627,7 @@ impl Global { let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); match cmd_buf_data.status { CommandEncoderStatus::Recording => { - if let Err(e) = cmd_buf_data.encoder.close() { + if let Err(e) = cmd_buf_data.encoder.close(&cmd_buf.device) { Some(e.into()) } else { cmd_buf_data.status = CommandEncoderStatus::Finished; @@ -671,7 +677,7 @@ impl Global { list.push(TraceCommand::PushDebugGroup(label.to_string())); } - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; if !self .instance .flags @@ -713,7 +719,7 @@ impl Global { .flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) { - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.insert_debug_marker(label); } @@ -744,7 +750,7 @@ impl Global { list.push(TraceCommand::PopDebugGroup); } - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; if !self .instance .flags diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index de5103ac8..6d9fa8021 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -346,7 +346,7 @@ impl Global { let encoder = &mut cmd_buf_data.encoder; let tracker = &mut cmd_buf_data.trackers; - let raw_encoder = encoder.open()?; + let raw_encoder = encoder.open(&cmd_buf.device)?; let query_set = hub .query_sets @@ -397,7 +397,7 @@ impl Global { let encoder = &mut cmd_buf_data.encoder; let tracker = &mut cmd_buf_data.trackers; let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions; - let raw_encoder = encoder.open()?; + let raw_encoder = encoder.open(&cmd_buf.device)?; if destination_offset % wgt::QUERY_RESOLVE_BUFFER_ALIGNMENT != 0 { return Err(QueryError::Resolve(ResolveError::BufferOffsetAlignment)); diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 684bf3612..17e04d14c 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1588,10 +1588,12 @@ impl Global { // We automatically keep extending command buffers over time, and because // we want to insert a command buffer _before_ what we're about to record, // we need to make sure to close the previous one. - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; // We will reset this to `Recording` if we succeed, acts as a fail-safe. *status = CommandEncoderStatus::Error; - encoder.open_pass(hal_label).map_pass_err(pass_scope)?; + encoder + .open_pass(hal_label, &cmd_buf.device) + .map_pass_err(pass_scope)?; let info = RenderPassInfo::start( device, @@ -1894,7 +1896,7 @@ impl Global { .finish(state.raw_encoder, state.snatch_guard) .map_pass_err(pass_scope)?; - encoder.close().map_pass_err(pass_scope)?; + encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?; (trackers, pending_discard_init_fixups) }; @@ -1906,7 +1908,7 @@ impl Global { let tracker = &mut cmd_buf_data.trackers; { - let transit = encoder.open().map_pass_err(pass_scope)?; + let transit = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?; fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), @@ -1922,7 +1924,9 @@ impl Global { } *status = CommandEncoderStatus::Recording; - encoder.close_and_swap().map_pass_err(pass_scope)?; + encoder + .close_and_swap(&cmd_buf.device) + .map_pass_err(pass_scope)?; Ok(()) } diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index de5ef9ed8..aeceb29af 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -432,7 +432,7 @@ fn handle_texture_init( // In rare cases we may need to insert an init operation immediately onto the command buffer. if !immediate_inits.is_empty() { - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = encoder.open(device)?; for init in immediate_inits { clear_texture( &init.texture, @@ -684,7 +684,7 @@ impl Global { dst_offset: destination_offset, size: wgt::BufferSize::new(size).unwrap(), }; - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; let barriers = src_barrier .into_iter() .chain(dst_barrier) @@ -855,7 +855,7 @@ impl Global { }) .collect::>(); - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_textures(&dst_barrier); cmd_buf_raw.transition_buffers(src_barrier.as_slice()); @@ -1030,7 +1030,7 @@ impl Global { } }) .collect::>(); - let cmd_buf_raw = encoder.open()?; + let cmd_buf_raw = encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_buffers(dst_barrier.as_slice()); cmd_buf_raw.transition_textures(&src_barrier); @@ -1209,7 +1209,7 @@ impl Global { } }) .collect::>(); - let cmd_buf_raw = cmd_buf_data.encoder.open()?; + let cmd_buf_raw = cmd_buf_data.encoder.open(&cmd_buf.device)?; unsafe { cmd_buf_raw.transition_textures(&barriers); cmd_buf_raw.copy_texture_to_texture( diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index dad7d96db..5e108df17 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -270,21 +270,27 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); let raw_buf = buffer.try_raw(&snatch_guard)?; - unsafe { - let mapping = device + + let mapping = unsafe { + device .raw() .map_buffer(raw_buf, offset..offset + data.len() as u64) - .map_err(DeviceError::from)?; - std::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()); - if !mapping.is_coherent { - #[allow(clippy::single_range_in_vec_init)] + } + .map_err(|e| device.handle_hal_error(e))?; + + unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) }; + + if !mapping.is_coherent { + #[allow(clippy::single_range_in_vec_init)] + unsafe { device .raw() - .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]); - } - device.raw().unmap_buffer(raw_buf); + .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]) + }; } + unsafe { device.raw().unmap_buffer(raw_buf) }; + Ok(()) } @@ -2006,7 +2012,9 @@ impl Global { hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { E::InvalidSurface } - hal::SurfaceError::Device(error) => E::Device(error.into()), + hal::SurfaceError::Device(error) => { + E::Device(device.handle_hal_error(error)) + } hal::SurfaceError::Other(message) => { log::error!("surface configuration failed: {}", message); E::InvalidSurface @@ -2289,16 +2297,6 @@ impl Global { } } - pub fn device_mark_lost(&self, device_id: DeviceId, message: &str) { - api_log!("Device::mark_lost {device_id:?}"); - - let hub = &self.hub; - - if let Ok(device) = hub.devices.get(device_id) { - device.lose(message); - } - } - pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters { let hub = &self.hub; if let Ok(device) = hub.devices.get(device_id) { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index b9c346775..71bbce19c 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -308,7 +308,7 @@ fn map_buffer( let raw_buffer = buffer.try_raw(snatch_guard)?; let mapping = unsafe { raw.map_buffer(raw_buffer, offset..offset + size) - .map_err(DeviceError::from)? + .map_err(|e| buffer.device.handle_hal_error(e))? }; if !mapping.is_coherent && kind == HostMap::Read { @@ -420,13 +420,16 @@ pub enum DeviceError { DeviceMismatch(#[from] Box), } -impl From for DeviceError { - fn from(error: hal::DeviceError) -> Self { +impl DeviceError { + /// Only use this function in contexts where there is no `Device`. + /// + /// Use [`Device::handle_hal_error`] otherwise. + pub fn from_hal(error: hal::DeviceError) -> Self { match error { - hal::DeviceError::Lost => DeviceError::Lost, - hal::DeviceError::OutOfMemory => DeviceError::OutOfMemory, - hal::DeviceError::ResourceCreationFailed => DeviceError::ResourceCreationFailed, - hal::DeviceError::Unexpected => DeviceError::Lost, + hal::DeviceError::Lost => Self::Lost, + hal::DeviceError::OutOfMemory => Self::OutOfMemory, + hal::DeviceError::ResourceCreationFailed => Self::ResourceCreationFailed, + hal::DeviceError::Unexpected => Self::Lost, } } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index e516e0dac..7058799a0 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -269,17 +269,20 @@ impl PendingWrites { fn pre_submit( &mut self, command_allocator: &CommandAllocator, - device: &dyn hal::DynDevice, - queue: &dyn hal::DynQueue, + device: &Device, + queue: &Queue, ) -> Result, DeviceError> { if self.is_recording { let pending_buffers = mem::take(&mut self.dst_buffers); let pending_textures = mem::take(&mut self.dst_textures); - let cmd_buf = unsafe { self.command_encoder.end_encoding()? }; + let cmd_buf = unsafe { self.command_encoder.end_encoding() } + .map_err(|e| device.handle_hal_error(e))?; self.is_recording = false; - let new_encoder = command_allocator.acquire_encoder(device, queue)?; + let new_encoder = command_allocator + .acquire_encoder(device.raw(), queue.raw()) + .map_err(|e| device.handle_hal_error(e))?; let encoder = EncoderInFlight { raw: mem::replace(&mut self.command_encoder, new_encoder), @@ -1194,14 +1197,12 @@ impl Global { // execute resource transitions unsafe { - baked - .encoder - .begin_encoding(hal_label( - Some("(wgpu internal) Transit"), - device.instance_flags, - )) - .map_err(DeviceError::from)? - }; + baked.encoder.begin_encoding(hal_label( + Some("(wgpu internal) Transit"), + device.instance_flags, + )) + } + .map_err(|e| device.handle_hal_error(e))?; //Note: locking the trackers has to be done after the storages let mut trackers = device.trackers.lock(); @@ -1224,14 +1225,12 @@ impl Global { // but here we have a command encoder by hand, so it's easier to use it. if !used_surface_textures.is_empty() { unsafe { - baked - .encoder - .begin_encoding(hal_label( - Some("(wgpu internal) Present"), - device.instance_flags, - )) - .map_err(DeviceError::from)? - }; + baked.encoder.begin_encoding(hal_label( + Some("(wgpu internal) Present"), + device.instance_flags, + )) + } + .map_err(|e| device.handle_hal_error(e))?; let texture_barriers = trackers .textures .set_from_usage_scope_and_drain_transitions( @@ -1299,7 +1298,7 @@ impl Global { } if let Some(pending_execution) = - pending_writes.pre_submit(&device.command_allocator, device.raw(), queue.raw())? + pending_writes.pre_submit(&device.command_allocator, device, &queue)? { active_executions.insert(0, pending_execution); } @@ -1324,15 +1323,13 @@ impl Global { } unsafe { - queue - .raw() - .submit( - &hal_command_buffers, - &submit_surface_textures, - (fence.as_mut(), submit_index), - ) - .map_err(DeviceError::from)?; + queue.raw().submit( + &hal_command_buffers, + &submit_surface_textures, + (fence.as_mut(), submit_index), + ) } + .map_err(|e| device.handle_hal_error(e))?; // Advance the successful submission index. device diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index cfa0a460e..253f2ca94 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -227,31 +227,29 @@ impl Device { desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, instance_flags: wgt::InstanceFlags, - ) -> Result { + ) -> Result { #[cfg(not(feature = "trace"))] if let Some(_) = trace_path { log::error!("Feature 'trace' is not enabled"); } - let fence = - unsafe { raw_device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?; + let fence = unsafe { raw_device.create_fence() }.map_err(DeviceError::from_hal)?; let command_allocator = command::CommandAllocator::new(); let pending_encoder = command_allocator .acquire_encoder(raw_device.as_ref(), raw_queue) - .map_err(|_| CreateDeviceError::OutOfMemory)?; + .map_err(DeviceError::from_hal)?; let mut pending_writes = PendingWrites::new(pending_encoder); // Create zeroed buffer used for texture clears. let zero_buffer = unsafe { - raw_device - .create_buffer(&hal::BufferDescriptor { - label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags), - size: ZERO_BUFFER_SIZE, - usage: hal::BufferUses::COPY_SRC | hal::BufferUses::COPY_DST, - memory_flags: hal::MemoryFlags::empty(), - }) - .map_err(DeviceError::from)? - }; + raw_device.create_buffer(&hal::BufferDescriptor { + label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags), + size: ZERO_BUFFER_SIZE, + usage: hal::BufferUses::COPY_SRC | hal::BufferUses::COPY_DST, + memory_flags: hal::MemoryFlags::empty(), + }) + } + .map_err(DeviceError::from_hal)?; pending_writes.activate(); unsafe { pending_writes @@ -339,6 +337,18 @@ impl Device { } } + pub fn handle_hal_error(&self, error: hal::DeviceError) -> DeviceError { + match error { + hal::DeviceError::OutOfMemory => {} + hal::DeviceError::Lost + | hal::DeviceError::ResourceCreationFailed + | hal::DeviceError::Unexpected => { + self.lose(&error.to_string()); + } + } + DeviceError::from_hal(error) + } + pub(crate) fn release_queue(&self, queue: Box) { assert!(self.queue_to_drop.set(queue).is_ok()); } @@ -441,11 +451,8 @@ impl Device { wgt::Maintain::Wait => self .last_successful_submission_index .load(Ordering::Acquire), - wgt::Maintain::Poll => unsafe { - self.raw() - .get_fence_value(fence.as_ref()) - .map_err(DeviceError::from)? - }, + wgt::Maintain::Poll => unsafe { self.raw().get_fence_value(fence.as_ref()) } + .map_err(|e| self.handle_hal_error(e))?, }; // If necessary, wait for that submission to complete. @@ -453,8 +460,8 @@ impl Device { unsafe { self.raw() .wait(fence.as_ref(), submission_index, CLEANUP_WAIT_MS) - .map_err(DeviceError::from)? - }; + } + .map_err(|e| self.handle_hal_error(e))?; } log::trace!("Device::maintain: waiting for submission index {submission_index}"); @@ -588,7 +595,8 @@ impl Device { usage, memory_flags: hal::MemoryFlags::empty(), }; - let buffer = unsafe { self.raw().create_buffer(&hal_desc) }.map_err(DeviceError::from)?; + let buffer = + unsafe { self.raw().create_buffer(&hal_desc) }.map_err(|e| self.handle_hal_error(e))?; let buffer = Buffer { raw: Snatchable::new(buffer), @@ -935,11 +943,8 @@ impl Device { view_formats: hal_view_formats, }; - let raw_texture = unsafe { - self.raw() - .create_texture(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw_texture = unsafe { self.raw().create_texture(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let clear_mode = if hal_usage .intersects(hal::TextureUses::DEPTH_STENCIL_WRITE | hal::TextureUses::COLOR_TARGET) @@ -982,7 +987,7 @@ impl Device { unsafe { self.raw().create_texture_view(raw_texture.as_ref(), &desc) } - .map_err(DeviceError::from)?, + .map_err(|e| self.handle_hal_error(e))?, )); }; } @@ -1288,11 +1293,8 @@ impl Device { range: resolved_range, }; - let raw = unsafe { - self.raw() - .create_texture_view(texture_raw, &hal_desc) - .map_err(|_| resource::CreateTextureViewError::OutOfMemory)? - }; + let raw = unsafe { self.raw().create_texture_view(texture_raw, &hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let selector = TextureSelector { mips: desc.range.base_mip_level..mip_level_end, @@ -1423,11 +1425,8 @@ impl Device { border_color: desc.border_color, }; - let raw = unsafe { - self.raw() - .create_sampler(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_sampler(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let sampler = Sampler { raw: ManuallyDrop::new(raw), @@ -1551,7 +1550,7 @@ impl Device { Err(error) => { return Err(match error { hal::ShaderError::Device(error) => { - pipeline::CreateShaderModuleError::Device(error.into()) + pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error)) } hal::ShaderError::Compilation(ref msg) => { log::error!("Shader error: {}", msg); @@ -1592,7 +1591,7 @@ impl Device { Err(error) => { return Err(match error { hal::ShaderError::Device(error) => { - pipeline::CreateShaderModuleError::Device(error.into()) + pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error)) } hal::ShaderError::Compilation(ref msg) => { log::error!("Shader error: {}", msg); @@ -1624,7 +1623,8 @@ impl Device { let encoder = self .command_allocator - .acquire_encoder(self.raw(), queue.raw())?; + .acquire_encoder(self.raw(), queue.raw()) + .map_err(|e| self.handle_hal_error(e))?; let command_buffer = command::CommandBuffer::new(encoder, self, label); @@ -1856,11 +1856,9 @@ impl Device { flags: bgl_flags, entries: &hal_bindings, }; - let raw = unsafe { - self.raw() - .create_bind_group_layout(&hal_desc) - .map_err(DeviceError::from)? - }; + + let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; let mut count_validator = binding_model::BindingTypeMaxCountValidator::default(); for entry in entry_map.values() { @@ -2290,11 +2288,8 @@ impl Device { textures: &hal_textures, acceleration_structures: &[], }; - let raw = unsafe { - self.raw() - .create_bind_group(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_bind_group(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; // collect in the order of BGL iteration let late_buffer_binding_sizes = layout @@ -2588,11 +2583,8 @@ impl Device { push_constant_ranges: desc.push_constant_ranges.as_ref(), }; - let raw = unsafe { - self.raw() - .create_pipeline_layout(&hal_desc) - .map_err(DeviceError::from)? - }; + let raw = unsafe { self.raw().create_pipeline_layout(&hal_desc) } + .map_err(|e| self.handle_hal_error(e))?; drop(raw_bind_group_layouts); @@ -2746,7 +2738,7 @@ impl Device { unsafe { self.raw().create_compute_pipeline(&pipeline_desc) }.map_err( |err| match err { hal::PipelineError::Device(error) => { - pipeline::CreateComputePipelineError::Device(error.into()) + pipeline::CreateComputePipelineError::Device(self.handle_hal_error(error)) } hal::PipelineError::Linkage(_stages, msg) => { pipeline::CreateComputePipelineError::Internal(msg) @@ -3326,7 +3318,7 @@ impl Device { unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err( |err| match err { hal::PipelineError::Device(error) => { - pipeline::CreateRenderPipelineError::Device(error.into()) + pipeline::CreateRenderPipelineError::Device(self.handle_hal_error(error)) } hal::PipelineError::Linkage(stage, msg) => { pipeline::CreateRenderPipelineError::Internal { stage, error: msg } @@ -3449,7 +3441,9 @@ impl Device { }; let raw = match unsafe { self.raw().create_pipeline_cache(&cache_desc) } { Ok(raw) => raw, - Err(e) => return Err(e.into()), + Err(e) => match e { + hal::PipelineCacheError::Device(e) => return Err(self.handle_hal_error(e).into()), + }, }; let cache = pipeline::PipelineCache { device: self.clone(), @@ -3506,9 +3500,11 @@ impl Device { submission_index: crate::SubmissionIndex, ) -> Result<(), DeviceError> { let fence = self.fence.read(); - let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref())? }; + let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref()) } + .map_err(|e| self.handle_hal_error(e))?; if last_done_index < submission_index { - unsafe { self.raw().wait(fence.as_ref(), submission_index, !0)? }; + unsafe { self.raw().wait(fence.as_ref(), submission_index, !0) } + .map_err(|e| self.handle_hal_error(e))?; drop(fence); let closures = self .lock_life() @@ -3567,7 +3563,7 @@ impl Device { Ok(query_set) } - pub(crate) fn lose(&self, message: &str) { + fn lose(&self, message: &str) { // Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device. // Mark the device explicitly as invalid. This is checked in various diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index b3ce11fd1..ca19d3c53 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -4,7 +4,7 @@ use std::{borrow::Cow, collections::HashMap}; use crate::hub::Hub; use crate::{ api_log, - device::{queue::Queue, resource::Device, DeviceDescriptor}, + device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError}, global::Global, hal_api::HalApi, id::{markers, AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId}, @@ -272,20 +272,19 @@ impl Adapter { ) -> Result<(Arc, Arc), RequestDeviceError> { api_log!("Adapter::create_device"); - if let Ok(device) = Device::new( + let device = Device::new( hal_device.device, hal_device.queue.as_ref(), self, desc, trace_path, instance_flags, - ) { - let device = Arc::new(device); - let queue = Arc::new(Queue::new(device.clone(), hal_device.queue)); - device.set_queue(&queue); - return Ok((device, queue)); - } - Err(RequestDeviceError::OutOfMemory) + )?; + + let device = Arc::new(device); + let queue = Arc::new(Queue::new(device.clone(), hal_device.queue)); + device.set_queue(&queue); + Ok((device, queue)) } #[allow(clippy::type_complexity)] @@ -338,12 +337,7 @@ impl Adapter { &desc.memory_hints, ) } - .map_err(|err| match err { - hal::DeviceError::Lost => RequestDeviceError::DeviceLost, - hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory, - hal::DeviceError::ResourceCreationFailed => RequestDeviceError::Internal, - hal::DeviceError::Unexpected => RequestDeviceError::DeviceLost, - })?; + .map_err(DeviceError::from_hal)?; self.create_device_and_queue_from_hal(open, desc, instance_flags, trace_path) } @@ -377,18 +371,14 @@ pub enum GetSurfaceSupportError { /// Error when requesting a device from the adaptor #[non_exhaustive] pub enum RequestDeviceError { + #[error(transparent)] + Device(#[from] DeviceError), #[error("Parent adapter is invalid")] InvalidAdapter, - #[error("Connection to device was lost during initialization")] - DeviceLost, - #[error("Device initialization failed due to implementation specific errors")] - Internal, #[error(transparent)] LimitsExceeded(#[from] FailedLimit), #[error("Device has no queue supporting graphics")] NoGraphicsQueue, - #[error("Not enough memory left to request device")] - OutOfMemory, #[error("Unsupported features were requested: {0:?}")] UnsupportedFeature(wgt::Features), } diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index db1c1ba76..e5eb9e555 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -286,16 +286,6 @@ pub enum CreatePipelineCacheError { Internal(String), } -impl From for CreatePipelineCacheError { - fn from(value: hal::PipelineCacheError) -> Self { - match value { - hal::PipelineCacheError::Device(device) => { - CreatePipelineCacheError::Device(device.into()) - } - } - } -} - #[derive(Debug)] pub struct PipelineCache { pub(crate) raw: ManuallyDrop>, diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 697156b35..b4fe0bbfb 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -191,7 +191,7 @@ impl Global { .raw() .create_texture_view(ast.texture.as_ref().borrow(), &clear_view_desc) } - .map_err(DeviceError::from)?; + .map_err(|e| device.handle_hal_error(e))?; let mut presentation = surface.presentation.lock(); let present = presentation.as_mut().unwrap(); @@ -238,7 +238,7 @@ impl Global { match err { hal::SurfaceError::Lost => Status::Lost, hal::SurfaceError::Device(err) => { - return Err(DeviceError::from(err).into()); + return Err(device.handle_hal_error(err).into()); } hal::SurfaceError::Outdated => Status::Outdated, hal::SurfaceError::Other(msg) => { @@ -315,7 +315,9 @@ impl Global { Ok(()) => Ok(Status::Good), Err(err) => match err { hal::SurfaceError::Lost => Ok(Status::Lost), - hal::SurfaceError::Device(err) => Err(SurfaceError::from(DeviceError::from(err))), + hal::SurfaceError::Device(err) => { + Err(SurfaceError::from(device.handle_hal_error(err))) + } hal::SurfaceError::Outdated => Ok(Status::Outdated), hal::SurfaceError::Other(msg) => { log::error!("acquire error: {}", msg); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 4c69266ae..dc0792cb3 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -832,8 +832,10 @@ impl StagingBuffer { memory_flags: hal::MemoryFlags::TRANSIENT, }; - let raw = unsafe { device.raw().create_buffer(&stage_desc)? }; - let mapping = unsafe { device.raw().map_buffer(raw.as_ref(), 0..size.get()) }?; + let raw = unsafe { device.raw().create_buffer(&stage_desc) } + .map_err(|e| device.handle_hal_error(e))?; + let mapping = unsafe { device.raw().map_buffer(raw.as_ref(), 0..size.get()) } + .map_err(|e| device.handle_hal_error(e))?; let staging_buffer = StagingBuffer { raw, @@ -1358,7 +1360,7 @@ impl Global { let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); let cmd_buf_raw = cmd_buf_data .encoder - .open() + .open(&cmd_buf.device) .ok() .and_then(|encoder| encoder.as_any_mut().downcast_mut()); hal_command_encoder_callback(cmd_buf_raw)