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