mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Proper GPUDevice cleanup (#32520)
* Make device cleanup right * Use weakref for GPUDevice in globalscope * No need to destroy device on drop * DeviceReason early return * make remove_gpu_device to be the only way to remove device
This commit is contained in:
parent
256c55eb81
commit
bf99cf7f30
6 changed files with 89 additions and 43 deletions
|
@ -169,6 +169,7 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'GPUDevice': {
|
||||
'weakReferenceable': True, # for usage in GlobalScope https://github.com/servo/servo/issues/32519
|
||||
'inRealms': ['PopErrorScope', 'CreateComputePipelineAsync', 'CreateRenderPipelineAsync'],
|
||||
}
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ pub struct GlobalScope {
|
|||
gpu_id_hub: Arc<Mutex<Identities>>,
|
||||
|
||||
/// WebGPU devices
|
||||
gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, Dom<GPUDevice>>>,
|
||||
gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>>>,
|
||||
|
||||
// https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
|
@ -3091,7 +3091,16 @@ impl GlobalScope {
|
|||
pub fn add_gpu_device(&self, device: &GPUDevice) {
|
||||
self.gpu_devices
|
||||
.borrow_mut()
|
||||
.insert(device.id(), Dom::from_ref(device));
|
||||
.insert(device.id(), WeakRef::new(device));
|
||||
}
|
||||
|
||||
pub fn remove_gpu_device(&self, device: WebGPUDevice) {
|
||||
let device = self
|
||||
.gpu_devices
|
||||
.borrow_mut()
|
||||
.remove(&device)
|
||||
.expect("GPUDevice should still be in devices hashmap");
|
||||
assert!(device.root().is_none())
|
||||
}
|
||||
|
||||
pub fn gpu_device_lost(&self, device: WebGPUDevice, reason: DeviceLostReason, msg: String) {
|
||||
|
@ -3100,15 +3109,24 @@ impl GlobalScope {
|
|||
DeviceLostReason::Destroyed => GPUDeviceLostReason::Destroyed,
|
||||
};
|
||||
let _ac = enter_realm(&*self);
|
||||
self.gpu_devices
|
||||
if let Some(device) = self
|
||||
.gpu_devices
|
||||
.borrow_mut()
|
||||
.remove(&device)
|
||||
.expect("GPUDevice should still exists")
|
||||
.lose(reason, msg);
|
||||
.get_mut(&device)
|
||||
.expect("GPUDevice should still be in devices hashmap")
|
||||
.root()
|
||||
{
|
||||
device.lose(reason, msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_uncaptured_gpu_error(&self, device: WebGPUDevice, error: webgpu::Error) {
|
||||
if let Some(gpu_device) = self.gpu_devices.borrow().get(&device) {
|
||||
if let Some(gpu_device) = self
|
||||
.gpu_devices
|
||||
.borrow()
|
||||
.get(&device)
|
||||
.and_then(|device| device.root())
|
||||
{
|
||||
gpu_device.fire_uncaptured_error(error);
|
||||
} else {
|
||||
warn!("Recived error for lost GPUDevice!")
|
||||
|
|
|
@ -1031,13 +1031,6 @@ impl AsyncWGPUListener for GPUDevice {
|
|||
|
||||
impl Drop for GPUDevice {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DestroyDevice(self.device.0))
|
||||
{
|
||||
warn!("Failed to send DestroyDevice ({:?}) ({})", self.device.0, e);
|
||||
}
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
|
|
|
@ -92,7 +92,7 @@ use style::dom::OpaqueNode;
|
|||
use style::thread_state::{self, ThreadState};
|
||||
use time::precise_time_ns;
|
||||
use url::Position;
|
||||
use webgpu::WebGPUMsg;
|
||||
use webgpu::{WebGPUDevice, WebGPUMsg};
|
||||
use webrender_api::DocumentId;
|
||||
use webrender_traits::WebRenderScriptApi;
|
||||
|
||||
|
@ -2423,7 +2423,14 @@ impl ScriptThread {
|
|||
fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg) {
|
||||
match msg {
|
||||
WebGPUMsg::FreeAdapter(id) => self.gpu_id_hub.lock().kill_adapter_id(id),
|
||||
WebGPUMsg::FreeDevice(id) => self.gpu_id_hub.lock().kill_device_id(id),
|
||||
WebGPUMsg::FreeDevice {
|
||||
device_id,
|
||||
pipeline_id,
|
||||
} => {
|
||||
self.gpu_id_hub.lock().kill_device_id(device_id);
|
||||
let global = self.documents.borrow().find_global(pipeline_id).unwrap();
|
||||
global.remove_gpu_device(WebGPUDevice(device_id));
|
||||
},
|
||||
WebGPUMsg::FreeBuffer(id) => self.gpu_id_hub.lock().kill_buffer_id(id),
|
||||
WebGPUMsg::FreePipelineLayout(id) => self.gpu_id_hub.lock().kill_pipeline_layout_id(id),
|
||||
WebGPUMsg::FreeComputePipeline(id) => {
|
||||
|
|
|
@ -25,7 +25,10 @@ pub enum DeviceLostReason {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum WebGPUMsg {
|
||||
FreeAdapter(AdapterId),
|
||||
FreeDevice(DeviceId),
|
||||
FreeDevice {
|
||||
device_id: DeviceId,
|
||||
pipeline_id: PipelineId,
|
||||
},
|
||||
FreeBuffer(BufferId),
|
||||
FreePipelineLayout(PipelineLayoutId),
|
||||
FreeComputePipeline(ComputePipelineId),
|
||||
|
|
|
@ -43,7 +43,9 @@ pub(crate) struct DeviceScope {
|
|||
pub device_id: DeviceId,
|
||||
pub pipeline_id: PipelineId,
|
||||
/// <https://www.w3.org/TR/webgpu/#dom-gpudevice-errorscopestack-slot>
|
||||
pub error_scope_stack: Vec<ErrorScope>,
|
||||
///
|
||||
/// Is `None` if device is lost
|
||||
pub error_scope_stack: Option<Vec<ErrorScope>>,
|
||||
// TODO:
|
||||
// Queue for this device (to remove transmutes)
|
||||
// queue_id: QueueId,
|
||||
|
@ -56,7 +58,7 @@ impl DeviceScope {
|
|||
Self {
|
||||
device_id,
|
||||
pipeline_id,
|
||||
error_scope_stack: Vec::new(),
|
||||
error_scope_stack: Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,9 +585,17 @@ impl WGPU {
|
|||
},
|
||||
WebGPURequest::DropDevice(device_id) => {
|
||||
let global = &self.global;
|
||||
// device_drop also calls device lost callback
|
||||
gfx_select!(device_id => global.device_drop(device_id));
|
||||
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeDevice(device_id)) {
|
||||
let device_scope = self
|
||||
.devices
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&device_id)
|
||||
.expect("Device should not be dropped by this point");
|
||||
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeDevice {
|
||||
device_id,
|
||||
pipeline_id: device_scope.pipeline_id,
|
||||
}) {
|
||||
warn!("Unable to send FreeDevice({:?}) ({:?})", device_id, e);
|
||||
};
|
||||
},
|
||||
|
@ -691,31 +701,36 @@ impl WGPU {
|
|||
let devices = Arc::clone(&self.devices);
|
||||
let callback =
|
||||
DeviceLostClosure::from_rust(Box::from(move |reason, msg| {
|
||||
let _ = devices.lock().unwrap().remove(&device_id);
|
||||
let reason = match reason {
|
||||
wgt::DeviceLostReason::Unknown => {
|
||||
Some(crate::DeviceLostReason::Unknown)
|
||||
crate::DeviceLostReason::Unknown
|
||||
},
|
||||
wgt::DeviceLostReason::Destroyed => {
|
||||
Some(crate::DeviceLostReason::Destroyed)
|
||||
crate::DeviceLostReason::Destroyed
|
||||
},
|
||||
wgt::DeviceLostReason::Dropped => None,
|
||||
wgt::DeviceLostReason::Dropped => return, // we handle this in WebGPUMsg::FreeDevice
|
||||
wgt::DeviceLostReason::ReplacedCallback => {
|
||||
panic!("DeviceLost callback should only be set once")
|
||||
},
|
||||
wgt::DeviceLostReason::DeviceInvalid => {
|
||||
Some(crate::DeviceLostReason::Unknown)
|
||||
crate::DeviceLostReason::Unknown
|
||||
},
|
||||
};
|
||||
if let Some(reason) = reason {
|
||||
if let Err(e) = script_sender.send(WebGPUMsg::DeviceLost {
|
||||
device: WebGPUDevice(device_id),
|
||||
pipeline_id,
|
||||
reason,
|
||||
msg,
|
||||
}) {
|
||||
warn!("Failed to send WebGPUMsg::DeviceLost: {e}");
|
||||
}
|
||||
// make device lost by removing error scopes stack
|
||||
let _ = devices
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_mut(&device_id)
|
||||
.expect("Device should not be dropped by this point")
|
||||
.error_scope_stack
|
||||
.take();
|
||||
if let Err(e) = script_sender.send(WebGPUMsg::DeviceLost {
|
||||
device: WebGPUDevice(device_id),
|
||||
pipeline_id,
|
||||
reason,
|
||||
msg,
|
||||
}) {
|
||||
warn!("Failed to send WebGPUMsg::DeviceLost: {e}");
|
||||
}
|
||||
}));
|
||||
gfx_select!(device_id => global.device_set_device_lost_closure(device_id, callback));
|
||||
|
@ -1105,8 +1120,11 @@ impl WGPU {
|
|||
WebGPURequest::PushErrorScope { device_id, filter } => {
|
||||
// <https://www.w3.org/TR/webgpu/#dom-gpudevice-pusherrorscope>
|
||||
let mut devices = self.devices.lock().unwrap();
|
||||
if let Some(device_scope) = devices.get_mut(&device_id) {
|
||||
device_scope.error_scope_stack.push(ErrorScope::new(filter));
|
||||
let device_scope = devices
|
||||
.get_mut(&device_id)
|
||||
.expect("Device should not be dropped by this point");
|
||||
if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
|
||||
error_scope_stack.push(ErrorScope::new(filter));
|
||||
} // else device is lost
|
||||
},
|
||||
WebGPURequest::DispatchError { device_id, error } => {
|
||||
|
@ -1114,9 +1132,12 @@ impl WGPU {
|
|||
},
|
||||
WebGPURequest::PopErrorScope { device_id, sender } => {
|
||||
// <https://www.w3.org/TR/webgpu/#dom-gpudevice-poperrorscope>
|
||||
if let Some(device_scope) = self.devices.lock().unwrap().get_mut(&device_id)
|
||||
{
|
||||
if let Some(error_scope) = device_scope.error_scope_stack.pop() {
|
||||
let mut devices = self.devices.lock().unwrap();
|
||||
let device_scope = devices
|
||||
.get_mut(&device_id)
|
||||
.expect("Device should not be dropped by this point");
|
||||
if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
|
||||
if let Some(error_scope) = error_scope_stack.pop() {
|
||||
if let Err(e) =
|
||||
sender.send(Some(Ok(WebGPUResponse::PoppedErrorScope(Ok(
|
||||
// TODO: Do actual selection instead of selecting first error
|
||||
|
@ -1167,9 +1188,12 @@ impl WGPU {
|
|||
|
||||
/// <https://www.w3.org/TR/webgpu/#abstract-opdef-dispatch-error>
|
||||
fn dispatch_error(&mut self, device_id: id::DeviceId, error: Error) {
|
||||
if let Some(device_scope) = self.devices.lock().unwrap().get_mut(&device_id) {
|
||||
if let Some(error_scope) = device_scope
|
||||
.error_scope_stack
|
||||
let mut devices = self.devices.lock().unwrap();
|
||||
let device_scope = devices
|
||||
.get_mut(&device_id)
|
||||
.expect("Device should not be dropped by this point");
|
||||
if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
|
||||
if let Some(error_scope) = error_scope_stack
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.find(|error_scope| error_scope.filter == error.filter())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue