diff --git a/VoidDisplay/Features/Capture/Views/ZeroCopyPreviewRenderer.swift b/VoidDisplay/Features/Capture/Views/ZeroCopyPreviewRenderer.swift index 76ea630..06a33cd 100644 --- a/VoidDisplay/Features/Capture/Views/ZeroCopyPreviewRenderer.swift +++ b/VoidDisplay/Features/Capture/Views/ZeroCopyPreviewRenderer.swift @@ -164,23 +164,23 @@ final class ZeroCopyHostView: NSView { private weak var displayLayer: AVSampleBufferDisplayLayer? func hostDisplayLayer(_ layer: AVSampleBufferDisplayLayer) { + if displayLayer === layer { + return + } + wantsLayer = true + if self.layer == nil { + self.layer = CALayer() + } layerContentsRedrawPolicy = .duringViewResize layer.frame = bounds + layer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable] + displayLayer?.removeFromSuperlayer() self.layer?.addSublayer(layer) displayLayer = layer syncLayerScale() } - override func layout() { - super.layout() - CATransaction.begin() - CATransaction.setDisableActions(true) - displayLayer?.frame = bounds - CATransaction.commit() - syncLayerScale() - } - override func viewDidMoveToWindow() { super.viewDidMoveToWindow() syncLayerScale() @@ -193,7 +193,6 @@ final class ZeroCopyHostView: NSView { private func syncLayerScale() { let scale = max(1, window?.backingScaleFactor ?? NSScreen.main?.backingScaleFactor ?? 1) - layer?.contentsScale = scale displayLayer?.contentsScale = scale } } diff --git a/VoidDisplayTests/Features/Capture/Views/ZeroCopyPreviewRendererTests.swift b/VoidDisplayTests/Features/Capture/Views/ZeroCopyPreviewRendererTests.swift index b610bde..c75fb05 100644 --- a/VoidDisplayTests/Features/Capture/Views/ZeroCopyPreviewRendererTests.swift +++ b/VoidDisplayTests/Features/Capture/Views/ZeroCopyPreviewRendererTests.swift @@ -1,3 +1,5 @@ +import AppKit +import AVFoundation import CoreGraphics import Testing @testable import VoidDisplay @@ -92,6 +94,18 @@ struct ZeroCopyPreviewRendererTests { #expect(renderer.hasReceivedFrame == false) } + @Test func hostViewDoesNotDuplicateHostedLayer() { + let view = ZeroCopyHostView(frame: NSRect(x: 0, y: 0, width: 320, height: 180)) + let layer = AVSampleBufferDisplayLayer() + + view.hostDisplayLayer(layer) + view.hostDisplayLayer(layer) + + #expect(view.layer != nil) + #expect(view.layer?.sublayers?.count == 1) + #expect(view.layer?.sublayers?.first === layer) + } + private func waitUntil( timeout: Duration = .seconds(1), condition: @escaping @Sendable () async -> Bool