Skip to content

Commit c543d19

Browse files
committed
Use higher stride on some platforms when cfg(debug_assertions)
To help with debugging incorrect stride/width calculations, it helps that there are more common backends (than Android) that have `stride != width * 4`.
1 parent a7abd65 commit c543d19

File tree

5 files changed

+37
-19
lines changed

5 files changed

+37
-19
lines changed

src/backends/cg.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,9 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
259259
}
260260

261261
fn buffer_mut(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
262+
let buffer_size = util::byte_stride(self.width as u32) as usize * self.height / 4;
262263
Ok(BufferImpl {
263-
buffer: util::PixelBuffer(vec![0; self.width * self.height]),
264+
buffer: util::PixelBuffer(vec![0; buffer_size]),
264265
width: self.width,
265266
height: self.height,
266267
color_space: &self.color_space,
@@ -280,7 +281,7 @@ pub struct BufferImpl<'a> {
280281

281282
impl BufferInterface for BufferImpl<'_> {
282283
fn byte_stride(&self) -> NonZeroU32 {
283-
NonZeroU32::new(self.width().get() * 4).unwrap()
284+
NonZeroU32::new(util::byte_stride(self.width as u32)).unwrap()
284285
}
285286

286287
fn width(&self) -> NonZeroU32 {
@@ -342,7 +343,7 @@ impl BufferInterface for BufferImpl<'_> {
342343
self.height,
343344
8,
344345
32,
345-
self.width * 4,
346+
util::byte_stride(self.width as u32) as usize,
346347
Some(self.color_space),
347348
bitmap_info,
348349
Some(&data_provider),

src/backends/wayland/buffer.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use wayland_client::{
1515
};
1616

1717
use super::State;
18+
use crate::util;
1819

1920
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
2021
fn create_memfile() -> File {
@@ -98,7 +99,7 @@ impl WaylandBuffer {
9899
0,
99100
width,
100101
height,
101-
width * 4,
102+
util::byte_stride(width as u32) as i32,
102103
wl_shm::Format::Xrgb8888,
103104
qh,
104105
released.clone(),
@@ -138,7 +139,7 @@ impl WaylandBuffer {
138139
0,
139140
width,
140141
height,
141-
width * 4,
142+
util::byte_stride(width as u32) as i32,
142143
wl_shm::Format::Xrgb8888,
143144
&self.qh,
144145
self.released.clone(),
@@ -158,7 +159,7 @@ impl WaylandBuffer {
158159
}
159160

160161
fn len(&self) -> usize {
161-
self.width as usize * self.height as usize
162+
util::byte_stride(self.width as u32) as usize * self.height as usize / 4
162163
}
163164

164165
#[inline]

src/backends/wayland/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
backend_interface::*,
33
error::{InitError, SwResultExt},
4-
Rect, SoftBufferError,
4+
util, Rect, SoftBufferError,
55
};
66
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
77
use std::{
@@ -220,7 +220,7 @@ pub struct BufferImpl<'a> {
220220

221221
impl BufferInterface for BufferImpl<'_> {
222222
fn byte_stride(&self) -> NonZeroU32 {
223-
NonZeroU32::new(self.width as u32 * 4).unwrap()
223+
NonZeroU32::new(util::byte_stride(self.width as u32)).unwrap()
224224
}
225225

226226
fn width(&self) -> NonZeroU32 {

src/backends/win32.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,9 @@ impl Buffer {
116116

117117
#[inline]
118118
fn pixels_mut(&mut self) -> &mut [u32] {
119-
unsafe {
120-
slice::from_raw_parts_mut(
121-
self.pixels.as_ptr(),
122-
i32::from(self.width) as usize * i32::from(self.height) as usize,
123-
)
124-
}
119+
let num_bytes =
120+
byte_stride(self.width.get() as u32, 32) as usize * i32::from(self.height) as usize;
121+
unsafe { slice::from_raw_parts_mut(self.pixels.as_ptr(), num_bytes / 4) }
125122
}
126123
}
127124

@@ -252,11 +249,7 @@ pub struct BufferImpl<'a> {
252249
impl BufferInterface for BufferImpl<'_> {
253250
fn byte_stride(&self) -> NonZeroU32 {
254251
let width = self.buffer.width.get() as u32;
255-
let bit_count = 32;
256-
// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader#calculating-surface-stride
257-
// When `bit_count == 32`, this is always just equal to `width * 4`.
258-
let stride = ((width * bit_count + 31) & !31) >> 3;
259-
NonZeroU32::new(stride).unwrap()
252+
NonZeroU32::new(byte_stride(width, 32)).unwrap()
260253
}
261254

262255
fn width(&self) -> NonZeroU32 {
@@ -476,3 +469,10 @@ impl<T> From<T> for OnlyUsedFromOrigin<T> {
476469
Self(t)
477470
}
478471
}
472+
473+
#[inline]
474+
fn byte_stride(width: u32, bit_count: u32) -> u32 {
475+
// <https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader#calculating-surface-stride>
476+
// When `bit_count == 32`, this is always just equal to `width * 4`.
477+
((width * bit_count + 31) & !31) >> 3
478+
}

src/util.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,19 @@ impl ops::DerefMut for PixelBuffer {
6565
&mut self.0
6666
}
6767
}
68+
69+
/// Compute the byte stride desired by Softbuffer when a platform can use any stride.
70+
///
71+
/// TODO(madsmtm): This should take the pixel format / bit depth as input after:
72+
/// <https://github.com/rust-windowing/softbuffer/issues/98>
73+
#[inline]
74+
pub(crate) fn byte_stride(width: u32) -> u32 {
75+
let row_alignment = if cfg!(debug_assertions) {
76+
16 // Use a higher alignment to help users catch issues with their stride calculations.
77+
} else {
78+
4 // At least 4 is necessary for `Buffer` to return `&mut [u32]`.
79+
};
80+
// TODO: Use `next_multiple_of` when in MSRV.
81+
let mask = row_alignment * 4 - 1;
82+
((width * 32 + mask) & !mask) >> 3
83+
}

0 commit comments

Comments
 (0)