use super::quality_acceleration::QualityAcceleration;
use super::quality_hardware::QualityBlas;
use super::record_cache::RecordKey;
use crate::error::RenderError;
use molgfx_core::{AtomGpu, BondGpu, PlacedStructure};
use molgfx_gpu::Device;
use std::collections::BTreeMap;
#[derive(Debug)]
pub(super) struct AccelerationCache<D: Device> {
entries: Vec<(RecordKey, SharedAcceleration<D>)>,
}
#[derive(Debug)]
pub(super) struct SharedAcceleration<D: Device> {
hierarchy: QualityAcceleration<D>,
hardware: QualityBlas<D>,
}
impl<D: Device> SharedAcceleration<D> {
pub(super) fn hierarchy(&self) -> &QualityAcceleration<D> {
&self.hierarchy
}
pub(super) fn blas(&self) -> Option<&D::Blas> {
self.hardware.blas()
}
pub(super) fn record(&mut self, encoder: &mut D::CommandEncoder) {
self.hardware.record(encoder);
}
#[must_use]
pub(super) fn resident_bytes(&self) -> u64 {
self.hierarchy
.resident_bytes()
.saturating_add(self.hardware.resident_bytes())
}
}
impl<D: Device> AccelerationCache<D> {
pub(super) const fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub(super) fn build(
&mut self,
key: RecordKey,
device: &D,
queue: &D::Queue,
atoms: &[AtomGpu],
bonds: &[BondGpu],
placed: &PlacedStructure,
) -> Result<(), RenderError> {
let mut acceleration = SharedAcceleration {
hierarchy: QualityAcceleration::new(),
hardware: QualityBlas::new(),
};
acceleration
.hierarchy
.sync_topology(device, queue, atoms, bonds, placed)?;
acceleration
.hardware
.sync(device, queue, atoms, bonds, placed);
let position = match self.entries.binary_search_by_key(&key, |(key, _)| *key) {
Ok(position) | Err(position) => position,
};
self.entries.insert(position, (key, acceleration));
Ok(())
}
pub(super) fn retain(
&mut self,
needed: &BTreeMap<RecordKey, usize>,
requires_bvh: bool,
ledger: &mut crate::DerivedCache,
frame: u64,
) {
if !requires_bvh {
self.entries.clear();
return;
}
self.entries.retain(|(key, acceleration)| {
ledger.retain(
*key,
crate::DerivedCacheClass::Acceleration,
crate::DerivedFootprint {
cpu_bytes: 0,
gpu_bytes: acceleration.resident_bytes(),
},
frame,
) && needed.contains_key(key)
});
}
#[must_use]
pub(super) fn get(&self, key: RecordKey) -> Option<&SharedAcceleration<D>> {
self.entries
.binary_search_by_key(&key, |(key, _)| *key)
.ok()
.and_then(|index| self.entries.get(index))
.map(|(_, acceleration)| acceleration)
}
pub(super) fn record_hardware(&mut self, encoder: &mut D::CommandEncoder) {
for (_, acceleration) in &mut self.entries {
acceleration.record(encoder);
}
}
}