1use std::collections::HashMap;
5
6use crate::render::atlas::{ATLAS_FORMAT, Atlas, AtlasKind};
7use crate::render::compositor::Compositor;
8use crate::render::shape::Shape;
9use crate::render::{atlas, compositor};
10use crate::resource::{Loader, Location, MAX_VARIANCE};
11use crate::{Error, Mat4x4, render};
12use guillotiere::AllocId;
13use parking_lot::RwLock;
14use smallvec::SmallVec;
15use std::any::TypeId;
16use std::sync::Arc;
17use swash::scale::ScaleContext;
18use wgpu::{PipelineLayout, ShaderModule};
19use winit::window::CursorIcon;
20
21#[inline]
24pub fn point_to_pixel(pt: f32, scale_factor: f32) -> f32 {
25 pt * (72.0 / 96.0) * scale_factor }
27
28pub type PipelineID = TypeId;
29
30#[derive_where::derive_where(Debug)]
31#[allow(clippy::type_complexity)]
32pub(crate) struct PipelineState {
33 layout: PipelineLayout,
34 shader: ShaderModule,
35 #[derive_where(skip)]
36 generator: Box<
37 dyn Fn(&PipelineLayout, &ShaderModule, &Driver) -> Box<dyn render::AnyPipeline>
38 + Send
39 + Sync,
40 >,
41}
42
43#[derive(Debug)]
44pub struct GlyphRegion {
45 pub offset: [i32; 2],
46 pub region: atlas::Region,
47}
48
49pub(crate) type GlyphCache = HashMap<cosmic_text::CacheKey, GlyphRegion>;
50
51#[derive(Debug)]
54pub struct ResourceInstance<'a> {
55 location: Result<Box<dyn Location>, &'a dyn Location>,
56 dpi: f32,
58 resizable: bool,
60}
61
62impl Clone for ResourceInstance<'static> {
63 fn clone(&self) -> Self {
64 Self {
65 location: self.location.clone(),
66 dpi: self.dpi,
67 resizable: self.resizable,
68 }
69 }
70}
71
72impl std::hash::Hash for ResourceInstance<'_> {
73 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
74 match &self.location {
75 Ok(l) => l.hash(state),
76 Err(l) => l.hash(state),
77 }
78 f32::to_bits(self.dpi).hash(state);
80 self.resizable.hash(state);
81 }
82}
83
84impl PartialEq for ResourceInstance<'_> {
85 fn eq(&self, other: &Self) -> bool {
86 let l = match &self.location {
87 Ok(l) => l.as_ref(),
88 Err(l) => *l,
89 };
90
91 let r = match &other.location {
92 Ok(l) => l.as_ref(),
93 Err(l) => *l,
94 };
95
96 *l == *r && self.dpi == other.dpi && self.resizable == other.resizable
97 }
98}
99
100impl Eq for ResourceInstance<'_> {}
102
103#[allow(clippy::type_complexity)]
107#[derive_where::derive_where(Debug)]
108pub struct Driver {
109 pub(crate) glyphs: RwLock<GlyphCache>,
110 pub(crate) prefetch: RwLock<HashMap<Box<dyn Location>, Box<dyn Loader>>>,
111 pub(crate) resources:
112 RwLock<HashMap<ResourceInstance<'static>, (SmallVec<[atlas::Region; 1]>, atlas::Size)>>,
113 pub(crate) locations:
114 RwLock<HashMap<Box<dyn Location>, SmallVec<[ResourceInstance<'static>; 1]>>>,
115 pub(crate) atlas: RwLock<Atlas>,
116 pub(crate) layer_atlas: [RwLock<Atlas>; 2],
117 pub(crate) layer_composite: [RwLock<compositor::Compositor>; 2],
118 pub(crate) shared: compositor::Shared,
119 pub(crate) pipelines: RwLock<HashMap<PipelineID, Box<dyn crate::render::AnyPipeline>>>,
120 pub(crate) registry: RwLock<HashMap<PipelineID, PipelineState>>,
121 pub(crate) queue: wgpu::Queue,
122 pub(crate) device: wgpu::Device,
123 pub(crate) adapter: wgpu::Adapter,
124 pub(crate) cursor: RwLock<CursorIcon>, #[derive_where(skip)]
126 pub(crate) swash_cache: RwLock<ScaleContext>,
127 pub(crate) font_system: RwLock<cosmic_text::FontSystem>,
128}
129
130impl Drop for Driver {
131 fn drop(&mut self) {
132 for (_, mut r) in self.glyphs.get_mut().drain() {
133 r.region.id = AllocId::deserialize(u32::MAX);
134 }
135
136 for (_, (regions, _)) in self.resources.get_mut().drain() {
137 for mut region in regions {
138 region.id = AllocId::deserialize(u32::MAX);
139 }
140 }
141 }
142}
143
144impl Driver {
145 pub async fn new(
146 weak: &mut std::sync::Weak<Self>,
147 instance: &wgpu::Instance,
148 surface: &wgpu::Surface<'static>,
149 on_driver: &mut Option<Box<dyn FnOnce(std::sync::Weak<Driver>) + 'static>>,
150 ) -> eyre::Result<Arc<Self>> {
151 if let Some(driver) = weak.upgrade() {
152 return Ok(driver);
153 }
154
155 let adapter = futures_lite::future::block_on(instance.request_adapter(
156 &wgpu::RequestAdapterOptions {
157 compatible_surface: Some(surface),
158 ..Default::default()
159 },
160 ))?;
161
162 let (device, queue) = adapter
164 .request_device(&wgpu::DeviceDescriptor {
165 label: Some("Feather UI wgpu Device"),
166 required_features: wgpu::Features::empty(),
167 required_limits: wgpu::Limits::default(),
168 memory_hints: wgpu::MemoryHints::MemoryUsage,
169 trace: wgpu::Trace::Off,
170 })
171 .await?;
172
173 let shared = compositor::Shared::new(&device);
174 let atlas = Atlas::new(&device, 512, AtlasKind::Primary);
175 let layer0 = Atlas::new(&device, 128, AtlasKind::Layer0);
176 let layer1 = Atlas::new(&device, 128, AtlasKind::Layer1);
177 let shape_shader = Shape::<0>::shader(&device);
178 let shape_pipeline = Shape::<0>::layout(&device);
179
180 let comp1 = Compositor::new(
181 &device,
182 &shared,
183 &atlas.view,
184 &layer1.view,
185 ATLAS_FORMAT,
186 true,
187 );
188 let comp2 = Compositor::new(
189 &device,
190 &shared,
191 &atlas.view,
192 &layer0.view,
193 ATLAS_FORMAT,
194 false,
195 );
196
197 let mut driver = Self {
198 adapter,
199 device,
200 queue,
201 swash_cache: ScaleContext::new().into(),
202 prefetch: HashMap::new().into(),
203 resources: HashMap::new().into(),
204 locations: HashMap::new().into(),
205 font_system: cosmic_text::FontSystem::new().into(),
206 cursor: CursorIcon::Default.into(),
207 pipelines: HashMap::new().into(),
208 glyphs: HashMap::new().into(),
209 registry: HashMap::new().into(),
210 shared,
211 atlas: atlas.into(),
212 layer_atlas: [layer0.into(), layer1.into()],
213 layer_composite: [comp1.into(), comp2.into()],
214 };
215
216 driver.register_pipeline::<Shape<0>>(
217 shape_pipeline.clone(),
218 shape_shader.clone(),
219 Shape::<0>::create,
220 );
221 driver.register_pipeline::<Shape<1>>(
222 shape_pipeline.clone(),
223 shape_shader.clone(),
224 Shape::<1>::create,
225 );
226 driver.register_pipeline::<Shape<2>>(
227 shape_pipeline.clone(),
228 shape_shader.clone(),
229 Shape::<2>::create,
230 );
231 driver.register_pipeline::<Shape<3>>(
232 shape_pipeline.clone(),
233 shape_shader.clone(),
234 Shape::<3>::create,
235 );
236
237 let driver = Arc::new(driver);
238 *weak = Arc::downgrade(&driver);
239
240 if let Some(f) = on_driver.take() {
241 f(weak.clone());
242 }
243 Ok(driver)
244 }
245
246 pub fn register_pipeline<T: 'static>(
247 &mut self,
248 layout: PipelineLayout,
249 shader: ShaderModule,
250 generator: impl Fn(&PipelineLayout, &ShaderModule, &Self) -> Box<dyn render::AnyPipeline>
251 + Send
252 + Sync
253 + 'static,
254 ) {
255 self.registry.write().insert(
256 TypeId::of::<T>(),
257 PipelineState {
258 layout,
259 shader,
260 generator: Box::new(generator),
261 },
262 );
263 }
264
265 pub fn reload_pipeline<T: 'static>(&self, shader: ShaderModule) {
267 let id = TypeId::of::<T>();
268 let mut registry = self.registry.write();
269 let pipeline = registry
270 .get_mut(&id)
271 .expect("Tried to reload unregistered pipeline!");
272 pipeline.shader = shader;
273 self.pipelines.write().remove(&id);
274 }
275 pub fn with_pipeline<T: crate::render::Pipeline + 'static>(&self, f: impl FnOnce(&mut T)) {
276 let id = TypeId::of::<T>();
277
278 if self.pipelines.read().get(&id).is_none() {
280 let PipelineState {
281 generator,
282 layout,
283 shader,
284 } = &self.registry.read()[&id];
285
286 self.pipelines
287 .write()
288 .insert(id, generator(layout, shader, self));
289 }
290
291 f(
292 (self.pipelines.write().get_mut(&id).unwrap().as_mut() as &mut dyn std::any::Any)
293 .downcast_mut()
294 .unwrap(),
295 );
296 }
297
298 pub fn prefetch(&self, location: &dyn Location) -> Result<(), Error> {
299 let mut resources = self.prefetch.write();
300
301 if !resources.contains_key(location) {
302 resources.insert(dyn_clone::clone_box(location), location.fetch()?);
303 }
304 Ok(())
305 }
306
307 pub fn load_and_resize(
311 &self,
312 location: &dyn Location,
313 size: atlas::Size,
314 dpi: f32,
315 resize: bool,
316 ) -> Result<atlas::Size, Error> {
317 let mut uvsize = atlas::Size::zero();
318 match self.load(location, size, dpi, resize, |r| {
319 uvsize = r.uv.size();
320 Ok(())
321 }) {
322 Err(Error::ResizeTextureAtlas(layers, kind)) => {
323 match kind {
325 AtlasKind::Primary => self.atlas.write(),
326 AtlasKind::Layer0 => self.layer_atlas[0].write(),
327 AtlasKind::Layer1 => self.layer_atlas[1].write(),
328 }
329 .resize(&self.device, &self.queue, layers);
330 self.load_and_resize(location, size, dpi, resize) }
332 Err(e) => Err(e),
333 Ok(_) => Ok(uvsize),
334 }
335 }
336
337 pub fn load(
338 &self,
339 location: &dyn Location,
340 mut size: atlas::Size,
341 dpi: f32,
342 resize: bool,
343 mut f: impl FnMut(&atlas::Region) -> Result<(), Error>,
344 ) -> Result<(), Error> {
345 use crate::resource;
346
347 if let Some((regions, native_size)) = self.resources.read().get(&ResourceInstance {
348 location: Err(location),
349 dpi: f32::INFINITY,
350 resizable: resize,
351 }) {
352 size = resource::fill_size(size, *native_size);
353
354 for r in regions {
357 if r.uv.size() == size
358 || (r.uv.area() >= resource::MIN_AREA
359 && resource::within_variance(size.width, r.uv.width(), MAX_VARIANCE)
360 && resource::within_variance(size.height, r.uv.height(), MAX_VARIANCE))
361 || (resize && size.width <= r.uv.width() && size.height < r.uv.height())
362 {
363 return f(r);
364 }
365 }
366 }
367
368 let (region, native) = {
370 let loader;
371 let reader = self.prefetch.read();
372 let refload = if let Some(res) = reader.get(location) {
373 res
374 } else {
375 loader = location.fetch()?;
376 &loader
377 };
378 let (raw, dim) = refload.preload(size, dpi)?;
379 refload.load(self, (raw, dim), resize)?
380 };
381
382 let key = ResourceInstance {
383 location: Ok(dyn_clone::clone_box(location)),
384 dpi: f32::INFINITY,
385 resizable: resize,
386 };
387
388 self.locations
389 .write()
390 .entry(dyn_clone::clone_box(location))
391 .and_modify(|x| x.push(key.clone()))
392 .or_insert(SmallVec::from_buf([key.clone()]));
393
394 if let Some((entry, _)) = self.resources.write().get_mut(&key) {
395 entry.push(region);
396 f(entry.last().as_ref().ok_or(Error::InternalFailure)?)
397 } else {
398 f(&self
399 .resources
400 .write()
401 .entry(key)
402 .insert_entry((SmallVec::from_buf([region]), native))
403 .get()
404 .0[0])
405 }
406 }
407
408 pub fn evict(&self, location: &dyn Location) {
410 if let Some(instances) = self.locations.read().get(location) {
411 for instance in instances {
412 if let Some((regions, _)) = self.resources.write().remove(instance) {
413 for mut region in regions {
414 self.atlas.write().destroy(&mut region);
415 }
416 }
417 }
418 }
419 }
420}
421
422static_assertions::assert_impl_all!(Driver: Send, Sync);
423
424static_assertions::const_assert!(size_of::<Mat4x4>() == size_of::<[f32; 16]>());
425
426pub fn mat4_proj(x: f32, y: f32, w: f32, h: f32, n: f32, f: f32) -> Mat4x4 {
429 Mat4x4::from_arrays([
430 [2.0 / w, 0.0, 0.0, 0.0],
431 [0.0, 2.0 / h, 0.0, 0.0],
432 [0.0, 0.0, 1.0 / (f - n), 1.0],
433 [-(2.0 * x + w) / w, -(2.0 * y + h) / h, -n / (f - n), 0.0],
434 ])
435}
436
437pub fn mat4_ortho(x: f32, y: f32, w: f32, h: f32, n: f32, f: f32) -> Mat4x4 {
439 Mat4x4::from_arrays([
440 [2.0 / w, 0.0, 0.0, 0.0],
441 [0.0, 2.0 / h, 0.0, 0.0],
442 [0.0, 0.0, -2.0 / (f - n), 0.0],
443 [
444 -(2.0 * x + w) / w,
445 -(2.0 * y + h) / h,
446 (f + n) / (f - n),
447 1.0,
448 ],
449 ])
450}
451
452macro_rules! gen_from_array {
453 ($s:path, $t:path, $i:literal) => {
454 impl From<[$t; $i]> for $s {
455 fn from(value: [$t; $i]) -> Self {
456 Self(value)
457 }
458 }
459 impl From<&[$t; $i]> for $s {
460 fn from(value: &[$t; $i]) -> Self {
461 Self(*value)
462 }
463 }
464 };
465}
466
467#[repr(C, align(8))]
468#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
469pub struct Vec2f(pub(crate) [f32; 2]);
470
471gen_from_array!(Vec2f, f32, 2);
472
473#[repr(C, align(16))]
474#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
475pub struct Vec4f(pub(crate) [f32; 4]);
476
477gen_from_array!(Vec4f, f32, 4);
478
479#[repr(C, align(8))]
480#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
481pub struct Vec2i(pub(crate) [i32; 2]);
482
483gen_from_array!(Vec2i, i32, 2);
484
485#[repr(C, align(16))]
486#[derive(Clone, Copy, Debug, Default, PartialEq, bytemuck::NoUninit)]
487pub struct Vec4i(pub(crate) [i32; 4]);
488
489gen_from_array!(Vec4i, i32, 4);