Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased

- Added `Surface::set_write_only()` for optimizing for write-only workloads.
- Added `Buffer::pixels()` for accessing the buffer's pixel data.
- Added `Buffer::pixel_rows()` for iterating over rows of the buffer data.
- Added `Buffer::pixels_iter()` for iterating over each pixel with its associated `x`/`y` coordinate.
Expand Down
9 changes: 9 additions & 0 deletions src/backend_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ macro_rules! make_dispatch {
}
}

fn set_write_only(&mut self, write_only: bool) {
match self {
$(
$(#[$attr])*
Self::$name(inner) => inner.set_write_only(write_only),
)*
}
}

fn buffer_mut(&mut self) -> Result<BufferDispatch<'_>, SoftBufferError> {
match self {
$(
Expand Down
5 changes: 5 additions & 0 deletions src/backend_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ pub(crate) trait SurfaceInterface<D: HasDisplayHandle + ?Sized, W: HasWindowHand
fn window(&self) -> &W;
/// Resize the internal buffer to the given width and height.
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError>;

fn set_write_only(&mut self, _write_only: bool) {
// No-op by default.
}

/// Get a mutable reference to the buffer.
fn buffer_mut(&mut self) -> Result<Self::Buffer<'_>, SoftBufferError>;
/// Fetch the buffer from the window.
Expand Down
71 changes: 44 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,47 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
self.surface_impl.resize(width, height)
}

/// Set the buffer as optimized for only being written to.
///
/// Setting this allows the underlying storage to bypass certain caches and reduce cache
/// pollution. In turn, this may make reading from the buffer data perform very poorly.
///
/// As such, when rendering with this set, you should make sure to set pixels in their entirety:
///
/// ```
/// # let pixel = &mut 0x00ffffff;
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
/// *pixel = blue | (green << 8) | (red << 16);
/// # assert_eq!(*pixel, 0x00332211);
/// ```
///
/// Instead of e.g. something like:
///
/// ```
/// # let pixel = &mut 0x00ffffff;
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
/// // DISCOURAGED!
/// *pixel &= 0x00000000; // Clear
/// *pixel |= blue; // Set blue pixel
/// *pixel |= green << 8; // Set green pixel
/// *pixel |= red << 16; // Set red pixel
/// # assert_eq!(*pixel, 0x00332211);
/// ```
///
/// This is disabled by default.
///
/// # Platform-specific
///
/// This isn't yet implemented on any platforms, and is simply a no-op.
///
/// On macOS, this may in the future set `kIOSurfaceCacheMode` to
/// `kIOSurfaceMapWriteCombineCache`.
#[inline]
// TODO: Add `write_only` getter? Would it ever really be useful?
pub fn set_write_only(&mut self, write_only: bool) {
self.surface_impl.set_write_only(write_only)
}

/// Copies the window contents into a buffer.
///
/// ## Platform Dependent Behavior
Expand Down Expand Up @@ -175,33 +216,9 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> HasWindowHandle for Surface<D, W>
///
/// # Reading buffer data
///
/// Reading from buffer data may perform very poorly, as the underlying storage of zero-copy
/// buffers, where implemented, may set options optimized for CPU writes, that allows them to bypass
/// certain caches and avoid cache pollution.
///
/// As such, when rendering, you should always set the pixel in its entirety:
///
/// ```
/// # let pixel = &mut 0x00ffffff;
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
/// *pixel = blue | (green << 8) | (red << 16);
/// # assert_eq!(*pixel, 0x00332211);
/// ```
///
/// Instead of e.g. something like:
///
/// ```
/// # let pixel = &mut 0x00ffffff;
/// # let (blue, green, red) = (0x11, 0x22, 0x33);
/// // DISCOURAGED!
/// *pixel &= 0x00000000; // Clear
/// *pixel |= blue; // Set blue pixel
/// *pixel |= green << 8; // Set green pixel
/// *pixel |= red << 16; // Set red pixel
/// # assert_eq!(*pixel, 0x00332211);
/// ```
///
/// To discourage reading from the buffer, `&self -> &[u8]` methods are intentionally not provided.
/// The API of this is simplified for writing to buffer data, so various `&self -> &[X]` methods are
/// intentionally not provided. You can still read from the buffer data via. the `&mut self` methods
/// though.
///
/// # Data representation
///
Expand Down