Reflect the video below the hinge in the tabletop layout

The iPhone Duo tabletop layout mirrors every presented frame into the
lower half, blurred and fading out, like a screen standing on a glossy
table. The render view blits a quarter-resolution copy of the display
framebuffer into a ring of IOSurface-backed buffers (no Y flip, so the
surface is already mirrored) and hands it to a CALayer hosted by
MPVReflectionView; the simulator's software renderer feeds the same
layer a flipped CGImage. Off during PiP, for audio-only streams, and
via the new Playback → Foldable → "Reflection Below Video" setting.
This commit is contained in:
Arkadiusz Fal
2026-10-01 20:59:48 +02:00
parent 2fd52fff27
commit 83895a1fd9
11 changed files with 431 additions and 0 deletions

View File

@@ -64,6 +64,15 @@ final class MPVSoftwareRenderView: UIView {
/// Callback when view is added to window (for PiP setup)
var onDidMoveToWindow: ((UIView) -> Void)?
/// Mirrored copy of every frame for the tabletop reflection (see `MPVRenderView`).
let reflectionLayer = MPVReflectionLayer()
var isReflectionEnabled = false {
didSet {
if !isReflectionEnabled { reflectionLayer.clear() }
}
}
/// Dedicated queue for rendering operations
private let renderQueue = DispatchQueue(label: "stream.yattee.mpv.software-render", qos: .userInitiated)
@@ -434,6 +443,9 @@ final class MPVSoftwareRenderView: UIView {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.layer.contents = image
if self.isReflectionEnabled {
self.reflectionLayer.displayMirrored(image)
}
}
// Notify on first frame rendered