Skip to content

Commit b791698

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 87b58ce commit b791698

File tree

5 files changed

+39
-21
lines changed

5 files changed

+39
-21
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![Pixel::default(); self.width * self.height]),
264+
buffer: util::PixelBuffer(vec![Pixel::default(); 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
use crate::Pixel;
1920

2021
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
@@ -99,7 +100,7 @@ impl WaylandBuffer {
99100
0,
100101
width,
101102
height,
102-
width * 4,
103+
util::byte_stride(width as u32) as i32,
103104
// This is documented as `0xXXRRGGBB` on a little-endian machine, which means a byte
104105
// order of `[B, G, R, X]`.
105106
wl_shm::Format::Xrgb8888,
@@ -141,7 +142,7 @@ impl WaylandBuffer {
141142
0,
142143
width,
143144
height,
144-
width * 4,
145+
util::byte_stride(width as u32) as i32,
145146
wl_shm::Format::Xrgb8888,
146147
&self.qh,
147148
self.released.clone(),
@@ -161,7 +162,7 @@ impl WaylandBuffer {
161162
}
162163

163164
fn len(&self) -> usize {
164-
self.width as usize * self.height as usize
165+
util::byte_stride(self.width as u32) as usize * self.height as usize / 4
165166
}
166167

167168
#[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-
Pixel, Rect, SoftBufferError,
4+
util, Pixel, 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: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
88

99
use std::io;
1010
use std::marker::PhantomData;
11-
use std::mem;
11+
use std::mem::size_of;
1212
use std::num::{NonZeroI32, NonZeroU32};
1313
use std::ptr::{self, NonNull};
1414
use std::slice;
@@ -55,7 +55,7 @@ impl Buffer {
5555
// Create a new bitmap info struct.
5656
let bitmap_info = BitmapInfo {
5757
bmi_header: Gdi::BITMAPINFOHEADER {
58-
biSize: mem::size_of::<Gdi::BITMAPINFOHEADER>() as u32,
58+
biSize: size_of::<Gdi::BITMAPINFOHEADER>() as u32,
5959
biWidth: width.get(),
6060
biHeight: -height.get(),
6161
biPlanes: 1,
@@ -116,12 +116,9 @@ impl Buffer {
116116

117117
#[inline]
118118
fn pixels_mut(&mut self) -> &mut [Pixel] {
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 * self.height.get() as usize;
121+
unsafe { slice::from_raw_parts_mut(self.pixels.as_ptr(), num_bytes / size_of::<Pixel>()) }
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)