asdf_overlay/surface/
texture.rs1use core::sync::atomic::{AtomicBool, Ordering};
12
13use anyhow::Context;
14use parking_lot::{RwLock, RwLockReadGuard};
15use windows::{
16 Win32::{
17 Foundation::{CloseHandle, HANDLE},
18 Graphics::{
19 Direct3D11::{D3D11_TEXTURE2D_DESC, ID3D11Device, ID3D11Device1, ID3D11Texture2D},
20 Dxgi::{Common::DXGI_FORMAT, IDXGIKeyedMutex},
21 },
22 },
23 core::Interface,
24};
25
26use crate::surface::SharedTextureHandle;
27
28pub struct OverlaySurface {
30 texture: ID3D11Texture2D,
31 handle: SharedTextureHandle,
32 mutex: Option<IDXGIKeyedMutex>,
33 size: (u32, u32),
34 format: DXGI_FORMAT,
35}
36
37impl OverlaySurface {
38 pub(crate) fn open(device: &ID3D11Device, handle: SharedTextureHandle) -> anyhow::Result<Self> {
40 unsafe {
41 let texture = match handle {
42 SharedTextureHandle::Kmt(handle) => {
43 let mut slot = None::<ID3D11Texture2D>;
44 device
45 .OpenSharedResource(HANDLE(handle as _), &mut slot)
46 .context("failed to open KMT shared texture")?;
47
48 slot.unwrap()
49 }
50
51 SharedTextureHandle::Nt(handle) => device
52 .cast::<ID3D11Device1>()?
53 .OpenSharedResource1::<ID3D11Texture2D>(HANDLE(handle as _))
54 .context("failed to open NT shared texture")?,
55 };
56
57 let mut desc = D3D11_TEXTURE2D_DESC::default();
58 texture.GetDesc(&mut desc);
59
60 let mutex = texture.cast::<IDXGIKeyedMutex>().ok();
61 Ok(Self {
62 texture,
63 handle,
64 mutex,
65 size: (desc.Width, desc.Height),
66 format: desc.Format,
67 })
68 }
69 }
70
71 #[inline]
72 pub const fn mutex(&self) -> Option<&IDXGIKeyedMutex> {
74 self.mutex.as_ref()
75 }
76
77 #[inline]
78 pub const fn size(&self) -> (u32, u32) {
80 self.size
81 }
82
83 #[inline]
84 pub const fn format(&self) -> DXGI_FORMAT {
86 self.format
87 }
88
89 #[inline]
90 pub const fn texture(&self) -> &ID3D11Texture2D {
92 &self.texture
93 }
94
95 #[inline]
96 pub fn shared_handle(&self) -> SharedTextureHandle {
98 self.handle
99 }
100}
101
102impl Drop for OverlaySurface {
103 fn drop(&mut self) {
104 if let SharedTextureHandle::Nt(handle) = self.handle {
105 unsafe {
106 _ = CloseHandle(HANDLE(handle as _));
107 }
108 }
109 }
110}
111
112pub struct OverlayTextureSlot {
113 inner: RwLock<Option<OverlaySurface>>,
114 updated: AtomicBool,
115}
116
117impl OverlayTextureSlot {
118 pub(crate) const fn new() -> Self {
119 Self {
120 inner: RwLock::new(None),
121 updated: AtomicBool::new(true),
122 }
123 }
124
125 #[doc(hidden)]
126 pub fn get(&self) -> RwLockReadGuard<'_, Option<OverlaySurface>> {
127 self.inner.read()
128 }
129
130 #[inline]
131 pub fn invalidate(&self) {
132 self.updated.store(true, Ordering::Relaxed);
133 }
134
135 pub(super) fn update(
136 &self,
137 device: &ID3D11Device,
138 handle: Option<SharedTextureHandle>,
139 ) -> anyhow::Result<()> {
140 self.updated.store(true, Ordering::Relaxed);
141 let Some(handle) = handle else {
142 *self.inner.write() = None;
143 return Ok(());
144 };
145
146 *self.inner.write() = Some(OverlaySurface::open(device, handle)?);
147 Ok(())
148 }
149
150 #[inline]
151 pub fn take_update(&self) -> bool {
152 self.updated.swap(false, Ordering::Relaxed)
153 }
154}