twizzler_display/
lib.rs

1//! This crate provides basic interfaces for working with the compositor and display manager.
2//!
3//! Currently, you can create and manage windows, and fill their framebuffers, and flip that
4//! to the compositor. This interface is unstable, and will be changing.
5
6use std::{
7    cell::UnsafeCell,
8    ops::{Index, IndexMut},
9    sync::atomic::{AtomicU32, AtomicU64, Ordering},
10    u32,
11};
12
13use secgate::util::Handle;
14use twizzler::{
15    error::TwzError,
16    object::{MapFlags, ObjID, Object, ObjectBuilder, TypedObject},
17    ptr::{InvPtr, RefSlice, RefSliceMut},
18    BaseType, Invariant,
19};
20use twizzler_abi::syscall::{
21    sys_thread_sync, ThreadSync, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference,
22    ThreadSyncSleep, ThreadSyncWake,
23};
24
25#[derive(Clone)]
26/// An object holding a double-buffered compositor surface for a window.
27pub struct BufferObject {
28    obj: Object<DisplayBufferBase>,
29}
30
31impl From<Object<DisplayBufferBase>> for BufferObject {
32    fn from(obj: Object<DisplayBufferBase>) -> Self {
33        Self { obj }
34    }
35}
36
37const DBF_PHASE: u64 = 0x1;
38const DBF_COMP_DONE: u64 = 0x2;
39
40const MAX_W: u64 = 8192;
41const MAX_H: u64 = 8192;
42const MAX_BUFFER_SIZE: u64 = MAX_W * MAX_H * 4;
43
44#[derive(Invariant, BaseType)]
45pub struct DisplayBufferBase {
46    pub flags: AtomicU64,
47    pub buffers: [DisplayBuffer; 2],
48}
49
50#[derive(Invariant, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct Rect {
52    pub x: u32,
53    pub y: u32,
54    pub w: u32,
55    pub h: u32,
56}
57
58impl From<WindowConfig> for Rect {
59    fn from(value: WindowConfig) -> Self {
60        Self {
61            x: value.x,
62            y: value.y,
63            w: value.w,
64            h: value.h,
65        }
66    }
67}
68
69impl Rect {
70    pub const fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
71        Self { x, y, w, h }
72    }
73
74    pub const fn full() -> Self {
75        Self {
76            x: 0,
77            y: 0,
78            w: u32::MAX,
79            h: u32::MAX,
80        }
81    }
82
83    pub fn is_covered_by_any(&self, rects: &[Rect]) -> bool {
84        for rect in rects {
85            if rect.x <= self.x
86                && rect.y <= self.y
87                && rect.x + rect.w >= self.x + self.w
88                && rect.y + rect.h >= self.y + self.h
89            {
90                return true;
91            }
92        }
93        false
94    }
95
96    pub fn extent_of(rects: &[Rect]) -> Self {
97        let x = rects.iter().min_by_key(|r| r.x).map(|r| r.x).unwrap_or(0);
98        let y = rects.iter().min_by_key(|r| r.y).map(|r| r.y).unwrap_or(0);
99        Rect {
100            x,
101            y,
102            w: rects
103                .iter()
104                .max_by_key(|r| r.x + r.w)
105                .map(|r| r.x + r.w)
106                .unwrap_or(0)
107                - x,
108            h: rects
109                .iter()
110                .max_by_key(|r| r.y + r.h)
111                .map(|r| r.y + r.h)
112                .unwrap_or(0)
113                - y,
114        }
115    }
116}
117
118const NUM_DAMAGE: usize = 8;
119const FULL_DAMAGE: u64 = 0xFFFFFFFFFFFFFFFF;
120
121#[derive(Invariant)]
122pub struct DisplayBuffer {
123    pub comp_width: AtomicU32,
124    pub comp_height: AtomicU32,
125    pub width: AtomicU32,
126    pub height: AtomicU32,
127    pub byte_len: u64,
128    pub ptr: InvPtr<u32>,
129    pub damage: UnsafeCell<[Rect; NUM_DAMAGE]>,
130    pub damage_count: AtomicU64,
131}
132
133pub struct Buffer<'a> {
134    buffer: &'a [u32],
135    db: &'a DisplayBuffer,
136}
137
138impl<'a> AsRef<[u32]> for Buffer<'a> {
139    fn as_ref(&self) -> &[u32] {
140        self.buffer
141    }
142}
143
144impl<'a> Index<usize> for Buffer<'a> {
145    type Output = u32;
146
147    fn index(&self, index: usize) -> &Self::Output {
148        &self.buffer[index]
149    }
150}
151
152impl<'a> Buffer<'a> {
153    fn new(s: &mut RefSlice<'a, u32>, db: &'a DisplayBuffer) -> Self {
154        Self {
155            buffer: s.as_slice(),
156            db,
157        }
158    }
159
160    pub fn damage_rects(&self) -> &[Rect] {
161        unsafe { self.db.damage() }
162    }
163
164    pub fn len(&self) -> usize {
165        self.buffer.len()
166    }
167
168    pub fn as_slice(&self) -> &[u32] {
169        self.buffer
170    }
171}
172
173pub struct BufferMut<'a> {
174    buffer: &'a mut [u32],
175    db: &'a DisplayBuffer,
176}
177
178impl<'a> AsRef<[u32]> for BufferMut<'a> {
179    fn as_ref(&self) -> &[u32] {
180        self.buffer
181    }
182}
183
184impl<'a> AsMut<[u32]> for BufferMut<'a> {
185    fn as_mut(&mut self) -> &mut [u32] {
186        self.buffer
187    }
188}
189
190impl<'a> Index<usize> for BufferMut<'a> {
191    type Output = u32;
192
193    fn index(&self, index: usize) -> &Self::Output {
194        &self.buffer[index]
195    }
196}
197
198impl<'a> IndexMut<usize> for BufferMut<'a> {
199    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
200        &mut self.buffer[index]
201    }
202}
203
204impl<'a> BufferMut<'a> {
205    fn new(s: &mut RefSliceMut<'a, u32>, db: &'a DisplayBuffer) -> Self {
206        Self {
207            buffer: s.as_slice_mut(),
208            db,
209        }
210    }
211
212    pub fn damage_rects(&self) -> &[Rect] {
213        unsafe { self.db.damage() }
214    }
215
216    pub fn damage(&self, dmg: Rect) {
217        unsafe { self.db.append_damage(dmg) };
218    }
219
220    pub fn len(&self) -> usize {
221        self.buffer.len()
222    }
223
224    pub fn as_slice(&self) -> &[u32] {
225        self.buffer
226    }
227
228    pub fn as_slice_mut(&mut self) -> &mut [u32] {
229        self.buffer
230    }
231}
232
233impl DisplayBuffer {
234    unsafe fn buffer_mut(&self) -> RefSliceMut<'_, u32> {
235        let ptr = self.ptr.resolve().as_mut();
236        let slice = RefSliceMut::from_ref(ptr, self.byte_len as usize);
237        slice
238    }
239
240    unsafe fn buffer(&self) -> RefSlice<'_, u32> {
241        let ptr = self.ptr.resolve();
242        let slice = RefSlice::from_ref(ptr, self.byte_len as usize);
243        slice
244    }
245
246    unsafe fn append_damage(&self, dmg: Rect) {
247        let current_count = self.damage_count.load(Ordering::SeqCst);
248        if current_count == FULL_DAMAGE {
249            return;
250        }
251        let damage = self.damage.get().as_mut().unwrap_unchecked();
252        if current_count as usize == NUM_DAMAGE {
253            damage[0] = Rect::extent_of(&damage.as_slice()[..(current_count as usize)]);
254            self.damage_count.store(1, Ordering::Release);
255            return;
256        }
257
258        if dmg.is_covered_by_any(&damage[..(current_count as usize)]) {
259            return;
260        }
261
262        damage[current_count as usize] = dmg;
263        self.damage_count.fetch_add(1, Ordering::Release);
264    }
265
266    unsafe fn reset_damage(&self) {
267        self.damage_count.store(0, Ordering::SeqCst);
268    }
269
270    unsafe fn damage(&self) -> &[Rect] {
271        const FD: [Rect; 1] = [Rect::full()];
272        let count = self.damage_count.load(Ordering::Acquire);
273        if count == FULL_DAMAGE {
274            return &FD;
275        }
276        &self.damage.get().as_ref().unwrap_unchecked()[..count as usize]
277    }
278}
279
280impl BufferObject {
281    pub fn id(&self) -> ObjID {
282        self.obj.id()
283    }
284
285    pub fn create_new(w: u32, h: u32) -> Result<Self, TwzError> {
286        let builder = ObjectBuilder::default();
287        let obj = builder.build_inplace(|mut obj| {
288            let buf1 = obj.static_alloc(0).unwrap();
289            let buf2 = obj.static_alloc(0).unwrap();
290
291            let base = DisplayBufferBase {
292                flags: AtomicU64::new(0),
293                buffers: [
294                    DisplayBuffer {
295                        comp_width: AtomicU32::new(w),
296                        comp_height: AtomicU32::new(h),
297                        width: AtomicU32::new(w),
298                        height: AtomicU32::new(h),
299                        byte_len: MAX_BUFFER_SIZE,
300                        ptr: InvPtr::from_raw_parts(0, buf1.offset()),
301                        damage_count: AtomicU64::new(0),
302                        damage: UnsafeCell::new([Rect::full(); NUM_DAMAGE]),
303                    },
304                    DisplayBuffer {
305                        comp_width: AtomicU32::new(w),
306                        comp_height: AtomicU32::new(h),
307                        width: AtomicU32::new(w),
308                        height: AtomicU32::new(h),
309                        byte_len: MAX_BUFFER_SIZE,
310                        ptr: InvPtr::from_raw_parts(0, buf2.offset()),
311                        damage_count: AtomicU64::new(0),
312                        damage: UnsafeCell::new([Rect::full(); NUM_DAMAGE]),
313                    },
314                ],
315            };
316            obj.write(base)
317        })?;
318
319        Ok(BufferObject { obj })
320    }
321
322    /// Returns true if the buffers currently need to be read out.
323    pub fn has_data_for_read(&self) -> bool {
324        self.obj.base().flags.load(Ordering::SeqCst) & DBF_COMP_DONE == 0
325    }
326
327    /// Read out the compositor buffer.
328    pub fn read_buffer<R>(&self, mut f: impl FnMut(Buffer, u32, u32) -> R) -> R {
329        let base = self.obj.base();
330        let flags = base.flags.load(Ordering::SeqCst);
331
332        let buffer = if flags & DBF_PHASE != 0 {
333            &base.buffers[0]
334        } else {
335            &base.buffers[1]
336        };
337        let cw = buffer.width.load(Ordering::SeqCst);
338        let ch = buffer.height.load(Ordering::SeqCst);
339        let buf = unsafe { buffer.buffer() };
340        let mut buf = buf.slice(0..((cw * ch) as usize));
341        let r = f(Buffer::new(&mut buf, buffer), cw, ch);
342        r
343    }
344
345    /// Mark that the compositor has finished reading the buffer. Provides the new width and height
346    /// to use next time this buffer should be filled out. These values may be unchanged.
347    pub fn read_done(&self, new_w: u32, new_h: u32) {
348        let base = self.obj.base();
349        let flags = base.flags.load(Ordering::SeqCst);
350        let buffer = if flags & DBF_PHASE != 0 {
351            &base.buffers[0]
352        } else {
353            &base.buffers[1]
354        };
355        buffer.comp_height.store(new_h, Ordering::Release);
356        buffer.comp_width.store(new_w, Ordering::Release);
357        unsafe { buffer.reset_damage() };
358        base.flags.fetch_or(DBF_COMP_DONE, Ordering::SeqCst);
359        let _ = sys_thread_sync(
360            &mut [ThreadSync::new_wake(ThreadSyncWake::new(
361                ThreadSyncReference::Virtual(&base.flags),
362                usize::MAX,
363            ))],
364            None,
365        );
366    }
367
368    /// Fill the current application-owned buffer with data within the callback.
369    pub fn update_buffer<R>(&self, mut f: impl FnMut(BufferMut, u32, u32) -> R) -> R {
370        let base = self.obj.base();
371        let flags = base.flags.load(Ordering::SeqCst);
372
373        let buffer = if flags & DBF_PHASE != 0 {
374            &base.buffers[1]
375        } else {
376            &base.buffers[0]
377        };
378        let cw = buffer.comp_width.load(Ordering::SeqCst);
379        let ch = buffer.comp_height.load(Ordering::SeqCst);
380
381        let buf = unsafe { buffer.buffer_mut() };
382        let mut buf = buf.slice(0..((cw * ch) as usize));
383        let r = f(BufferMut::new(&mut buf, buffer), cw, ch);
384        buffer.height.store(ch, Ordering::Release);
385        buffer.width.store(cw, Ordering::Release);
386        r
387    }
388
389    /// Flip the buffer, indicating that the compositor can now read the buffer.
390    pub fn flip(&self) {
391        let base = self.obj.base();
392        let mut flags = base.flags.load(Ordering::SeqCst);
393
394        while flags & DBF_COMP_DONE == 0 {
395            let _ = sys_thread_sync(
396                &mut [ThreadSync::new_sleep(ThreadSyncSleep::new(
397                    ThreadSyncReference::Virtual(&base.flags),
398                    flags,
399                    ThreadSyncOp::Equal,
400                    ThreadSyncFlags::empty(),
401                ))],
402                None,
403            );
404            flags = base.flags.load(Ordering::SeqCst);
405        }
406
407        let (src_buffer, dst_buffer) = if flags & DBF_PHASE != 0 {
408            (&base.buffers[0], &base.buffers[1])
409        } else {
410            (&base.buffers[1], &base.buffers[0])
411        };
412
413        let w = src_buffer.width.load(Ordering::Acquire);
414        let h = src_buffer.height.load(Ordering::Acquire);
415        for dmg in unsafe { src_buffer.damage() } {
416            for y in dmg.y..(dmg.y + dmg.h.min(h - dmg.y)) {
417                let start = (y * w + dmg.x) as usize;
418                let len = dmg.w.min(w - dmg.x) as usize;
419                let src = &unsafe { src_buffer.buffer().as_slice() }[start..(start + len)];
420                let dst =
421                    &mut unsafe { dst_buffer.buffer_mut().as_slice_mut() }[start..(start + len)];
422                dst.copy_from_slice(src);
423            }
424        }
425
426        let new_flags = (flags ^ DBF_PHASE) & !DBF_COMP_DONE;
427        base.flags.store(new_flags, Ordering::SeqCst);
428
429        let _ = sys_thread_sync(
430            &mut [ThreadSync::new_wake(ThreadSyncWake::new(
431                ThreadSyncReference::Virtual(&base.flags),
432                usize::MAX,
433            ))],
434            None,
435        );
436    }
437}
438
439#[secgate::gatecall]
440pub fn start_display() -> Result<(), TwzError> {}
441#[secgate::gatecall]
442pub fn create_window(winfo: WindowConfig) -> Result<(ObjID, u32), TwzError> {}
443#[secgate::gatecall]
444pub fn drop_window(handle: u32) -> Result<(), TwzError> {}
445#[secgate::gatecall]
446pub fn reconfigure_window(handle: u32, wconfig: WindowConfig) -> Result<(), TwzError> {}
447#[secgate::gatecall]
448pub fn get_window_config(handle: u32) -> Result<WindowConfig, TwzError> {}
449#[secgate::gatecall]
450pub fn get_display_info() -> Result<WindowConfig, TwzError> {}
451
452#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
453#[repr(C)]
454pub struct WindowConfig {
455    pub w: u32,
456    pub h: u32,
457    pub x: u32,
458    pub y: u32,
459    pub z: u32,
460}
461#[repr(C)]
462/// A window handle for the compositor. Provides a compositing buffer.
463pub struct WindowHandle {
464    key: u32,
465    pub window_buffer: BufferObject,
466}
467
468impl WindowHandle {
469    /// Change window parameters, such as position, size, or z-sorting.
470    pub fn reconfigure(&self, wconfig: WindowConfig) -> Result<(), TwzError> {
471        reconfigure_window(self.key, wconfig)
472    }
473
474    /// Get the current window configuration.
475    pub fn get_config(&self) -> Result<WindowConfig, TwzError> {
476        get_window_config(self.key)
477    }
478}
479
480impl Drop for WindowHandle {
481    fn drop(&mut self) {
482        self.release();
483    }
484}
485
486impl Handle for WindowHandle {
487    type OpenError = TwzError;
488
489    type OpenInfo = WindowConfig;
490
491    fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
492    where
493        Self: Sized,
494    {
495        let (id, key) = create_window(info)?;
496        Ok(WindowHandle {
497            key,
498            window_buffer: BufferObject::from(unsafe {
499                Object::map_unchecked(id, MapFlags::READ | MapFlags::WRITE)
500            }?),
501        })
502    }
503
504    fn release(&mut self) {
505        let _ = drop_window(self.key);
506    }
507}