Skip to main content

script/dom/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/. */
4
5use dom_struct::dom_struct;
6use js::context::{JSContext, NoGC};
7use script_bindings::cell::DomRefCell;
8use script_bindings::codegen::GenericBindings::WebGPUBinding::{GPUDeviceMethods, GPUQueryType};
9use script_bindings::error::{Error, Fallible};
10use script_bindings::reflector::{Reflector, reflect_dom_object};
11use script_bindings::root::DomRoot;
12use script_webgpu::gpuconvert::WebGPUConvert;
13use script_webgpu::traits::GPUQuerySetTrait;
14use webgpu_traits::{WebGPU, WebGPUQuerySet, WebGPURequest};
15
16use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
17    GPUQuerySetDescriptor, GPUQuerySetMethods,
18};
19use crate::dom::bindings::reflector::DomGlobal as _;
20use crate::dom::bindings::str::USVString;
21use crate::dom::types::{GPUDevice, GlobalScope};
22
23#[derive(JSTraceable, MallocSizeOf)]
24struct DroppableGPUQuerySet {
25    #[no_trace]
26    channel: WebGPU,
27    #[no_trace]
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(crate) struct GPUQuerySet {
48    reflector_: Reflector,
49    droppable: DroppableGPUQuerySet,
50    label: DomRefCell<USVString>,
51    r#type: GPUQueryType,
52    count: u32,
53}
54
55impl GPUQuerySet {
56    pub(crate) fn new_inherited(
57        label: USVString,
58        channel: WebGPU,
59        query_set: WebGPUQuerySet,
60        r#type: GPUQueryType,
61        count: u32,
62    ) -> Self {
63        GPUQuerySet {
64            reflector_: Reflector::new(),
65            label: DomRefCell::new(label),
66            droppable: DroppableGPUQuerySet { channel, query_set },
67            r#type,
68            count,
69        }
70    }
71
72    pub(crate) fn new(
73        cx: &mut JSContext,
74        global: &GlobalScope,
75        label: USVString,
76        channel: WebGPU,
77        query_set: WebGPUQuerySet,
78        r#type: GPUQueryType,
79        count: u32,
80    ) -> DomRoot<Self> {
81        reflect_dom_object(
82            cx,
83            Box::new(GPUQuerySet::new_inherited(
84                label, channel, query_set, r#type, count,
85            )),
86            global,
87        )
88    }
89
90    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createqueryset>
91    pub(crate) fn create(
92        cx: &mut JSContext,
93        device: &GPUDevice,
94        descriptor: &GPUQuerySetDescriptor,
95    ) -> Fallible<DomRoot<Self>> {
96        // 1. If descriptor.type is "timestamp", but "timestamp-query" is not enabled for this:
97        if descriptor.type_ == GPUQueryType::Timestamp &&
98            !device
99                .Features()
100                .wgpu_features()
101                .contains(wgpu_types::Features::TIMESTAMP_QUERY)
102        {
103            // Throw a TypeError.
104            return Err(Error::Type(
105                c"The device does not support timestamp queries".to_owned(),
106            ));
107        }
108        // 2. Let q be ! create a new WebGPU object(this, GPUQuerySet, descriptor).
109        let query_set_id = device.global().wgpu_id_hub().create_query_set_id();
110        // 5. Issue the initialization steps on the Device timeline of this.
111        let channel = device.channel();
112        if let Err(error) = channel.0.send(WebGPURequest::CreateQuerySet {
113            device_id: device.id().0,
114            query_set_id,
115            descriptor: descriptor.convert(),
116        }) {
117            warn!("Failed to send WebGPURequest::CreateQuerySet: {error}");
118        }
119        // 6. Return q
120        Ok(Self::new(
121            cx,
122            &device.global(),
123            descriptor.parent.label.clone(),
124            channel,
125            WebGPUQuerySet(query_set_id),
126            // 3. Set q.type to descriptor.type.
127            descriptor.type_,
128            // 4. Set q.count to descriptor.count.
129            descriptor.count,
130        ))
131    }
132
133    pub(crate) fn id(&self) -> WebGPUQuerySet {
134        self.droppable.query_set
135    }
136}
137
138impl GPUQuerySetMethods<crate::DomTypeHolder> for GPUQuerySet {
139    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-destroy>
140    fn Destroy(&self) {
141        // 1. Issue the subsequent steps on the device timeline.
142        if let Err(error) = self
143            .droppable
144            .channel
145            .0
146            .send(WebGPURequest::DestroyQuerySet(self.id().0))
147        {
148            warn!(
149                "Failed to send WebGPURequest::DestroyQuerySet({:?}) ({error})",
150                self.id().0
151            );
152        }
153    }
154
155    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
156    fn Label(&self) -> USVString {
157        self.label.borrow().clone()
158    }
159
160    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
161    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
162        *self.label.safe_borrow_mut(no_gc) = value;
163    }
164
165    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-type>
166    fn Type(&self) -> GPUQueryType {
167        self.r#type
168    }
169
170    /// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-count>
171    fn Count(&self) -> u32 {
172        self.count
173    }
174}
175
176impl GPUQuerySetTrait for GPUQuerySet {
177    fn id(&self) -> WebGPUQuerySet {
178        self.id()
179    }
180}