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::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
17use webgpu_traits::{WebGPU, WebGPUDevice, WebGPURequest, WebGPUSampler};
18use wgpu_core::resource::SamplerDescriptor;
19
20use crate::JSTraceable;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::str::USVString;
23use crate::gpuconvert::WebGPUConvert;
24use crate::traits::{Equivalence, GPUDeviceTrait, WebGPUGlobalTrait};
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            Box::new(GPUSampler::new_inherited(
87                channel,
88                device,
89                compare_enable,
90                sampler,
91                label,
92            )),
93            global,
94            cx,
95            GPUSamplerWrap::<D>,
96        )
97    }
98}
99
100impl<D> GPUSampler<D>
101where
102    D: Equivalence,
103    D::GlobalScope: WebGPUGlobalTrait,
104    D::GPUDevice: GPUDeviceTrait<D>,
105{
106    pub(crate) fn id(&self) -> WebGPUSampler {
107        self.dropppable.sampler
108    }
109
110    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createsampler>
111    pub fn create(
112        cx: &mut JSContext,
113        device: &D::GPUDevice,
114        descriptor: &GPUSamplerDescriptor,
115    ) -> DomRoot<GPUSampler<D>> {
116        let sampler_id = device
117            .global_from_reflector()
118            .global_wgpu_id_hub()
119            .create_sampler_id();
120        let compare_enable = descriptor.compare.is_some();
121        let desc = SamplerDescriptor {
122            label: (&descriptor.parent).convert(),
123            address_modes: [
124                descriptor.addressModeU.convert(),
125                descriptor.addressModeV.convert(),
126                descriptor.addressModeW.convert(),
127            ],
128            mag_filter: descriptor.magFilter.convert(),
129            min_filter: descriptor.minFilter.convert(),
130            mipmap_filter: descriptor.mipmapFilter.convert(),
131            lod_min_clamp: *descriptor.lodMinClamp,
132            lod_max_clamp: *descriptor.lodMaxClamp,
133            compare: descriptor.compare.map(WebGPUConvert::convert),
134            anisotropy_clamp: 1,
135            border_color: None,
136        };
137
138        device
139            .channel()
140            .0
141            .send(WebGPURequest::CreateSampler {
142                device_id: device.id().0,
143                sampler_id,
144                descriptor: desc,
145            })
146            .expect("Failed to create WebGPU sampler");
147
148        let sampler = WebGPUSampler(sampler_id);
149
150        GPUSampler::new(
151            cx,
152            &*device.global_from_reflector(),
153            device.channel(),
154            device.id(),
155            compare_enable,
156            sampler,
157            descriptor.parent.label.clone(),
158        )
159    }
160}
161
162impl<D: DomTypes> GPUSamplerMethods<D> for GPUSampler<D> {
163    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
164    fn Label(&self) -> USVString {
165        self.label.borrow().clone()
166    }
167
168    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
169    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
170        *self.label.safe_borrow_mut(no_gc) = value;
171    }
172}