blob: b7ad4bc73afb06a1c58ed7094c309e3c182c7d07 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use display_utils::BufferCollectionId;
use std::collections::BTreeSet;
pub mod sysmem;
#[cfg(test)]
use std::ops::Range;
// TODO(https://fxbug.dev/42080389): Use display_utils structs instead.
pub type ImageId = u64;
#[derive(Debug)]
pub struct FrameSet {
// TODO(https://fxbug.dev/42165549)
#[allow(unused)]
collection_id: BufferCollectionId,
image_count: usize,
available: BTreeSet<ImageId>,
pub prepared: Option<ImageId>,
presented: BTreeSet<ImageId>,
}
impl FrameSet {
pub fn new(collection_id: BufferCollectionId, available: BTreeSet<ImageId>) -> FrameSet {
FrameSet {
collection_id,
image_count: available.len(),
available,
prepared: None,
presented: BTreeSet::new(),
}
}
#[cfg(test)]
pub fn new_with_range(r: Range<ImageId>) -> FrameSet {
let mut available = BTreeSet::new();
for image_id in r {
available.insert(image_id);
}
Self::new(BufferCollectionId(0), available)
}
pub fn mark_presented(&mut self, image_id: ImageId) {
assert!(
!self.presented.contains(&image_id),
"Attempted to mark as presented image {} which was already in the presented image set",
image_id
);
self.presented.insert(image_id);
self.prepared = None;
}
pub fn mark_done_presenting(&mut self, image_id: ImageId) {
assert!(
self.presented.remove(&image_id),
"Attempted to mark as freed image {} which was not the presented image",
image_id
);
self.available.insert(image_id);
}
pub fn mark_prepared(&mut self, image_id: ImageId) {
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());
self.prepared.replace(image_id);
self.available.remove(&image_id);
}
pub fn get_available_image(&mut self) -> Option<ImageId> {
let first = self.available.iter().next().map(|a| *a);
if let Some(first) = first {
self.available.remove(&first);
}
first
}
pub fn return_image(&mut self, image_id: ImageId) {
self.available.insert(image_id);
}
pub fn no_images_in_use(&self) -> bool {
self.available.len() == self.image_count
}
}
#[cfg(test)]
mod frameset_tests {
use crate::{FrameSet, ImageId};
use std::ops::Range;
const IMAGE_RANGE: Range<ImageId> = 200..202;
#[test]
#[should_panic]
fn test_double_prepare() {
let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
fs.mark_prepared(100);
fs.mark_prepared(200);
}
#[test]
#[should_panic]
fn test_not_presented() {
let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
fs.mark_done_presenting(100);
}
#[test]
#[should_panic]
fn test_already_presented() {
let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
fs.mark_presented(100);
fs.mark_presented(100);
}
#[test]
fn test_basic_use() {
let mut fs = FrameSet::new_with_range(IMAGE_RANGE);
let avail = fs.get_available_image();
assert!(avail.is_some());
let avail = avail.unwrap();
assert!(!fs.available.contains(&avail));
assert!(!fs.presented.contains(&avail));
fs.mark_prepared(avail);
assert_eq!(fs.prepared.unwrap(), avail);
fs.mark_presented(avail);
assert!(fs.prepared.is_none());
assert!(!fs.available.contains(&avail));
assert!(fs.presented.contains(&avail));
fs.mark_done_presenting(avail);
assert!(fs.available.contains(&avail));
assert!(!fs.presented.contains(&avail));
}
}
// TODO: this should eventually be removed in favor of client adding
// CPU access requirements if needed
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameUsage {
Cpu,
Gpu,
}