Add a Buffer::age() method
Fixes https://github.com/rust-windowing/softbuffer/issues/90.
This commit is contained in:
parent
c1d6716eec
commit
29b3f4a978
8 changed files with 126 additions and 20 deletions
|
|
@ -87,6 +87,10 @@ impl<'a> BufferImpl<'a> {
|
||||||
&mut self.buffer
|
&mut self.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
let data_provider = CGDataProvider::from_buffer(Arc::new(Buffer(self.buffer)));
|
let data_provider = CGDataProvider::from_buffer(Arc::new(Buffer(self.buffer)));
|
||||||
let image = CGImage::new(
|
let image = CGImage::new(
|
||||||
|
|
|
||||||
21
src/lib.rs
21
src/lib.rs
|
|
@ -124,6 +124,15 @@ macro_rules! make_dispatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
$(
|
||||||
|
$(#[$attr])*
|
||||||
|
Self::$name(inner) => inner.age(),
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
|
|
@ -326,7 +335,7 @@ impl Surface {
|
||||||
|
|
||||||
/// Return a [`Buffer`] that the next frame should be rendered into. The size must
|
/// Return a [`Buffer`] that the next frame should be rendered into. The size must
|
||||||
/// be set with [`Surface::resize`] first. The initial contents of the buffer may be zeroed, or
|
/// be set with [`Surface::resize`] first. The initial contents of the buffer may be zeroed, or
|
||||||
/// may contain a previous frame.
|
/// may contain a previous frame. Call [`Buffer::age`] to determine this.
|
||||||
pub fn buffer_mut(&mut self) -> Result<Buffer, SoftBufferError> {
|
pub fn buffer_mut(&mut self) -> Result<Buffer, SoftBufferError> {
|
||||||
Ok(Buffer {
|
Ok(Buffer {
|
||||||
buffer_impl: self.surface_impl.buffer_mut()?,
|
buffer_impl: self.surface_impl.buffer_mut()?,
|
||||||
|
|
@ -377,6 +386,16 @@ pub struct Buffer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Buffer<'a> {
|
impl<'a> Buffer<'a> {
|
||||||
|
/// Is age is the number of frames ago this buffer was last presented. So if the value is
|
||||||
|
/// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame
|
||||||
|
/// before that (for backends using double buffering). If the value is `0`, it is a new
|
||||||
|
/// buffer that has unspecified contents.
|
||||||
|
///
|
||||||
|
/// This can be used to update only a portion of the buffer.
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
self.buffer_impl.age()
|
||||||
|
}
|
||||||
|
|
||||||
/// Presents buffer to the window.
|
/// Presents buffer to the window.
|
||||||
///
|
///
|
||||||
/// # Platform dependent behavior
|
/// # Platform dependent behavior
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ pub struct OrbitalImpl {
|
||||||
handle: OrbitalWindowHandle,
|
handle: OrbitalWindowHandle,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
presented: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrbitalImpl {
|
impl OrbitalImpl {
|
||||||
|
|
@ -65,12 +66,18 @@ impl OrbitalImpl {
|
||||||
handle,
|
handle,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
presented: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
|
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
|
||||||
self.width = width.get();
|
let width = width.get();
|
||||||
self.height = height.get();
|
let height = height.get();
|
||||||
|
if width != self.width && height != self.height {
|
||||||
|
self.presented = false;
|
||||||
|
self.width = width;
|
||||||
|
self.height = height;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,11 +179,19 @@ impl<'a> BufferImpl<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
match self.pixels {
|
||||||
|
Pixels::Mapping(_) if self.imp.presented => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
match self.pixels {
|
match self.pixels {
|
||||||
Pixels::Mapping(mapping) => {
|
Pixels::Mapping(mapping) => {
|
||||||
drop(mapping);
|
drop(mapping);
|
||||||
syscall::fsync(self.imp.window_fd()).expect("failed to sync orbital window");
|
syscall::fsync(self.imp.window_fd()).expect("failed to sync orbital window");
|
||||||
|
self.imp.presented = true;
|
||||||
}
|
}
|
||||||
Pixels::Buffer(buffer) => {
|
Pixels::Buffer(buffer) => {
|
||||||
self.imp
|
self.imp
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ pub(super) struct WaylandBuffer {
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
released: Arc<AtomicBool>,
|
released: Arc<AtomicBool>,
|
||||||
|
pub age: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaylandBuffer {
|
impl WaylandBuffer {
|
||||||
|
|
@ -125,6 +126,7 @@ impl WaylandBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
released,
|
released,
|
||||||
|
age: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,14 @@ impl WaylandImpl {
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BufferImpl(util::BorrowStack::new(self, |buffer| {
|
let age = self.buffers.as_mut().unwrap().1.age;
|
||||||
Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() })
|
|
||||||
})?))
|
Ok(BufferImpl {
|
||||||
|
stack: util::BorrowStack::new(self, |buffer| {
|
||||||
|
Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() })
|
||||||
|
})?,
|
||||||
|
age,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
|
|
@ -138,6 +143,11 @@ impl WaylandImpl {
|
||||||
.dispatch_pending(&mut State);
|
.dispatch_pending(&mut State);
|
||||||
|
|
||||||
if let Some((front, back)) = &mut self.buffers {
|
if let Some((front, back)) = &mut self.buffers {
|
||||||
|
front.age = 1;
|
||||||
|
if back.age != 0 {
|
||||||
|
back.age += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Swap front and back buffer
|
// Swap front and back buffer
|
||||||
std::mem::swap(front, back);
|
std::mem::swap(front, back);
|
||||||
|
|
||||||
|
|
@ -170,25 +180,32 @@ impl WaylandImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferImpl<'a>(util::BorrowStack<'a, WaylandImpl, [u32]>);
|
pub struct BufferImpl<'a> {
|
||||||
|
stack: util::BorrowStack<'a, WaylandImpl, [u32]>,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> BufferImpl<'a> {
|
impl<'a> BufferImpl<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pixels(&self) -> &[u32] {
|
pub fn pixels(&self) -> &[u32] {
|
||||||
self.0.member()
|
self.stack.member()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pixels_mut(&mut self) -> &mut [u32] {
|
pub fn pixels_mut(&mut self) -> &mut [u32] {
|
||||||
self.0.member_mut()
|
self.stack.member_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
self.age
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
self.0.into_container().present_with_damage(damage)
|
self.stack.into_container().present_with_damage(damage)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
let imp = self.0.into_container();
|
let imp = self.stack.into_container();
|
||||||
let (width, height) = imp
|
let (width, height) = imp
|
||||||
.size
|
.size
|
||||||
.expect("Must set size of surface before calling `present()`");
|
.expect("Must set size of surface before calling `present()`");
|
||||||
|
|
|
||||||
31
src/web.rs
31
src/web.rs
|
|
@ -41,8 +41,14 @@ pub struct WebImpl {
|
||||||
/// The buffer that we're drawing to.
|
/// The buffer that we're drawing to.
|
||||||
buffer: Vec<u32>,
|
buffer: Vec<u32>,
|
||||||
|
|
||||||
|
/// Buffer has been presented.
|
||||||
|
buffer_presented: bool,
|
||||||
|
|
||||||
/// The current width of the canvas.
|
/// The current width of the canvas.
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
||||||
|
/// The current height of the canvas.
|
||||||
|
height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebImpl {
|
impl WebImpl {
|
||||||
|
|
@ -70,7 +76,9 @@ impl WebImpl {
|
||||||
canvas,
|
canvas,
|
||||||
ctx,
|
ctx,
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
|
buffer_presented: false,
|
||||||
width: 0,
|
width: 0,
|
||||||
|
height: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,10 +91,15 @@ impl WebImpl {
|
||||||
let width = width.get();
|
let width = width.get();
|
||||||
let height = height.get();
|
let height = height.get();
|
||||||
|
|
||||||
self.buffer.resize(total_len(width, height), 0);
|
if width != self.width || height != self.height {
|
||||||
self.canvas.set_width(width);
|
self.buffer_presented = false;
|
||||||
self.canvas.set_height(height);
|
self.buffer.resize(total_len(width, height), 0);
|
||||||
self.width = width;
|
self.canvas.set_width(width);
|
||||||
|
self.canvas.set_height(height);
|
||||||
|
self.width = width;
|
||||||
|
self.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,6 +122,14 @@ impl<'a> BufferImpl<'a> {
|
||||||
&mut self.imp.buffer
|
&mut self.imp.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
if self.imp.buffer_presented {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Push the buffer to the canvas.
|
/// Push the buffer to the canvas.
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
// Create a bitmap from the buffer.
|
// Create a bitmap from the buffer.
|
||||||
|
|
@ -151,6 +172,8 @@ impl<'a> BufferImpl<'a> {
|
||||||
// This can only throw an error if `data` is detached, which is impossible.
|
// This can only throw an error if `data` is detached, which is impossible.
|
||||||
self.imp.ctx.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
self.imp.ctx.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||||
|
|
||||||
|
self.imp.buffer_presented = true;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
src/win32.rs
14
src/win32.rs
|
|
@ -27,6 +27,7 @@ struct Buffer {
|
||||||
pixels: NonNull<u32>,
|
pixels: NonNull<u32>,
|
||||||
width: NonZeroI32,
|
width: NonZeroI32,
|
||||||
height: NonZeroI32,
|
height: NonZeroI32,
|
||||||
|
presented: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Buffer {
|
impl Drop for Buffer {
|
||||||
|
|
@ -101,6 +102,7 @@ impl Buffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
pixels,
|
pixels,
|
||||||
|
presented: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,8 +205,8 @@ impl Win32Impl {
|
||||||
Ok(BufferImpl(self))
|
Ok(BufferImpl(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn present_with_damage(&self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
let buffer = self.buffer.as_ref().unwrap();
|
let buffer = self.buffer.as_mut().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
for Rect {
|
for Rect {
|
||||||
x,
|
x,
|
||||||
|
|
@ -229,6 +231,7 @@ impl Win32Impl {
|
||||||
// Validate the window.
|
// Validate the window.
|
||||||
Gdi::ValidateRect(self.window, ptr::null_mut());
|
Gdi::ValidateRect(self.window, ptr::null_mut());
|
||||||
}
|
}
|
||||||
|
buffer.presented = true;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +250,13 @@ impl<'a> BufferImpl<'a> {
|
||||||
self.0.buffer.as_mut().unwrap().pixels_mut()
|
self.0.buffer.as_mut().unwrap().pixels_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
match self.0.buffer.as_ref() {
|
||||||
|
Some(buffer) if buffer.presented => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
let imp = self.0;
|
let imp = self.0;
|
||||||
let buffer = imp.buffer.as_ref().unwrap();
|
let buffer = imp.buffer.as_ref().unwrap();
|
||||||
|
|
|
||||||
22
src/x11.rs
22
src/x11.rs
|
|
@ -107,6 +107,9 @@ pub struct X11Impl {
|
||||||
/// The buffer we draw to.
|
/// The buffer we draw to.
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
|
|
||||||
|
/// Buffer has been presented.
|
||||||
|
buffer_presented: bool,
|
||||||
|
|
||||||
/// The current buffer width.
|
/// The current buffer width.
|
||||||
width: u16,
|
width: u16,
|
||||||
|
|
||||||
|
|
@ -223,6 +226,7 @@ impl X11Impl {
|
||||||
gc,
|
gc,
|
||||||
depth: geometry_reply.depth,
|
depth: geometry_reply.depth,
|
||||||
buffer,
|
buffer,
|
||||||
|
buffer_presented: false,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
})
|
})
|
||||||
|
|
@ -255,6 +259,7 @@ impl X11Impl {
|
||||||
}))?;
|
}))?;
|
||||||
|
|
||||||
if width != self.width || height != self.height {
|
if width != self.width || height != self.height {
|
||||||
|
self.buffer_presented = false;
|
||||||
self.buffer
|
self.buffer
|
||||||
.resize(&self.display.connection, width, height)
|
.resize(&self.display.connection, width, height)
|
||||||
.swbuf_err("Failed to resize X11 buffer")?;
|
.swbuf_err("Failed to resize X11 buffer")?;
|
||||||
|
|
@ -294,13 +299,21 @@ impl<'a> BufferImpl<'a> {
|
||||||
unsafe { self.0.buffer.buffer_mut() }
|
unsafe { self.0.buffer.buffer_mut() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn age(&self) -> u8 {
|
||||||
|
if self.0.buffer_presented {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Push the buffer to the window.
|
/// Push the buffer to the window.
|
||||||
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
let imp = self.0;
|
let imp = self.0;
|
||||||
|
|
||||||
log::trace!("present: window={:X}", imp.window);
|
log::trace!("present: window={:X}", imp.window);
|
||||||
|
|
||||||
let result = match imp.buffer {
|
match imp.buffer {
|
||||||
Buffer::Wire(ref wire) => {
|
Buffer::Wire(ref wire) => {
|
||||||
// This is a suboptimal strategy, raise a stink in the debug logs.
|
// This is a suboptimal strategy, raise a stink in the debug logs.
|
||||||
log::debug!("Falling back to non-SHM method for window drawing.");
|
log::debug!("Falling back to non-SHM method for window drawing.");
|
||||||
|
|
@ -368,9 +381,12 @@ impl<'a> BufferImpl<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
.swbuf_err("Failed to draw image to window")?;
|
||||||
|
|
||||||
result.swbuf_err("Failed to draw image to window")
|
imp.buffer_presented = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue