1use std::marker::PhantomData;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::jsapi::HandleObject;
10use js::realm::CurrentRealm;
11use jstraceable_derive::JSTraceable;
12use log::warn;
13use malloc_size_of_derive::MallocSizeOf;
14use script_bindings::DomTypes;
15use script_bindings::codegen::GenericBindings::WebGPUBinding::{
16 GPUMethods, GPUPowerPreference, GPURequestAdapterOptions, GPUTextureFormat, GPUWrap,
17};
18use script_bindings::dom::MutNullableDom;
19use script_bindings::interfaces::{GlobalScopeHelpers, PromiseHelpers};
20use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
21use script_bindings::root::DomRoot;
22use script_bindings::routed_promise::RoutedPromiseListener;
23use script_bindings::str::DOMString;
24use servo_constellation_traits::ScriptToConstellationMessage;
25use webgpu_traits::{PowerPreference, RequestAdapterOptions, WebGPUAdapterResponse};
26
27use super::wgsllanguagefeatures::WGSLLanguageFeatures;
28use crate::dom::bindings::error::Error;
29use crate::gpuadapter::GPUAdapter;
30use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise, WebGPUPromiseCallbackTrait};
31
32#[dom_struct]
33pub struct GPU<D: DomTypes> {
34 reflector_: Reflector,
35 wgsl_language_features: MutNullableDom<WGSLLanguageFeatures<D>>,
37 #[no_trace = "PhantomData does not exist"]
38 phantom: PhantomData<D>,
39}
40
41impl<D: Equivalence> GPU<D> {
42 pub(crate) fn new_inherited() -> GPU<D> {
43 GPU {
44 reflector_: Reflector::new(),
45 wgsl_language_features: MutNullableDom::default(),
46 phantom: PhantomData,
47 }
48 }
49
50 pub fn new(cx: &mut JSContext, global: &D::GlobalScope) -> DomRoot<GPU<D>> {
51 reflect_dom_object_with_wrap::<D, _, _>(
52 cx,
53 Box::new(GPU::new_inherited()),
54 global,
55 GPUWrap::<D>,
56 )
57 }
58}
59
60impl<D> GPUMethods<D> for GPU<D>
61where
62 D: Equivalence,
63 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
64 Self: DomGlobalGeneric<D>,
65{
66 fn RequestAdapter(
68 &self,
69 cx: &mut CurrentRealm,
70 options: &GPURequestAdapterOptions,
71 ) -> <D::Promise as PromiseHelpers<D>>::StackRoot {
72 let global = self.global_from_reflector();
73 let promise = D::Promise::new_in_realm(cx);
75 let callback = promise.callback_promise_dom_manipulation_task_source(self);
76
77 let power_preference = match options.powerPreference {
78 Some(GPUPowerPreference::Low_power) => PowerPreference::LowPower,
79 Some(GPUPowerPreference::High_performance) => PowerPreference::HighPerformance,
80 None => PowerPreference::default(),
81 };
82 let ids = global.global_wgpu_id_hub().create_adapter_id();
83
84 match &*options.featureLevel.str() {
95 "core" => {},
96 "compatibility" => {
97 },
100 _ => {
101 promise.resolve_native(cx, &None::<GPUAdapter<D>>);
102 return promise;
103 },
104 }
105 let script_to_constellation_chan = global.script_to_constellation_chan();
106 if script_to_constellation_chan
107 .send(ScriptToConstellationMessage::RequestAdapter(
108 callback,
109 RequestAdapterOptions {
110 power_preference,
111 compatible_surface: None,
112 force_fallback_adapter: options.forceFallbackAdapter,
113 apply_limit_buckets: false,
114 },
115 ids,
116 ))
117 .is_err()
118 {
119 promise.reject_error(
120 cx,
121 Error::Operation(Some(
122 "Could not send `requestAdapter` request from script thread to constellation thread".into(),
123 )),
124 );
125 }
126 promise
128 }
129
130 fn GetPreferredCanvasFormat(&self) -> GPUTextureFormat {
132 if cfg!(target_os = "android") {
134 GPUTextureFormat::Rgba8unorm
135 } else {
136 GPUTextureFormat::Bgra8unorm
137 }
138 }
139
140 fn WgslLanguageFeatures(
142 &self,
143 cx: &mut js::context::JSContext,
144 ) -> DomRoot<WGSLLanguageFeatures<D>> {
145 self.wgsl_language_features
146 .or_init(|| WGSLLanguageFeatures::new(cx, &*self.global_from_reflector(), None))
147 }
148}
149
150impl<D: Equivalence> RoutedPromiseListener<D, WebGPUAdapterResponse> for GPU<D>
151where
152 Self: DomGlobalGeneric<D>,
153{
154 fn handle_response(
155 &self,
156 cx: &mut js::context::JSContext,
157 response: WebGPUAdapterResponse,
158 promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
159 ) {
160 match response {
161 Some(Ok(adapter)) => {
162 let adapter = GPUAdapter::<D>::new(
163 cx,
164 &self.global_from_reflector(),
165 adapter.channel,
166 DOMString::from(format!(
167 "{} ({:?})",
168 adapter.adapter_info.name, adapter.adapter_id.0
169 )),
170 HandleObject::null(),
171 adapter.features,
172 adapter.limits,
173 adapter.adapter_info,
174 adapter.adapter_id,
175 );
176 promise.resolve_native(cx, &adapter);
177 },
178 Some(Err(e)) => {
179 warn!("Could not get GPUAdapter ({:?})", e);
180 promise.resolve_native(cx, &None::<GPUAdapter<D>>);
181 },
182 None => {
183 warn!("Couldn't get a response, because WebGPU is disabled");
184 promise.resolve_native(cx, &None::<GPUAdapter<D>>);
185 },
186 }
187 }
188}