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];
19- (CALayer*)contentLayer
21 return m_contentLayer;
24- (
void)setContentsGravity:(CALayerContentsGravity)gravity
27 [super setContentsGravity:gravity];
28 m_contentLayer.contentsGravity = gravity;
31- (
void)layoutSublayers
37 m_contentLayer.frame = self.bounds;
40- (
void)setNeedsDisplay
42 [self setNeedsDisplayInRect:CGRectInfinite];
45- (
void)setNeedsDisplayInRect:(CGRect)rect
47 [super setNeedsDisplayInRect:rect];
48 [self.contentLayer setNeedsDisplayInRect:rect];
52@implementation QNSView (Drawing)
57 const QSurfaceFormat surfaceFormat = m_platformWindow->format();
58 if (QColorSpace colorSpace = surfaceFormat.colorSpace(); colorSpace.isValid()) {
59 NSData *iccData = colorSpace.iccProfile().toNSData();
60 self.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
64 self.wantsLayer = YES;
69 if (!m_platformWindow)
71 return m_platformWindow->isOpaque();
79- (NSColorSpace*)colorSpace
82 return m_colorSpace ? m_colorSpace : self.window.colorSpace;
87- (BOOL)shouldUseMetalLayer
89 if (!m_platformWindow)
93 QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType();
94 return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114- (CALayer *)makeBackingLayer
116 if ([self shouldUseMetalLayer]) {
120 if ([MTLCreateSystemDefaultDevice() autorelease]) {
121 static bool allowPresentsWithTransaction =
122 !qEnvironmentVariableIsSet(
"QT_MTL_NO_TRANSACTION");
125 const bool isVulkanSurface =
126 m_platformWindow->window()->surfaceType() == QSurface::VulkanSurface;
127 return allowPresentsWithTransaction && !isVulkanSurface ?
128 [QMetalLayer layer] : [CAMetalLayer layer];
130 qCWarning(lcQpaDrawing) <<
"Failed to create QWindow::MetalSurface."
131 <<
"Metal is not supported by any of the GPUs in this system.";
140 return [CALayer layer];
144
145
146
147
148
149
150- (
void)setLayer:(CALayer *)layer
152 if (!m_platformWindow) {
153 [super setLayer:layer];
157 qCDebug(lcQpaDrawing) <<
"Making" << self
158 << (self.wantsLayer ?
"layer-backed" :
"layer-hosted")
161 if (layer.delegate && layer.delegate != self) {
162 qCWarning(lcQpaDrawing) <<
"Layer already has delegate" << layer.delegate
163 <<
"This delegate is responsible for all view updates for" << self;
165 layer.delegate = self;
168 layer.name = @
"Qt content layer";
170 static const bool containerLayerOptOut = qEnvironmentVariableIsSet(
"QT_MAC_NO_CONTAINER_LAYER");
171 if (m_platformWindow->window()->surfaceType() != QSurface::OpenGLSurface && !containerLayerOptOut) {
172 qCDebug(lcQpaDrawing) <<
"Wrapping content layer" << layer <<
"in container layer";
173 auto *containerLayer = [[[QContainerLayer alloc] initWithContentLayer:layer] autorelease];
174 containerLayer.name = @
"Qt container layer";
175 containerLayer.delegate = self;
176 layer = containerLayer;
179 [super setLayer:layer];
181 [self propagateBackingProperties];
183 if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
187 layer.backgroundColor = NSColor.magentaColor.CGColor;
193- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
197 return NSViewLayerContentsRedrawDuringViewResize;
200- (NSViewLayerContentsPlacement)layerContentsPlacement
206 return NSViewLayerContentsPlacementTopLeft;
209- (
void)viewDidChangeBackingProperties
211 qCDebug(lcQpaDrawing) <<
"Backing properties changed for" << self;
213 if (!m_platformWindow)
216 [self propagateBackingProperties];
225 QWindowSystemInterface::handleWindowDevicePixelRatioChanged
226 <QWindowSystemInterface::SynchronousDelivery>(m_platformWindow->window());
230 [self setNeedsDisplay:YES];
233- (
void)propagateBackingProperties
245 auto devicePixelRatio = m_platformWindow->devicePixelRatio();
246 auto *contentLayer = m_platformWindow->contentLayer();
247 qCDebug(lcQpaDrawing) <<
"Updating" << contentLayer <<
"content scale to" << devicePixelRatio;
248 contentLayer.contentsScale = devicePixelRatio;
250 if ([contentLayer isKindOfClass:CAMetalLayer.
class]) {
251 CAMetalLayer *metalLayer =
static_cast<CAMetalLayer *>(contentLayer);
252 metalLayer.colorspace = self.colorSpace.CGColorSpace;
253 qCDebug(lcQpaDrawing) <<
"Set" << metalLayer <<
"color space to" << metalLayer.colorspace;
258
259
260
261
262
263- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
274
275
276
277
278- (
void)displayLayer:(CALayer *)layer
280 if (
auto *containerLayer = qt_objc_cast<QContainerLayer*>(layer)) {
281 qCDebug(lcQpaDrawing) <<
"Skipping display of" << containerLayer
282 <<
"as display is handled by content layer" << containerLayer.contentLayer;
286 if (!m_platformWindow)
289 auto *qtMetalLayer = qt_objc_cast<QMetalLayer *>(layer);
298 QMetaObject::invokeMethod(m_platformWindow, [qtMetalLayer]{
299 qCDebug(lcMetalLayer) <<
"Unlocking" << qtMetalLayer <<
"after finishing display-cycle";
300 qtMetalLayer.displayLock.unlock();
301 }, Qt::QueuedConnection);
304 if (!NSThread.isMainThread) {
308 qCWarning(lcQpaDrawing) <<
"Display non non-main thread! Deferring to main thread";
309 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
313 if (m_platformWindow->m_deliveringUpdateRequest) {
318 qCWarning(lcQpaDrawing) <<
"Asked to display during update-request delivery. Deferring.";
319 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
323 auto *currentScreen =
static_cast<QCocoaScreen*>(m_platformWindow->screen());
324 if (!currentScreen || !currentScreen->isOnline()) {
325 qCWarning(lcQpaDrawing) <<
"Display requested for non-online display" << currentScreen
326 <<
"Deferring to next runloop pass";
327 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
331 const auto handleExposeEvent = [&]{
332 const auto bounds = QRectF::fromCGRect(self.bounds).toRect();
333 qCDebug(lcQpaDrawing) <<
"[QNSView displayLayer]" << m_platformWindow->window() << bounds;
334 m_platformWindow->handleExposeEvent(bounds);
338 const bool presentedWithTransaction = qtMetalLayer.presentsWithTransaction;
339 qtMetalLayer.presentsWithTransaction = YES;
351 QMacAutoReleasePool pool;
355 if (
auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) {
356 mainThreadPresentation();
357 qtMetalLayer.mainThreadPresentation = nil;
361 qtMetalLayer.presentsWithTransaction = presentedWithTransaction;