#[cfg(any(feature = "graphics", feature = "compute"))]
use std::collections::HashMap;
pub struct PipelineCache {
#[cfg(feature = "graphics")]
render_pipelines: HashMap<u64, crate::render_pipeline::RenderPipeline>,
#[cfg(feature = "compute")]
compute_pipelines: HashMap<u64, crate::compute::ComputePipeline>,
}
impl PipelineCache {
#[must_use]
pub fn new() -> Self {
Self {
#[cfg(feature = "graphics")]
render_pipelines: HashMap::new(),
#[cfg(feature = "compute")]
compute_pipelines: HashMap::new(),
}
}
#[cfg(feature = "graphics")]
pub fn get_or_insert_render(
&mut self,
key: u64,
create_fn: impl FnOnce() -> crate::render_pipeline::RenderPipeline,
) -> &crate::render_pipeline::RenderPipeline {
self.render_pipelines.entry(key).or_insert_with(|| {
tracing::debug!(key, "pipeline cache: compiling render pipeline");
create_fn()
})
}
#[cfg(feature = "compute")]
pub fn get_or_insert_compute(
&mut self,
key: u64,
create_fn: impl FnOnce() -> crate::compute::ComputePipeline,
) -> &crate::compute::ComputePipeline {
self.compute_pipelines.entry(key).or_insert_with(|| {
tracing::debug!(key, "pipeline cache: compiling compute pipeline");
create_fn()
})
}
#[cfg(feature = "graphics")]
#[must_use]
#[inline]
pub fn contains_render(&self, key: u64) -> bool {
self.render_pipelines.contains_key(&key)
}
#[cfg(feature = "compute")]
#[must_use]
#[inline]
pub fn contains_compute(&self, key: u64) -> bool {
self.compute_pipelines.contains_key(&key)
}
#[cfg(feature = "graphics")]
#[must_use]
pub fn get_render(&self, key: u64) -> Option<&crate::render_pipeline::RenderPipeline> {
self.render_pipelines.get(&key)
}
#[cfg(feature = "compute")]
#[must_use]
pub fn get_compute(&self, key: u64) -> Option<&crate::compute::ComputePipeline> {
self.compute_pipelines.get(&key)
}
#[cfg(feature = "graphics")]
pub fn invalidate_render(&mut self, key: u64) -> bool {
let removed = self.render_pipelines.remove(&key).is_some();
if removed {
tracing::debug!(key, "pipeline cache: invalidated render pipeline");
}
removed
}
#[cfg(feature = "compute")]
pub fn invalidate_compute(&mut self, key: u64) -> bool {
let removed = self.compute_pipelines.remove(&key).is_some();
if removed {
tracing::debug!(key, "pipeline cache: invalidated compute pipeline");
}
removed
}
pub fn clear(&mut self) {
#[cfg(feature = "graphics")]
self.render_pipelines.clear();
#[cfg(feature = "compute")]
self.compute_pipelines.clear();
}
#[must_use]
#[inline]
pub fn len(&self) -> usize {
let total = 0;
#[cfg(feature = "graphics")]
let total = total + self.render_pipelines.len();
#[cfg(feature = "compute")]
let total = total + self.compute_pipelines.len();
total
}
#[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Default for PipelineCache {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_empty() {
let cache = PipelineCache::new();
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
}
#[test]
fn cache_default() {
let cache = PipelineCache::default();
assert!(cache.is_empty());
}
#[test]
#[cfg(feature = "graphics")]
fn cache_get_render_none() {
let cache = PipelineCache::new();
assert!(!cache.contains_render(1));
assert!(cache.get_render(1).is_none());
}
#[test]
#[cfg(feature = "compute")]
fn cache_get_compute_none() {
let cache = PipelineCache::new();
assert!(!cache.contains_compute(1));
assert!(cache.get_compute(1).is_none());
}
#[test]
fn cache_types() {
let _size = std::mem::size_of::<PipelineCache>();
}
#[test]
fn cache_clear() {
let mut cache = PipelineCache::new();
cache.clear();
assert!(cache.is_empty());
}
#[test]
#[cfg(feature = "graphics")]
fn invalidate_render_missing() {
let mut cache = PipelineCache::new();
assert!(!cache.invalidate_render(42));
}
#[test]
#[cfg(feature = "compute")]
fn invalidate_compute_missing() {
let mut cache = PipelineCache::new();
assert!(!cache.invalidate_compute(42));
}
}