Optimize image updates
This commit is contained in:
		
							parent
							
								
									d16c5363da
								
							
						
					
					
						commit
						dfcfd17bfc
					
				
							
								
								
									
										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