5#include <AppKit/AppKit.h>
12#include <QtCore/private/qcore_mac_p.h>
19 if (
const GLubyte *s = glGetString(param))
20 return QByteArray(
reinterpret_cast<
const char*>(s));
37 m_context = [nativeContext retain];
46 if (QPlatformOpenGLContext *shareContext = context()->shareHandle())
47 m_shareContext =
static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
49 updateSurfaceFormat();
56 if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
57 m_format.setRenderableType(QSurfaceFormat::OpenGL);
58 if (m_format.renderableType() != QSurfaceFormat::OpenGL)
61 if (QPlatformOpenGLContext *shareContext = context()->shareHandle()) {
62 m_shareContext =
static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
69 GLint shareContextRequestedProfile;
70 [m_shareContext.pixelFormat getValues:&shareContextRequestedProfile
71 forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:0];
72 auto shareContextActualProfile = shareContext->format().version();
74 if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core
75 && shareContextActualProfile >= qMakePair(4, 1)) {
79 if (m_format.version() >= qMakePair(4, 1))
80 m_format.setVersion(3, 2);
86 NSOpenGLPixelFormat *pixelFormat = [pixelFormatForSurfaceFormat(m_format) autorelease];
87 m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext];
89 if (!m_context && m_shareContext) {
90 qCWarning(lcQpaOpenGLContext,
"Could not create NSOpenGLContext with shared context, "
91 "falling back to unshared context.");
92 m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
97 qCWarning(lcQpaOpenGLContext,
"Failed to create NSOpenGLContext");
103 const GLint interval = m_format.swapInterval() >= 0 ? m_format.swapInterval() : 1;
104 [m_context setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval];
106 if (m_format.alphaBufferSize() > 0) {
108 [m_context setValues:&zeroOpacity forParameter:NSOpenGLContextParameterSurfaceOpacity];
113 const GLint order = qt_mac_resolveOption(1,
"QT_MAC_OPENGL_SURFACE_ORDER");
114 [m_context setValues:&order forParameter:NSOpenGLContextParameterSurfaceOrder];
116 updateSurfaceFormat();
118 qCDebug(lcQpaOpenGLContext).verbosity(3) <<
"Created" <<
this <<
"based on requested" << context()->format();
121NSOpenGLPixelFormat *
QCocoaGLContext::pixelFormatForSurfaceFormat(
const QSurfaceFormat &format)
123 QVector<NSOpenGLPixelFormatAttribute> attrs;
125 attrs << NSOpenGLPFAOpenGLProfile;
126 if (format.profile() == QSurfaceFormat::CoreProfile) {
127 if (format.version() >= qMakePair(4, 1))
128 attrs << NSOpenGLProfileVersion4_1Core;
129 else if (format.version() >= qMakePair(3, 2))
130 attrs << NSOpenGLProfileVersion3_2Core;
132 attrs << NSOpenGLProfileVersionLegacy;
134 attrs << NSOpenGLProfileVersionLegacy;
137 switch (format.swapBehavior()) {
138 case QSurfaceFormat::SingleBuffer:
140 case QSurfaceFormat::DefaultSwapBehavior:
144 case QSurfaceFormat::DoubleBuffer:
145 attrs.append(NSOpenGLPFADoubleBuffer);
147 case QSurfaceFormat::TripleBuffer:
148 attrs.append(NSOpenGLPFATripleBuffer);
152 if (format.depthBufferSize() > 0)
153 attrs << NSOpenGLPFADepthSize << format.depthBufferSize();
154 if (format.stencilBufferSize() > 0)
155 attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize();
156 if (format.alphaBufferSize() > 0)
157 attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize();
159 auto rbz = format.redBufferSize();
160 auto gbz = format.greenBufferSize();
161 auto bbz = format.blueBufferSize();
162 if (rbz > 0 || gbz > 0 || bbz > 0) {
163 auto fallbackSize = qMax(rbz, qMax(gbz, bbz));
164 auto colorSize = (rbz > 0 ? rbz : fallbackSize)
165 + (gbz > 0 ? gbz : fallbackSize)
166 + (bbz > 0 ? bbz : fallbackSize);
167 attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy;
170 if (format.samples() > 0) {
171 attrs << NSOpenGLPFAMultisample
172 << NSOpenGLPFASampleBuffers << NSOpenGLPixelFormatAttribute(1)
173 << NSOpenGLPFASamples << NSOpenGLPixelFormatAttribute(format.samples());
178 static bool offlineRenderersAllowed = qEnvironmentVariableIsEmpty(
"QT_MAC_PRO_WEBENGINE_WORKAROUND");
179 if (offlineRenderersAllowed) {
181 attrs << NSOpenGLPFAAllowOfflineRenderers;
184 if (qGuiApp->testAttribute(Qt::AA_UseSoftwareOpenGL)) {
187 attrs << NSOpenGLPFARendererID << kCGLRendererGenericFloatID;
191 return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()];
195
196
197
198
201 NSOpenGLContext *oldContext = [NSOpenGLContext currentContext];
202 [m_context makeCurrentContext];
206 int major = 0, minor = 0;
207 QByteArray versionString(getGlString(GL_VERSION));
208 if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
209 m_format.setMajorVersion(major);
210 m_format.setMinorVersion(minor);
213 m_format.setProfile(QSurfaceFormat::NoProfile);
214 if (m_format.version() >= qMakePair(3, 2)) {
216 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
217 if (value & GL_CONTEXT_CORE_PROFILE_BIT)
218 m_format.setProfile(QSurfaceFormat::CoreProfile);
219 else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
220 m_format.setProfile(QSurfaceFormat::CompatibilityProfile);
223 m_format.setOption(QSurfaceFormat::DeprecatedFunctions, [&]() {
224 if (m_format.version() < qMakePair(3, 0)) {
228 glGetIntegerv(GL_CONTEXT_FLAGS, &value);
229 return !(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
234 m_format.setOption(QSurfaceFormat::DebugContext,
false);
237 m_format.setOption(QSurfaceFormat::StereoBuffers,
false);
241 NSOpenGLPixelFormat *pixelFormat = m_context.pixelFormat;
243 GLint virtualScreen = [&,
this]() {
244 auto *platformScreen =
static_cast<
QCocoaScreen*>(context()->screen()->handle());
245 auto displayId = platformScreen->nativeScreen().qt_displayId;
246 auto requestedDisplay = CGDisplayIDToOpenGLDisplayMask(displayId);
247 for (
int i = 0; i < pixelFormat.numberOfVirtualScreens; ++i) {
248 GLint supportedDisplays;
249 [pixelFormat getValues:&supportedDisplays forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:i];
254 if (requestedDisplay & supportedDisplays)
257 qCWarning(lcQpaOpenGLContext) <<
"Could not find virtual screen for"
258 << platformScreen <<
"with displayId" << displayId;
262 auto pixelFormatAttribute = [&](NSOpenGLPixelFormatAttribute attribute) {
264 [pixelFormat getValues:&value forAttribute:attribute forVirtualScreen:virtualScreen];
268 int colorSize = pixelFormatAttribute(NSOpenGLPFAColorSize);
270 m_format.setRedBufferSize(colorSize);
271 m_format.setGreenBufferSize(colorSize);
272 m_format.setBlueBufferSize(colorSize);
279 if (m_format.alphaBufferSize() > 0)
280 m_format.setAlphaBufferSize(pixelFormatAttribute(NSOpenGLPFAAlphaSize));
282 m_format.setDepthBufferSize(pixelFormatAttribute(NSOpenGLPFADepthSize));
283 m_format.setStencilBufferSize(pixelFormatAttribute(NSOpenGLPFAStencilSize));
284 m_format.setSamples(pixelFormatAttribute(NSOpenGLPFASamples));
286 if (pixelFormatAttribute(NSOpenGLPFATripleBuffer))
287 m_format.setSwapBehavior(QSurfaceFormat::TripleBuffer);
288 else if (pixelFormatAttribute(NSOpenGLPFADoubleBuffer))
289 m_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
291 m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
293 m_isSoftwareContext = (pixelFormatAttribute(NSOpenGLPFARendererID)
294 & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID;
298 auto glContextParameter = [&](NSOpenGLContextParameter parameter) {
300 [m_context getValues:&value forParameter:parameter];
304 m_format.setSwapInterval(glContextParameter(NSOpenGLContextParameterSwapInterval));
307 [oldContext makeCurrentContext];
309 [NSOpenGLContext clearCurrentContext];
319 QMacAutoReleasePool pool;
321 qCDebug(lcQpaOpenGLContext) <<
"Making" <<
this <<
"current"
322 <<
"in" << QThread::currentThread() <<
"for" << surface;
324 Q_ASSERT(surface->surface()->supportsOpenGL());
326 if (!setDrawable(surface))
329 [m_context makeCurrentContext];
331 if (surface->surface()->surfaceClass() == QSurface::Window) {
332 if (m_needsUpdate.fetchAndStoreRelaxed(
false))
341 QMacAutoReleasePool pool;
343 Q_ASSERT(context() && context()->surface());
344 auto *surface = context()->surface()->surfaceHandle();
347 qCDebug(lcQpaOpenGLContext) <<
"Beginning frame for" <<
this
348 <<
"in" << QThread::currentThread() <<
"for" << surface;
350 Q_ASSERT(surface->surface()->supportsOpenGL());
352 if (surface->surface()->surfaceClass() == QSurface::Window) {
353 if (m_needsUpdate.fetchAndStoreRelaxed(
false))
359
360
361
367 QMacAutoReleasePool pool;
369 if (!surface || surface->surface()->surfaceClass() == QSurface::Offscreen) {
373 qCDebug(lcQpaOpenGLContext) <<
"Clearing current drawable" << QT_IGNORE_DEPRECATIONS(m_context.view) <<
"for" << m_context;
374 [m_context clearDrawable];
378 Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
379 auto *cocoaWindow =
static_cast<
QCocoaWindow *>(surface);
380 QNSView *view = qnsview_cast(cocoaWindow->view());
382 if (view == QT_IGNORE_DEPRECATIONS(m_context.view))
389 QT_IGNORE_DEPRECATIONS(view.wantsBestResolutionOpenGLSurface) = qt_mac_resolveOption(YES,
390 cocoaWindow->window(),
"_q_mac_wantsBestResolutionOpenGLSurface",
391 "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
399 auto updateCallback = [
this, view]() {
400 Q_ASSERT(QThread::currentThread() == qApp->thread());
401 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
403 m_needsUpdate =
true;
406 m_updateObservers.clear();
408 m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback));
409 m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
411 m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication],
412 NSApplicationDidChangeScreenParametersNotification, updateCallback));
414 m_updateObservers.append(QMacNotificationObserver(view,
415 QCocoaWindowWillReleaseQNSViewNotification, [
this, view] {
416 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
418 qCDebug(lcQpaOpenGLContext) << view <<
"about to be released."
419 <<
"Clearing current drawable for" << m_context;
420 [m_context clearDrawable];
429 QT_IGNORE_DEPRECATIONS(m_context.view) = view;
430 if (QT_IGNORE_DEPRECATIONS(m_context.view) != view) {
431 qCInfo(lcQpaOpenGLContext) <<
"Failed to set" << view <<
"as drawable for" << m_context;
432 m_updateObservers.clear();
436 qCInfo(lcQpaOpenGLContext) <<
"Set drawable for" << m_context <<
"to" << QT_IGNORE_DEPRECATIONS(m_context.view);
443Q_CONSTINIT
static QMutex s_reentrancyMutex;
450 QMacAutoReleasePool pool;
452 QMutexLocker locker(&s_reentrancyMutex);
453 qCInfo(lcQpaOpenGLContext) <<
"Updating" << m_context <<
"for" << QT_IGNORE_DEPRECATIONS(m_context.view);
459 QMacAutoReleasePool pool;
461 qCDebug(lcQpaOpenGLContext) <<
"Swapping" << m_context
462 <<
"in" << QThread::currentThread() <<
"to" << surface;
464 if (surface->surface()->surfaceClass() == QSurface::Offscreen)
467 if (!setDrawable(surface)) {
468 qCWarning(lcQpaOpenGLContext) <<
"Can't flush" << m_context
469 <<
"without" << surface <<
"as drawable";
479 auto *cocoaWindow =
static_cast<
QCocoaWindow *>(surface);
480 if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
481 qCInfo(lcQpaOpenGLContext) <<
"Window exposed size does not match geometry (yet)."
482 <<
"Skipping flush to avoid visual artifacts.";
486 QMutexLocker locker(&s_reentrancyMutex);
487 [m_context flushBuffer];
492 QMacAutoReleasePool pool;
494 qCDebug(lcQpaOpenGLContext) <<
"Clearing current context"
495 << [NSOpenGLContext currentContext] <<
"in" << QThread::currentThread();
501 [NSOpenGLContext clearCurrentContext];
511 return m_context != nil;
516 return m_shareContext != nil;
521 return m_isSoftwareContext;
531 return (QFunctionPointer)dlsym(RTLD_NEXT, procName);
534#ifndef QT_NO_DEBUG_STREAM
537 QDebugStateSaver saver(debug);
539 debug <<
"QCocoaGLContext(" << (
const void *)context;
541 if (debug.verbosity() > QDebug::DefaultVerbosity)
542 debug <<
", " << context->format();
543 debug <<
", " << context->nativeContext();
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")