7@implementation QContainerLayer {
8 CALayer *m_contentLayer;
10- (instancetype)initWithContentLayer:(CALayer *)contentLayer
12 if ((self = [super init])) {
13 m_contentLayer = contentLayer;
14 [self addSublayer:contentLayer];
15 contentLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
20- (CALayer*)contentLayer
22 return m_contentLayer;
25- (
void)setNeedsDisplay
27 [self setNeedsDisplayInRect:CGRectInfinite];
30- (
void)setNeedsDisplayInRect:(CGRect)rect
32 [super setNeedsDisplayInRect:rect];
33 [self.contentLayer setNeedsDisplayInRect:rect];
37@implementation QNSView (Drawing)
42 const QSurfaceFormat surfaceFormat = m_platformWindow->format();
43 if (QColorSpace colorSpace = surfaceFormat.colorSpace(); colorSpace.isValid()) {
44 NSData *iccData = colorSpace.iccProfile().toNSData();
45 self.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
49 self.wantsLayer = YES;
54 if (!m_platformWindow)
56 return m_platformWindow->isOpaque();
64- (NSColorSpace*)colorSpace
67 return m_colorSpace ? m_colorSpace : self.window.colorSpace;
72- (BOOL)shouldUseMetalLayer
75 QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType();
76 return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96- (CALayer *)makeBackingLayer
98 if ([self shouldUseMetalLayer]) {
102 if ([MTLCreateSystemDefaultDevice() autorelease]) {
103 static bool allowPresentsWithTransaction =
104 !qEnvironmentVariableIsSet(
"QT_MTL_NO_TRANSACTION");
105 return allowPresentsWithTransaction ?
106 [QMetalLayer layer] : [CAMetalLayer layer];
108 qCWarning(lcQpaDrawing) <<
"Failed to create QWindow::MetalSurface."
109 <<
"Metal is not supported by any of the GPUs in this system.";
118 return [CALayer layer];
122
123
124
125
126
127
128- (
void)setLayer:(CALayer *)layer
130 qCDebug(lcQpaDrawing) <<
"Making" << self
131 << (self.wantsLayer ?
"layer-backed" :
"layer-hosted")
134 if (layer.delegate && layer.delegate != self) {
135 qCWarning(lcQpaDrawing) <<
"Layer already has delegate" << layer.delegate
136 <<
"This delegate is responsible for all view updates for" << self;
138 layer.delegate = self;
141 layer.name = @
"Qt content layer";
143 static const bool containerLayerOptOut = qEnvironmentVariableIsSet(
"QT_MAC_NO_CONTAINER_LAYER");
144 if (m_platformWindow->window()->surfaceType() != QSurface::OpenGLSurface && !containerLayerOptOut) {
145 qCDebug(lcQpaDrawing) <<
"Wrapping content layer" << layer <<
"in container layer";
146 auto *containerLayer = [[[QContainerLayer alloc] initWithContentLayer:layer] autorelease];
147 containerLayer.name = @
"Qt container layer";
148 containerLayer.delegate = self;
149 layer = containerLayer;
152 [super setLayer:layer];
154 [self propagateBackingProperties];
156 if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
160 layer.backgroundColor = NSColor.magentaColor.CGColor;
166- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
170 return NSViewLayerContentsRedrawDuringViewResize;
173- (NSViewLayerContentsPlacement)layerContentsPlacement
179 return NSViewLayerContentsPlacementTopLeft;
182- (
void)viewDidChangeBackingProperties
184 qCDebug(lcQpaDrawing) <<
"Backing properties changed for" << self;
186 if (!m_platformWindow)
189 [self propagateBackingProperties];
198 QWindowSystemInterface::handleWindowDevicePixelRatioChanged
199 <QWindowSystemInterface::SynchronousDelivery>(m_platformWindow->window());
203 [self setNeedsDisplay:YES];
206- (
void)propagateBackingProperties
218 auto devicePixelRatio = m_platformWindow->devicePixelRatio();
219 auto *contentLayer = m_platformWindow->contentLayer();
220 qCDebug(lcQpaDrawing) <<
"Updating" << contentLayer <<
"content scale to" << devicePixelRatio;
221 contentLayer.contentsScale = devicePixelRatio;
223 if ([contentLayer isKindOfClass:CAMetalLayer.
class]) {
224 CAMetalLayer *metalLayer =
static_cast<CAMetalLayer *>(contentLayer);
225 metalLayer.colorspace = self.colorSpace.CGColorSpace;
226 qCDebug(lcQpaDrawing) <<
"Set" << metalLayer <<
"color space to" << metalLayer.colorspace;
231
232
233
234
235
236- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
247
248
249
250
251- (
void)displayLayer:(CALayer *)layer
253 if (
auto *containerLayer = qt_objc_cast<QContainerLayer*>(layer)) {
254 qCDebug(lcQpaDrawing) <<
"Skipping display of" << containerLayer
255 <<
"as display is handled by content layer" << containerLayer.contentLayer;
259 if (!m_platformWindow)
262 if (!NSThread.isMainThread) {
266 qCWarning(lcQpaDrawing) <<
"Display non non-main thread! Deferring to main thread";
267 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
271 const auto handleExposeEvent = [&]{
272 const auto bounds = QRectF::fromCGRect(self.bounds).toRect();
273 qCDebug(lcQpaDrawing) <<
"[QNSView displayLayer]" << m_platformWindow->window() << bounds;
274 m_platformWindow->handleExposeEvent(bounds);
277 if (
auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(layer)) {
278 const bool presentedWithTransaction = qtMetalLayer.presentsWithTransaction;
279 qtMetalLayer.presentsWithTransaction = YES;
291 QMacAutoReleasePool pool;
295 if (
auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) {
296 mainThreadPresentation();
297 qtMetalLayer.mainThreadPresentation = nil;
301 qtMetalLayer.presentsWithTransaction = presentedWithTransaction;
308 QMetaObject::invokeMethod(m_platformWindow, [qtMetalLayer]{
309 qCDebug(lcMetalLayer) <<
"Unlocking" << qtMetalLayer <<
"after finishing display-cycle";
310 qtMetalLayer.displayLock.unlock();
311 }, Qt::QueuedConnection);