1use std::collections::HashMap;
5
6use crate::render;
7use crate::render::atlas::ATLAS_FORMAT;
8use crate::render::{atlas, compositor};
9use guillotiere::AllocId;
10use parking_lot::RwLock;
11use std::any::TypeId;
12use std::sync::Arc;
13use swash::scale::ScaleContext;
14use ultraviolet::{Mat4, Vec2, Vec4};
15use wgpu::{PipelineLayout, ShaderModule};
16use winit::window::CursorIcon;
17
18#[inline]
21pub fn point_to_pixel(pt: f32, scale_factor: f32) -> f32 {
22 pt * (72.0 / 96.0) * scale_factor }
24
25#[inline]
26pub fn pixel_to_vec(p: winit::dpi::PhysicalPosition<f32>) -> Vec2 {
27 Vec2::new(p.x, p.y)
28}
29
30pub type PipelineID = TypeId;
31
32#[derive_where::derive_where(Debug)]
33#[allow(clippy::type_complexity)]
34pub(crate) struct PipelineState {
35 layout: PipelineLayout,
36 shader: ShaderModule,
37 #[derive_where(skip)]
38 generator: Box<
39 dyn Fn(&PipelineLayout, &ShaderModule, &Driver) -> Box<dyn render::AnyPipeline>
40 + Send
41 + Sync,
42 >,
43}
44
45#[derive(Debug)]
46pub struct GlyphRegion {
47 pub offset: [i32; 2],
48 pub region: atlas::Region,
49}
50
51pub(crate) type GlyphCache = HashMap<cosmic_text::CacheKey, GlyphRegion>;
52
53#[derive_where::derive_where(Debug)]
57pub struct Driver {
58 pub(crate) glyphs: RwLock<GlyphCache>,
59 pub(crate) atlas: RwLock<atlas::Atlas>,
60 pub(crate) layer_atlas: [RwLock<atlas::Atlas>; 2],
61 pub(crate) layer_composite: [RwLock<compositor::Compositor>; 2],
62 pub(crate) shared: compositor::Shared,
63 pub(crate) pipelines: RwLock<HashMap<PipelineID, Box<dyn crate::render::AnyPipeline>>>,
64 pub(crate) registry: RwLock<HashMap<PipelineID, PipelineState>>,
65 pub(crate) queue: wgpu::Queue,
66 pub(crate) device: wgpu::Device,
67 pub(crate) adapter: wgpu::Adapter,
68 pub(crate) cursor: RwLock<CursorIcon>, #[derive_where(skip)]
70 pub(crate) swash_cache: RwLock<ScaleContext>,
71 pub(crate) font_system: RwLock<cosmic_text::FontSystem>,
72}
73
74impl Drop for Driver {
75 fn drop(&mut self) {
76 for (_, mut r) in self.glyphs.get_mut().drain() {
77 r.region.id = AllocId::deserialize(u32::MAX);
78 }
79 }
80}
81
82impl Driver {
83 pub async fn new(
84 weak: &mut std::sync::Weak<Self>,
85 instance: &wgpu::Instance,
86 surface: &wgpu::Surface<'static>,
87 on_driver: &mut Option<Box<dyn FnOnce(std::sync::Weak<Driver>) + 'static>>,
88 ) -> eyre::Result<Arc<Self>> {
89 if let Some(driver) = weak.upgrade() {
90 return Ok(driver);
91 }
92
93 let adapter = futures_lite::future::block_on(instance.request_adapter(
94 &wgpu::RequestAdapterOptions {
95 compatible_surface: Some(surface),
96 ..Default::default()
97 },
98 ))?;
99
100 let (device, queue) = adapter
102 .request_device(&wgpu::DeviceDescriptor {
103 label: Some("Feather UI wgpu Device"),
104 required_features: wgpu::Features::empty(),
105 required_limits: wgpu::Limits::default(),
106 memory_hints: wgpu::MemoryHints::MemoryUsage,
107 trace: wgpu::Trace::Off,
108 })
109 .await?;
110
111 let shared = compositor::Shared::new(&device);
112 let atlas = atlas::Atlas::new(&device, 512, atlas::AtlasKind::Primary);
113 let layer0 = atlas::Atlas::new(&device, 128, atlas::AtlasKind::Layer0);
114 let layer1 = atlas::Atlas::new(&device, 128, atlas::AtlasKind::Layer1);
115 let shape_shader = crate::render::shape::Shape::<0>::shader(&device);
116 let shape_pipeline = crate::render::shape::Shape::<0>::layout(&device);
117
118 let comp1 = crate::render::compositor::Compositor::new(
119 &device,
120 &shared,
121 &atlas.view,
122 &layer1.view,
123 ATLAS_FORMAT,
124 true,
125 );
126 let comp2 = crate::render::compositor::Compositor::new(
127 &device,
128 &shared,
129 &atlas.view,
130 &layer0.view,
131 ATLAS_FORMAT,
132 false,
133 );
134
135 let mut driver = Self {
136 adapter,
137 device,
138 queue,
139 swash_cache: ScaleContext::new().into(),
140 font_system: cosmic_text::FontSystem::new().into(),
141 cursor: CursorIcon::Default.into(),
142 pipelines: HashMap::new().into(),
143 glyphs: HashMap::new().into(),
144 registry: HashMap::new().into(),
145 shared,
146 atlas: atlas.into(),
147 layer_atlas: [layer0.into(), layer1.into()],
148 layer_composite: [comp1.into(), comp2.into()],
149 };
150
151 driver.register_pipeline::<crate::render::shape::Shape<0>>(
152 shape_pipeline.clone(),
153 shape_shader.clone(),
154 crate::render::shape::Shape::<0>::create,
155 );
156 driver.register_pipeline::<crate::render::shape::Shape<1>>(
157 shape_pipeline.clone(),
158 shape_shader.clone(),
159 crate::render::shape::Shape::<1>::create,
160 );
161 driver.register_pipeline::<crate::render::shape::Shape<2>>(
162 shape_pipeline.clone(),
163 shape_shader.clone(),
164 crate::render::shape::Shape::<2>::create,
165 );
166 driver.register_pipeline::<crate::render::shape::Shape<3>>(
167 shape_pipeline.clone(),
168 shape_shader.clone(),
169 crate::render::shape::Shape::<3>::create,
170 );
171
172 let driver = Arc::new(driver);
173 *weak = Arc::downgrade(&driver);
174
175 if let Some(f) = on_driver.take() {
176 f(weak.clone());
177 }
178 Ok(driver)
179 }
180
181 pub fn register_pipeline<T: 'static>(
182 &mut self,
183 layout: PipelineLayout,
184 shader: ShaderModule,
185 generator: impl Fn(&PipelineLayout, &ShaderModule, &Self) -> Box<dyn render::AnyPipeline>
186 + Send
187 + Sync
188 + 'static,
189 ) {
190 self.registry.write().insert(
191 TypeId::of::<T>(),
192 PipelineState {
193 layout,
194 shader,
195 generator: Box::new(generator),
196 },
197 );
198 }
199
200 pub fn reload_pipeline<T: 'static>(&self, shader: ShaderModule) {
202 let id = TypeId::of::<T>();
203 let mut registry = self.registry.write();
204 let pipeline = registry
205 .get_mut(&id)
206 .expect("Tried to reload unregistered pipeline!");
207 pipeline.shader = shader;
208 self.pipelines.write().remove(&id);
209 }
210 pub fn with_pipeline<T: crate::render::Pipeline + 'static>(&self, f: impl FnOnce(&mut T)) {
211 let id = TypeId::of::<T>();
212
213 if self.pipelines.read().get(&id).is_none() {
215 let PipelineState {
216 generator,
217 layout,
218 shader,
219 } = &self.registry.read()[&id];
220
221 self.pipelines
222 .write()
223 .insert(id, generator(layout, shader, self));
224 }
225
226 f(
227 (self.pipelines.write().get_mut(&id).unwrap().as_mut() as &mut dyn std::any::Any)
228 .downcast_mut()
229 .unwrap(),
230 );
231 }
232}
233
234static_assertions::assert_impl_all!(Driver: Send, Sync);
235
236pub fn mat4_proj(x: f32, y: f32, w: f32, h: f32, n: f32, f: f32) -> Mat4 {
239 Mat4 {
240 cols: [
241 Vec4::new(2.0 / w, 0.0, 0.0, 0.0),
242 Vec4::new(0.0, 2.0 / h, 0.0, 0.0),
243 Vec4::new(0.0, 0.0, 1.0 / (f - n), 1.0),
244 Vec4::new(-(2.0 * x + w) / w, -(2.0 * y + h) / h, -n / (f - n), 0.0),
245 ],
246 }
247}
248
249pub fn mat4_ortho(x: f32, y: f32, w: f32, h: f32, n: f32, f: f32) -> Mat4 {
251 Mat4 {
252 cols: [
253 Vec4::new(2.0 / w, 0.0, 0.0, 0.0),
254 Vec4::new(0.0, 2.0 / h, 0.0, 0.0),
255 Vec4::new(0.0, 0.0, -2.0 / (f - n), 0.0),
256 Vec4::new(
257 -(2.0 * x + w) / w,
258 -(2.0 * y + h) / h,
259 (f + n) / (f - n),
260 1.0,
261 ),
262 ],
263 }
264}
265
266macro_rules! gen_from_array {
267 ($s:path, $t:path, $i:literal) => {
268 impl From<[$t; $i]> for $s {
269 fn from(value: [$t; $i]) -> Self {
270 Self(value)
271 }
272 }
273 impl From<&[$t; $i]> for $s {
274 fn from(value: &[$t; $i]) -> Self {
275 Self(*value)
276 }
277 }
278 };
279}
280
281#[repr(C, align(8))]
282#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
283pub struct Vec2f(pub(crate) [f32; 2]);
284
285gen_from_array!(Vec2f, f32, 2);
286
287#[repr(C, align(16))]
288#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
289pub struct Vec4f(pub(crate) [f32; 4]);
290
291gen_from_array!(Vec4f, f32, 4);
292
293#[repr(C, align(8))]
294#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
295pub struct Vec2i(pub(crate) [i32; 2]);
296
297gen_from_array!(Vec2i, i32, 2);
298
299#[repr(C, align(16))]
300#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
301pub struct Vec4i(pub(crate) [i32; 4]);
302
303gen_from_array!(Vec4i, i32, 4);