use device as d;
use device::Resources;
struct Entry<R: Resources> {
last_used: u16,
bound: Option<(d::tex::Kind, R::Texture, Option<(R::Sampler, d::tex::SamplerInfo)>)>,
}
pub struct TextureCache<R: Resources> {
count: u16,
textures: Vec<Entry<R>>
}
fn age(now: u16, age: u16) -> u16 {
use std::num::Wrapping;
(Wrapping(now) - Wrapping(age)).0
}
impl<R> TextureCache<R> where R: Resources {
pub fn new(slots: usize) -> TextureCache<R> {
return TextureCache{
count: 0,
textures: (0..slots).map(|_| Entry {
last_used: 0,
bound: None
}).collect()
}
}
pub fn number_of_slots(&self) -> usize {
self.textures.len()
}
pub fn bind_texture<C>(&mut self,
kind: d::tex::Kind,
tex: R::Texture,
samp: Option<(R::Sampler, d::tex::SamplerInfo)>,
cb: &mut C) -> d::TextureSlot
where C: d::draw::CommandBuffer<R>
{
self.count += 1;
let count = self.count;
let bind = (kind, tex, samp);
for (i, ent) in self.textures.iter_mut().enumerate() {
if let Some(ref bound) = ent.bound {
if bound.0 == bind.0 && bound.1 == bind.1 && bound.2 == bind.2 {
ent.last_used = count;
return i as d::TextureSlot;
}
}
}
let mut oldest = 0;
for i in 0..self.textures.len() {
if self.textures[i].bound.is_none() {
oldest = i;
break;
}
if age(count, self.textures[i].last_used) > age(count, self.textures[oldest].last_used) {
oldest = i;
}
}
cb.bind_texture(oldest as d::TextureSlot, bind.0, bind.1, bind.2);
self.textures[oldest].last_used = count;
self.textures[oldest].bound = Some(bind);
return oldest as d::TextureSlot;
}
pub fn clear(&mut self) {
self.count = 0;
for ent in self.textures.iter_mut() {
ent.last_used = 0;
ent.bound = None;
}
}
}
#[test]
fn test_age() {
assert_eq!(age(100, 0), 100);
assert_eq!(age(0, 0), 0);
assert_eq!(age(0, 0xFFFF), 1);
assert_eq!(age(0, 0xFFFE), 2);
}