22
33use std:: fmt:: Display ;
44use std:: fmt:: Formatter ;
5- use std:: sync:: Mutex ;
6- use std:: sync:: OnceLock ;
5+ use std:: sync:: Arc ;
76
87use deno_core:: v8;
98
109use deno_core:: JsRuntime ;
11- use deno_core:: V8TaskSpawner ;
1210use wgpu_core:: binding_model:: CreateBindGroupError ;
1311use wgpu_core:: binding_model:: CreateBindGroupLayoutError ;
1412use wgpu_core:: binding_model:: CreatePipelineLayoutError ;
@@ -24,6 +22,7 @@ use wgpu_core::command::RenderBundleError;
2422use wgpu_core:: command:: RenderPassError ;
2523use wgpu_core:: device:: queue:: QueueSubmitError ;
2624use wgpu_core:: device:: queue:: QueueWriteError ;
25+ use wgpu_core:: device:: Device ;
2726use wgpu_core:: device:: DeviceError ;
2827use wgpu_core:: pipeline:: CreateComputePipelineError ;
2928use wgpu_core:: pipeline:: CreateRenderPipelineError ;
@@ -35,31 +34,18 @@ use wgpu_core::resource::CreateQuerySetError;
3534use wgpu_core:: resource:: CreateSamplerError ;
3635use wgpu_core:: resource:: CreateTextureError ;
3736use wgpu_core:: resource:: CreateTextureViewError ;
37+ use wgpu_types:: error:: ErrorFilter ;
3838use wgpu_types:: error:: { ErrorType , WebGpuError } ;
3939
4040pub type ErrorHandler = std:: rc:: Rc < DeviceErrorHandler > ;
4141
4242pub struct DeviceErrorHandler {
43- pub scopes : Mutex < Vec < ( GPUErrorFilter , Option < GPUError > ) > > ,
44- spawner : V8TaskSpawner ,
45-
46- // The error handler is constructed before the device. A weak
47- // reference to the device is placed here with `set_device`
48- // after the device is constructed.
49- device : OnceLock < v8:: Weak < v8:: Object > > ,
43+ device : Arc < Device > ,
5044}
5145
5246impl DeviceErrorHandler {
53- pub fn new ( spawner : V8TaskSpawner ) -> Self {
54- Self {
55- scopes : Mutex :: new ( vec ! [ ] ) ,
56- device : OnceLock :: new ( ) ,
57- spawner,
58- }
59- }
60-
61- pub fn set_device ( & self , device : v8:: Weak < v8:: Object > ) {
62- self . device . set ( device) . unwrap ( )
47+ pub fn new ( device : Arc < Device > ) -> Self {
48+ Self { device }
6349 }
6450
6551 pub fn push_error < E : Into < GPUError > > ( & self , err : Option < E > ) {
@@ -69,64 +55,7 @@ impl DeviceErrorHandler {
6955
7056 let err = err. into ( ) ;
7157
72- let error_filter = match err {
73- GPUError :: Lost => return ,
74- GPUError :: Validation ( _) => GPUErrorFilter :: Validation ,
75- GPUError :: OutOfMemory => GPUErrorFilter :: OutOfMemory ,
76- GPUError :: Internal => GPUErrorFilter :: Internal ,
77- } ;
78-
79- let mut scopes = self . scopes . lock ( ) . unwrap ( ) ;
80- let scope = scopes
81- . iter_mut ( )
82- . rfind ( |( filter, _) | filter == & error_filter) ;
83-
84- if let Some ( scope) = scope {
85- // Only saving the first error in the scope as it's likely the culprit.
86- if scope. 1 . is_none ( ) {
87- scope. 1 = Some ( err) ;
88- }
89- } else {
90- let device = self
91- . device
92- . get ( )
93- . expect ( "set_device was not called" )
94- . clone ( ) ;
95- self . spawner . spawn ( move |scope| {
96- let state = JsRuntime :: op_state_from ( & * scope) ;
97- let Some ( device) = device. to_local ( scope) else {
98- // The device has already gone away, so we don't have
99- // anywhere to report the error.
100- return ;
101- } ;
102- let key = v8:: String :: new ( scope, "dispatchEvent" ) . unwrap ( ) ;
103- let val = device. get ( scope, key. into ( ) ) . unwrap ( ) ;
104- let func =
105- v8:: Global :: new ( scope, val. try_cast :: < v8:: Function > ( ) . unwrap ( ) ) ;
106- let device = v8:: Global :: new ( scope, device. cast :: < v8:: Value > ( ) ) ;
107- let error_event_class =
108- state. borrow ( ) . borrow :: < crate :: ErrorEventClass > ( ) . 0 . clone ( ) ;
109-
110- let error = deno_core:: error:: to_v8_error ( scope, & err) ;
111-
112- let error_event_class =
113- v8:: Local :: new ( scope, error_event_class. clone ( ) ) ;
114- let constructor =
115- v8:: Local :: < v8:: Function > :: try_from ( error_event_class) . unwrap ( ) ;
116- let kind = v8:: String :: new ( scope, "uncapturederror" ) . unwrap ( ) ;
117-
118- let obj = v8:: Object :: new ( scope) ;
119- let key = v8:: String :: new ( scope, "error" ) . unwrap ( ) ;
120- obj. set ( scope, key. into ( ) , error) ;
121-
122- let event = constructor
123- . new_instance ( scope, & [ kind. into ( ) , obj. into ( ) ] )
124- . unwrap ( ) ;
125-
126- let recv = v8:: Local :: new ( scope, device) ;
127- func. open ( scope) . call ( scope, recv, & [ event. into ( ) ] ) ;
128- } ) ;
129- }
58+ self . device . handle_error_nolabel ( err, "" ) ;
13059 }
13160}
13261
@@ -138,6 +67,16 @@ pub enum GPUErrorFilter {
13867 Internal ,
13968}
14069
70+ impl From < GPUErrorFilter > for ErrorFilter {
71+ fn from ( filter : GPUErrorFilter ) -> Self {
72+ match filter {
73+ GPUErrorFilter :: Validation => ErrorFilter :: Validation ,
74+ GPUErrorFilter :: OutOfMemory => ErrorFilter :: OutOfMemory ,
75+ GPUErrorFilter :: Internal => ErrorFilter :: Internal ,
76+ }
77+ }
78+ }
79+
14180#[ derive( Debug , deno_error:: JsError ) ]
14281pub enum GPUError {
14382 // TODO(@crowlKats): consider adding an unreachable value that uses unreachable!()
@@ -165,16 +104,46 @@ impl Display for GPUError {
165104impl std:: error:: Error for GPUError { }
166105
167106impl GPUError {
168- fn from_webgpu ( e : impl WebGpuError ) -> Self {
107+ pub ( crate ) fn from_webgpu ( e : impl WebGpuError ) -> Self {
169108 match e. webgpu_error_type ( ) {
170109 ErrorType :: Internal => GPUError :: Internal ,
171- ErrorType :: DeviceLost => GPUError :: Lost , // TODO: this variant should be ignored, register the lost callback instead.
110+ ErrorType :: DeviceLost => GPUError :: Lost , // this will be ignored by handle_error in wgpu-core
172111 ErrorType :: OutOfMemory => GPUError :: OutOfMemory ,
173112 ErrorType :: Validation => GPUError :: Validation ( fmt_err ( & e) ) ,
174113 }
175114 }
176115}
177116
117+ impl From < wgpu_types:: error:: Error > for GPUError {
118+ fn from ( err : wgpu_types:: error:: Error ) -> Self {
119+ match err {
120+ wgpu_types:: error:: Error :: Validation {
121+ description,
122+ source,
123+ } => {
124+ if let Some ( e) = source. source ( ) {
125+ GPUError :: Validation ( fmt_err ( e) )
126+ } else {
127+ GPUError :: Validation ( description)
128+ }
129+ }
130+ wgpu_types:: error:: Error :: OutOfMemory { .. } => GPUError :: OutOfMemory ,
131+ wgpu_types:: error:: Error :: Internal { .. } => GPUError :: Internal ,
132+ }
133+ }
134+ }
135+
136+ impl WebGpuError for GPUError {
137+ fn webgpu_error_type ( & self ) -> ErrorType {
138+ match self {
139+ GPUError :: Lost => ErrorType :: DeviceLost ,
140+ GPUError :: Validation ( _) => ErrorType :: Validation ,
141+ GPUError :: OutOfMemory => ErrorType :: OutOfMemory ,
142+ GPUError :: Internal => ErrorType :: Internal ,
143+ }
144+ }
145+ }
146+
178147pub ( crate ) fn fmt_err ( err : & ( dyn std:: error:: Error + ' static ) ) -> String {
179148 let mut output = err. to_string ( ) ;
180149
0 commit comments