fuchsia_framebuffer/
lib.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use display_utils::BufferCollectionId;
6use std::collections::BTreeSet;
7
8pub mod sysmem;
9
10#[cfg(test)]
11use std::ops::Range;
12
13// TODO(https://fxbug.dev/42080389): Use display_utils structs instead.
14pub type ImageId = u64;
15
16#[derive(Debug)]
17pub struct FrameSet {
18    // TODO(https://fxbug.dev/42165549)
19    #[allow(unused)]
20    collection_id: BufferCollectionId,
21    image_count: usize,
22    available: BTreeSet<ImageId>,
23    pub prepared: Option<ImageId>,
24    presented: BTreeSet<ImageId>,
25}
26
27impl FrameSet {
28    pub fn new(collection_id: BufferCollectionId, available: BTreeSet<ImageId>) -> FrameSet {
29        FrameSet {
30            collection_id,
31            image_count: available.len(),
32            available,
33            prepared: None,
34            presented: BTreeSet::new(),
35        }
36    }
37
38    #[cfg(test)]
39    pub fn new_with_range(r: Range<ImageId>) -> FrameSet {
40        let mut available = BTreeSet::new();
41        for image_id in r {
42            available.insert(image_id);
43        }
44        Self::new(BufferCollectionId(0), available)
45    }
46
47    pub fn mark_presented(&mut self, image_id: ImageId) {
48        assert!(
49            !self.presented.contains(&image_id),
50            "Attempted to mark as presented image {} which was already in the presented image set",
51            image_id
52        );
53        self.presented.insert(image_id);
54        self.prepared = None;
55    }
56
57    pub fn mark_done_presenting(&mut self, image_id: ImageId) {
58        assert!(
59            self.presented.remove(&image_id),
60            "Attempted to mark as freed image {} which was not the presented image",
61            image_id
62        );
63        self.available.insert(image_id);
64    }
65
66    pub fn mark_prepared(&mut self, image_id: ImageId) {
67        assert!(self.prepared.is_none(), "Trying to mark image {} as prepared when image {} is prepared and has not been presented", image_id, self.prepared.unwrap());
68        self.prepared.replace(image_id);
69        self.available.remove(&image_id);
70    }
71
72    pub fn get_available_image(&mut self) -> Option<ImageId> {
73        let first = self.available.iter().next().map(|a| *a);
74        if let Some(first) = first {
75            self.available.remove(&first);
76        }
77        first
78    }
79
80    pub fn return_image(&mut self, image_id: ImageId) {
81        self.available.insert(image_id);
82    }
83
84    pub fn no_images_in_use(&self) -> bool {
85        self.available.len() == self.image_count
86    }
87}
88
89#[cfg(test)]
90mod frameset_tests {
91    use crate::{FrameSet, ImageId};
92    use std::ops::Range;
93
94    const IMAGE_RANGE: Range<ImageId> = 200..202;
95
96    #[fuchsia::test]
97    #[should_panic]
98    fn test_double_prepare() {
99        let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
100
101        fs.mark_prepared(100);
102        fs.mark_prepared(200);
103    }
104
105    #[fuchsia::test]
106    #[should_panic]
107    fn test_not_presented() {
108        let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
109        fs.mark_done_presenting(100);
110    }
111
112    #[fuchsia::test]
113    #[should_panic]
114    fn test_already_presented() {
115        let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
116        fs.mark_presented(100);
117        fs.mark_presented(100);
118    }
119
120    #[fuchsia::test]
121    fn test_basic_use() {
122        let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
123        let avail = fs.get_available_image();
124        assert!(avail.is_some());
125        let avail = avail.unwrap();
126        assert!(!fs.available.contains(&avail));
127        assert!(!fs.presented.contains(&avail));
128        fs.mark_prepared(avail);
129        assert_eq!(fs.prepared.unwrap(), avail);
130        fs.mark_presented(avail);
131        assert!(fs.prepared.is_none());
132        assert!(!fs.available.contains(&avail));
133        assert!(fs.presented.contains(&avail));
134        fs.mark_done_presenting(avail);
135        assert!(fs.available.contains(&avail));
136        assert!(!fs.presented.contains(&avail));
137    }
138}
139
140// TODO: this should eventually be removed in favor of client adding
141// CPU access requirements if needed
142#[derive(Debug, Clone, Copy, PartialEq)]
143pub enum FrameUsage {
144    Cpu,
145    Gpu,
146}