Skip to main content

pebble/wgpu/
samplers.rs

1use std::collections::HashMap;
2
3use crate::{assets::singleton_asset::LazyResource, wgpu::backend::WGPUBackend};
4
5#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6pub enum SamplerKind {
7    LinearRepeat,
8    LinearClamp,
9    LinearClampNoMip,
10    Nearest,
11    NearestClampBorder,
12    CompareLess,
13}
14
15impl SamplerKind {
16    pub fn descriptor(&self) -> wgpu::SamplerDescriptor<'static> {
17        match self {
18            SamplerKind::LinearRepeat => wgpu::SamplerDescriptor {
19                address_mode_u: wgpu::AddressMode::Repeat,
20                address_mode_v: wgpu::AddressMode::Repeat,
21                address_mode_w: wgpu::AddressMode::Repeat,
22                mag_filter: wgpu::FilterMode::Linear,
23                min_filter: wgpu::FilterMode::Linear,
24                mipmap_filter: wgpu::MipmapFilterMode::Linear,
25                ..Default::default()
26            },
27            SamplerKind::LinearClamp => wgpu::SamplerDescriptor {
28                address_mode_u: wgpu::AddressMode::ClampToEdge,
29                address_mode_v: wgpu::AddressMode::ClampToEdge,
30                address_mode_w: wgpu::AddressMode::ClampToEdge,
31                mag_filter: wgpu::FilterMode::Linear,
32                min_filter: wgpu::FilterMode::Linear,
33                mipmap_filter: wgpu::MipmapFilterMode::Linear,
34                ..Default::default()
35            },
36            SamplerKind::LinearClampNoMip => wgpu::SamplerDescriptor {
37                address_mode_u: wgpu::AddressMode::ClampToEdge,
38                address_mode_v: wgpu::AddressMode::ClampToEdge,
39                address_mode_w: wgpu::AddressMode::ClampToEdge,
40                mag_filter: wgpu::FilterMode::Linear,
41                min_filter: wgpu::FilterMode::Linear,
42                mipmap_filter: wgpu::MipmapFilterMode::Linear,
43                lod_min_clamp: 0.0,
44                lod_max_clamp: 0.0,
45                ..Default::default()
46            },
47            SamplerKind::Nearest => wgpu::SamplerDescriptor {
48                mag_filter: wgpu::FilterMode::Nearest,
49                min_filter: wgpu::FilterMode::Nearest,
50                mipmap_filter: wgpu::MipmapFilterMode::Linear,
51                ..Default::default()
52            },
53            SamplerKind::NearestClampBorder => {
54                let address_mode = if cfg!(target_arch = "wasm32") {
55                    wgpu::AddressMode::ClampToEdge
56                } else {
57                    wgpu::AddressMode::ClampToBorder
58                };
59                wgpu::SamplerDescriptor {
60                    address_mode_u: address_mode,
61                    address_mode_v: address_mode,
62                    address_mode_w: address_mode,
63                    mag_filter: wgpu::FilterMode::Nearest,
64                    min_filter: wgpu::FilterMode::Nearest,
65                    mipmap_filter: wgpu::MipmapFilterMode::Nearest,
66                    border_color: if cfg!(target_arch = "wasm32") {
67                        None
68                    } else {
69                        Some(wgpu::SamplerBorderColor::OpaqueWhite)
70                    },
71                    ..Default::default()
72                }
73            }
74            SamplerKind::CompareLess => wgpu::SamplerDescriptor {
75                address_mode_u: wgpu::AddressMode::ClampToEdge,
76                address_mode_v: wgpu::AddressMode::ClampToEdge,
77                address_mode_w: wgpu::AddressMode::ClampToEdge,
78                mag_filter: wgpu::FilterMode::Linear,
79                min_filter: wgpu::FilterMode::Linear,
80                mipmap_filter: wgpu::MipmapFilterMode::Linear,
81                compare: Some(wgpu::CompareFunction::Less),
82                ..Default::default()
83            },
84        }
85    }
86}
87
88const ALL_SAMPLER_KINDS: [SamplerKind; 6] = [
89    SamplerKind::LinearRepeat,
90    SamplerKind::LinearClamp,
91    SamplerKind::LinearClampNoMip,
92    SamplerKind::Nearest,
93    SamplerKind::NearestClampBorder,
94    SamplerKind::CompareLess,
95];
96
97/// Every [`SamplerKind`] built once and shared across all materials, rather
98/// than each material instance creating its own duplicate `wgpu::Sampler`.
99pub struct GlobalSamplers {
100    samplers: HashMap<SamplerKind, wgpu::Sampler>,
101}
102
103impl GlobalSamplers {
104    /// Look up a shared sampler by kind. Panics if `kind` is somehow missing
105    /// — every [`SamplerKind`] variant is built eagerly in [`LazyResource::construct`].
106    pub fn get(&self, kind: SamplerKind) -> &wgpu::Sampler {
107        self.samplers
108            .get(&kind)
109            .expect("GlobalSamplers: all SamplerKind variants are built at construction")
110    }
111}
112
113impl LazyResource<WGPUBackend> for GlobalSamplers {
114    type Deps<'a> = ();
115
116    fn construct<'a>(backend: &WGPUBackend, _deps: &()) -> Option<Self> {
117        let samplers = ALL_SAMPLER_KINDS
118            .iter()
119            .map(|&kind| (kind, backend.device.create_sampler(&kind.descriptor())))
120            .collect();
121        Some(Self { samplers })
122    }
123}