VIP inspection tooling #4
107
src/vram.rs
107
src/vram.rs
|
@ -40,12 +40,10 @@ impl VramProcessor {
|
||||||
&self,
|
&self,
|
||||||
renderer: R,
|
renderer: R,
|
||||||
) -> ([VramImageHandle; N], VramParams<R::Params>) {
|
) -> ([VramImageHandle; N], VramParams<R::Params>) {
|
||||||
let handles = renderer.sizes().map(|[width, height]| {
|
let states = renderer.sizes().map(VramRenderImageState::new);
|
||||||
let data = Arc::new(Mutex::new(None));
|
let handles = states.clone().map(|state| VramImageHandle {
|
||||||
VramImageHandle {
|
size: state.size.map(|i| i as f32),
|
||||||
size: [width as f32, height as f32],
|
data: state.sink,
|
||||||
data,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
let images = renderer
|
let images = renderer
|
||||||
.sizes()
|
.sizes()
|
||||||
|
@ -55,7 +53,7 @@ impl VramProcessor {
|
||||||
renderer,
|
renderer,
|
||||||
params: Arc::downgrade(&sink),
|
params: Arc::downgrade(&sink),
|
||||||
images,
|
images,
|
||||||
sinks: handles.clone().map(|i| i.data),
|
states,
|
||||||
}));
|
}));
|
||||||
let params = VramParams {
|
let params = VramParams {
|
||||||
value: R::Params::default(),
|
value: R::Params::default(),
|
||||||
|
@ -101,42 +99,35 @@ impl VramProcessorWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum VramImage {
|
pub struct VramImage {
|
||||||
Unchanged(Option<Arc<ColorImage>>),
|
size: [usize; 2],
|
||||||
Changed(ColorImage),
|
shades: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VramImage {
|
impl VramImage {
|
||||||
pub fn new(width: usize, height: usize) -> Self {
|
pub fn new(width: usize, height: usize) -> Self {
|
||||||
Self::Changed(ColorImage::new([width, height], Color32::BLACK))
|
Self {
|
||||||
}
|
size: [width, height],
|
||||||
|
shades: vec![0; width * height],
|
||||||
pub fn write(&mut self, coords: (usize, usize), shade: u8) {
|
|
||||||
match self {
|
|
||||||
Self::Unchanged(image) => {
|
|
||||||
if image.as_ref().is_none_or(|i| i[coords].r() == shade) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let Some(mut new_image) = image.take().map(Arc::unwrap_or_clone) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
new_image[coords] = Color32::from_gray(shade);
|
|
||||||
*self = Self::Changed(new_image);
|
|
||||||
}
|
|
||||||
Self::Changed(image) => {
|
|
||||||
image[coords] = Color32::from_gray(shade);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take(&mut self) -> Option<Arc<ColorImage>> {
|
pub fn write(&mut self, coords: (usize, usize), shade: u8) {
|
||||||
match self {
|
self.shades[coords.1 * self.size[0] + coords.0] = shade;
|
||||||
Self::Unchanged(_) => None,
|
}
|
||||||
Self::Changed(image) => {
|
|
||||||
let arced = Arc::new(std::mem::take(image));
|
pub fn changed(&self, image: &ColorImage) -> bool {
|
||||||
*self = Self::Unchanged(Some(arced.clone()));
|
image
|
||||||
Some(arced)
|
.pixels
|
||||||
}
|
.iter()
|
||||||
|
.map(|p| p.r())
|
||||||
|
.zip(&self.shades)
|
||||||
|
.any(|(a, b)| a != *b)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, image: &mut ColorImage) {
|
||||||
|
for (pixel, shade) in image.pixels.iter_mut().zip(&self.shades) {
|
||||||
|
*pixel = Color32::from_gray(*shade);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,11 +172,47 @@ pub trait VramRenderer<const N: usize>: Send {
|
||||||
fn render(&mut self, params: &Self::Params, images: &mut [VramImage; N]);
|
fn render(&mut self, params: &Self::Params, images: &mut [VramImage; N]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct VramRenderImageState {
|
||||||
|
size: [usize; 2],
|
||||||
|
buffers: [Arc<ColorImage>; 2],
|
||||||
|
last_buffer: usize,
|
||||||
|
sink: Arc<Mutex<Option<Arc<ColorImage>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VramRenderImageState {
|
||||||
|
fn new(size: [usize; 2]) -> Self {
|
||||||
|
let buffers = [
|
||||||
|
Arc::new(ColorImage::new(size, Color32::BLACK)),
|
||||||
|
Arc::new(ColorImage::new(size, Color32::BLACK)),
|
||||||
|
];
|
||||||
|
let sink = buffers[0].clone();
|
||||||
|
Self {
|
||||||
|
size,
|
||||||
|
buffers,
|
||||||
|
last_buffer: 0,
|
||||||
|
sink: Arc::new(Mutex::new(Some(sink))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn try_send_update(&mut self, image: &VramImage) {
|
||||||
|
let last = &self.buffers[self.last_buffer];
|
||||||
|
if !image.changed(last) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_buffer = (self.last_buffer + 1) % self.buffers.len();
|
||||||
|
let next = &mut self.buffers[next_buffer];
|
||||||
|
image.read(Arc::make_mut(next));
|
||||||
|
self.last_buffer = next_buffer;
|
||||||
|
self.sink.lock().unwrap().replace(next.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct VramRendererWrapper<const N: usize, R: VramRenderer<N>> {
|
struct VramRendererWrapper<const N: usize, R: VramRenderer<N>> {
|
||||||
renderer: R,
|
renderer: R,
|
||||||
params: Weak<Mutex<R::Params>>,
|
params: Weak<Mutex<R::Params>>,
|
||||||
images: [VramImage; N],
|
images: [VramImage; N],
|
||||||
sinks: [Arc<Mutex<Option<Arc<ColorImage>>>>; N],
|
states: [VramRenderImageState; N],
|
||||||
}
|
}
|
||||||
|
|
||||||
trait VramRendererImpl: Send {
|
trait VramRendererImpl: Send {
|
||||||
|
@ -203,10 +230,8 @@ impl<const N: usize, R: VramRenderer<N> + Send> VramRendererImpl for VramRendere
|
||||||
};
|
};
|
||||||
self.renderer.render(¶ms, &mut self.images);
|
self.renderer.render(¶ms, &mut self.images);
|
||||||
|
|
||||||
for (image, sink) in self.images.iter_mut().zip(&self.sinks) {
|
for (state, image) in self.states.iter_mut().zip(&self.images) {
|
||||||
if let Some(update) = image.take() {
|
state.try_send_update(image);
|
||||||
sink.lock().unwrap().replace(update);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue