Skip to content
Draft
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
Expand Up @@ -17,6 +17,7 @@
- **Breaking:** Removed `DamageOutOfRange` error case. If the damage value is greater than the backend supports, it is instead clamped to an appropriate value.
- **Breaking:** Removed `SurfaceExtWeb` and the associated `NoDisplayHandle` and `NoWindowHandle` helpers. Use `RawWindowHandle::WebCanvas` or `RawWindowHandle::WebOffscreenCanvas` instead.
- Fixed `present_with_damage` with bounds out of range on Windows, Web and X11.
- Reduced flickering when presenting while resizing on macOS.

# 0.4.8

Expand Down
24 changes: 20 additions & 4 deletions src/backends/cg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,14 +418,30 @@ impl BufferInterface for BufferImpl<'_> {
}
.unwrap();

// Wrap layer modifications in a transaction. Unclear if we should keep doing this, see
// <https://github.com/rust-windowing/softbuffer/pull/275> for discussion about this.
CATransaction::begin();
// Wrap things in a transaction if the event loop isn't currently running.
//
// The event loop implicitly commits pending layer updates at the end of the current run
// loop iteration, as documented in:
// <https://developer.apple.com/documentation/quartzcore/catransaction?language=objc>
//
//
//
// This is a bit overly conservative; the full check on macOS could. But it doesn't matter _that_ much, if users decide to render in weird ways, we'll still support it when emitting a transaction, it'll just be slightly less efficient.
let use_transaction = objc2_core_foundation::CFRunLoop::current()
.unwrap()
.current_mode()
.is_none();

if use_transaction {
CATransaction::begin();
}

// SAFETY: The contents is `CGImage`, which is a valid class for `contents`.
unsafe { layer.setContents(Some(image.as_ref())) };

CATransaction::commit();
if use_transaction {
CATransaction::commit();
}

Ok(())
}
Expand Down
15 changes: 15 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,21 @@ impl Buffer<'_> {
///
/// If the caller wishes to synchronize other surface/window changes, such requests must be sent to the
/// Wayland compositor before calling this function.
///
/// ## macOS / iOS
///
/// On macOS/iOS/etc., this sets the [contents] of the underlying [`CALayer`], but doesn't yet
/// actually commit those contents to the compositor; that is instead done automatically by
/// QuartzCore at the end of the current iteration of the runloop. This synchronizes the
/// contents with the rest of the window, which is important to avoid flickering when resizing.
///
/// If you need to send the contents to the compositor immediately (might be useful when
/// rendering from a separate thread or when using Softbuffer without the standard AppKit/UIKit
/// runloop), you'll want to wrap this function in a [`CATransaction`].
///
/// [contents]: https://developer.apple.com/documentation/quartzcore/calayer/contents?language=objc
/// [`CALayer`]: https://developer.apple.com/documentation/quartzcore/calayer?language=objc
/// [`CATransaction`]: https://developer.apple.com/documentation/quartzcore/catransaction?language=objc
#[inline]
pub fn present(self) -> Result<(), SoftBufferError> {
// Damage the entire buffer.
Expand Down