From ffae448dc3fd4028aa62acc8710f8a11b1985f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 1 Aug 2018 13:38:53 +0200 Subject: macOS: Reorganize QCocoaGLContext Group methods by their areas of responsibility to make it easier to follow the logic of the code. Change-Id: I64dbf60004d0f4c281312451e0781da31997c64d Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoaglcontext.h | 16 +- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 347 ++++++++++++------------- 2 files changed, 180 insertions(+), 183 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 0530aa8201..c3640f56ab 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -55,28 +55,26 @@ public: QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle); ~QCocoaGLContext(); - QSurfaceFormat format() const override; - - void swapBuffers(QPlatformSurface *surface) override; - bool makeCurrent(QPlatformSurface *surface) override; + void swapBuffers(QPlatformSurface *surface) override; void doneCurrent() override; - QFunctionPointer getProcAddress(const char *procName) override; - void update(); - static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format); - NSOpenGLContext *nsOpenGLContext() const; - + QSurfaceFormat format() const override; bool isSharing() const override; bool isValid() const override; void windowWasHidden(); + NSOpenGLContext *nsOpenGLContext() const; QVariant nativeHandle() const; + QFunctionPointer getProcAddress(const char *procName) override; + private: + static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format); + void setActiveWindow(QWindow *window); void updateSurfaceFormat(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 35fa8d0c34..d49f8d7bae 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -47,10 +47,6 @@ #import -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaOpenGLContext, "qt.qpa.openglcontext"); - static inline QByteArray getGlString(GLenum param) { if (const GLubyte *s = glGetString(param)) @@ -78,49 +74,9 @@ static inline QByteArray getGlString(GLenum param) #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #endif -static void updateFormatFromContext(QSurfaceFormat *format) -{ - Q_ASSERT(format); - - // Update the version, profile, and context bit of the format - int major = 0, minor = 0; - QByteArray versionString(getGlString(GL_VERSION)); - if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) { - format->setMajorVersion(major); - format->setMinorVersion(minor); - } - - format->setProfile(QSurfaceFormat::NoProfile); - - Q_ASSERT(format->renderableType() == QSurfaceFormat::OpenGL); - if (format->version() < qMakePair(3, 0)) { - format->setOption(QSurfaceFormat::DeprecatedFunctions); - return; - } - - // Version 3.0 onwards - check if it includes deprecated functionality - GLint value = 0; - glGetIntegerv(GL_CONTEXT_FLAGS, &value); - if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) - format->setOption(QSurfaceFormat::DeprecatedFunctions); - - // Debug context option not supported on OS X - - if (format->version() < qMakePair(3, 2)) - return; - - // Version 3.2 and newer have a profile - value = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); - - if (value & GL_CONTEXT_CORE_PROFILE_BIT) - format->setProfile(QSurfaceFormat::CoreProfile); - else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) - format->setProfile(QSurfaceFormat::CompatibilityProfile); -} +QT_BEGIN_NAMESPACE - // NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579) -static QMutex s_contextMutex; +Q_LOGGING_CATEGORY(lcQpaOpenGLContext, "qt.qpa.openglcontext"); QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle) @@ -217,95 +173,107 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo updateSurfaceFormat(); } -QCocoaGLContext::~QCocoaGLContext() +NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat(const QSurfaceFormat &format) { - if (m_currentWindow && m_currentWindow.data()->handle()) - static_cast(m_currentWindow.data()->handle())->setCurrentContext(0); + QVector attrs; - [m_context release]; -} + if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer + || format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior) + attrs.append(NSOpenGLPFADoubleBuffer); + else if (format.swapBehavior() == QSurfaceFormat::TripleBuffer) + attrs.append(NSOpenGLPFATripleBuffer); -QVariant QCocoaGLContext::nativeHandle() const -{ - return QVariant::fromValue(QCocoaNativeContext(m_context)); -} -QSurfaceFormat QCocoaGLContext::format() const -{ - return m_format; -} - -void QCocoaGLContext::windowWasHidden() -{ - // If the window is hidden, we need to unset the m_currentWindow - // variable so that succeeding makeCurrent's will not abort prematurely - // because of the optimization in setActiveWindow. - // Doing a full doneCurrent here is not preferable, because the GL context - // might be rendering in a different thread at this time. - m_currentWindow.clear(); -} + // Select OpenGL profile + attrs << NSOpenGLPFAOpenGLProfile; + if (format.profile() == QSurfaceFormat::CoreProfile) { + if (format.version() >= qMakePair(4, 1)) + attrs << NSOpenGLProfileVersion4_1Core; + else if (format.version() >= qMakePair(3, 2)) + attrs << NSOpenGLProfileVersion3_2Core; + else + attrs << NSOpenGLProfileVersionLegacy; + } else { + attrs << NSOpenGLProfileVersionLegacy; + } -void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) -{ - if (surface->surface()->surfaceClass() == QSurface::Offscreen) - return; // Nothing to do + if (format.depthBufferSize() > 0) + attrs << NSOpenGLPFADepthSize << format.depthBufferSize(); + if (format.stencilBufferSize() > 0) + attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize(); + if (format.alphaBufferSize() > 0) + attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize(); + if ((format.redBufferSize() > 0) && + (format.greenBufferSize() > 0) && + (format.blueBufferSize() > 0)) { + const int colorSize = format.redBufferSize() + + format.greenBufferSize() + + format.blueBufferSize(); + attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy; + } - QWindow *window = static_cast(surface)->window(); - setActiveWindow(window); + if (format.samples() > 0) { + attrs << NSOpenGLPFAMultisample + << NSOpenGLPFASampleBuffers << (NSOpenGLPixelFormatAttribute) 1 + << NSOpenGLPFASamples << (NSOpenGLPixelFormatAttribute) format.samples(); + } - QMutexLocker locker(&s_contextMutex); - [m_context flushBuffer]; -} + if (format.stereo()) + attrs << NSOpenGLPFAStereo; -bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) -{ - Q_ASSERT(surface->surface()->supportsOpenGL()); + attrs << NSOpenGLPFAAllowOfflineRenderers; - QMacAutoReleasePool pool; - [m_context makeCurrentContext]; + QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER"); + if (!useLayer.isEmpty() && useLayer.toInt() > 0) { + // Disable the software rendering fallback. This makes compositing + // OpenGL and raster NSViews using Core Animation layers possible. + attrs << NSOpenGLPFANoRecovery; + } - if (surface->surface()->surfaceClass() == QSurface::Offscreen) - return true; + attrs << 0; - QWindow *window = static_cast(surface)->window(); - setActiveWindow(window); + return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()]; +} - // Disable high-resolution surfaces when using the software renderer, which has the - // problem that the system silently falls back to a to using a low-resolution buffer - // when a high-resolution buffer is requested. This is not detectable using the NSWindow - // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt - // will display a quarter of the window content when running in a virtual machine. - if (!m_didCheckForSoftwareContext) { - m_didCheckForSoftwareContext = true; +static void updateFormatFromContext(QSurfaceFormat *format) +{ + Q_ASSERT(format); - const GLubyte* renderer = glGetString(GL_RENDERER); - if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) { - NSView *view = static_cast(surface)->m_view; - [view setWantsBestResolutionOpenGLSurface:NO]; - } + // Update the version, profile, and context bit of the format + int major = 0, minor = 0; + QByteArray versionString(getGlString(GL_VERSION)); + if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) { + format->setMajorVersion(major); + format->setMinorVersion(minor); } - update(); - return true; -} + format->setProfile(QSurfaceFormat::NoProfile); -void QCocoaGLContext::setActiveWindow(QWindow *window) -{ - if (window == m_currentWindow.data()) + Q_ASSERT(format->renderableType() == QSurfaceFormat::OpenGL); + if (format->version() < qMakePair(3, 0)) { + format->setOption(QSurfaceFormat::DeprecatedFunctions); return; + } - if (m_currentWindow && m_currentWindow.data()->handle()) - static_cast(m_currentWindow.data()->handle())->setCurrentContext(0); + // Version 3.0 onwards - check if it includes deprecated functionality + GLint value = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &value); + if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) + format->setOption(QSurfaceFormat::DeprecatedFunctions); - Q_ASSERT(window->handle()); + // Debug context option not supported on OS X - m_currentWindow = window; + if (format->version() < qMakePair(3, 2)) + return; - QCocoaWindow *cocoaWindow = static_cast(window->handle()); - cocoaWindow->setCurrentContext(this); + // Version 3.2 and newer have a profile + value = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); - Q_ASSERT(!cocoaWindow->isForeignWindow()); - [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this]; + if (value & GL_CONTEXT_CORE_PROFILE_BIT) + format->setProfile(QSurfaceFormat::CoreProfile); + else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + format->setProfile(QSurfaceFormat::CompatibilityProfile); } void QCocoaGLContext::updateSurfaceFormat() @@ -389,87 +357,119 @@ void QCocoaGLContext::updateSurfaceFormat() CGLSetCurrentContext(oldContext); } -void QCocoaGLContext::doneCurrent() +QCocoaGLContext::~QCocoaGLContext() { if (m_currentWindow && m_currentWindow.data()->handle()) - static_cast(m_currentWindow.data()->handle())->setCurrentContext(nullptr); + static_cast(m_currentWindow.data()->handle())->setCurrentContext(0); - m_currentWindow.clear(); + [m_context release]; +} - [NSOpenGLContext clearCurrentContext]; +bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) +{ + Q_ASSERT(surface->surface()->supportsOpenGL()); + + QMacAutoReleasePool pool; + [m_context makeCurrentContext]; + + if (surface->surface()->surfaceClass() == QSurface::Offscreen) + return true; + + QWindow *window = static_cast(surface)->window(); + setActiveWindow(window); + + // Disable high-resolution surfaces when using the software renderer, which has the + // problem that the system silently falls back to a to using a low-resolution buffer + // when a high-resolution buffer is requested. This is not detectable using the NSWindow + // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt + // will display a quarter of the window content when running in a virtual machine. + if (!m_didCheckForSoftwareContext) { + m_didCheckForSoftwareContext = true; + + const GLubyte* renderer = glGetString(GL_RENDERER); + if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) { + NSView *view = static_cast(surface)->m_view; + [view setWantsBestResolutionOpenGLSurface:NO]; + } + } + + update(); + return true; } -QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName) +void QCocoaGLContext::setActiveWindow(QWindow *window) { - return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName); + if (window == m_currentWindow.data()) + return; + + if (m_currentWindow && m_currentWindow.data()->handle()) + static_cast(m_currentWindow.data()->handle())->setCurrentContext(0); + + Q_ASSERT(window->handle()); + + m_currentWindow = window; + + QCocoaWindow *cocoaWindow = static_cast(window->handle()); + cocoaWindow->setCurrentContext(this); + + Q_ASSERT(!cocoaWindow->isForeignWindow()); + [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this]; } +// NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579) +static QMutex s_contextMutex; + void QCocoaGLContext::update() { QMutexLocker locker(&s_contextMutex); [m_context update]; } -NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat(const QSurfaceFormat &format) +void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) { - QVector attrs; - - if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer - || format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior) - attrs.append(NSOpenGLPFADoubleBuffer); - else if (format.swapBehavior() == QSurfaceFormat::TripleBuffer) - attrs.append(NSOpenGLPFATripleBuffer); + if (surface->surface()->surfaceClass() == QSurface::Offscreen) + return; // Nothing to do + QWindow *window = static_cast(surface)->window(); + setActiveWindow(window); - // Select OpenGL profile - attrs << NSOpenGLPFAOpenGLProfile; - if (format.profile() == QSurfaceFormat::CoreProfile) { - if (format.version() >= qMakePair(4, 1)) - attrs << NSOpenGLProfileVersion4_1Core; - else if (format.version() >= qMakePair(3, 2)) - attrs << NSOpenGLProfileVersion3_2Core; - else - attrs << NSOpenGLProfileVersionLegacy; - } else { - attrs << NSOpenGLProfileVersionLegacy; - } + QMutexLocker locker(&s_contextMutex); + [m_context flushBuffer]; +} - if (format.depthBufferSize() > 0) - attrs << NSOpenGLPFADepthSize << format.depthBufferSize(); - if (format.stencilBufferSize() > 0) - attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize(); - if (format.alphaBufferSize() > 0) - attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize(); - if ((format.redBufferSize() > 0) && - (format.greenBufferSize() > 0) && - (format.blueBufferSize() > 0)) { - const int colorSize = format.redBufferSize() + - format.greenBufferSize() + - format.blueBufferSize(); - attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy; - } +void QCocoaGLContext::doneCurrent() +{ + if (m_currentWindow && m_currentWindow.data()->handle()) + static_cast(m_currentWindow.data()->handle())->setCurrentContext(nullptr); - if (format.samples() > 0) { - attrs << NSOpenGLPFAMultisample - << NSOpenGLPFASampleBuffers << (NSOpenGLPixelFormatAttribute) 1 - << NSOpenGLPFASamples << (NSOpenGLPixelFormatAttribute) format.samples(); - } + m_currentWindow.clear(); - if (format.stereo()) - attrs << NSOpenGLPFAStereo; + [NSOpenGLContext clearCurrentContext]; +} - attrs << NSOpenGLPFAAllowOfflineRenderers; +void QCocoaGLContext::windowWasHidden() +{ + // If the window is hidden, we need to unset the m_currentWindow + // variable so that succeeding makeCurrent's will not abort prematurely + // because of the optimization in setActiveWindow. + // Doing a full doneCurrent here is not preferable, because the GL context + // might be rendering in a different thread at this time. + m_currentWindow.clear(); +} - QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER"); - if (!useLayer.isEmpty() && useLayer.toInt() > 0) { - // Disable the software rendering fallback. This makes compositing - // OpenGL and raster NSViews using Core Animation layers possible. - attrs << NSOpenGLPFANoRecovery; - } +QSurfaceFormat QCocoaGLContext::format() const +{ + return m_format; +} - attrs << 0; +bool QCocoaGLContext::isValid() const +{ + return m_context != nil; +} - return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()]; +bool QCocoaGLContext::isSharing() const +{ + return m_shareContext != nil; } NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const @@ -477,15 +477,14 @@ NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const return m_context; } -bool QCocoaGLContext::isValid() const +QVariant QCocoaGLContext::nativeHandle() const { - return m_context != nil; + return QVariant::fromValue(QCocoaNativeContext(m_context)); } -bool QCocoaGLContext::isSharing() const +QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName) { - return m_shareContext != nil; + return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName); } QT_END_NAMESPACE - -- cgit v1.2.3