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