11// Copyright 2018-2025 the Deno authors. MIT license.
22
3+ use deno_core:: cppgc:: make_cppgc_object;
34use deno_core:: op2;
5+ use deno_core:: v8;
46use deno_core:: webidl:: WebIdlInterfaceConverter ;
57use deno_core:: GarbageCollected ;
68use deno_core:: WebIDL ;
9+ use wgpu_core:: pipeline;
710
811use crate :: Instance ;
912
1013pub struct GPUShaderModule {
1114 pub instance : Instance ,
1215 pub id : wgpu_core:: id:: ShaderModuleId ,
1316 pub label : String ,
17+ pub compilation_info : v8:: Global < v8:: Object > ,
1418}
1519
1620impl Drop for GPUShaderModule {
@@ -37,6 +41,16 @@ impl GPUShaderModule {
3741 fn label ( & self , #[ webidl] _label : String ) {
3842 // TODO(@crowlKats): no-op, needs wpgu to implement changing the label
3943 }
44+
45+ fn get_compilation_info < ' a > (
46+ & self ,
47+ scope : & mut v8:: HandleScope < ' a > ,
48+ ) -> v8:: Local < ' a , v8:: Promise > {
49+ let resolver = v8:: PromiseResolver :: new ( scope) . unwrap ( ) ;
50+ let info = v8:: Local :: new ( scope, self . compilation_info . clone ( ) ) ;
51+ resolver. resolve ( scope, info. into ( ) ) . unwrap ( ) ;
52+ resolver. get_promise ( scope)
53+ }
4054}
4155
4256#[ derive( WebIDL ) ]
@@ -47,3 +61,143 @@ pub(crate) struct GPUShaderModuleDescriptor {
4761
4862 pub code : String ,
4963}
64+
65+ pub struct GPUCompilationMessage {
66+ message : String ,
67+ r#type : GPUCompilationMessageType ,
68+ line_num : u64 ,
69+ line_pos : u64 ,
70+ offset : u64 ,
71+ length : u64 ,
72+ }
73+
74+ impl GarbageCollected for GPUCompilationMessage { }
75+
76+ #[ op2]
77+ impl GPUCompilationMessage {
78+ #[ getter]
79+ #[ string]
80+ fn message ( & self ) -> String {
81+ self . message . clone ( )
82+ }
83+
84+ // Naming this `type` or `r#type` does not work.
85+ // https://github.com/gfx-rs/wgpu/issues/7778
86+ #[ getter]
87+ #[ string]
88+ fn ty ( & self ) -> & ' static str {
89+ self . r#type . as_str ( )
90+ }
91+
92+ #[ getter]
93+ #[ number]
94+ fn line_num ( & self ) -> u64 {
95+ self . line_num
96+ }
97+
98+ #[ getter]
99+ #[ number]
100+ fn line_pos ( & self ) -> u64 {
101+ self . line_pos
102+ }
103+
104+ #[ getter]
105+ #[ number]
106+ fn offset ( & self ) -> u64 {
107+ self . offset
108+ }
109+
110+ #[ getter]
111+ #[ number]
112+ fn length ( & self ) -> u64 {
113+ self . length
114+ }
115+ }
116+
117+ impl GPUCompilationMessage {
118+ fn new ( error : & pipeline:: CreateShaderModuleError , source : & str ) -> Self {
119+ let message = error. to_string ( ) ;
120+
121+ let loc = match error {
122+ pipeline:: CreateShaderModuleError :: Parsing ( e) => e. inner . location ( source) ,
123+ pipeline:: CreateShaderModuleError :: Validation ( e) => e. inner . location ( source) ,
124+ _ => None ,
125+ } ;
126+
127+ match loc {
128+ Some ( loc) => {
129+ let len_utf16 = |s : & str | s. chars ( ) . map ( |c| c. len_utf16 ( ) as u64 ) . sum ( ) ;
130+
131+ let start = loc. offset as usize ;
132+
133+ // Naga reports a `line_pos` using UTF-8 bytes, so we cannot use it.
134+ let line_start = source[ 0 ..start] . rfind ( '\n' ) . map ( |pos| pos + 1 ) . unwrap_or ( 0 ) ;
135+ let line_pos = len_utf16 ( & source[ line_start..start] ) + 1 ;
136+
137+ Self {
138+ message,
139+ r#type : GPUCompilationMessageType :: Error ,
140+ line_num : loc. line_number . into ( ) ,
141+ line_pos,
142+ offset : len_utf16 ( & source[ 0 ..start] ) ,
143+ length : len_utf16 ( & source[ start..start + loc. length as usize ] ) ,
144+ }
145+ }
146+ _ => Self {
147+ message,
148+ r#type : GPUCompilationMessageType :: Error ,
149+ line_num : 0 ,
150+ line_pos : 0 ,
151+ offset : 0 ,
152+ length : 0 ,
153+ } ,
154+ }
155+ }
156+ }
157+
158+ pub struct GPUCompilationInfo {
159+ messages : v8:: Global < v8:: Object > ,
160+ }
161+
162+ impl GarbageCollected for GPUCompilationInfo { }
163+
164+ #[ op2]
165+ impl GPUCompilationInfo {
166+ #[ getter]
167+ #[ global]
168+ fn messages ( & self ) -> v8:: Global < v8:: Object > {
169+ self . messages . clone ( )
170+ }
171+ }
172+
173+ impl GPUCompilationInfo {
174+ pub fn new < ' args , ' scope > (
175+ scope : & mut v8:: HandleScope < ' scope > ,
176+ messages : impl ExactSizeIterator < Item = & ' args pipeline:: CreateShaderModuleError > ,
177+ source : & ' args str ,
178+ ) -> Self {
179+ let array = v8:: Array :: new ( scope, messages. len ( ) . try_into ( ) . unwrap ( ) ) ;
180+ for ( i, message) in messages. enumerate ( ) {
181+ let message_object =
182+ make_cppgc_object ( scope, GPUCompilationMessage :: new ( message, source) ) ;
183+ array. set_index ( scope, i. try_into ( ) . unwrap ( ) , message_object. into ( ) ) ;
184+ }
185+
186+ let object: v8:: Local < v8:: Object > = array. into ( ) ;
187+ object
188+ . set_integrity_level ( scope, v8:: IntegrityLevel :: Frozen )
189+ . unwrap ( ) ;
190+
191+ Self {
192+ messages : v8:: Global :: new ( scope, object) ,
193+ }
194+ }
195+ }
196+
197+ #[ derive( WebIDL , Clone ) ]
198+ #[ webidl( enum ) ]
199+ pub ( crate ) enum GPUCompilationMessageType {
200+ Error ,
201+ Warning ,
202+ Info ,
203+ }
0 commit comments