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::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
17use script_bindings::root::DomRoot;
18use webgpu_traits::{WebGPU, WebGPUQuerySet, WebGPURequest};
19
20use crate::JSTraceable;
21use crate::dom::bindings::str::USVString;
22use crate::gpuconvert::WebGPUConvert;
23use crate::traits::{Equivalence, GPUDeviceTrait, WebGPUGlobalTrait};
24
25#[derive(MallocSizeOf)]
26struct DroppableGPUQuerySet {
27    channel: WebGPU,
28    query_set: WebGPUQuerySet,
29}
30
31impl Drop for DroppableGPUQuerySet {
32    fn drop(&mut self) {
33        if let Err(error) = self
34            .channel
35            .0
36            .send(WebGPURequest::DropQuerySet(self.query_set.0))
37        {
38            warn!(
39                "Failed to send WebGPURequest::DropQuerySet({:?}) ({error})",
40                self.query_set.0
41            );
42        }
43    }
44}
45
46#[dom_struct]
47pub struct GPUQuerySet<D: DomTypes> {
48    reflector_: Reflector,
49    #[no_trace]
50    droppable: DroppableGPUQuerySet,
51    label: DomRefCell<USVString>,
52    r#type: GPUQueryType,
53    count: u32,
54    #[no_trace = "PhantomData does not exist"]
55    phantom: PhantomData<D>,
56}
57
58impl<D> GPUQuerySet<D>
59where
60    D: Equivalence,
61    D::GPUDevice: GPUDeviceTrait<D>,
62    D::GlobalScope: WebGPUGlobalTrait,
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            Box::new(GPUQuerySet::new_inherited(
92                label, channel, query_set, r#type, count,
93            )),
94            global,
95            cx,
96            GPUQuerySetWrap::<D>,
97        )
98    }
99
100    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createqueryset>
101    pub 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(wgpu_types::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::GPUDevice: GPUDeviceTrait<D>,
155    D::GlobalScope: WebGPUGlobalTrait,
156{
157    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-destroy>
158    fn Destroy(&self) {
159        // 1. Issue the subsequent steps on the device timeline.
160        if let Err(error) = self
161            .droppable
162            .channel
163            .0
164            .send(WebGPURequest::DestroyQuerySet(self.id().0))
165        {
166            warn!(
167                "Failed to send WebGPURequest::DestroyQuerySet({:?}) ({error})",
168                self.id().0
169            );
170        }
171    }
172
173    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
174    fn Label(&self) -> USVString {
175        self.label.borrow().clone()
176    }
177
178    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
179    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
180        *self.label.safe_borrow_mut(no_gc) = value;
181    }
182
183    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-type>
184    fn Type(&self) -> GPUQueryType {
185        self.r#type
186    }
187
188    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-count>
189    fn Count(&self) -> u32 {
190        self.count
191    }
192}