iOS: Check FBO status and return failure from QIOSContext::makeCurrent()

The Khronos documentation for glCheckFramebufferStatus recommends calling
the function to see if the framebuffer is complete prior to rendering.

We now give more info to clients that call makeCurrent(), by storing the
state of the default FBO and returning that, instead of always returning
true and leaving the clients vulnerable to calling OpenGL functions on a
non-complete FBO.

Change-Id: Ia99c21f811ac799b350f07e73b2ae4b173d71120
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
This commit is contained in:
Tor Arne Vestbø 2014-03-26 15:58:15 +01:00 committed by The Qt Project
parent 98e90f700a
commit 2654fdb346
2 changed files with 36 additions and 6 deletions

View File

@ -85,10 +85,12 @@ private:
GLuint depthRenderbuffer;
GLint renderbufferWidth;
GLint renderbufferHeight;
bool isComplete;
};
static void deleteBuffers(const FramebufferObject &framebufferObject);
FramebufferObject &backingFramebufferObjectFor(QPlatformSurface *) const;
mutable QHash<QIOSWindow *, FramebufferObject> m_framebufferObjects;
};

View File

@ -94,14 +94,33 @@ QSurfaceFormat QIOSContext::format() const
return m_format;
}
#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1Literal(#val)
static QString fboStatusString(GLenum status)
{
switch (status) {
QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_UNSUPPORTED);
default:
return QString(QStringLiteral("unknown status: %x")).arg(status);
}
}
bool QIOSContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
[EAGLContext setCurrentContext:m_eaglContext];
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject(surface));
FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
return true;
// 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()
@ -121,7 +140,7 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface)
[m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
}
GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatformSurface *surface) const
{
Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
QIOSWindow *window = static_cast<QIOSWindow *>(surface);
@ -181,11 +200,20 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
}
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
framebufferObject.isComplete = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
if (!framebufferObject.isComplete) {
qWarning("QIOSContext failed to make complete framebuffer object (%s)",
qPrintable(fboStatusString(glCheckFramebufferStatus(GL_FRAMEBUFFER))));
}
}
return framebufferObject.handle;
return framebufferObject;
}
GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
return backingFramebufferObjectFor(surface).handle;
}
void QIOSContext::windowDestroyed(QObject *object)