aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webgpu/gpuadapter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/webgpu/gpuadapter.rs')
-rw-r--r--components/script/dom/webgpu/gpuadapter.rs254
1 files changed, 254 insertions, 0 deletions
diff --git a/components/script/dom/webgpu/gpuadapter.rs b/components/script/dom/webgpu/gpuadapter.rs
new file mode 100644
index 00000000000..da81c8d7d4c
--- /dev/null
+++ b/components/script/dom/webgpu/gpuadapter.rs
@@ -0,0 +1,254 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use std::rc::Rc;
+
+use dom_struct::dom_struct;
+use js::jsapi::{Heap, JSObject};
+use webgpu::wgc::instance::RequestDeviceError;
+use webgpu::wgt::MemoryHints;
+use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
+
+use super::gpusupportedfeatures::GPUSupportedFeatures;
+use super::gpusupportedlimits::set_limit;
+use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
+ GPUAdapterMethods, GPUDeviceDescriptor, GPUDeviceLostReason,
+};
+use crate::dom::bindings::error::Error;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::gpudevice::GPUDevice;
+use crate::dom::gpusupportedfeatures::gpu_to_wgt_feature;
+use crate::dom::promise::Promise;
+use crate::dom::types::{GPUAdapterInfo, GPUSupportedLimits};
+use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener};
+use crate::realms::InRealm;
+use crate::script_runtime::CanGc;
+
+#[dom_struct]
+pub struct GPUAdapter {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "channels are hard"]
+ #[no_trace]
+ channel: WebGPU,
+ name: DOMString,
+ #[ignore_malloc_size_of = "mozjs"]
+ extensions: Heap<*mut JSObject>,
+ features: Dom<GPUSupportedFeatures>,
+ limits: Dom<GPUSupportedLimits>,
+ info: Dom<GPUAdapterInfo>,
+ #[no_trace]
+ adapter: WebGPUAdapter,
+}
+
+impl GPUAdapter {
+ fn new_inherited(
+ channel: WebGPU,
+ name: DOMString,
+ extensions: Heap<*mut JSObject>,
+ features: &GPUSupportedFeatures,
+ limits: &GPUSupportedLimits,
+ info: &GPUAdapterInfo,
+ adapter: WebGPUAdapter,
+ ) -> Self {
+ Self {
+ reflector_: Reflector::new(),
+ channel,
+ name,
+ extensions,
+ features: Dom::from_ref(features),
+ limits: Dom::from_ref(limits),
+ info: Dom::from_ref(info),
+ adapter,
+ }
+ }
+
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ global: &GlobalScope,
+ channel: WebGPU,
+ name: DOMString,
+ extensions: Heap<*mut JSObject>,
+ features: wgt::Features,
+ limits: wgt::Limits,
+ info: wgt::AdapterInfo,
+ adapter: WebGPUAdapter,
+ can_gc: CanGc,
+ ) -> DomRoot<Self> {
+ let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap();
+ let limits = GPUSupportedLimits::new(global, limits);
+ let info = GPUAdapterInfo::new(global, info);
+ reflect_dom_object(
+ Box::new(GPUAdapter::new_inherited(
+ channel, name, extensions, &features, &limits, &info, adapter,
+ )),
+ global,
+ )
+ }
+}
+
+impl Drop for GPUAdapter {
+ fn drop(&mut self) {
+ if let Err(e) = self
+ .channel
+ .0
+ .send(WebGPURequest::DropAdapter(self.adapter.0))
+ {
+ warn!(
+ "Failed to send WebGPURequest::DropAdapter({:?}) ({})",
+ self.adapter.0, e
+ );
+ };
+ }
+}
+
+impl GPUAdapterMethods<crate::DomTypeHolder> for GPUAdapter {
+ /// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestdevice>
+ fn RequestDevice(
+ &self,
+ descriptor: &GPUDeviceDescriptor,
+ comp: InRealm,
+ can_gc: CanGc,
+ ) -> Rc<Promise> {
+ // Step 2
+ let promise = Promise::new_in_current_realm(comp, can_gc);
+ let sender = response_async(&promise, self);
+ let mut required_features = wgt::Features::empty();
+ for &ext in descriptor.requiredFeatures.iter() {
+ if let Some(feature) = gpu_to_wgt_feature(ext) {
+ required_features.insert(feature);
+ } else {
+ promise.reject_error(Error::Type(format!(
+ "{} is not supported feature",
+ ext.as_str()
+ )));
+ return promise;
+ }
+ }
+
+ let mut required_limits = wgt::Limits::default();
+ if let Some(limits) = &descriptor.requiredLimits {
+ for (limit, value) in (*limits).iter() {
+ if !set_limit(&mut required_limits, limit.as_ref(), *value) {
+ warn!("Unknown GPUDevice limit: {limit}");
+ promise.reject_error(Error::Operation);
+ return promise;
+ }
+ }
+ }
+
+ let desc = wgt::DeviceDescriptor {
+ required_features,
+ required_limits,
+ label: Some(descriptor.parent.label.to_string()),
+ memory_hints: MemoryHints::MemoryUsage,
+ };
+ let device_id = self.global().wgpu_id_hub().create_device_id();
+ let queue_id = self.global().wgpu_id_hub().create_queue_id();
+ let pipeline_id = self.global().pipeline_id();
+ if self
+ .channel
+ .0
+ .send(WebGPURequest::RequestDevice {
+ sender,
+ adapter_id: self.adapter,
+ descriptor: desc,
+ device_id,
+ queue_id,
+ pipeline_id,
+ })
+ .is_err()
+ {
+ promise.reject_error(Error::Operation);
+ }
+ // Step 5
+ promise
+ }
+
+ /// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-isfallbackadapter>
+ fn IsFallbackAdapter(&self) -> bool {
+ //TODO
+ false
+ }
+
+ /// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestadapterinfo>
+ fn RequestAdapterInfo(
+ &self,
+ unmask_hints: Vec<DOMString>,
+ comp: InRealm,
+ can_gc: CanGc,
+ ) -> Rc<Promise> {
+ // XXX: Adapter info should be generated here ...
+ // Step 1
+ let promise = Promise::new_in_current_realm(comp, can_gc);
+ // Step 4
+ if !unmask_hints.is_empty() {
+ todo!("unmaskHints on RequestAdapterInfo");
+ }
+ promise.resolve_native(&*self.info);
+ // Step 5
+ promise
+ }
+
+ /// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-features>
+ fn Features(&self) -> DomRoot<GPUSupportedFeatures> {
+ DomRoot::from_ref(&self.features)
+ }
+
+ /// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-limits>
+ fn Limits(&self) -> DomRoot<GPUSupportedLimits> {
+ DomRoot::from_ref(&self.limits)
+ }
+}
+
+impl AsyncWGPUListener for GPUAdapter {
+ fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc) {
+ match response {
+ WebGPUResponse::Device((device_id, queue_id, Ok(descriptor))) => {
+ let device = GPUDevice::new(
+ &self.global(),
+ self.channel.clone(),
+ self,
+ Heap::default(),
+ descriptor.required_features,
+ descriptor.required_limits,
+ device_id,
+ queue_id,
+ descriptor.label.unwrap_or_default(),
+ can_gc,
+ );
+ self.global().add_gpu_device(&device);
+ promise.resolve_native(&device);
+ },
+ WebGPUResponse::Device((_, _, Err(RequestDeviceError::UnsupportedFeature(f)))) => {
+ promise.reject_error(Error::Type(
+ RequestDeviceError::UnsupportedFeature(f).to_string(),
+ ))
+ },
+ WebGPUResponse::Device((_, _, Err(RequestDeviceError::LimitsExceeded(_)))) => {
+ promise.reject_error(Error::Operation)
+ },
+ WebGPUResponse::Device((device_id, queue_id, Err(e))) => {
+ let device = GPUDevice::new(
+ &self.global(),
+ self.channel.clone(),
+ self,
+ Heap::default(),
+ wgt::Features::default(),
+ wgt::Limits::default(),
+ device_id,
+ queue_id,
+ String::new(),
+ can_gc,
+ );
+ device.lose(GPUDeviceLostReason::Unknown, e.to_string());
+ promise.resolve_native(&device);
+ },
+ WebGPUResponse::None => unreachable!("Failed to get a response for RequestDevice"),
+ _ => unreachable!("GPUAdapter received wrong WebGPUResponse"),
+ }
+ }
+}