Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcocoaglcontext.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <AppKit/AppKit.h>
6
8#include "qcocoawindow.h"
10#include "qcocoascreen.h"
11
12#include <QtCore/private/qcore_mac_p.h>
13
14#include <qdebug.h>
15#include <dlfcn.h>
16
17static inline QByteArray getGlString(GLenum param)
18{
19 if (const GLubyte *s = glGetString(param))
20 return QByteArray(reinterpret_cast<const char*>(s));
21 return QByteArray();
22}
23
24#if defined(Q_PROCESSOR_X86_64)
25QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNoopDisplayDelegate, NSObject<CALayerDelegate>)
26#endif
27
29
30Q_LOGGING_CATEGORY(lcQpaOpenGLContext, "qt.qpa.openglcontext", QtWarningMsg);
31
32QCocoaGLContext::QCocoaGLContext(QOpenGLContext *context)
35{
36}
37
38QCocoaGLContext::QCocoaGLContext(NSOpenGLContext *nativeContext)
40{
41 m_context = [nativeContext retain];
42}
43
45{
46 if (m_context) {
47 // Note: We have no way of knowing whether the NSOpenGLContext was created with the
48 // share context as reported by the QOpenGLContext, but we just have to trust that
49 // it was. It's okey, as the only thing we're using it for is to report isShared().
50 if (QPlatformOpenGLContext *shareContext = context()->shareHandle())
51 m_shareContext = static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
52
53 updateSurfaceFormat();
54 return;
55 }
56
57 // ----------- Default case, we own the NSOpenGLContext -----------
58
59 // We only support OpenGL contexts under Cocoa
60 if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
61 m_format.setRenderableType(QSurfaceFormat::OpenGL);
62 if (m_format.renderableType() != QSurfaceFormat::OpenGL)
63 return;
64
65 if (QPlatformOpenGLContext *shareContext = context()->shareHandle()) {
66 m_shareContext = static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
67
68 // Allow sharing between 3.2 Core and 4.1 Core profile versions in
69 // cases where NSOpenGLContext creates a 4.1 context where a 3.2
70 // context was requested. Due to the semantics of QSurfaceFormat
71 // this 4.1 version can find its way onto the format for the new
72 // context, even though it was at no point requested by the user.
73 GLint shareContextRequestedProfile;
74 [m_shareContext.pixelFormat getValues:&shareContextRequestedProfile
75 forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:0];
76 auto shareContextActualProfile = shareContext->format().version();
77
78 if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core
79 && shareContextActualProfile >= qMakePair(4, 1)) {
80 // There is a mismatch. Downgrade requested format to make the
81 // NSOpenGLPFAOpenGLProfile attributes match. (NSOpenGLContext
82 // will fail to create a new context if there is a mismatch).
83 if (m_format.version() >= qMakePair(4, 1))
84 m_format.setVersion(3, 2);
85 }
86 }
87
88 // ------------------------- Create NSOpenGLContext -------------------------
89
90 NSOpenGLPixelFormat *pixelFormat = [pixelFormatForSurfaceFormat(m_format) autorelease];
91 m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext];
92
93 if (!m_context && m_shareContext) {
94 qCWarning(lcQpaOpenGLContext, "Could not create NSOpenGLContext with shared context, "
95 "falling back to unshared context.");
96 m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
97 m_shareContext = nil;
98 }
99
100 if (!m_context) {
101 qCWarning(lcQpaOpenGLContext, "Failed to create NSOpenGLContext");
102 return;
103 }
104
105 // --------------------- Set NSOpenGLContext properties ---------------------
106
107 const GLint interval = m_format.swapInterval() >= 0 ? m_format.swapInterval() : 1;
108 [m_context setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval];
109
110 if (m_format.alphaBufferSize() > 0) {
111 int zeroOpacity = 0;
112 [m_context setValues:&zeroOpacity forParameter:NSOpenGLContextParameterSurfaceOpacity];
113 }
114
115 // OpenGL surfaces can be ordered either above(default) or below the NSWindow
116 // FIXME: Promote to QSurfaceFormat option or property
117 const GLint order = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
118 [m_context setValues:&order forParameter:NSOpenGLContextParameterSurfaceOrder];
119
120 updateSurfaceFormat();
121
122 qCDebug(lcQpaOpenGLContext).verbosity(3) << "Created" << this << "based on requested" << context()->format();
123}
124
125NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format)
126{
127 QVector<NSOpenGLPixelFormatAttribute> attrs;
128
129 attrs << NSOpenGLPFAOpenGLProfile;
130 if (format.profile() == QSurfaceFormat::CoreProfile) {
131 if (format.version() >= qMakePair(4, 1))
132 attrs << NSOpenGLProfileVersion4_1Core;
133 else if (format.version() >= qMakePair(3, 2))
134 attrs << NSOpenGLProfileVersion3_2Core;
135 else
136 attrs << NSOpenGLProfileVersionLegacy;
137 } else {
138 attrs << NSOpenGLProfileVersionLegacy;
139 }
140
141 switch (format.swapBehavior()) {
142 case QSurfaceFormat::SingleBuffer:
143 break; // The NSOpenGLPixelFormat default, no attribute to set
144 case QSurfaceFormat::DefaultSwapBehavior:
145 // Technically this should be single-buffered, but we force double-buffered
146 // FIXME: Why do we force double-buffered?
147 Q_FALLTHROUGH();
148 case QSurfaceFormat::DoubleBuffer:
149 attrs.append(NSOpenGLPFADoubleBuffer);
150 break;
151 case QSurfaceFormat::TripleBuffer:
152 attrs.append(NSOpenGLPFATripleBuffer);
153 break;
154 }
155
156 if (format.depthBufferSize() > 0)
157 attrs << NSOpenGLPFADepthSize << format.depthBufferSize();
158 if (format.stencilBufferSize() > 0)
159 attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize();
160 if (format.alphaBufferSize() > 0)
161 attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize();
162
163 auto rbz = format.redBufferSize();
164 auto gbz = format.greenBufferSize();
165 auto bbz = format.blueBufferSize();
166 if (rbz > 0 || gbz > 0 || bbz > 0) {
167 auto fallbackSize = qMax(rbz, qMax(gbz, bbz));
168 auto colorSize = (rbz > 0 ? rbz : fallbackSize)
169 + (gbz > 0 ? gbz : fallbackSize)
170 + (bbz > 0 ? bbz : fallbackSize);
171 attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy;
172 }
173
174 if (format.samples() > 0) {
175 attrs << NSOpenGLPFAMultisample
176 << NSOpenGLPFASampleBuffers << NSOpenGLPixelFormatAttribute(1)
177 << NSOpenGLPFASamples << NSOpenGLPixelFormatAttribute(format.samples());
178 }
179
180 //Workaround for problems with Chromium and offline renderers on the lat 2013 MacPros.
181 //FIXME: Think if this could be solved via QSurfaceFormat in the future.
182 static bool offlineRenderersAllowed = qEnvironmentVariableIsEmpty("QT_MAC_PRO_WEBENGINE_WORKAROUND");
183 if (offlineRenderersAllowed) {
184 // Allow rendering on GPUs without a connected display
185 attrs << NSOpenGLPFAAllowOfflineRenderers;
186 }
187
188 if (qGuiApp->testAttribute(Qt::AA_UseSoftwareOpenGL)) {
189 // kCGLRendererGenericFloatID is the modern software renderer on macOS,
190 // as opposed to kCGLRendererGenericID, which is deprecated.
191 attrs << NSOpenGLPFARendererID << kCGLRendererGenericFloatID;
192 }
193
194 attrs << 0; // 0-terminate array
195 return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()];
196}
197
198/*!
199 Updates the surface format of this context based on properties of
200 the native context and GL state, so that the result of creating
201 the context is reflected back in QOpenGLContext.
202*/
203void QCocoaGLContext::updateSurfaceFormat()
204{
205 NSOpenGLContext *oldContext = [NSOpenGLContext currentContext];
206 [m_context makeCurrentContext];
207
208 // --------------------- Query GL state ---------------------
209
210 int major = 0, minor = 0;
211 QByteArray versionString(getGlString(GL_VERSION));
212 if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
213 m_format.setMajorVersion(major);
214 m_format.setMinorVersion(minor);
215 }
216
217 m_format.setProfile(QSurfaceFormat::NoProfile);
218 if (m_format.version() >= qMakePair(3, 2)) {
219 GLint value = 0;
220 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
221 if (value & GL_CONTEXT_CORE_PROFILE_BIT)
222 m_format.setProfile(QSurfaceFormat::CoreProfile);
223 else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
224 m_format.setProfile(QSurfaceFormat::CompatibilityProfile);
225 }
226
227 m_format.setOption(QSurfaceFormat::DeprecatedFunctions, [&]() {
228 if (m_format.version() < qMakePair(3, 0)) {
229 return true;
230 } else {
231 GLint value = 0;
232 glGetIntegerv(GL_CONTEXT_FLAGS, &value);
233 return !(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
234 }
235 }());
236
237 // Debug contexts not supported on macOS
238 m_format.setOption(QSurfaceFormat::DebugContext, false);
239
240 // Nor are stereo buffers (deprecated in macOS 10.12)
241 m_format.setOption(QSurfaceFormat::StereoBuffers, false);
242
243 // ------------------ Query the pixel format ------------------
244
245 NSOpenGLPixelFormat *pixelFormat = m_context.pixelFormat;
246
247 GLint virtualScreen = [&, this]() {
248 auto *platformScreen = static_cast<QCocoaScreen*>(context()->screen()->handle());
249 auto displayId = platformScreen->nativeScreen().qt_displayId;
250 auto requestedDisplay = CGDisplayIDToOpenGLDisplayMask(displayId);
251 for (int i = 0; i < pixelFormat.numberOfVirtualScreens; ++i) {
252 GLint supportedDisplays;
253 [pixelFormat getValues:&supportedDisplays forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:i];
254 // Note: The mask returned for NSOpenGLPFAScreenMask is a bit mask of
255 // physical displays that the renderer can drive, while the one returned
256 // from CGDisplayIDToOpenGLDisplayMask has a single bit set, representing
257 // that particular display.
258 if (requestedDisplay & supportedDisplays)
259 return i;
260 }
261 qCWarning(lcQpaOpenGLContext) << "Could not find virtual screen for"
262 << platformScreen << "with displayId" << displayId;
263 return 0;
264 }();
265
266 auto pixelFormatAttribute = [&](NSOpenGLPixelFormatAttribute attribute) {
267 int value = 0;
268 [pixelFormat getValues:&value forAttribute:attribute forVirtualScreen:virtualScreen];
269 return value;
270 };
271
272 // Resolve color channel bits from GL, rather than NSOpenGLPFAColorSize,
273 // as the latter is not specific enough (combines all channels).
274 GLint redBits, greenBits, blueBits;
275 glGetIntegerv(GL_RED_BITS, &redBits);
276 glGetIntegerv(GL_GREEN_BITS, &greenBits);
277 glGetIntegerv(GL_BLUE_BITS, &blueBits);
278 m_format.setRedBufferSize(redBits);
279 m_format.setGreenBufferSize(greenBits);
280 m_format.setBlueBufferSize(blueBits);
281
282 // Surfaces on macOS always have an alpha channel, but unless the user requested
283 // one via setAlphaBufferSize(), which triggered setting NSOpenGLCPSurfaceOpacity
284 // to make the surface non-opaque, we don't want to report back the actual alpha
285 // size, as that will make the user believe the alpha channel can be used for
286 // something useful, when in reality it can't, due to the surface being opaque.
287 if (m_format.alphaBufferSize() > 0) {
288 GLint alphaBits;
289 glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
290 m_format.setAlphaBufferSize(alphaBits);
291 }
292
293 m_format.setDepthBufferSize(pixelFormatAttribute(NSOpenGLPFADepthSize));
294 m_format.setStencilBufferSize(pixelFormatAttribute(NSOpenGLPFAStencilSize));
295 m_format.setSamples(pixelFormatAttribute(NSOpenGLPFASamples));
296
297 if (pixelFormatAttribute(NSOpenGLPFATripleBuffer))
298 m_format.setSwapBehavior(QSurfaceFormat::TripleBuffer);
299 else if (pixelFormatAttribute(NSOpenGLPFADoubleBuffer))
300 m_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
301 else
302 m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
303
304 m_isSoftwareContext = (pixelFormatAttribute(NSOpenGLPFARendererID)
305 & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID;
306
307 // ------------------- Query the context -------------------
308
309 auto glContextParameter = [&](NSOpenGLContextParameter parameter) {
310 int value = 0;
311 [m_context getValues:&value forParameter:parameter];
312 return value;
313 };
314
315 m_format.setSwapInterval(glContextParameter(NSOpenGLContextParameterSwapInterval));
316
317 if (oldContext)
318 [oldContext makeCurrentContext];
319 else
320 [NSOpenGLContext clearCurrentContext];
321}
322
324{
325 [m_context release];
326}
327
328bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
329{
330 QMacAutoReleasePool pool;
331
332 qCDebug(lcQpaOpenGLContext) << "Making" << this << "current"
333 << "in" << QThread::currentThread() << "for" << surface;
334
335 Q_ASSERT(surface->surface()->supportsOpenGL());
336
337 if (!setDrawable(surface))
338 return false;
339
340 [m_context makeCurrentContext];
341
342 if (surface->surface()->surfaceClass() == QSurface::Window) {
343 if (m_needsUpdate.fetchAndStoreRelaxed(false))
344 update();
345 }
346
347 return true;
348}
349
351{
352 QMacAutoReleasePool pool;
353
354 Q_ASSERT(context() && context()->surface());
355 auto *surface = context()->surface()->surfaceHandle();
356 Q_ASSERT(surface);
357
358 qCDebug(lcQpaOpenGLContext) << "Beginning frame for" << this
359 << "in" << QThread::currentThread() << "for" << surface;
360
361 Q_ASSERT(surface->surface()->supportsOpenGL());
362
363 if (surface->surface()->surfaceClass() == QSurface::Window) {
364 if (m_needsUpdate.fetchAndStoreRelaxed(false))
365 update();
366 }
367}
368
369/*!
370 Sets the drawable object of the NSOpenGLContext, which is the
371 frame buffer that is the target of OpenGL drawing operations.
372*/
373bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
374{
375 // Make sure any surfaces released during this process are deallocated
376 // straight away, otherwise we may run out of surfaces when spinning a
377 // render-loop that doesn't return to one of the outer pools.
378 QMacAutoReleasePool pool;
379
380 if (!surface || surface->surface()->surfaceClass() == QSurface::Offscreen) {
381 // Clear the current drawable and reset the active window, so that GL
382 // commands that don't target a specific FBO will not end up stomping
383 // on the previously set drawable.
384 qCDebug(lcQpaOpenGLContext) << "Clearing current drawable" << QT_IGNORE_DEPRECATIONS(m_context.view) << "for" << m_context;
385 [m_context clearDrawable];
386 return true;
387 }
388
389 Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
390 auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
391 QNSView *view = qnsview_cast(cocoaWindow->view());
392
393 if (view == QT_IGNORE_DEPRECATIONS(m_context.view))
394 return true;
395
396 // We generally want high-DPI GL surfaces, unless the user has explicitly disabled them.
397 // According to the documentation, layer-backed views ignore wantsBestResolutionOpenGLSurface
398 // and configure their own backing surface at an appropriate resolution, but in some cases
399 // we've seen this fail (plugin views embedded in surface-backed hosts), so we do it anyways.
400 QT_IGNORE_DEPRECATIONS(view.wantsBestResolutionOpenGLSurface) = qt_mac_resolveOption(YES,
401 cocoaWindow->window(), "_q_mac_wantsBestResolutionOpenGLSurface",
402 "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
403
404 // Setting the drawable may happen on a separate thread as a result of
405 // a call to makeCurrent, so we need to set up the observers before we
406 // associate the view with the context. That way we will guarantee that
407 // as long as the view is the drawable of the context we will know about
408 // any updates to the view that require surface invalidation.
409
410 auto updateCallback = [this, view]() {
411 Q_ASSERT(QThread::currentThread() == qApp->thread());
412 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
413 return;
414 m_needsUpdate = true;
415 };
416
417 m_updateObservers.clear();
418
419 m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback));
420 m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
421
422 m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication],
423 NSApplicationDidChangeScreenParametersNotification, updateCallback));
424
425 m_updateObservers.append(QMacNotificationObserver(view,
426 QCocoaWindowWillReleaseQNSViewNotification, [this, view] {
427 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
428 return;
429 qCDebug(lcQpaOpenGLContext) << view << "about to be released."
430 << "Clearing current drawable for" << m_context;
431 [m_context clearDrawable];
432 }));
433
434 // If any of the observers fire at this point it's fine. We check the
435 // view association (atomically) in the update callback, and skip the
436 // update if we haven't associated yet. Setting the drawable below will
437 // have the same effect as an update.
438
439 // Now we are ready to associate the view with the context
440 QT_IGNORE_DEPRECATIONS(m_context.view) = view;
441 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view) {
442 qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context;
443 m_updateObservers.clear();
444 return false;
445 }
446
447 qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << QT_IGNORE_DEPRECATIONS(m_context.view);
448 return true;
449}
450
451// NSOpenGLContext is not re-entrant. Even when using separate contexts per thread,
452// view, and window, calls into the API will still deadlock. For more information
453// see https://openradar.appspot.com/37064579
454Q_CONSTINIT static QMutex s_reentrancyMutex;
455
457{
458 // Make sure any surfaces released during this process are deallocated
459 // straight away, otherwise we may run out of surfaces when spinning a
460 // render-loop that doesn't return to one of the outer pools.
461 QMacAutoReleasePool pool;
462
463 QMutexLocker locker(&s_reentrancyMutex);
464 qCInfo(lcQpaOpenGLContext) << "Updating" << m_context << "for" << QT_IGNORE_DEPRECATIONS(m_context.view);
465
466 // On macOS 26 on Intel machines, when using the software GL backend,
467 // -[NSOpenGLContext update] triggers a display of the GL layer, and
468 // then crashes in glClear during the display.
469#if defined(Q_PROCESSOR_X86_64)
470 static bool tahoeOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe;
471 auto *layer = QT_IGNORE_DEPRECATIONS(m_context.view.layer);
472 if (tahoeOrAbove && isSoftwareContext() && layer.needsDisplay) {
473 static QNoopDisplayDelegate *noopDisplayDelegate = [QNoopDisplayDelegate new];
474 qCDebug(lcQpaOpenGLContext) << "Layer needs display. Installing noop display delegate" << noopDisplayDelegate;
475 auto *orignalDelegate = layer.delegate;
476 layer.delegate = noopDisplayDelegate;
477
478 [m_context update];
479
480 qCDebug(lcQpaOpenGLContext) << "Restoring original layer delegate" << orignalDelegate;
481 layer.delegate = orignalDelegate;
482 [layer setNeedsDisplay];
483
484 return;
485 }
486#endif
487
488 [m_context update];
489}
490
491void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
492{
493 QMacAutoReleasePool pool;
494
495 qCDebug(lcQpaOpenGLContext) << "Swapping" << m_context
496 << "in" << QThread::currentThread() << "to" << surface;
497
498 if (surface->surface()->surfaceClass() == QSurface::Offscreen)
499 return; // Nothing to do
500
501 if (!setDrawable(surface)) {
502 qCWarning(lcQpaOpenGLContext) << "Can't flush" << m_context
503 << "without" << surface << "as drawable";
504 return;
505 }
506
507 // Flushing an NSOpenGLContext will hit the screen immediately, ignoring
508 // any Core Animation transactions in place. This may result in major
509 // visual artifacts if the flush happens out of sync with the size
510 // of the layer, view, and window reflected by other parts of the UI,
511 // e.g. if the application flushes in the resize event or a timer during
512 // window resizing, instead of in the expose event.
513 auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
514 if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
515 qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
516 << "Skipping flush to avoid visual artifacts.";
517 return;
518 }
519
520 QMutexLocker locker(&s_reentrancyMutex);
521 [m_context flushBuffer];
522}
523
525{
526 QMacAutoReleasePool pool;
527
528 qCDebug(lcQpaOpenGLContext) << "Clearing current context"
529 << [NSOpenGLContext currentContext] << "in" << QThread::currentThread();
530
531 // Note: We do not need to clear the current drawable here.
532 // As long as there is no current context, GL calls will
533 // do nothing.
534
535 [NSOpenGLContext clearCurrentContext];
536}
537
539{
540 return m_format;
541}
542
544{
545 return m_context != nil;
546}
547
549{
550 return m_shareContext != nil;
551}
552
554{
555 return m_isSoftwareContext;
556}
557
559{
560 return m_context;
561}
562
564{
565 return (QFunctionPointer)dlsym(RTLD_NEXT, procName);
566}
567
568#ifndef QT_NO_DEBUG_STREAM
569QDebug operator<<(QDebug debug, const QCocoaGLContext *context)
570{
571 QDebugStateSaver saver(debug);
572 debug.nospace();
573 debug << "QCocoaGLContext(" << (const void *)context;
574 if (context) {
575 if (debug.verbosity() > QDebug::DefaultVerbosity)
576 debug << ", " << context->format();
577 debug << ", " << context->nativeContext();
578 }
579 debug << ')';
580 return debug;
581}
582#endif // !QT_NO_DEBUG_STREAM
583
584QT_END_NAMESPACE
585
586#if defined(Q_PROCESSOR_X86_64)
587@implementation QNoopDisplayDelegate
588- (void)displayLayer:(CALayer *)layer
589{
590 qCWarning(lcQpaOpenGLContext) << "Ignoring display of" << layer << "during [NSOpenGLContext update]";
591}
592@end
593#endif
NSOpenGLContext * nativeContext() const override
void swapBuffers(QPlatformSurface *surface) override
Reimplement in subclass to native swap buffers calls.
void doneCurrent() override
QSurfaceFormat format() const override
bool isSoftwareContext() const
bool isSharing() const override
void initialize() override
Called after a new instance is constructed.
void beginFrame() override
Called when the RHI begins rendering a new frame in the context.
QFunctionPointer getProcAddress(const char *procName) override
Reimplement in subclass to allow dynamic querying of OpenGL symbols.
QCocoaGLContext(QOpenGLContext *context)
bool makeCurrent(QPlatformSurface *surface) override
bool isValid() const override
static QByteArray getGlString(GLenum param)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")