1pub mod texture;
6
7use core::sync::atomic::{AtomicI32, AtomicU32, Ordering};
8
9use anyhow::Context;
10use asdf_overlay_event::{Event, SurfaceEvent, SurfaceInfo};
11use once_cell::sync::Lazy;
12
13use crate::{
14 event_sink::OverlayEventSink, interop::DxInterop, surface::texture::OverlayTextureSlot,
15 types::IntDashMap,
16};
17
18static SURFACES: Lazy<Surfaces> = Lazy::new(|| Surfaces {
19 map: IntDashMap::default(),
20});
21
22pub struct Surfaces {
24 map: IntDashMap<u64, SurfaceState>,
25}
26
27impl Surfaces {
28 pub fn iter() -> impl Iterator<Item = u64> {
30 SURFACES.map.iter().map(|r| *r.key())
31 }
32
33 pub fn state<R>(id: u64, f: impl FnOnce(&SurfaceState) -> R) -> Option<R> {
35 SURFACES.map.get(&id).map(|r| f(&r))
36 }
37
38 pub fn contains(id: u64) -> bool {
39 SURFACES.map.contains_key(&id)
40 }
41
42 pub fn reset() {
43 for state in SURFACES.map.iter() {
44 state.reset();
45 }
46 }
47
48 #[doc(hidden)]
49 pub fn with<R>(
50 id: u64,
51 setup_fn: impl FnOnce() -> anyhow::Result<SurfaceState>,
52 f: impl FnOnce(&SurfaceState) -> R,
53 ) -> anyhow::Result<R> {
54 if let Some(backend) = SURFACES.map.get(&id) {
55 return Ok(f(&backend));
56 }
57
58 let backend = SURFACES
59 .map
60 .entry(id)
61 .or_try_insert_with(|| {
62 let state = setup_fn().context("failed to setup surface state")?;
63
64 let (width, height) = state.size();
65 OverlayEventSink::emit(Event::Surface {
66 id,
67 event: SurfaceEvent::Added {
68 width,
69 height,
70 info: state.info,
71 },
72 });
73
74 Ok::<_, anyhow::Error>(state)
75 })?
76 .downgrade();
77
78 Ok(f(backend.value()))
79 }
80
81 #[doc(hidden)]
82 pub fn cleanup_state(id: u64) {
83 SURFACES.map.remove(&id);
84
85 OverlayEventSink::emit(Event::Surface {
86 id,
87 event: SurfaceEvent::Destroyed,
88 });
89 }
90}
91
92#[non_exhaustive]
94pub struct SurfaceState {
95 position: (AtomicI32, AtomicI32),
96 size: (AtomicU32, AtomicU32),
97
98 pub interop: DxInterop,
99 pub info: SurfaceInfo,
100
101 #[doc(hidden)]
102 pub texture: OverlayTextureSlot,
103}
104
105impl SurfaceState {
106 pub fn new(interop: DxInterop, size: (u32, u32), info: SurfaceInfo) -> anyhow::Result<Self> {
107 let surface = OverlayTextureSlot::new();
108
109 Ok(Self {
110 position: (AtomicI32::new(0), AtomicI32::new(0)),
111 size: (AtomicU32::new(size.0), AtomicU32::new(size.1)),
112 interop,
113 info,
114 texture: surface,
115 })
116 }
117
118 #[doc(hidden)]
119 pub fn texture_size(&self) -> Option<(u32, u32)> {
120 self.texture.get().as_ref().map(|surface| surface.size())
121 }
122
123 pub fn size(&self) -> (u32, u32) {
124 (
125 self.size.0.load(Ordering::Relaxed),
126 self.size.1.load(Ordering::Relaxed),
127 )
128 }
129
130 #[doc(hidden)]
131 pub fn resize(&self, width: u32, height: u32) {
132 self.size.0.store(width, Ordering::Relaxed);
133 self.size.1.store(height, Ordering::Relaxed);
134 }
135
136 pub fn position(&self) -> (i32, i32) {
137 (
138 self.position.0.load(Ordering::Relaxed),
139 self.position.1.load(Ordering::Relaxed),
140 )
141 }
142
143 pub fn reposition(&self, x: i32, y: i32) {
144 self.position.0.store(x, Ordering::Relaxed);
145 self.position.1.store(y, Ordering::Relaxed);
146 }
147
148 pub fn commit_overlay_texture(
149 &self,
150 handle: Option<SharedTextureHandle>,
151 ) -> anyhow::Result<()> {
152 self.texture.update(&self.interop.device, handle)
153 }
154
155 pub fn reset(&self) {
158 self.reposition(0, 0);
159 _ = self.commit_overlay_texture(None);
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum SharedTextureHandle {
165 Kmt(u32),
167
168 Nt(u32),
170}
171
172impl SharedTextureHandle {
173 pub fn as_raw(&self) -> u32 {
174 match self {
175 Self::Kmt(handle) | Self::Nt(handle) => *handle,
176 }
177 }
178}