use std::marker::PhantomData;
use dom_struct::dom_struct;
use js::context::{JSContext, NoGC};
use log::warn;
use malloc_size_of_derive::MallocSizeOf;
use script_bindings::DomTypes;
use script_bindings::cell::DomRefCell;
use script_bindings::codegen::GenericBindings::WebGPUBinding::{
GPUDeviceMethods, GPUQuerySetDescriptor, GPUQuerySetMethods, GPUQuerySetWrap, GPUQueryType,
};
use script_bindings::error::{Error, Fallible};
use script_bindings::interfaces::PromiseHelpers;
use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
use script_bindings::root::DomRoot;
use webgpu_traits::{Features, WebGPU, WebGPUQuerySet, WebGPURequest};
use crate::JSTraceable;
use crate::dom::bindings::str::USVString;
use crate::gpuconvert::WebGPUConvert;
use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise};
#[derive(MallocSizeOf)]
struct DroppableGPUQuerySet {
channel: WebGPU,
query_set: WebGPUQuerySet,
}
impl Drop for DroppableGPUQuerySet {
fn drop(&mut self) {
if let Err(error) = self
.channel
.0
.send(WebGPURequest::DropQuerySet(self.query_set.0))
{
warn!(
"Failed to send WebGPURequest::DropQuerySet({:?}) ({error})",
self.query_set.0
);
}
}
}
#[dom_struct]
pub struct GPUQuerySet<D: DomTypes> {
reflector_: Reflector,
#[no_trace]
droppable: DroppableGPUQuerySet,
label: DomRefCell<USVString>,
r#type: GPUQueryType,
count: u32,
#[no_trace = "PhantomData does not exist"]
phantom: PhantomData<D>,
}
impl<D> GPUQuerySet<D>
where
D: Equivalence,
<D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
{
pub(crate) fn new_inherited(
label: USVString,
channel: WebGPU,
query_set: WebGPUQuerySet,
r#type: GPUQueryType,
count: u32,
) -> Self {
GPUQuerySet {
reflector_: Reflector::new(),
label: DomRefCell::new(label),
droppable: DroppableGPUQuerySet { channel, query_set },
r#type,
count,
phantom: PhantomData,
}
}
pub(crate) fn new(
cx: &mut JSContext,
global: &D::GlobalScope,
label: USVString,
channel: WebGPU,
query_set: WebGPUQuerySet,
r#type: GPUQueryType,
count: u32,
) -> DomRoot<Self> {
reflect_dom_object_with_wrap::<D, _, _>(
cx,
Box::new(GPUQuerySet::new_inherited(
label, channel, query_set, r#type, count,
)),
global,
GPUQuerySetWrap::<D>,
)
}
pub(crate) fn create(
cx: &mut JSContext,
device: &D::GPUDevice,
descriptor: &GPUQuerySetDescriptor,
) -> Fallible<DomRoot<Self>> {
if descriptor.type_ == GPUQueryType::Timestamp &&
!device
.Features()
.wgpu_features()
.contains(Features::TIMESTAMP_QUERY)
{
return Err(Error::Type(
c"The device does not support timestamp queries".to_owned(),
));
}
let query_set_id = device
.global_from_reflector()
.global_wgpu_id_hub()
.create_query_set_id();
let channel = device.channel();
if let Err(error) = channel.0.send(WebGPURequest::CreateQuerySet {
device_id: device.id().0,
query_set_id,
descriptor: descriptor.convert(),
}) {
warn!("Failed to send WebGPURequest::CreateQuerySet: {error}");
}
Ok(Self::new(
cx,
&device.global_from_reflector(),
descriptor.parent.label.clone(),
channel,
WebGPUQuerySet(query_set_id),
descriptor.type_,
descriptor.count,
))
}
pub(crate) fn id(&self) -> WebGPUQuerySet {
self.droppable.query_set
}
}
impl<D> GPUQuerySetMethods<D> for GPUQuerySet<D>
where
D: Equivalence,
<D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
{
fn Destroy(&self) {
if let Err(error) = self
.droppable
.channel
.0
.send(WebGPURequest::DestroyQuerySet(self.id().0))
{
warn!(
"Failed to send WebGPURequest::DestroyQuerySet({:?}) ({error})",
self.id().0
);
}
}
fn Label(&self) -> USVString {
self.label.borrow().clone()
}
fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
*self.label.safe_borrow_mut(no_gc) = value;
}
fn Type(&self) -> GPUQueryType {
self.r#type
}
fn Count(&self) -> u32 {
self.count
}
}