Skip to content

Commit

Permalink
Error callbacks
Browse files Browse the repository at this point in the history
Implements wgpuDeviceSetDeviceLostCallback() and
wgpuDeviceSetUncapturedErrorCallback()

wgpuDeviceCreateShaderModule() and wgpuSwapChainGetCurrentTextureView() have
been ported to use handle_device_error(), meaning they no longer panic if an
error occurs.

Most (all?) check_error() uses should be converted to handle_device_error().
  • Loading branch information
sqaxomonophonen committed Jan 1, 2022
1 parent 9d962ef commit 5ebd50e
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 12 deletions.
46 changes: 34 additions & 12 deletions src/device.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::conv::{map_adapter_options, map_device_descriptor, map_shader_module};
use crate::{check_error, conv, follow_chain, make_slice, native, OwnedLabel, GLOBAL};
use crate::{
check_error, conv, follow_chain, handle_device_error, make_slice, native, OwnedLabel, GLOBAL,
};
use lazy_static::lazy_static;
use std::{
borrow::Cow,
Expand Down Expand Up @@ -176,7 +178,7 @@ fn write_limits_struct(
pub unsafe extern "C" fn wgpuDeviceCreateShaderModule(
device: id::DeviceId,
descriptor: &native::WGPUShaderModuleDescriptor,
) -> id::ShaderModuleId {
) -> Option<id::ShaderModuleId> {
let label = OwnedLabel::new(descriptor.label);
let source = follow_chain!(
map_shader_module(descriptor,
Expand All @@ -188,9 +190,13 @@ pub unsafe extern "C" fn wgpuDeviceCreateShaderModule(
label: label.as_cow(),
shader_bound_checks: wgt::ShaderBoundChecks::default(),
};
check_error(
gfx_select!(device => GLOBAL.device_create_shader_module(device, &desc, source, PhantomData)),
)
let (module, err) = gfx_select!(device => GLOBAL.device_create_shader_module(device, &desc, source, PhantomData));
if let Some(err) = err {
handle_device_error(device, native::WGPUErrorType_Unknown, &format!("{}", err));
None
} else {
Some(module)
}
}

#[no_mangle]
Expand Down Expand Up @@ -689,13 +695,29 @@ pub extern "C" fn wgpuSwapChainGetCurrentTextureView(
let surface_id = swap_chain;
let device_id = get_device_from_surface(surface_id);
let result =
gfx_select!(device_id => GLOBAL.surface_get_current_texture(surface_id, PhantomData));
let texture = result
.expect("Unable to get swap chain texture view")
.texture_id
.unwrap();
let desc = wgc::resource::TextureViewDescriptor::default();
Some(gfx_select!(texture => GLOBAL.texture_create_view(texture, &desc, PhantomData)).0)
gfx_select!(device_id => GLOBAL.surface_get_current_texture(surface_id, PhantomData))
.expect("Unable to get swap chain texture view");

match result.status {
wgt::SurfaceStatus::Good | wgt::SurfaceStatus::Suboptimal => {
let texture = result.texture_id.unwrap();
let desc = wgc::resource::TextureViewDescriptor::default();
Some(gfx_select!(texture => GLOBAL.texture_create_view(texture, &desc, PhantomData)).0)
}
wgt::SurfaceStatus::Timeout => {
handle_device_error(device_id, native::WGPUErrorType_Unknown, "timeout");
None
}
wgt::SurfaceStatus::Outdated => {
handle_device_error(device_id, native::WGPUErrorType_Unknown, "outdated");
None
}
wgt::SurfaceStatus::Lost => {
handle_device_error(device_id, native::WGPUErrorType_Unknown, "lost");
//handle_device_error(device_id, native::WGPUErrorType_DeviceLost, "lost"); // <<< ???
None
}
}
}

#[no_mangle]
Expand Down
92 changes: 92 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use log;
use std::ffi::CString;
use std::{borrow::Cow, marker::PhantomData, sync::Arc};
use wgc::id;

Expand Down Expand Up @@ -281,3 +283,93 @@ pub unsafe extern "C" fn wgpuSurfaceGetPreferredFormat(
};
return preferred_format;
}

struct DeviceCallback<T> {
device: id::DeviceId,
callback: T,
userdata: *mut std::os::raw::c_void,
}

type DeviceCallbackList<T> = Vec<DeviceCallback<T>>;

trait DeviceCallbackListExt<T> {
fn set_callback(&mut self, v: DeviceCallback<T>);
fn get_by_device(&self, device: id::DeviceId) -> Option<*const DeviceCallback<T>>;
}

impl<T> DeviceCallbackListExt<T> for DeviceCallbackList<T> {
fn set_callback(&mut self, v: DeviceCallback<T>) {
for i in 0..self.len() {
if self[i].device == v.device {
self[i] = v;
return;
}
}
self.push(v);
}
fn get_by_device(&self, device: id::DeviceId) -> Option<*const DeviceCallback<T>> {
for i in 0..self.len() {
let e = &self[i];
if e.device == device {
return Some(e);
}
}
return None;
}
}

static mut UNCAPTURED_ERROR_CALLBACKS: DeviceCallbackList<native::WGPUErrorCallback> =
DeviceCallbackList::new();
static mut DEVICE_LOST_CALLBACKS: DeviceCallbackList<native::WGPUDeviceLostCallback> =
DeviceCallbackList::new();

#[no_mangle]
pub unsafe extern "C" fn wgpuDeviceSetDeviceLostCallback(
device: id::DeviceId,
callback: native::WGPUDeviceLostCallback,
userdata: *mut std::os::raw::c_void,
) {
DEVICE_LOST_CALLBACKS.set_callback(DeviceCallback {
device: device,
callback: callback,
userdata: userdata,
});
}

#[no_mangle]
pub unsafe extern "C" fn wgpuDeviceSetUncapturedErrorCallback(
device: id::DeviceId,
callback: native::WGPUErrorCallback,
userdata: *mut std::os::raw::c_void,
) {
UNCAPTURED_ERROR_CALLBACKS.set_callback(DeviceCallback {
device: device,
callback: callback,
userdata: userdata,
});
}

pub fn handle_device_error(device: id::DeviceId, typ: native::WGPUErrorType, msg: &str) {
log::debug!("Device error ({}): {}", typ, msg);
let msg_c = CString::new(msg).unwrap();
unsafe {
match typ {
native::WGPUErrorType_DeviceLost => {
let cb = DEVICE_LOST_CALLBACKS.get_by_device(device);
if let Some(cb) = cb {
(*cb).callback.unwrap()(
native::WGPUDeviceLostReason_Destroyed,
msg_c.as_ptr(),
(*cb).userdata,
);
}
}
_ => {
let cb = UNCAPTURED_ERROR_CALLBACKS.get_by_device(device);
if let Some(cb) = cb {
(*cb).callback.unwrap()(typ, msg_c.as_ptr(), (*cb).userdata);
}
}
}
}
}

0 comments on commit 5ebd50e

Please sign in to comment.