Skip to main content

script_webgpu/
gpuqueryset.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4use std::marker::PhantomData;
5
6use dom_struct::dom_struct;
7use js::context::{JSContext, NoGC};
8use log::warn;
9use malloc_size_of_derive::MallocSizeOf;
10use script_bindings::DomTypes;
11use script_bindings::cell::DomRefCell;
12use script_bindings::codegen::GenericBindings::WebGPUBinding::{
13    GPUDeviceMethods, GPUQuerySetDescriptor, GPUQuerySetMethods, GPUQuerySetWrap, GPUQueryType,
14};
15use script_bindings::error::{Error, Fallible};
16use script_bindings::interfaces::PromiseHelpers;
17use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
18use script_bindings::root::DomRoot;
19use webgpu_traits::{Features, WebGPU, WebGPUQuerySet, WebGPURequest};
20
21use crate::JSTraceable;
22use crate::dom::bindings::str::USVString;
23use crate::gpuconvert::WebGPUConvert;
24use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise};
25
26#[derive(MallocSizeOf)]
27struct DroppableGPUQuerySet {
28    channel: WebGPU,
29    query_set: WebGPUQuerySet,
30}
31
32impl Drop for DroppableGPUQuerySet {
33    fn drop(&mut self) {
34        if let Err(error) = self
35            .channel
36            .0
37            .send(WebGPURequest::DropQuerySet(self.query_set.0))
38        {
39            warn!(
40                "Failed to send WebGPURequest::DropQuerySet({:?}) ({error})",
41                self.query_set.0
42            );
43        }
44    }
45}
46
47#[dom_struct]
48pub struct GPUQuerySet<D: DomTypes> {
49    reflector_: Reflector,
50    #[no_trace]
51    droppable: DroppableGPUQuerySet,
52    label: DomRefCell<USVString>,
53    r#type: GPUQueryType,
54    count: u32,
55    #[no_trace = "PhantomData does not exist"]
56    phantom: PhantomData<D>,
57}
58
59impl<D> GPUQuerySet<D>
60where
61    D: Equivalence,
62    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
63{
64    pub(crate) fn new_inherited(
65        label: USVString,
66        channel: WebGPU,
67        query_set: WebGPUQuerySet,
68        r#type: GPUQueryType,
69        count: u32,
70    ) -> Self {
71        GPUQuerySet {
72            reflector_: Reflector::new(),
73            label: DomRefCell::new(label),
74            droppable: DroppableGPUQuerySet { channel, query_set },
75            r#type,
76            count,
77            phantom: PhantomData,
78        }
79    }
80
81    pub(crate) fn new(
82        cx: &mut JSContext,
83        global: &D::GlobalScope,
84        label: USVString,
85        channel: WebGPU,
86        query_set: WebGPUQuerySet,
87        r#type: GPUQueryType,
88        count: u32,
89    ) -> DomRoot<Self> {
90        reflect_dom_object_with_wrap::<D, _, _>(
91            cx,
92            Box::new(GPUQuerySet::new_inherited(
93                label, channel, query_set, r#type, count,
94            )),
95            global,
96            GPUQuerySetWrap::<D>,
97        )
98    }
99
100    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createqueryset>
101    pub(crate) fn create(
102        cx: &mut JSContext,
103        device: &D::GPUDevice,
104        descriptor: &GPUQuerySetDescriptor,
105    ) -> Fallible<DomRoot<Self>> {
106        // 1. If descriptor.type is "timestamp", but "timestamp-query" is not enabled for this:
107        if descriptor.type_ == GPUQueryType::Timestamp &&
108            !device
109                .Features()
110                .wgpu_features()
111                .contains(Features::TIMESTAMP_QUERY)
112        {
113            // Throw a TypeError.
114            return Err(Error::Type(
115                c"The device does not support timestamp queries".to_owned(),
116            ));
117        }
118        // 2. Let q be ! create a new WebGPU object(this, GPUQuerySet, descriptor).
119        let query_set_id = device
120            .global_from_reflector()
121            .global_wgpu_id_hub()
122            .create_query_set_id();
123        // 5. Issue the initialization steps on the Device timeline of this.
124        let channel = device.channel();
125        if let Err(error) = channel.0.send(WebGPURequest::CreateQuerySet {
126            device_id: device.id().0,
127            query_set_id,
128            descriptor: descriptor.convert(),
129        }) {
130            warn!("Failed to send WebGPURequest::CreateQuerySet: {error}");
131        }
132        // 6. Return q
133        Ok(Self::new(
134            cx,
135            &device.global_from_reflector(),
136            descriptor.parent.label.clone(),
137            channel,
138            WebGPUQuerySet(query_set_id),
139            // 3. Set q.type to descriptor.type.
140            descriptor.type_,
141            // 4. Set q.count to descriptor.count.
142            descriptor.count,
143        ))
144    }
145
146    pub(crate) fn id(&self) -> WebGPUQuerySet {
147        self.droppable.query_set
148    }
149}
150
151impl<D> GPUQuerySetMethods<D> for GPUQuerySet<D>
152where
153    D: Equivalence,
154    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
155{
156    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-destroy>
157    fn Destroy(&self) {
158        // 1. Issue the subsequent steps on the device timeline.
159        if let Err(error) = self
160            .droppable
161            .channel
162            .0
163            .send(WebGPURequest::DestroyQuerySet(self.id().0))
164        {
165            warn!(
166                "Failed to send WebGPURequest::DestroyQuerySet({:?}) ({error})",
167                self.id().0
168            );
169        }
170    }
171
172    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
173    fn Label(&self) -> USVString {
174        self.label.borrow().clone()
175    }
176
177    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
178    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
179        *self.label.safe_borrow_mut(no_gc) = value;
180    }
181
182    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-type>
183    fn Type(&self) -> GPUQueryType {
184        self.r#type
185    }
186
187    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-count>
188    fn Count(&self) -> u32 {
189        self.count
190    }
191}