veridian_kernel/desktop/wayland/
buffer.rs1#![allow(dead_code)]
8
9use alloc::{collections::BTreeMap, vec, vec::Vec};
10
11use spin::Mutex;
12
13use crate::{error::KernelError, graphics::PixelFormat};
14
15pub struct WlShmPool {
26 pub id: u32,
28 pub client_id: u32,
30 data: Vec<u8>,
32 pub size: usize,
34 buffers: BTreeMap<u32, WlBuffer>,
36 next_buffer_id: u32,
38}
39
40impl WlShmPool {
41 pub fn new(id: u32, client_id: u32, size: usize) -> Self {
43 Self {
44 id,
45 client_id,
46 data: vec![0u8; size],
47 size,
48 buffers: BTreeMap::new(),
49 next_buffer_id: 1,
50 }
51 }
52
53 pub fn create_buffer(
61 &mut self,
62 offset: u32,
63 width: u32,
64 height: u32,
65 stride: u32,
66 format: PixelFormat,
67 ) -> Result<u32, KernelError> {
68 let end = offset as usize + (stride as usize) * (height as usize);
70 if end > self.size {
71 return Err(KernelError::InvalidArgument {
72 name: "buffer region",
73 value: "exceeds pool size",
74 });
75 }
76 if stride < width * format.bpp() {
77 return Err(KernelError::InvalidArgument {
78 name: "stride",
79 value: "smaller than row width",
80 });
81 }
82
83 let buf_id = self.next_buffer_id;
84 self.next_buffer_id += 1;
85
86 let buffer = WlBuffer {
87 id: buf_id,
88 pool_id: self.id,
89 offset,
90 width,
91 height,
92 stride,
93 format,
94 released: true, };
96 self.buffers.insert(buf_id, buffer);
97 Ok(buf_id)
98 }
99
100 pub fn get_buffer(&self, buffer_id: u32) -> Option<&WlBuffer> {
102 self.buffers.get(&buffer_id)
103 }
104
105 pub fn destroy_buffer(&mut self, buffer_id: u32) -> bool {
107 self.buffers.remove(&buffer_id).is_some()
108 }
109
110 pub fn read_buffer_pixels(&self, buffer_id: u32) -> Option<&[u8]> {
114 let buf = self.buffers.get(&buffer_id)?;
115 let start = buf.offset as usize;
116 let len = buf.stride as usize * buf.height as usize;
117 if start + len > self.data.len() {
118 return None;
119 }
120 Some(&self.data[start..start + len])
121 }
122
123 pub fn write_buffer_pixels(&mut self, buffer_id: u32, pixels: &[u8]) -> bool {
128 let buf = match self.buffers.get(&buffer_id) {
129 Some(b) => b,
130 None => return false,
131 };
132 let start = buf.offset as usize;
133 let len = buf.stride as usize * buf.height as usize;
134 if start + len > self.data.len() || pixels.len() < len {
135 return false;
136 }
137 self.data[start..start + len].copy_from_slice(&pixels[..len]);
138 true
139 }
140
141 pub fn data(&self) -> &[u8] {
144 &self.data
145 }
146
147 pub fn write_data(&mut self, offset: usize, data: &[u8]) {
151 let end = (offset + data.len()).min(self.data.len());
152 let src_len = end - offset;
153 self.data[offset..end].copy_from_slice(&data[..src_len]);
154 }
155
156 pub fn resize(&mut self, new_size: usize) -> Result<(), KernelError> {
158 if new_size < self.size {
159 return Err(KernelError::InvalidArgument {
160 name: "pool size",
161 value: "cannot shrink",
162 });
163 }
164 self.data.resize(new_size, 0);
165 self.size = new_size;
166 Ok(())
167 }
168}
169
170#[derive(Debug, Clone)]
176pub struct WlBuffer {
177 pub id: u32,
179 pub pool_id: u32,
181 pub offset: u32,
183 pub width: u32,
185 pub height: u32,
187 pub stride: u32,
189 pub format: PixelFormat,
191 pub released: bool,
193}
194
195impl WlBuffer {
196 pub fn byte_size(&self) -> usize {
198 self.stride as usize * self.height as usize
199 }
200}
201
202static SHM_POOLS: Mutex<Option<BTreeMap<u32, WlShmPool>>> = Mutex::new(None);
211
212pub fn init_shm_pools() {
214 let mut pools = SHM_POOLS.lock();
215 if pools.is_none() {
216 *pools = Some(BTreeMap::new());
217 }
218}
219
220pub fn register_pool(pool: WlShmPool) -> u32 {
222 let id = pool.id;
223 let mut guard = SHM_POOLS.lock();
224 if let Some(ref mut pools) = *guard {
225 pools.insert(id, pool);
226 }
227 id
228}
229
230pub fn with_pool_mut<R, F: FnOnce(&mut WlShmPool) -> R>(pool_id: u32, f: F) -> Option<R> {
232 let mut guard = SHM_POOLS.lock();
233 guard
234 .as_mut()
235 .and_then(|pools| pools.get_mut(&pool_id).map(f))
236}
237
238pub fn with_pool<R, F: FnOnce(&WlShmPool) -> R>(pool_id: u32, f: F) -> Option<R> {
240 let guard = SHM_POOLS.lock();
241 guard.as_ref().and_then(|pools| pools.get(&pool_id).map(f))
242}
243
244pub fn unregister_pool(pool_id: u32) -> Option<WlShmPool> {
246 let mut guard = SHM_POOLS.lock();
247 guard.as_mut().and_then(|pools| pools.remove(&pool_id))
248}
249
250#[derive(Debug, Clone)]
257pub struct Buffer {
258 pub id: u32,
260 pub width: u32,
262 pub height: u32,
264 pub stride: u32,
266 pub format: PixelFormat,
268 pub pool_id: u32,
270 pub pool_buffer_id: u32,
272}
273
274impl Buffer {
275 pub fn new(id: u32, width: u32, height: u32, format: PixelFormat) -> Self {
277 let stride = width * format.bpp();
278 Self {
279 id,
280 width,
281 height,
282 stride,
283 format,
284 pool_id: 0,
285 pool_buffer_id: 0,
286 }
287 }
288
289 pub fn from_pool(
291 id: u32,
292 pool_id: u32,
293 pool_buffer_id: u32,
294 width: u32,
295 height: u32,
296 stride: u32,
297 format: PixelFormat,
298 ) -> Self {
299 Self {
300 id,
301 width,
302 height,
303 stride,
304 format,
305 pool_id,
306 pool_buffer_id,
307 }
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn test_pixel_format_bpp() {
317 assert_eq!(PixelFormat::Argb8888.bpp(), 4);
318 assert_eq!(PixelFormat::Xrgb8888.bpp(), 4);
319 assert_eq!(PixelFormat::Rgb565.bpp(), 2);
320 }
321
322 #[test]
323 fn test_pool_create_buffer() {
324 let mut pool = WlShmPool::new(1, 1, 1024 * 768 * 4);
325 let buf_id = pool
326 .create_buffer(0, 1024, 768, 1024 * 4, PixelFormat::Xrgb8888)
327 .unwrap();
328 assert_eq!(buf_id, 1);
329 let buf = pool.get_buffer(buf_id).unwrap();
330 assert_eq!(buf.width, 1024);
331 assert_eq!(buf.height, 768);
332 }
333
334 #[test]
335 fn test_pool_buffer_out_of_bounds() {
336 let mut pool = WlShmPool::new(1, 1, 100);
337 let result = pool.create_buffer(0, 100, 100, 400, PixelFormat::Argb8888);
339 assert!(result.is_err());
340 }
341
342 #[test]
343 fn test_pool_write_read_pixels() {
344 let mut pool = WlShmPool::new(1, 1, 16);
345 let buf_id = pool
346 .create_buffer(0, 2, 2, 8, PixelFormat::Xrgb8888)
347 .unwrap();
348 let pixels = [0xFFu8; 16];
349 assert!(pool.write_buffer_pixels(buf_id, &pixels));
350 let read = pool.read_buffer_pixels(buf_id).unwrap();
351 assert_eq!(read, &pixels[..]);
352 }
353
354 #[test]
355 fn test_format_from_wl() {
356 assert_eq!(PixelFormat::from_wl_format(0), Some(PixelFormat::Argb8888));
357 assert_eq!(PixelFormat::from_wl_format(1), Some(PixelFormat::Xrgb8888));
358 assert_eq!(PixelFormat::from_wl_format(999), None);
359 }
360}