VIP inspection tooling #4

Merged
SonicSwordcane merged 34 commits from vram into main 2025-02-24 04:01:18 +00:00
1 changed files with 66 additions and 41 deletions
Showing only changes of commit dfcfd17bfc - Show all commits

View File

@ -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(&params, &mut self.images); self.renderer.render(&params, &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(())
} }