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