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)layoutSublayers
30 m_contentLayer.frame = self.bounds;
33- (
void)setNeedsDisplay
35 [self setNeedsDisplayInRect:CGRectInfinite];
38- (
void)setNeedsDisplayInRect:(CGRect)rect
40 [super setNeedsDisplayInRect:rect];
41 [self.contentLayer setNeedsDisplayInRect:rect];
45@implementation QNSView (Drawing)
50 const QSurfaceFormat surfaceFormat = m_platformWindow->format();
51 if (QColorSpace colorSpace = surfaceFormat.colorSpace(); colorSpace.isValid()) {
52 NSData *iccData = colorSpace.iccProfile().toNSData();
53 self.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
57 self.wantsLayer = YES;
62 if (!m_platformWindow)
64 return m_platformWindow->isOpaque();
72- (NSColorSpace*)colorSpace
75 return m_colorSpace ? m_colorSpace : self.window.colorSpace;
80- (BOOL)shouldUseMetalLayer
83 QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType();
84 return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104- (CALayer *)makeBackingLayer
106 if ([self shouldUseMetalLayer]) {
110 if ([MTLCreateSystemDefaultDevice() autorelease]) {
111 static bool allowPresentsWithTransaction =
112 !qEnvironmentVariableIsSet(
"QT_MTL_NO_TRANSACTION");
113 return allowPresentsWithTransaction ?
114 [QMetalLayer layer] : [CAMetalLayer layer];
116 qCWarning(lcQpaDrawing) <<
"Failed to create QWindow::MetalSurface."
117 <<
"Metal is not supported by any of the GPUs in this system.";
126 return [CALayer layer];
130
131
132
133
134
135
136- (
void)setLayer:(CALayer *)layer
138 qCDebug(lcQpaDrawing) <<
"Making" << self
139 << (self.wantsLayer ?
"layer-backed" :
"layer-hosted")
142 if (layer.delegate && layer.delegate != self) {
143 qCWarning(lcQpaDrawing) <<
"Layer already has delegate" << layer.delegate
144 <<
"This delegate is responsible for all view updates for" << self;
146 layer.delegate = self;
149 layer.name = @
"Qt content layer";
151 static const bool containerLayerOptOut = qEnvironmentVariableIsSet(
"QT_MAC_NO_CONTAINER_LAYER");
152 if (m_platformWindow->window()->surfaceType() != QSurface::OpenGLSurface && !containerLayerOptOut) {
153 qCDebug(lcQpaDrawing) <<
"Wrapping content layer" << layer <<
"in container layer";
154 auto *containerLayer = [[[QContainerLayer alloc] initWithContentLayer:layer] autorelease];
155 containerLayer.name = @
"Qt container layer";
156 containerLayer.delegate = self;
157 layer = containerLayer;
160 [super setLayer:layer];
162 [self propagateBackingProperties];
164 if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
168 layer.backgroundColor = NSColor.magentaColor.CGColor;
174- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
178 return NSViewLayerContentsRedrawDuringViewResize;
181- (NSViewLayerContentsPlacement)layerContentsPlacement
187 return NSViewLayerContentsPlacementTopLeft;
190- (
void)viewDidChangeBackingProperties
192 qCDebug(lcQpaDrawing) <<
"Backing properties changed for" << self;
194 if (!m_platformWindow)
197 [self propagateBackingProperties];
206 QWindowSystemInterface::handleWindowDevicePixelRatioChanged
207 <QWindowSystemInterface::SynchronousDelivery>(m_platformWindow->window());
211 [self setNeedsDisplay:YES];
214- (
void)propagateBackingProperties
226 auto devicePixelRatio = m_platformWindow->devicePixelRatio();
227 auto *contentLayer = m_platformWindow->contentLayer();
228 qCDebug(lcQpaDrawing) <<
"Updating" << contentLayer <<
"content scale to" << devicePixelRatio;
229 contentLayer.contentsScale = devicePixelRatio;
231 if ([contentLayer isKindOfClass:CAMetalLayer.
class]) {
232 CAMetalLayer *metalLayer =
static_cast<CAMetalLayer *>(contentLayer);
233 metalLayer.colorspace = self.colorSpace.CGColorSpace;
234 qCDebug(lcQpaDrawing) <<
"Set" << metalLayer <<
"color space to" << metalLayer.colorspace;
239
240
241
242
243
244- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
255
256
257
258
259- (
void)displayLayer:(CALayer *)layer
261 if (
auto *containerLayer = qt_objc_cast<QContainerLayer*>(layer)) {
262 qCDebug(lcQpaDrawing) <<
"Skipping display of" << containerLayer
263 <<
"as display is handled by content layer" << containerLayer.contentLayer;
267 if (!m_platformWindow)
270 if (!NSThread.isMainThread) {
274 qCWarning(lcQpaDrawing) <<
"Display non non-main thread! Deferring to main thread";
275 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
279 if (m_platformWindow->m_deliveringUpdateRequest) {
284 qCWarning(lcQpaDrawing) <<
"Asked to display during update-request delivery. Deferring.";
285 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
289 auto *currentScreen =
static_cast<QCocoaScreen*>(m_platformWindow->screen());
290 if (!currentScreen || !currentScreen->isOnline()) {
291 qCWarning(lcQpaDrawing) <<
"Display requested for non-online display" << currentScreen
292 <<
"Deferring to next runloop pass";
293 dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
297 const auto handleExposeEvent = [&]{
298 const auto bounds = QRectF::fromCGRect(self.bounds).toRect();
299 qCDebug(lcQpaDrawing) <<
"[QNSView displayLayer]" << m_platformWindow->window() << bounds;
300 m_platformWindow->handleExposeEvent(bounds);
303 if (
auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(layer)) {
304 const bool presentedWithTransaction = qtMetalLayer.presentsWithTransaction;
305 qtMetalLayer.presentsWithTransaction = YES;
317 QMacAutoReleasePool pool;
321 if (
auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) {
322 mainThreadPresentation();
323 qtMetalLayer.mainThreadPresentation = nil;
327 qtMetalLayer.presentsWithTransaction = presentedWithTransaction;
334 QMetaObject::invokeMethod(m_platformWindow, [qtMetalLayer]{
335 qCDebug(lcMetalLayer) <<
"Unlocking" << qtMetalLayer <<
"after finishing display-cycle";
336 qtMetalLayer.displayLock.unlock();
337 }, Qt::QueuedConnection);