Fix macOS black video after player close/reopen

The macOS CAOpenGLLayer is pull-based: after the shared render view is
re-parented into a reopened player window, a single forced repaint is
issued. draw() consumed the forceDraw flag before validating the
viewport, so when that repaint landed while the layer was still 0x0
(the expanded window builds its content a runloop late), the request
was swallowed. With mpv paused during load, nothing repainted again,
leaving the video permanently black with working audio.

- Validate viewport/framebuffer in draw() before consuming flags;
  on failure keep the forced draw armed and retry (bounded, 5x50ms)
- Repaint from setFrameSize on the first non-zero layout while a
  forced draw is still pending
- Drop the stale fbo=1 fallback; render only into the validated
  live framebuffer binding
- clearToBlack: take the CGL lock and skip glClear when no
  framebuffer is bound - clearing FBO 0 on this core-profile context
  latched GL_INVALID_FRAMEBUFFER_OPERATION, which libmpv reported on
  every load
- Add diagnostics for dropped draws and the first-frame render
This commit is contained in:
Arkadiusz Fal
2026-06-03 22:00:28 +02:00
parent 8acf0f6d3f
commit 5c8c55f41c
2 changed files with 104 additions and 21 deletions

View File

@@ -191,6 +191,19 @@ final class MPVOGLView: NSView {
updateDisplayRefreshRate()
}
override func setFrameSize(_ newSize: NSSize) {
super.setFrameSize(newSize)
// If a forced draw was requested while the layer had no size/drawable
// (shared view re-parented into the deferred expanded sheet), repaint
// on the first non-zero layout. Gated on hasPendingForcedDraw so
// ordinary resizes don't trigger redundant redraws.
guard newSize.width > 0, newSize.height > 0,
let videoLayer, videoLayer.hasPendingForcedDraw else { return }
LoggingService.shared.debug("MPVOGLView: retrying pending forced draw after resize to \(newSize)", category: .mpv)
videoLayer.update(force: true)
}
override func draw(_ dirtyRect: NSRect) {
// No-op - the layer handles all drawing
}