1use std::rc::Rc;
6
7use constellation_traits::ScriptToConstellationMessage;
8use dom_struct::dom_struct;
9use js::jsapi::HandleObject;
10use webgpu_traits::WebGPUAdapterResponse;
11use wgpu_types::PowerPreference;
12
13use super::wgsllanguagefeatures::WGSLLanguageFeatures;
14use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
15 GPUMethods, GPUPowerPreference, GPURequestAdapterOptions, GPUTextureFormat,
16};
17use crate::dom::bindings::error::Error;
18use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
19use crate::dom::bindings::root::{DomRoot, MutNullableDom};
20use crate::dom::bindings::str::DOMString;
21use crate::dom::globalscope::GlobalScope;
22use crate::dom::promise::Promise;
23use crate::dom::webgpu::gpuadapter::GPUAdapter;
24use crate::realms::InRealm;
25use crate::routed_promise::{RoutedPromiseListener, route_promise};
26use crate::script_runtime::CanGc;
27
28#[dom_struct]
29#[allow(clippy::upper_case_acronyms)]
30pub(crate) struct GPU {
31 reflector_: Reflector,
32 wgsl_language_features: MutNullableDom<WGSLLanguageFeatures>,
34}
35
36impl GPU {
37 pub(crate) fn new_inherited() -> GPU {
38 GPU {
39 reflector_: Reflector::new(),
40 wgsl_language_features: MutNullableDom::default(),
41 }
42 }
43
44 pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<GPU> {
45 reflect_dom_object(Box::new(GPU::new_inherited()), global, can_gc)
46 }
47}
48
49impl GPUMethods<crate::DomTypeHolder> for GPU {
50 fn RequestAdapter(
52 &self,
53 options: &GPURequestAdapterOptions,
54 comp: InRealm,
55 can_gc: CanGc,
56 ) -> Rc<Promise> {
57 let global = &self.global();
58 let promise = Promise::new_in_current_realm(comp, can_gc);
59 let task_source = global.task_manager().dom_manipulation_task_source();
60 let sender = route_promise(&promise, self, task_source);
61
62 let power_preference = match options.powerPreference {
63 Some(GPUPowerPreference::Low_power) => PowerPreference::LowPower,
64 Some(GPUPowerPreference::High_performance) => PowerPreference::HighPerformance,
65 None => PowerPreference::default(),
66 };
67 let ids = global.wgpu_id_hub().create_adapter_id();
68
69 let script_to_constellation_chan = global.script_to_constellation_chan();
70 if script_to_constellation_chan
71 .send(ScriptToConstellationMessage::RequestAdapter(
72 sender,
73 wgpu_core::instance::RequestAdapterOptions {
74 power_preference,
75 compatible_surface: None,
76 force_fallback_adapter: options.forceFallbackAdapter,
77 },
78 ids,
79 ))
80 .is_err()
81 {
82 promise.reject_error(Error::Operation, can_gc);
83 }
84 promise
85 }
86
87 fn GetPreferredCanvasFormat(&self) -> GPUTextureFormat {
89 if cfg!(target_os = "android") {
91 GPUTextureFormat::Rgba8unorm
92 } else {
93 GPUTextureFormat::Bgra8unorm
94 }
95 }
96
97 fn WgslLanguageFeatures(&self, can_gc: CanGc) -> DomRoot<WGSLLanguageFeatures> {
99 self.wgsl_language_features
100 .or_init(|| WGSLLanguageFeatures::new(&self.global(), None, can_gc))
101 }
102}
103
104impl RoutedPromiseListener<WebGPUAdapterResponse> for GPU {
105 fn handle_response(
106 &self,
107 response: WebGPUAdapterResponse,
108 promise: &Rc<Promise>,
109 can_gc: CanGc,
110 ) {
111 match response {
112 Some(Ok(adapter)) => {
113 let adapter = GPUAdapter::new(
114 &self.global(),
115 adapter.channel,
116 DOMString::from(format!(
117 "{} ({:?})",
118 adapter.adapter_info.name, adapter.adapter_id.0
119 )),
120 HandleObject::null(),
121 adapter.features,
122 adapter.limits,
123 adapter.adapter_info,
124 adapter.adapter_id,
125 can_gc,
126 );
127 promise.resolve_native(&adapter, can_gc);
128 },
129 Some(Err(e)) => {
130 warn!("Could not get GPUAdapter ({:?})", e);
131 promise.resolve_native(&None::<GPUAdapter>, can_gc);
132 },
133 None => {
134 warn!("Couldn't get a response, because WebGPU is disabled");
135 promise.resolve_native(&None::<GPUAdapter>, can_gc);
136 },
137 }
138 }
139}