use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::rc::Rc;
use std::rc::Weak;
use libva::Display;
use libva::Surface;
use libva::SurfaceMemoryDescriptor;
use libva::VASurfaceID;
use crate::decoder::FramePool;
use crate::Resolution;
pub struct PooledVaSurface<M: SurfaceMemoryDescriptor> {
surface: Option<Surface<M>>,
pool: Weak<RefCell<VaSurfacePoolInner<M>>>,
}
impl<M: SurfaceMemoryDescriptor> PooledVaSurface<M> {
fn new(surface: Surface<M>, pool: &Rc<RefCell<VaSurfacePoolInner<M>>>) -> Self {
Self { surface: Some(surface), pool: Rc::downgrade(pool) }
}
pub fn detach_from_pool(mut self) -> Surface<M> {
let surface = self.surface.take().unwrap();
if let Some(pool) = self.pool.upgrade() {
(*pool).borrow_mut().managed_surfaces.remove(&surface.id());
}
surface
}
}
impl<M: SurfaceMemoryDescriptor> Borrow<Surface<M>> for PooledVaSurface<M> {
fn borrow(&self) -> &Surface<M> {
self.surface.as_ref().unwrap()
}
}
impl<M: SurfaceMemoryDescriptor> AsRef<M> for PooledVaSurface<M> {
fn as_ref(&self) -> &M {
<Self as Borrow<Surface<M>>>::borrow(self).as_ref()
}
}
impl<M: SurfaceMemoryDescriptor> Drop for PooledVaSurface<M> {
fn drop(&mut self) {
if let Some(surface) = self.surface.take() {
if let Some(pool) = self.pool.upgrade() {
let mut pool_borrowed = (*pool).borrow_mut();
if pool_borrowed.managed_surfaces.contains_key(&surface.id()) {
pool_borrowed.surfaces.push_back(surface);
return;
}
}
log::debug!("Dropping stale surface: {}, ({:?})", surface.id(), surface.size())
}
}
}
struct VaSurfacePoolInner<M: SurfaceMemoryDescriptor> {
display: Rc<Display>,
rt_format: u32,
usage_hint: Option<libva::UsageHint>,
coded_resolution: Resolution,
surfaces: VecDeque<Surface<M>>,
managed_surfaces: BTreeMap<VASurfaceID, Resolution>,
}
pub struct VaSurfacePool<M: SurfaceMemoryDescriptor> {
inner: Rc<RefCell<VaSurfacePoolInner<M>>>,
}
impl<M: SurfaceMemoryDescriptor> VaSurfacePool<M> {
#[allow(dead_code)]
fn add_surface(&mut self, surface: Surface<M>) -> Result<(), Surface<M>> {
let mut inner = (*self.inner).borrow_mut();
if Resolution::from(surface.size()).can_contain(inner.coded_resolution) {
inner.managed_surfaces.insert(surface.id(), surface.size().into());
inner.surfaces.push_back(surface);
Ok(())
} else {
Err(surface)
}
}
pub fn new(
display: Rc<Display>,
rt_format: u32,
usage_hint: Option<libva::UsageHint>,
coded_resolution: Resolution,
) -> Self {
Self {
inner: Rc::new(RefCell::new(VaSurfacePoolInner {
display,
rt_format,
usage_hint,
coded_resolution,
surfaces: VecDeque::new(),
managed_surfaces: Default::default(),
})),
}
}
pub fn get_surface(&mut self) -> Option<PooledVaSurface<M>> {
let mut inner = (*self.inner).borrow_mut();
let surface = inner.surfaces.pop_front();
debug_assert!({
match surface.as_ref() {
Some(s) => Resolution::from(s.size()).can_contain(inner.coded_resolution),
None => true,
}
});
surface.map(|s| PooledVaSurface::new(s, &self.inner))
}
}
impl<M: SurfaceMemoryDescriptor> FramePool for VaSurfacePool<M> {
type Descriptor = M;
fn coded_resolution(&self) -> Resolution {
(*self.inner).borrow().coded_resolution
}
fn set_coded_resolution(&mut self, resolution: Resolution) {
let mut inner = (*self.inner).borrow_mut();
inner.coded_resolution = resolution;
inner.managed_surfaces.retain(|_, res| res.can_contain(resolution));
inner.surfaces.retain(|s| Resolution::from(s.size()).can_contain(resolution));
}
fn add_frames(&mut self, descriptors: Vec<Self::Descriptor>) -> Result<(), anyhow::Error> {
let mut inner = (*self.inner).borrow_mut();
let surfaces = inner
.display
.create_surfaces(
inner.rt_format,
None,
inner.coded_resolution.width,
inner.coded_resolution.height,
inner.usage_hint,
descriptors,
)
.map_err(|e| anyhow::anyhow!(e))?;
for surface in &surfaces {
inner.managed_surfaces.insert(surface.id(), surface.size().into());
}
inner.surfaces.extend(surfaces);
Ok(())
}
fn num_free_frames(&self) -> usize {
(*self.inner).borrow().surfaces.len()
}
fn num_managed_frames(&self) -> usize {
(*self.inner).borrow().managed_surfaces.len()
}
fn clear(&mut self) {
let mut pool = (*self.inner).borrow_mut();
pool.surfaces.clear();
pool.managed_surfaces.clear();
}
}