1 // Copyright 2023 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::borrow::Borrow; 6 use std::cell::RefCell; 7 use std::collections::BTreeMap; 8 use std::collections::VecDeque; 9 use std::rc::Rc; 10 use std::rc::Weak; 11 12 use libva::Display; 13 use libva::Surface; 14 use libva::SurfaceMemoryDescriptor; 15 use libva::VASurfaceID; 16 17 use crate::decoder::FramePool; 18 use crate::Resolution; 19 20 /// A VA Surface obtained from a `[SurfacePool]`. 21 /// 22 /// The surface will automatically be returned to its pool upon dropping, provided the pool still 23 /// exists and the surface is still compatible with it. 24 pub struct PooledVaSurface<M: SurfaceMemoryDescriptor> { 25 surface: Option<Surface<M>>, 26 pool: Weak<RefCell<VaSurfacePoolInner<M>>>, 27 } 28 29 impl<M: SurfaceMemoryDescriptor> PooledVaSurface<M> { new(surface: Surface<M>, pool: &Rc<RefCell<VaSurfacePoolInner<M>>>) -> Self30 fn new(surface: Surface<M>, pool: &Rc<RefCell<VaSurfacePoolInner<M>>>) -> Self { 31 Self { surface: Some(surface), pool: Rc::downgrade(pool) } 32 } 33 34 /// Detach this surface from the pool. It will not be returned, and we can dispose of it 35 /// freely. detach_from_pool(mut self) -> Surface<M>36 pub fn detach_from_pool(mut self) -> Surface<M> { 37 // `unwrap` will never fail as `surface` is `Some` up to this point. 38 let surface = self.surface.take().unwrap(); 39 40 if let Some(pool) = self.pool.upgrade() { 41 (*pool).borrow_mut().managed_surfaces.remove(&surface.id()); 42 } 43 44 surface 45 } 46 } 47 48 impl<M: SurfaceMemoryDescriptor> Borrow<Surface<M>> for PooledVaSurface<M> { borrow(&self) -> &Surface<M>49 fn borrow(&self) -> &Surface<M> { 50 // `unwrap` will never fail as `surface` is `Some` until the object is dropped. 51 self.surface.as_ref().unwrap() 52 } 53 } 54 55 impl<M: SurfaceMemoryDescriptor> AsRef<M> for PooledVaSurface<M> { as_ref(&self) -> &M56 fn as_ref(&self) -> &M { 57 <Self as Borrow<Surface<M>>>::borrow(self).as_ref() 58 } 59 } 60 61 impl<M: SurfaceMemoryDescriptor> Drop for PooledVaSurface<M> { drop(&mut self)62 fn drop(&mut self) { 63 // If the surface has not been detached... 64 if let Some(surface) = self.surface.take() { 65 // ... and the pool still exists... 66 if let Some(pool) = self.pool.upgrade() { 67 let mut pool_borrowed = (*pool).borrow_mut(); 68 // ... and the pool is still managing this surface, return it. 69 if pool_borrowed.managed_surfaces.contains_key(&surface.id()) { 70 pool_borrowed.surfaces.push_back(surface); 71 return; 72 } 73 } 74 75 // The surface cannot be returned to the pool and can be gracefully dropped. 76 log::debug!("Dropping stale surface: {}, ({:?})", surface.id(), surface.size()) 77 } 78 } 79 } 80 81 struct VaSurfacePoolInner<M: SurfaceMemoryDescriptor> { 82 display: Rc<Display>, 83 rt_format: u32, 84 usage_hint: Option<libva::UsageHint>, 85 coded_resolution: Resolution, 86 surfaces: VecDeque<Surface<M>>, 87 /// All the surfaces managed by this pool, indexed by their surface ID. We keep their 88 /// resolution so we can remove them in case of a coded resolution change even if they 89 /// are currently borrowed. 90 managed_surfaces: BTreeMap<VASurfaceID, Resolution>, 91 } 92 93 /// A surface pool to reduce the number of costly Surface allocations. 94 /// 95 /// The pool only houses Surfaces that fits the pool's coded resolution. 96 /// Stale surfaces are dropped when either the pool resolution changes, or when 97 /// stale surfaces are retrieved. 98 /// 99 /// This means that this pool is suitable for inter-frame DRC, as the stale 100 /// surfaces will gracefully be dropped, which is arguably better than the 101 /// alternative of having more than one pool active at a time. 102 pub struct VaSurfacePool<M: SurfaceMemoryDescriptor> { 103 inner: Rc<RefCell<VaSurfacePoolInner<M>>>, 104 } 105 106 impl<M: SurfaceMemoryDescriptor> VaSurfacePool<M> { 107 /// Add a surface to the pool. 108 /// 109 /// This can be an entirely new surface, or one that has been previously obtained using 110 /// `get_surface` and is returned. 111 /// 112 /// Returns an error (and the passed `surface` back) if the surface is not at least as 113 /// large as the current coded resolution of the pool. 114 #[allow(dead_code)] add_surface(&mut self, surface: Surface<M>) -> Result<(), Surface<M>>115 fn add_surface(&mut self, surface: Surface<M>) -> Result<(), Surface<M>> { 116 let mut inner = (*self.inner).borrow_mut(); 117 118 if Resolution::from(surface.size()).can_contain(inner.coded_resolution) { 119 inner.managed_surfaces.insert(surface.id(), surface.size().into()); 120 inner.surfaces.push_back(surface); 121 Ok(()) 122 } else { 123 Err(surface) 124 } 125 } 126 127 /// Create a new pool. 128 /// 129 // # Arguments 130 /// 131 /// * `display` - the VA display to create the surfaces from. 132 /// * `rt_format` - the VA RT format to use for the surfaces. 133 /// * `usage_hint` - hint about how the surfaces from this pool will be used. 134 /// * `coded_resolution` - resolution of the surfaces. new( display: Rc<Display>, rt_format: u32, usage_hint: Option<libva::UsageHint>, coded_resolution: Resolution, ) -> Self135 pub fn new( 136 display: Rc<Display>, 137 rt_format: u32, 138 usage_hint: Option<libva::UsageHint>, 139 coded_resolution: Resolution, 140 ) -> Self { 141 Self { 142 inner: Rc::new(RefCell::new(VaSurfacePoolInner { 143 display, 144 rt_format, 145 usage_hint, 146 coded_resolution, 147 surfaces: VecDeque::new(), 148 managed_surfaces: Default::default(), 149 })), 150 } 151 } 152 153 /// Gets a free surface from the pool. get_surface(&mut self) -> Option<PooledVaSurface<M>>154 pub fn get_surface(&mut self) -> Option<PooledVaSurface<M>> { 155 let mut inner = (*self.inner).borrow_mut(); 156 let surface = inner.surfaces.pop_front(); 157 158 // Make sure the invariant holds when debugging. Can save costly 159 // debugging time during future refactors, if any. 160 debug_assert!({ 161 match surface.as_ref() { 162 Some(s) => Resolution::from(s.size()).can_contain(inner.coded_resolution), 163 None => true, 164 } 165 }); 166 167 surface.map(|s| PooledVaSurface::new(s, &self.inner)) 168 } 169 } 170 171 impl<M: SurfaceMemoryDescriptor> FramePool for VaSurfacePool<M> { 172 type Descriptor = M; 173 coded_resolution(&self) -> Resolution174 fn coded_resolution(&self) -> Resolution { 175 (*self.inner).borrow().coded_resolution 176 } 177 set_coded_resolution(&mut self, resolution: Resolution)178 fn set_coded_resolution(&mut self, resolution: Resolution) { 179 let mut inner = (*self.inner).borrow_mut(); 180 181 inner.coded_resolution = resolution; 182 inner.managed_surfaces.retain(|_, res| res.can_contain(resolution)); 183 inner.surfaces.retain(|s| Resolution::from(s.size()).can_contain(resolution)); 184 } 185 add_frames(&mut self, descriptors: Vec<Self::Descriptor>) -> Result<(), anyhow::Error>186 fn add_frames(&mut self, descriptors: Vec<Self::Descriptor>) -> Result<(), anyhow::Error> { 187 let mut inner = (*self.inner).borrow_mut(); 188 189 let surfaces = inner 190 .display 191 .create_surfaces( 192 inner.rt_format, 193 // Let the hardware decide the best internal format - we will get the desired fourcc 194 // when creating the image. 195 None, 196 inner.coded_resolution.width, 197 inner.coded_resolution.height, 198 inner.usage_hint, 199 descriptors, 200 ) 201 .map_err(|e| anyhow::anyhow!(e))?; 202 203 for surface in &surfaces { 204 inner.managed_surfaces.insert(surface.id(), surface.size().into()); 205 } 206 inner.surfaces.extend(surfaces); 207 208 Ok(()) 209 } 210 num_free_frames(&self) -> usize211 fn num_free_frames(&self) -> usize { 212 (*self.inner).borrow().surfaces.len() 213 } 214 num_managed_frames(&self) -> usize215 fn num_managed_frames(&self) -> usize { 216 (*self.inner).borrow().managed_surfaces.len() 217 } 218 clear(&mut self)219 fn clear(&mut self) { 220 let mut pool = (*self.inner).borrow_mut(); 221 222 pool.surfaces.clear(); 223 pool.managed_surfaces.clear(); 224 } 225 } 226