Skip to content

Commit 2ac7aa8

Browse files
committed
Add API for making buffers write-only
To allow reading from the buffer by default.
1 parent 0eeed70 commit 2ac7aa8

File tree

4 files changed

+59
-27
lines changed

4 files changed

+59
-27
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22

3+
- Added `Surface::set_write_only()` for optimizing for write-only workloads.
34
- Added `Buffer::pixels()` for accessing the buffer's pixel data.
45
- Added `Buffer::pixel_rows()` for iterating over rows of the buffer data.
56
- Added `Buffer::pixels_iter()` for iterating over each pixel with its associated `x`/`y` coordinate.

src/backend_dispatch.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ macro_rules! make_dispatch {
108108
}
109109
}
110110

111+
fn set_write_only(&mut self, write_only: bool) {
112+
match self {
113+
$(
114+
$(#[$attr])*
115+
Self::$name(inner) => inner.set_write_only(write_only),
116+
)*
117+
}
118+
}
119+
111120
fn buffer_mut(&mut self) -> Result<BufferDispatch<'_>, SoftBufferError> {
112121
match self {
113122
$(

src/backend_interface.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ pub(crate) trait SurfaceInterface<D: HasDisplayHandle + ?Sized, W: HasWindowHand
2626
fn window(&self) -> &W;
2727
/// Resize the internal buffer to the given width and height.
2828
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError>;
29+
30+
fn set_write_only(&mut self, _write_only: bool) {
31+
// No-op by default.
32+
}
33+
2934
/// Get a mutable reference to the buffer.
3035
fn buffer_mut(&mut self) -> Result<Self::Buffer<'_>, SoftBufferError>;
3136
/// Fetch the buffer from the window.

src/lib.rs

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,47 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
114114
self.surface_impl.resize(width, height)
115115
}
116116

117+
/// Set the buffer as optimized for only being written to.
118+
///
119+
/// Setting this allows the underlying storage to bypass certain caches and reduce cache
120+
/// pollution. In turn, this may make reading from the buffer data perform very poorly.
121+
///
122+
/// As such, when rendering with this set, you should make sure to set pixels in their entirety:
123+
///
124+
/// ```
125+
/// # let pixel = &mut 0x00ffffff;
126+
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
127+
/// *pixel = blue | (green << 8) | (red << 16);
128+
/// # assert_eq!(*pixel, 0x00332211);
129+
/// ```
130+
///
131+
/// Instead of e.g. something like:
132+
///
133+
/// ```
134+
/// # let pixel = &mut 0x00ffffff;
135+
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
136+
/// // DISCOURAGED!
137+
/// *pixel &= 0x00000000; // Clear
138+
/// *pixel |= blue; // Set blue pixel
139+
/// *pixel |= green << 8; // Set green pixel
140+
/// *pixel |= red << 16; // Set red pixel
141+
/// # assert_eq!(*pixel, 0x00332211);
142+
/// ```
143+
///
144+
/// This is disabled by default.
145+
///
146+
/// # Platform-specific
147+
///
148+
/// This isn't yet implemented on any platforms, and is simply a no-op.
149+
///
150+
/// On macOS, this may in the future set `kIOSurfaceCacheMode` to
151+
/// `kIOSurfaceMapWriteCombineCache`.
152+
#[inline]
153+
// TODO: Add `write_only` getter? Would it ever really be useful?
154+
pub fn set_write_only(&mut self, write_only: bool) {
155+
self.surface_impl.set_write_only(write_only)
156+
}
157+
117158
/// Copies the window contents into a buffer.
118159
///
119160
/// ## Platform Dependent Behavior
@@ -175,33 +216,9 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> HasWindowHandle for Surface<D, W>
175216
///
176217
/// # Reading buffer data
177218
///
178-
/// Reading from buffer data may perform very poorly, as the underlying storage of zero-copy
179-
/// buffers, where implemented, may set options optimized for CPU writes, that allows them to bypass
180-
/// certain caches and avoid cache pollution.
181-
///
182-
/// As such, when rendering, you should always set the pixel in its entirety:
183-
///
184-
/// ```
185-
/// # let pixel = &mut 0x00ffffff;
186-
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
187-
/// *pixel = blue | (green << 8) | (red << 16);
188-
/// # assert_eq!(*pixel, 0x00332211);
189-
/// ```
190-
///
191-
/// Instead of e.g. something like:
192-
///
193-
/// ```
194-
/// # let pixel = &mut 0x00ffffff;
195-
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
196-
/// // DISCOURAGED!
197-
/// *pixel &= 0x00000000; // Clear
198-
/// *pixel |= blue; // Set blue pixel
199-
/// *pixel |= green << 8; // Set green pixel
200-
/// *pixel |= red << 16; // Set red pixel
201-
/// # assert_eq!(*pixel, 0x00332211);
202-
/// ```
203-
///
204-
/// To discourage reading from the buffer, `&self -> &[u8]` methods are intentionally not provided.
219+
/// The API of this is simplified for writing to buffer data, so various `&self -> &[X]` methods are
220+
/// intentionally not provided. You can still read from the buffer data via. the `&mut self` methods
221+
/// though.
205222
///
206223
/// # Data representation
207224
///

0 commit comments

Comments
 (0)