use api::{ImageKey, PropertyBindingId, ColorU};
use crate::invalidation::PrimitiveCompareResult;
use crate::internal_types::FastHashMap;
use crate::resource_cache::{ResourceCache, ImageGeneration};
use crate::invalidation::cached_surface::{PrimitiveDependencyIndex, PrimitiveDescriptor, CachedSurfaceDescriptor};
use crate::intern::ItemUid;
use crate::invalidation::vert_buffer::VertRange;
use peek_poke::{PeekPoke, peek_from_slice};
#[derive(Debug)]
pub struct BindingInfo<T> {
pub value: T,
pub changed: bool,
}
#[derive(Debug, PartialEq, Clone, Copy, PeekPoke)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum Binding<T> {
Value(T),
Binding(PropertyBindingId),
}
impl<T: Default> Default for Binding<T> {
fn default() -> Self {
Binding::Value(T::default())
}
}
impl<T> From<api::PropertyBinding<T>> for Binding<T> {
fn from(binding: api::PropertyBinding<T>) -> Binding<T> {
match binding {
api::PropertyBinding::Binding(key, _) => Binding::Binding(key.id),
api::PropertyBinding::Value(value) => Binding::Value(value),
}
}
}
pub type OpacityBinding = Binding<f32>;
pub type OpacityBindingInfo = BindingInfo<f32>;
pub type ColorBinding = Binding<ColorU>;
pub type ColorBindingInfo = BindingInfo<ColorU>;
#[derive(PeekPoke)]
pub enum PrimitiveDependency {
OpacityBinding {
binding: OpacityBinding,
},
ColorBinding {
binding: ColorBinding,
},
Image {
image: ImageDependency,
},
Clip {
prim_uid: ItemUid,
vert_range: VertRange,
},
}
#[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ImageDependency {
pub key: ImageKey,
pub generation: ImageGeneration,
}
impl ImageDependency {
pub const INVALID: ImageDependency = ImageDependency {
key: ImageKey::DUMMY,
generation: ImageGeneration::INVALID,
};
}
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct PrimitiveComparisonKey {
pub prev_index: PrimitiveDependencyIndex,
pub curr_index: PrimitiveDependencyIndex,
}
pub struct PrimitiveComparer<'a> {
prev: &'a CachedSurfaceDescriptor,
curr: &'a CachedSurfaceDescriptor,
resource_cache: &'a ResourceCache,
opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
}
impl<'a> PrimitiveComparer<'a> {
pub fn new(
prev: &'a CachedSurfaceDescriptor,
curr: &'a CachedSurfaceDescriptor,
resource_cache: &'a ResourceCache,
opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
) -> Self {
PrimitiveComparer {
prev,
curr,
resource_cache,
opacity_bindings,
color_bindings,
}
}
pub fn compare_prim(
&mut self,
prev_desc: &PrimitiveDescriptor,
curr_desc: &PrimitiveDescriptor,
) -> PrimitiveCompareResult {
if prev_desc.prim_uid != curr_desc.prim_uid {
return PrimitiveCompareResult::Descriptor;
}
let prev_range = prev_desc.prim_corners;
let prev_end = (prev_range.offset + prev_range.count) as usize;
let prev_verts = &self.prev.vert_data[prev_range.offset as usize .. prev_end];
let curr_range = curr_desc.prim_corners;
let curr_end = (curr_range.offset + curr_range.count) as usize;
let curr_verts = &self.curr.vert_data[curr_range.offset as usize .. curr_end];
if prev_verts != curr_verts {
return PrimitiveCompareResult::Descriptor;
}
let prev_range = prev_desc.coverage_corners;
let prev_end = (prev_range.offset + prev_range.count) as usize;
let prev_verts = &self.prev.vert_data[prev_range.offset as usize .. prev_end];
let curr_range = curr_desc.coverage_corners;
let curr_end = (curr_range.offset + curr_range.count) as usize;
let curr_verts = &self.curr.vert_data[curr_range.offset as usize .. curr_end];
if prev_verts != curr_verts {
return PrimitiveCompareResult::Descriptor;
}
if prev_desc.dep_count != curr_desc.dep_count {
return PrimitiveCompareResult::Descriptor;
}
let mut prev_dep_data = &self.prev.dep_data[prev_desc.dep_offset as usize ..];
let mut curr_dep_data = &self.curr.dep_data[curr_desc.dep_offset as usize ..];
let mut prev_dep = PrimitiveDependency::Image { image: ImageDependency::INVALID };
let mut curr_dep = PrimitiveDependency::Image { image: ImageDependency::INVALID };
for _ in 0 .. prev_desc.dep_count {
prev_dep_data = peek_from_slice(prev_dep_data, &mut prev_dep);
curr_dep_data = peek_from_slice(curr_dep_data, &mut curr_dep);
match (&prev_dep, &curr_dep) {
(PrimitiveDependency::Clip { prim_uid: prev_uid, vert_range: prev_range }, PrimitiveDependency::Clip { prim_uid: curr_uid, vert_range: curr_range }) => {
if prev_uid != curr_uid {
return PrimitiveCompareResult::Clip;
}
let prev_end = (prev_range.offset + prev_range.count) as usize;
let prev_verts: &[i32] = if prev_range.is_valid() && prev_end <= self.prev.vert_data.len() {
&self.prev.vert_data[prev_range.offset as usize .. prev_end]
} else {
&[]
};
let curr_end = (curr_range.offset + curr_range.count) as usize;
let curr_verts: &[i32] = if curr_range.is_valid() && curr_end <= self.curr.vert_data.len() {
&self.curr.vert_data[curr_range.offset as usize .. curr_end]
} else {
&[]
};
if prev_verts != curr_verts {
return PrimitiveCompareResult::Clip;
}
}
(PrimitiveDependency::Image { image: prev }, PrimitiveDependency::Image { image: curr }) => {
if prev != curr {
return PrimitiveCompareResult::Image;
}
if self.resource_cache.get_image_generation(curr.key) != curr.generation {
return PrimitiveCompareResult::Image;
}
}
(PrimitiveDependency::OpacityBinding { binding: prev }, PrimitiveDependency::OpacityBinding { binding: curr }) => {
if prev != curr {
return PrimitiveCompareResult::OpacityBinding;
}
if let OpacityBinding::Binding(id) = curr {
if self.opacity_bindings.get(id).map_or(true, |info| info.changed) {
return PrimitiveCompareResult::OpacityBinding;
}
}
}
(PrimitiveDependency::ColorBinding { binding: prev }, PrimitiveDependency::ColorBinding { binding: curr }) => {
if prev != curr {
return PrimitiveCompareResult::ColorBinding;
}
if let ColorBinding::Binding(id) = curr {
if self.color_bindings.get(id).map_or(true, |info| info.changed) {
return PrimitiveCompareResult::ColorBinding;
}
}
}
_ => {
return PrimitiveCompareResult::Descriptor;
}
}
}
PrimitiveCompareResult::Equal
}
}