Skip to main content

script_webgpu/
gpusampler.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 std::marker::PhantomData;
6
7use dom_struct::dom_struct;
8use js::context::{JSContext, NoGC};
9use log::warn;
10use malloc_size_of_derive::MallocSizeOf;
11use script_bindings::DomTypes;
12use script_bindings::cell::DomRefCell;
13use script_bindings::codegen::GenericBindings::WebGPUBinding::{
14    GPUSamplerDescriptor, GPUSamplerMethods, GPUSamplerWrap,
15};
16use script_bindings::interfaces::PromiseHelpers;
17use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
18use webgpu_traits::{SamplerDescriptor, WebGPU, WebGPUDevice, WebGPURequest, WebGPUSampler};
19
20use crate::JSTraceable;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::str::USVString;
23use crate::gpuconvert::WebGPUConvert;
24use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise};
25
26#[derive(JSTraceable, MallocSizeOf)]
27struct DroppableGPUSampler {
28    #[no_trace]
29    channel: WebGPU,
30    #[no_trace]
31    sampler: WebGPUSampler,
32}
33
34impl Drop for DroppableGPUSampler {
35    fn drop(&mut self) {
36        if let Err(e) = self
37            .channel
38            .0
39            .send(WebGPURequest::DropSampler(self.sampler.0))
40        {
41            warn!("Failed to send DropSampler ({:?}) ({})", self.sampler.0, e);
42        }
43    }
44}
45
46#[dom_struct]
47pub struct GPUSampler<D: DomTypes> {
48    reflector_: Reflector,
49    label: DomRefCell<USVString>,
50    #[no_trace]
51    device: WebGPUDevice,
52    compare_enable: bool,
53    dropppable: DroppableGPUSampler,
54    #[no_trace = "PhantomData does not exist"]
55    phantom: PhantomData<D>,
56}
57
58impl<D: Equivalence> GPUSampler<D> {
59    fn new_inherited(
60        channel: WebGPU,
61        device: WebGPUDevice,
62        compare_enable: bool,
63        sampler: WebGPUSampler,
64        label: USVString,
65    ) -> Self {
66        Self {
67            reflector_: Reflector::new(),
68            label: DomRefCell::new(label),
69            device,
70            compare_enable,
71            dropppable: DroppableGPUSampler { channel, sampler },
72            phantom: PhantomData,
73        }
74    }
75
76    pub(crate) fn new(
77        cx: &mut JSContext,
78        global: &D::GlobalScope,
79        channel: WebGPU,
80        device: WebGPUDevice,
81        compare_enable: bool,
82        sampler: WebGPUSampler,
83        label: USVString,
84    ) -> DomRoot<Self> {
85        reflect_dom_object_with_wrap::<D, _, _>(
86            cx,
87            Box::new(GPUSampler::new_inherited(
88                channel,
89                device,
90                compare_enable,
91                sampler,
92                label,
93            )),
94            global,
95            GPUSamplerWrap::<D>,
96        )
97    }
98}
99
100impl<D> GPUSampler<D>
101where
102    D: Equivalence,
103    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
104{
105    pub(crate) fn id(&self) -> WebGPUSampler {
106        self.dropppable.sampler
107    }
108
109    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createsampler>
110    pub(crate) fn create(
111        cx: &mut JSContext,
112        device: &D::GPUDevice,
113        descriptor: &GPUSamplerDescriptor,
114    ) -> DomRoot<GPUSampler<D>> {
115        let sampler_id = device
116            .global_from_reflector()
117            .global_wgpu_id_hub()
118            .create_sampler_id();
119        let compare_enable = descriptor.compare.is_some();
120        let desc = SamplerDescriptor {
121            label: (&descriptor.parent).convert(),
122            address_modes: [
123                descriptor.addressModeU.convert(),
124                descriptor.addressModeV.convert(),
125                descriptor.addressModeW.convert(),
126            ],
127            mag_filter: descriptor.magFilter.convert(),
128            min_filter: descriptor.minFilter.convert(),
129            mipmap_filter: descriptor.mipmapFilter.convert(),
130            lod_min_clamp: *descriptor.lodMinClamp,
131            lod_max_clamp: *descriptor.lodMaxClamp,
132            compare: descriptor.compare.map(WebGPUConvert::convert),
133            anisotropy_clamp: 1,
134            border_color: None,
135        };
136
137        device
138            .channel()
139            .0
140            .send(WebGPURequest::CreateSampler {
141                device_id: device.id().0,
142                sampler_id,
143                descriptor: desc,
144            })
145            .expect("Failed to create WebGPU sampler");
146
147        let sampler = WebGPUSampler(sampler_id);
148
149        GPUSampler::new(
150            cx,
151            &*device.global_from_reflector(),
152            device.channel(),
153            device.id(),
154            compare_enable,
155            sampler,
156            descriptor.parent.label.clone(),
157        )
158    }
159}
160
161impl<D: DomTypes> GPUSamplerMethods<D> for GPUSampler<D> {
162    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
163    fn Label(&self) -> USVString {
164        self.label.borrow().clone()
165    }
166
167    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
168    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
169        *self.label.safe_borrow_mut(no_gc) = value;
170    }
171}