summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/qioscontext.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/ios/qioscontext.mm')
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm159
1 files changed, 93 insertions, 66 deletions
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 546b003d14..d18e317bfb 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -48,6 +48,8 @@
#import <OpenGLES/ES2/glext.h>
#import <QuartzCore/CAEAGLLayer.h>
+Q_LOGGING_CATEGORY(lcQpaGLContext, "qt.qpa.glcontext");
+
QIOSContext::QIOSContext(QOpenGLContext *context)
: QPlatformOpenGLContext()
, m_sharedContext(static_cast<QIOSContext *>(context->shareHandle()))
@@ -81,6 +83,8 @@ QIOSContext::QIOSContext(QOpenGLContext *context)
// could take advantage of the unchanged buffer, but this means clients (and Qt)
// will also assume that swapBufferes() is not needed, which is _not_ the case.
m_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+
+ qCDebug(lcQpaGLContext) << "created context with format" << m_format << "shared with" << m_sharedContext;
}
QIOSContext::~QIOSContext()
@@ -123,10 +127,12 @@ static QString fboStatusString(GLenum status)
}
}
+#define Q_ASSERT_IS_GL_SURFACE(surface) \
+ Q_ASSERT(surface && (surface->surface()->surfaceType() & (QSurface::OpenGLSurface | QSurface::RasterGLSurface)))
+
bool QIOSContext::makeCurrent(QPlatformSurface *surface)
{
- Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface
- || surface->surface()->surfaceType() == QSurface::RasterGLSurface));
+ Q_ASSERT_IS_GL_SURFACE(surface);
[EAGLContext setCurrentContext:m_eaglContext];
@@ -134,54 +140,11 @@ bool QIOSContext::makeCurrent(QPlatformSurface *surface)
if (surface->surface()->surfaceClass() == QSurface::Offscreen)
return true;
+ Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
- // We bind the default FBO even if it's incomplete, so that clients who
- // call glCheckFramebufferStatus as a result of this function returning
- // false will get a matching error code.
- glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
-
- return framebufferObject.isComplete;
-}
-
-void QIOSContext::doneCurrent()
-{
- [EAGLContext setCurrentContext:nil];
-}
-
-void QIOSContext::swapBuffers(QPlatformSurface *surface)
-{
- Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface
- || surface->surface()->surfaceType() == QSurface::RasterGLSurface));
-
- if (surface->surface()->surfaceClass() == QSurface::Offscreen)
- return; // Nothing to do
-
- FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
-
- [EAGLContext setCurrentContext:m_eaglContext];
- glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
- [m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
-}
-
-QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatformSurface *surface) const
-{
- // We keep track of default-FBOs in the root context of a share-group. This assumes
- // that the contexts form a tree, where leaf nodes are always destroyed before their
- // parents. If that assumption (based on the current implementation) doesn't hold we
- // should probably use QOpenGLMultiGroupSharedResource to track the shared default-FBOs.
- if (m_sharedContext)
- return m_sharedContext->backingFramebufferObjectFor(surface);
-
- Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
- QIOSWindow *window = static_cast<QIOSWindow *>(surface);
-
- FramebufferObject &framebufferObject = m_framebufferObjects[window];
-
- // Set up an FBO for the window if it hasn't been created yet
if (!framebufferObject.handle) {
- [EAGLContext setCurrentContext:m_eaglContext];
-
+ // Set up an FBO for the window if it hasn't been created yet
glGenFramebuffers(1, &framebufferObject.handle);
glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
@@ -201,17 +164,17 @@ QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatfo
framebufferObject.depthRenderbuffer);
}
- connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*)));
+ connect(static_cast<QIOSWindow *>(surface), SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*)));
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
}
- // Ensure that the FBO's buffers match the size of the layer
- UIView *view = reinterpret_cast<UIView *>(window->winId());
- CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer);
- if (framebufferObject.renderbufferWidth != (layer.frame.size.width * layer.contentsScale) ||
- framebufferObject.renderbufferHeight != (layer.frame.size.height * layer.contentsScale)) {
-
- [EAGLContext setCurrentContext:m_eaglContext];
- glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
+ if (needsRenderbufferResize(surface)) {
+ // Ensure that the FBO's buffers match the size of the layer
+ CAEAGLLayer *layer = static_cast<QIOSWindow *>(surface)->eaglLayer();
+ qCDebug(lcQpaGLContext, "Reallocating renderbuffer storage - current: %dx%d, layer: %gx%g",
+ framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight,
+ layer.frame.size.width * layer.contentsScale, layer.frame.size.height * layer.contentsScale);
glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
[m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
@@ -234,12 +197,54 @@ QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatfo
framebufferObject.isComplete = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
if (!framebufferObject.isComplete) {
- qWarning("QIOSContext failed to make complete framebuffer object (%s)",
+ qCWarning(lcQpaGLContext, "QIOSContext failed to make complete framebuffer object (%s)",
qPrintable(fboStatusString(glCheckFramebufferStatus(GL_FRAMEBUFFER))));
}
}
- return framebufferObject;
+ return framebufferObject.isComplete;
+}
+
+void QIOSContext::doneCurrent()
+{
+ [EAGLContext setCurrentContext:nil];
+}
+
+void QIOSContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_ASSERT_IS_GL_SURFACE(surface);
+
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return; // Nothing to do
+
+ if (!static_cast<QIOSWindow *>(surface)->isExposed()) {
+ qCWarning(lcQpaGLContext, "Detected swapBuffers on a non-exposed window, skipping flush");
+ return;
+ }
+
+ FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
+ Q_ASSERT_X(framebufferObject.isComplete, "QIOSContext", "swapBuffers on incomplete FBO");
+
+ if (needsRenderbufferResize(surface)) {
+ qCWarning(lcQpaGLContext, "CAEAGLLayer was resized between makeCurrent and swapBuffers, skipping flush");
+ return;
+ }
+
+ [EAGLContext setCurrentContext:m_eaglContext];
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
+ [m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
+}
+
+QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatformSurface *surface) const
+{
+ // We keep track of default-FBOs in the root context of a share-group. This assumes
+ // that the contexts form a tree, where leaf nodes are always destroyed before their
+ // parents. If that assumption (based on the current implementation) doesn't hold we
+ // should probably use QOpenGLMultiGroupSharedResource to track the shared default-FBOs.
+ if (m_sharedContext)
+ return m_sharedContext->backingFramebufferObjectFor(surface);
+ else
+ return m_framebufferObjects[surface];
}
GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
@@ -251,19 +256,41 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
return 0;
}
- return backingFramebufferObjectFor(surface).handle;
+ FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
+ Q_ASSERT_X(framebufferObject.handle, "QIOSContext", "can't resolve default FBO before makeCurrent");
+
+ return framebufferObject.handle;
+}
+
+bool QIOSContext::needsRenderbufferResize(QPlatformSurface *surface) const
+{
+ Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
+
+ FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
+ CAEAGLLayer *layer = static_cast<QIOSWindow *>(surface)->eaglLayer();
+
+ if (framebufferObject.renderbufferWidth != (layer.frame.size.width * layer.contentsScale))
+ return true;
+
+ if (framebufferObject.renderbufferHeight != (layer.frame.size.height * layer.contentsScale))
+ return true;
+
+ return false;
}
void QIOSContext::windowDestroyed(QObject *object)
{
QIOSWindow *window = static_cast<QIOSWindow *>(object);
- if (m_framebufferObjects.contains(window)) {
- EAGLContext *originalContext = [EAGLContext currentContext];
- [EAGLContext setCurrentContext:m_eaglContext];
- deleteBuffers(m_framebufferObjects[window]);
- m_framebufferObjects.remove(window);
- [EAGLContext setCurrentContext:originalContext];
- }
+ if (!m_framebufferObjects.contains(window))
+ return;
+
+ qCDebug(lcQpaGLContext) << object << "destroyed, deleting corresponding FBO";
+
+ EAGLContext *originalContext = [EAGLContext currentContext];
+ [EAGLContext setCurrentContext:m_eaglContext];
+ deleteBuffers(m_framebufferObjects[window]);
+ m_framebufferObjects.remove(window);
+ [EAGLContext setCurrentContext:originalContext];
}
QFunctionPointer QIOSContext::getProcAddress(const char *functionName)