use std::collections::HashMap;
use drmkit_core::{Device, Result as CoreResult};
use crate::hdr::{HdrBlob, HdrMetadataBlob, HdrSourceMetadata, hdr_metadata_hash};
#[derive(Debug)]
struct Entry<B> {
blob: B,
hash: u64,
}
#[derive(Debug)]
pub struct HdrMetadataCache<B> {
active: HashMap<u32, Entry<B>>,
pending_destruction: Vec<B>,
}
impl<B> Default for HdrMetadataCache<B> {
fn default() -> Self {
Self::new()
}
}
impl<B> HdrMetadataCache<B> {
#[must_use]
pub fn new() -> Self {
Self {
active: HashMap::new(),
pending_destruction: Vec::new(),
}
}
#[must_use]
pub fn pending_destruction_count(&self) -> usize {
self.pending_destruction.len()
}
pub fn acknowledge_committed(&mut self) {
self.pending_destruction.clear();
}
}
impl<B: HdrBlob> HdrMetadataCache<B> {
#[must_use]
pub fn current_blob_id(&self, crtc_id: u32) -> u32 {
self.active
.get(&crtc_id)
.map_or(0, |entry| entry.blob.blob_id())
}
#[must_use]
pub fn current_content_hash(&self, crtc_id: u32) -> u64 {
self.active.get(&crtc_id).map_or(0, |entry| entry.hash)
}
pub fn set_with<E, F>(
&mut self,
crtc_id: u32,
src: Option<&HdrSourceMetadata>,
factory: F,
) -> Result<u32, E>
where
F: FnOnce(&HdrSourceMetadata) -> Result<B, E>,
{
let Some(src) = src else {
if let Some(entry) = self.active.remove(&crtc_id) {
self.pending_destruction.push(entry.blob);
}
return Ok(0);
};
let hash = hdr_metadata_hash(src);
if let Some(entry) = self.active.get(&crtc_id)
&& entry.hash == hash
{
return Ok(entry.blob.blob_id());
}
let blob = factory(src)?;
let blob_id = blob.blob_id();
if let Some(previous) = self.active.insert(crtc_id, Entry { blob, hash }) {
self.pending_destruction.push(previous.blob);
}
Ok(blob_id)
}
pub fn clear_for_session_loss(&mut self) {
for (_, entry) in self.active.drain() {
entry.blob.forget();
}
for blob in self.pending_destruction.drain(..) {
blob.forget();
}
}
pub fn flush(&mut self) {
self.active.clear();
self.pending_destruction.clear();
}
}
impl<'a> HdrMetadataCache<HdrMetadataBlob<'a>> {
pub fn set(
&mut self,
device: &'a Device,
crtc_id: u32,
src: Option<&HdrSourceMetadata>,
) -> CoreResult<u32> {
self.set_with(crtc_id, src, |s| HdrMetadataBlob::create(device, s))
}
}