diff --git a/src/builder.rs b/src/builder.rs index 2f1018d5..a89280f5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,6 +1,7 @@ use crate::renderers::{ScalingMatrix, ScalingRenderer}; use crate::{Error, Pixels, PixelsContext, SurfaceSize, SurfaceTexture, TextureError}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use std::cell::Cell; /// A builder to help create customized pixel buffers. pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle> { @@ -342,6 +343,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle> surface_texture_format, blend_state, pixels, + dirty: Cell::new(false), scaling_matrix_inverse, alpha_mode, }; diff --git a/src/lib.rs b/src/lib.rs index 538ae9e7..a3718944 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ pub use crate::builder::{check_texture_size, PixelsBuilder}; pub use crate::renderers::ScalingRenderer; pub use raw_window_handle; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use std::cell::Cell; use thiserror::Error; pub use wgpu; @@ -103,6 +104,7 @@ pub struct Pixels { // Pixel buffer pixels: Vec, + dirty: Cell, // The inverse of the scaling matrix used by the renderer // Used to convert physical coordinates back to pixel coordinates (for the mouse) @@ -333,6 +335,7 @@ impl Pixels { // Resize the pixel buffer self.pixels .resize_with(pixels_buffer_size, Default::default); + self.dirty.set(true); Ok(()) } @@ -514,23 +517,27 @@ impl Pixels { }); // Update the pixel buffer texture view - let bytes_per_row = - (self.context.texture_extent.width as f32 * self.context.texture_format_size) as u32; - self.context.queue.write_texture( - wgpu::ImageCopyTexture { - texture: &self.context.texture, - mip_level: 0, - origin: wgpu::Origin3d { x: 0, y: 0, z: 0 }, - aspect: wgpu::TextureAspect::All, - }, - &self.pixels, - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: Some(bytes_per_row), - rows_per_image: Some(self.context.texture_extent.height), - }, - self.context.texture_extent, - ); + if self.dirty.get() { + self.dirty.set(false); + + let bytes_per_row = (self.context.texture_extent.width as f32 + * self.context.texture_format_size) as u32; + self.context.queue.write_texture( + wgpu::ImageCopyTexture { + texture: &self.context.texture, + mip_level: 0, + origin: wgpu::Origin3d { x: 0, y: 0, z: 0 }, + aspect: wgpu::TextureAspect::All, + }, + &self.pixels, + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(bytes_per_row), + rows_per_image: Some(self.context.texture_extent.height), + }, + self.context.texture_extent, + ); + } let view = frame .texture @@ -565,6 +572,9 @@ impl Pixels { /// Get a mutable byte slice for the pixel buffer. The buffer is _not_ cleared for you; it will /// retain the previous frame's contents until you clear it yourself. pub fn frame_mut(&mut self) -> &mut [u8] { + // Optimistically assume the caller will change the buffer when acquiring mutable access. + self.dirty.set(true); + &mut self.pixels }