1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! A Buffer Pool containing and managing HardwareBuffers
16 
17 use std::{
18     collections::HashMap,
19     sync::{Arc, Mutex, Weak},
20 };
21 
22 use nativewindow::*;
23 
24 use crate::StreamConfig;
25 
26 use super::{Buffer, BufferOwner};
27 
28 pub(super) struct BufferPoolInner {
29     size: usize,
30     hardware_buffers: HashMap<u64, HardwareBuffer>,
31     available_buffers: Vec<u64>,
32 }
33 
34 impl BufferPoolInner {
return_buffer(&mut self, buffer_id: u64)35     pub(super) fn return_buffer(&mut self, buffer_id: u64) {
36         assert!(self.hardware_buffers.contains_key(&buffer_id));
37         assert!(!self.available_buffers.contains(&buffer_id));
38 
39         self.available_buffers.push(buffer_id);
40     }
41 }
42 
43 struct BufferPoolOwner(Weak<Mutex<BufferPoolInner>>);
44 
45 impl BufferOwner for BufferPoolOwner {
on_return(&self, buffer: &Buffer)46     fn on_return(&self, buffer: &Buffer) {
47         if let Some(locked_buffer_pool) = self.0.upgrade() {
48             let mut buffer_pool = locked_buffer_pool.lock().unwrap();
49 
50             buffer_pool.return_buffer(buffer.id());
51         }
52     }
53 }
54 
55 /// A thread-safe collection of buffers.
56 ///
57 /// A buffer pool can be of arbitrary size. It creates and then holds references to all buffers
58 /// associated with it.
59 pub struct BufferPool(Arc<Mutex<BufferPoolInner>>);
60 
61 impl BufferPool {
62     /// Creates a new buffer pool of size pool_size. All buffers will be created according to
63     /// the stream config.
64     ///
65     /// This constructor creates all buffers at initialization.
new(pool_size: usize, stream_config: StreamConfig) -> Option<Self>66     pub fn new(pool_size: usize, stream_config: StreamConfig) -> Option<Self> {
67         let mut hardware_buffers = HashMap::new();
68         let mut available_buffers = Vec::new();
69         for _ in 0..pool_size {
70             if let Some(buffer) = stream_config.create_hardware_buffer() {
71                 available_buffers.push(buffer.id());
72                 hardware_buffers.insert(buffer.id(), buffer);
73             } else {
74                 return None;
75             }
76         }
77         Some(Self(Arc::new(Mutex::new(BufferPoolInner {
78             size: pool_size,
79             hardware_buffers,
80             available_buffers,
81         }))))
82     }
83 
84     /// Try to acquire the next available buffer in the buffer pool.
85     ///
86     /// If all buffers are in use it will return None.
next_buffer(&mut self) -> Option<Buffer>87     pub fn next_buffer(&mut self) -> Option<Buffer> {
88         let mut inner = self.0.lock().unwrap();
89         if let Some(buffer_id) = inner.available_buffers.pop() {
90             Some(Buffer::new(
91                 Box::new(BufferPoolOwner(Arc::downgrade(&self.0))),
92                 inner.hardware_buffers[&buffer_id].clone(),
93             ))
94         } else {
95             None
96         }
97     }
98 
99     /// Gets the size of the buffer pool.
size(&self) -> usize100     pub fn size(&self) -> usize {
101         let inner = self.0.lock().unwrap();
102         inner.size
103     }
104 }
105 
106 #[cfg(test)]
107 mod test {
108     use super::*;
109 
110     const STREAM_CONFIG: StreamConfig = StreamConfig {
111         width: 1,
112         height: 1,
113         layers: 1,
114         format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
115         usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
116         stride: 0,
117     };
118 
119     #[test]
buffer_pool_next_buffer()120     fn buffer_pool_next_buffer() {
121         let mut buffer_pool = BufferPool::new(1, STREAM_CONFIG).unwrap();
122         let next_buffer = buffer_pool.next_buffer();
123 
124         assert!(next_buffer.is_some());
125         assert!(buffer_pool.next_buffer().is_none());
126     }
127 
128     #[test]
drop_buffer_returns_to_pool()129     fn drop_buffer_returns_to_pool() {
130         let mut buffer_pool = BufferPool::new(1, STREAM_CONFIG).unwrap();
131         let next_buffer = buffer_pool.next_buffer();
132 
133         assert!(next_buffer.is_some());
134         drop(next_buffer);
135         assert!(buffer_pool.next_buffer().is_some());
136     }
137 }
138