• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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