Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
- **Breaking:** Removed generic type parameters `D` and `W` from `Buffer<'_>` struct.
- **Breaking:** Removed `Deref[Mut]` implementation on `Buffer<'_>`. Use `Buffer::pixels()` instead.
- **Breaking:** Removed unintentional Cargo features for Softbuffer's optional dependencies.
- **Breaking:** Removed `DamageOutOfRange` error case. If the damage value is greater than the backend supports, it is instead clamped to an appropriate value.
- Fixed `present_with_damage` with bounds out of range on Windows, Web and X11.

# 0.4.7

Expand Down
9 changes: 0 additions & 9 deletions src/backend_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,6 @@ macro_rules! make_dispatch {
}
}

fn present(self) -> Result<(), SoftBufferError> {
match self {
$(
$(#[$attr])*
Self::$name(inner) => inner.present(),
)*
}
}

fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
match self {
$(
Expand Down
1 change: 0 additions & 1 deletion src/backend_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,4 @@ pub(crate) trait BufferInterface {
fn pixels_mut(&mut self) -> &mut [u32];
fn age(&self) -> u8;
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError>;
fn present(self) -> Result<(), SoftBufferError>;
}
19 changes: 11 additions & 8 deletions src/backends/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,17 @@ impl BufferInterface for BufferImpl<'_> {
}

// TODO: This function is pretty slow this way
fn present(mut self) -> Result<(), SoftBufferError> {
fn present_with_damage(mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
// TODO: Android requires the damage rect _at lock time_
// Since we're faking the backing buffer _anyway_, we could even fake the surface lock
// and lock it here (if it doesn't influence timings).
//
// Android seems to do this because the region can be expanded by the
// system, requesting the user to actually redraw a larger region.
// It's unclear if/when this is used, or if corruption/artifacts occur
// when the enlarged damage region is not re-rendered?
let _ = damage;

let input_lines = self.buffer.chunks(self.native_window_buffer.width());
for (output, input) in self
.native_window_buffer
Expand All @@ -165,11 +175,4 @@ impl BufferInterface for BufferImpl<'_> {
}
Ok(())
}

fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
// TODO: Android requires the damage rect _at lock time_
// Since we're faking the backing buffer _anyway_, we could even fake the surface lock
// and lock it here (if it doesn't influence timings).
self.present()
}
}
6 changes: 1 addition & 5 deletions src/backends/cg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ impl BufferInterface for BufferImpl<'_> {
0
}

fn present(self) -> Result<(), SoftBufferError> {
fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
unsafe extern "C-unwind" fn release(
_info: *mut c_void,
data: NonNull<c_void>,
Expand Down Expand Up @@ -361,10 +361,6 @@ impl BufferInterface for BufferImpl<'_> {
CATransaction::commit();
Ok(())
}

fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
self.present()
}
}

#[derive(Debug)]
Expand Down
37 changes: 10 additions & 27 deletions src/backends/kms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::sync::Arc;

use crate::backend_interface::*;
use crate::error::{InitError, SoftBufferError, SwResultExt};
use crate::util;

#[derive(Debug, Clone)]
struct DrmDevice<'a> {
Expand Down Expand Up @@ -325,24 +326,17 @@ impl BufferInterface for BufferImpl<'_> {

#[inline]
fn present_with_damage(self, damage: &[crate::Rect]) -> Result<(), SoftBufferError> {
let rectangles = damage
let rectangles: Vec<_> = damage
.iter()
.map(|&rect| {
let err = || SoftBufferError::DamageOutOfRange { rect };
Ok::<_, SoftBufferError>(ClipRect::new(
rect.x.try_into().map_err(|_| err())?,
rect.y.try_into().map_err(|_| err())?,
rect.x
.checked_add(rect.width.get())
.and_then(|x| x.try_into().ok())
.ok_or_else(err)?,
rect.y
.checked_add(rect.height.get())
.and_then(|y| y.try_into().ok())
.ok_or_else(err)?,
))
.map(|rect| {
ClipRect::new(
util::to_u16_saturating(rect.x),
util::to_u16_saturating(rect.y),
util::to_u16_saturating(rect.x.saturating_add(rect.width.get())),
util::to_u16_saturating(rect.y.saturating_add(rect.height.get())),
)
})
.collect::<Result<Vec<_>, _>>()?;
.collect();

// Dirty the framebuffer with out damage rectangles.
//
Expand Down Expand Up @@ -378,17 +372,6 @@ impl BufferInterface for BufferImpl<'_> {

Ok(())
}

#[inline]
fn present(self) -> Result<(), SoftBufferError> {
let (width, height) = self.size;
self.present_with_damage(&[crate::Rect {
x: 0,
y: 0,
width,
height,
}])
}
}

impl SharedBuffer {
Expand Down
6 changes: 1 addition & 5 deletions src/backends/orbital.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl BufferInterface for BufferImpl<'_> {
}
}

fn present(self) -> Result<(), SoftBufferError> {
fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
match self.pixels {
Pixels::Mapping(mapping) => {
drop(mapping);
Expand All @@ -190,10 +190,6 @@ impl BufferInterface for BufferImpl<'_> {

Ok(())
}

fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
self.present()
}
}

// Read the current width and size
Expand Down
30 changes: 9 additions & 21 deletions src/backends/wayland/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
backend_interface::*,
error::{InitError, SwResultExt},
Rect, SoftBufferError,
util, Rect, SoftBufferError,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use std::{
Expand Down Expand Up @@ -260,16 +260,15 @@ impl BufferInterface for BufferImpl<'_> {
self.surface.damage(0, 0, i32::MAX, i32::MAX);
} else {
for rect in damage {
// Damage that falls outside the surface is ignored, so we don't need to clamp the
// rect manually.
// https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_surface
let x = util::to_i32_saturating(rect.x);
let y = util::to_i32_saturating(rect.y);
let width = util::to_i32_saturating(rect.width.get());
let height = util::to_i32_saturating(rect.height.get());

// Introduced in version 4, it is an error to use this request in version 3 or lower.
let (x, y, width, height) = (|| {
Some((
i32::try_from(rect.x).ok()?,
i32::try_from(rect.y).ok()?,
i32::try_from(rect.width.get()).ok()?,
i32::try_from(rect.height.get()).ok()?,
))
})()
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
self.surface.damage_buffer(x, y, width, height);
}
}
Expand All @@ -284,17 +283,6 @@ impl BufferInterface for BufferImpl<'_> {

Ok(())
}

fn present(self) -> Result<(), SoftBufferError> {
let (width, height) = (self.width, self.height);
self.present_with_damage(&[Rect {
x: 0,
y: 0,
// We know width/height will be non-negative and non-zero.
width: (width as u32).try_into().unwrap(),
height: (height as u32).try_into().unwrap(),
}])
}
}

impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
Expand Down
22 changes: 6 additions & 16 deletions src/backends/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,25 +331,13 @@ impl BufferInterface for BufferImpl<'_> {
}

/// Push the buffer to the canvas.
fn present(self) -> Result<(), SoftBufferError> {
let (width, height) = self
.size
.expect("Must set size of surface before calling `present()`");
self.present_with_damage(&[Rect {
x: 0,
y: 0,
width,
height,
}])
}

fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
let (buffer_width, _buffer_height) = self
let (buffer_width, buffer_height) = self
.size
.expect("Must set size of surface before calling `present_with_damage()`");

let union_damage = if let Some(rect) = util::union_damage(damage) {
rect
util::clamp_rect(rect, buffer_width, buffer_height)
} else {
return Ok(());
};
Expand All @@ -370,8 +358,8 @@ impl BufferInterface for BufferImpl<'_> {
.collect();

debug_assert_eq!(
bitmap.len() as u32,
union_damage.width.get() * union_damage.height.get() * 4
bitmap.len(),
union_damage.width.get() as usize * union_damage.height.get() as usize * 4
);

#[cfg(target_feature = "atomics")]
Expand Down Expand Up @@ -407,6 +395,8 @@ impl BufferInterface for BufferImpl<'_> {
let image_data = result.unwrap();

for rect in damage {
let rect = util::clamp_rect(*rect, buffer_width, buffer_height);

// This can only throw an error if `data` is detached, which is impossible.
self.canvas
.put_image_data(
Expand Down
34 changes: 12 additions & 22 deletions src/backends/win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module converts the input buffer into a bitmap and then stretches it to the window.

use crate::backend_interface::*;
use crate::{Rect, SoftBufferError};
use crate::{util, Rect, SoftBufferError};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};

use std::io;
Expand Down Expand Up @@ -271,29 +271,19 @@ impl BufferInterface for BufferImpl<'_> {
}
}

fn present(self) -> Result<(), SoftBufferError> {
let (width, height) = (self.buffer.width, self.buffer.height);
self.present_with_damage(&[Rect {
x: 0,
y: 0,
// We know width/height will be non-negative
width: width.try_into().unwrap(),
height: height.try_into().unwrap(),
}])
}

fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
unsafe {
for rect in damage.iter().copied() {
let (x, y, width, height) = (|| {
Some((
i32::try_from(rect.x).ok()?,
i32::try_from(rect.y).ok()?,
i32::try_from(rect.width.get()).ok()?,
i32::try_from(rect.height.get()).ok()?,
))
})()
.ok_or(SoftBufferError::DamageOutOfRange { rect })?;
for rect in damage {
let rect = util::clamp_rect(
*rect,
self.buffer.width.try_into().unwrap(),
self.buffer.height.try_into().unwrap(),
);
let x = util::to_i32_saturating(rect.x);
let y = util::to_i32_saturating(rect.y);
let width = util::to_i32_saturating(rect.width.get());
let height = util::to_i32_saturating(rect.height.get());

Gdi::BitBlt(
self.dc.0,
x,
Expand Down
36 changes: 12 additions & 24 deletions src/backends/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,18 +469,18 @@ impl BufferInterface for BufferImpl<'_> {
damage
.iter()
.try_for_each(|rect| {
let (src_x, src_y, dst_x, dst_y, width, height) = (|| {
Some((
u16::try_from(rect.x).ok()?,
u16::try_from(rect.y).ok()?,
i16::try_from(rect.x).ok()?,
i16::try_from(rect.y).ok()?,
u16::try_from(rect.width.get()).ok()?,
u16::try_from(rect.height.get()).ok()?,
))
})(
)
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
let rect = util::clamp_rect(
*rect,
surface_width.into(),
surface_height.into(),
);
let src_x = util::to_u16_saturating(rect.x);
let src_y = util::to_u16_saturating(rect.y);
let dst_x = util::to_i16_saturating(rect.x);
let dst_y = util::to_i16_saturating(rect.y);
let width = util::to_u16_saturating(rect.width.get());
let height = util::to_u16_saturating(rect.height.get());

self.connection
.shm_put_image(
self.window,
Expand Down Expand Up @@ -516,18 +516,6 @@ impl BufferInterface for BufferImpl<'_> {

Ok(())
}

fn present(self) -> Result<(), SoftBufferError> {
let (width, height) = self
.size
.expect("Must set size of surface before calling `present()`");
self.present_with_damage(&[Rect {
x: 0,
y: 0,
width: width.into(),
height: height.into(),
}])
}
}

impl Buffer {
Expand Down
11 changes: 0 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,6 @@ pub enum SoftBufferError {
height: NonZeroU32,
},

/// The provided damage rect is outside of the range supported by the backend.
DamageOutOfRange {
/// The damage rect that was out of range.
rect: crate::Rect,
},

/// A platform-specific backend error occurred.
///
/// The first field provides a human-readable description of the error. The second field
Expand Down Expand Up @@ -133,11 +127,6 @@ impl fmt::Display for SoftBufferError {
),
Self::PlatformError(msg, None) => write!(f, "Platform error: {msg:?}"),
Self::PlatformError(msg, Some(err)) => write!(f, "Platform error: {msg:?}: {err}"),
Self::DamageOutOfRange { rect } => write!(
f,
"Damage rect {}x{} at ({}, {}) out of range for backend.",
rect.width, rect.height, rect.x, rect.y
),
Self::Unimplemented => write!(f, "This function is unimplemented on this platform."),
}
}
Expand Down
Loading