1#![cfg(not(target_arch = "wasm32"))]
4#![warn(unsafe_op_in_unsafe_fn)]
5
6use std::cell::RefCell;
7use std::rc::Rc;
8use std::sync::Arc;
9
10use deno_core::GarbageCollected;
11use deno_core::OpState;
12use deno_core::cppgc::SameObject;
13use deno_core::op2;
14use deno_core::v8;
15pub use wgpu_core;
16pub use wgpu_types;
17use wgpu_types::PowerPreference;
18
19use crate::error::GPUGenericError;
20
21mod adapter;
22mod bind_group;
23mod bind_group_layout;
24pub mod buffer;
25mod byow;
26mod command_buffer;
27mod command_encoder;
28mod compute_pass;
29mod compute_pipeline;
30mod device;
31pub mod error;
32mod pipeline_layout;
33mod query_set;
34mod queue;
35mod render_bundle;
36mod render_pass;
37mod render_pipeline;
38mod sampler;
39mod shader;
40mod surface;
41pub mod texture;
42mod webidl;
43
44pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
45
46#[allow(clippy::print_stdout, reason = "cargo build script output")]
47pub fn print_linker_flags(name: &str) {
48 if cfg!(windows) {
49 let dlls = [
51 "d3dcompiler_47",
53 "OPENGL32",
54 "gdi32",
55 "setupapi",
56 "oleaut32",
57 "combase",
58 "iphlpapi",
60 "winmm",
62 "dbghelp",
64 "psapi",
65 ];
66 for dll in dlls {
67 println!("cargo:rustc-link-arg-bin={name}=/delayload:{dll}.dll");
68 }
69 println!("cargo:rustc-link-arg-bin={name}=delayimp.lib");
71 }
72}
73
74pub type Instance = Arc<wgpu_core::global::Global>;
75
76deno_core::extension!(
77 deno_webgpu,
78 deps = [deno_webidl, deno_web],
79 ops = [
80 op_create_gpu,
81 device::op_webgpu_device_start_capture,
82 device::op_webgpu_device_stop_capture,
83 ],
84 objects = [
85 GPU,
86 adapter::GPUAdapter,
87 adapter::GPUAdapterInfo,
88 bind_group::GPUBindGroup,
89 bind_group_layout::GPUBindGroupLayout,
90 buffer::GPUBuffer,
91 command_buffer::GPUCommandBuffer,
92 command_encoder::GPUCommandEncoder,
93 compute_pass::GPUComputePassEncoder,
94 compute_pipeline::GPUComputePipeline,
95 device::GPUDevice,
96 device::GPUDeviceLostInfo,
97 pipeline_layout::GPUPipelineLayout,
98 query_set::GPUQuerySet,
99 queue::GPUQueue,
100 render_bundle::GPURenderBundle,
101 render_bundle::GPURenderBundleEncoder,
102 render_pass::GPURenderPassEncoder,
103 render_pipeline::GPURenderPipeline,
104 sampler::GPUSampler,
105 shader::GPUCompilationInfo,
106 shader::GPUCompilationMessage,
107 shader::GPUShaderModule,
108 adapter::GPUSupportedFeatures,
109 adapter::GPUSupportedLimits,
110 texture::GPUTexture,
111 texture::GPUTextureView,
112 texture::GPUExternalTexture,
113 byow::UnsafeWindowSurface,
114 surface::GPUCanvasContext,
115 ],
116 esm = ["00_init.js", "02_surface.js"],
117 lazy_loaded_esm = ["01_webgpu.js"],
118);
119
120#[op2]
121#[cppgc]
122pub fn op_create_gpu(
123 state: &mut OpState,
124 scope: &mut v8::PinScope<'_, '_>,
125 webidl_brand: v8::Local<v8::Value>,
126 set_event_target_data: v8::Local<v8::Value>,
127 error_event_class: v8::Local<v8::Value>,
128) -> GPU {
129 state.put(EventTargetSetup {
130 brand: v8::Global::new(scope, webidl_brand),
131 set_event_target_data: v8::Global::new(scope, set_event_target_data),
132 });
133 state.put(ErrorEventClass(v8::Global::new(scope, error_event_class)));
134 GPU
135}
136
137struct EventTargetSetup {
138 brand: v8::Global<v8::Value>,
139 set_event_target_data: v8::Global<v8::Value>,
140}
141struct ErrorEventClass(v8::Global<v8::Value>);
142
143pub struct GPU;
144
145unsafe impl GarbageCollected for GPU {
147 fn trace(&self, _visitor: &mut v8::cppgc::Visitor) {}
148
149 fn get_name(&self) -> &'static std::ffi::CStr {
150 c"GPU"
151 }
152}
153
154#[op2]
155impl GPU {
156 #[constructor]
157 #[cppgc]
158 fn constructor(_: bool) -> Result<GPU, GPUGenericError> {
159 Err(GPUGenericError::InvalidConstructor)
160 }
161
162 #[cppgc]
163 async fn request_adapter(
164 &self,
165 state: Rc<RefCell<OpState>>,
166 #[webidl] options: adapter::GPURequestAdapterOptions,
167 ) -> Option<adapter::GPUAdapter> {
168 let mut state = state.borrow_mut();
169
170 let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
171 |_| wgpu_types::Backends::all(),
172 |s| wgpu_types::Backends::from_comma_list(&s),
173 );
174 let instance = if let Some(instance) = state.try_borrow::<Instance>() {
175 instance
176 } else {
177 state.put(Arc::new(wgpu_core::global::Global::new(
178 "webgpu",
179 &wgpu_types::InstanceDescriptor {
180 backends,
181 flags: wgpu_types::InstanceFlags::from_build_config(),
182 memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds {
183 for_resource_creation: Some(97),
184 for_device_loss: Some(99),
185 },
186 backend_options: wgpu_types::BackendOptions {
187 dx12: wgpu_types::Dx12BackendOptions {
188 shader_compiler: wgpu_types::Dx12Compiler::Fxc,
189 ..Default::default()
190 },
191 gl: wgpu_types::GlBackendOptions::default(),
192 noop: wgpu_types::NoopBackendOptions::default(),
193 },
194 },
195 None,
196 )));
197 state.borrow::<Instance>()
198 };
199
200 let descriptor = wgpu_core::instance::RequestAdapterOptions {
201 power_preference: options
202 .power_preference
203 .map(|pp| match pp {
204 adapter::GPUPowerPreference::LowPower => PowerPreference::LowPower,
205 adapter::GPUPowerPreference::HighPerformance => {
206 PowerPreference::HighPerformance
207 }
208 })
209 .unwrap_or_default(),
210 force_fallback_adapter: options.force_fallback_adapter,
211 compatible_surface: None, };
213 let id = instance.request_adapter(&descriptor, backends, None).ok()?;
214
215 Some(adapter::GPUAdapter {
216 instance: instance.clone(),
217 features: SameObject::new(),
218 limits: SameObject::new(),
219 info: Rc::new(SameObject::new()),
220 id,
221 })
222 }
223
224 #[string]
225 fn getPreferredCanvasFormat(&self) -> &'static str {
226 if cfg!(target_os = "android") {
228 texture::GPUTextureFormat::Rgba8unorm.as_str()
229 } else {
230 texture::GPUTextureFormat::Bgra8unorm.as_str()
231 }
232 }
233}
234
235fn transform_label<'a>(label: String) -> Option<std::borrow::Cow<'a, str>> {
236 if label.is_empty() {
237 None
238 } else {
239 Some(std::borrow::Cow::Owned(label))
240 }
241}