Add EGL_KHR_create_context support

[ChangeLog] GLES3 and desktop OpenGL are now fully supported with EGL

Task-number: QTBUG-37332
Change-Id: Ic695db573d90b3a204941d105a370f5c63182b63
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Laszlo Agocs 2014-03-07 16:50:22 +01:00 committed by The Qt Project
parent 08b9e51c47
commit 4b3d11efc0
2 changed files with 123 additions and 36 deletions

View File

@ -64,31 +64,48 @@ QT_BEGIN_NAMESPACE
surface). Other than that, no further customization is necessary. surface). Other than that, no further customization is necessary.
*/ */
static inline void bindApi(const QSurfaceFormat &format) // Constants from EGL_KHR_create_context
{ #ifndef EGL_CONTEXT_MINOR_VERSION_KHR
switch (format.renderableType()) { #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
case QSurfaceFormat::OpenVG: #endif
eglBindAPI(EGL_OPENVG_API); #ifndef EGL_CONTEXT_FLAGS_KHR
break; #define EGL_CONTEXT_FLAGS_KHR 0x30FC
#ifdef EGL_VERSION_1_4 #endif
case QSurfaceFormat::DefaultRenderableType: #ifndef EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
#ifndef QT_NO_OPENGL #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) #endif
eglBindAPI(EGL_OPENGL_API); #ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
else #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
#endif // QT_NO_OPENGL #endif
eglBindAPI(EGL_OPENGL_ES_API); #ifndef EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
break; #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
case QSurfaceFormat::OpenGL: #endif
eglBindAPI(EGL_OPENGL_API); #ifndef EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
break; #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
#endif
#ifndef EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
#endif
// Constants for OpenGL which are not available in the ES headers.
#ifndef GL_CONTEXT_FLAGS
#define GL_CONTEXT_FLAGS 0x821E
#endif
#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
#endif
#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
#endif
#ifndef GL_CONTEXT_PROFILE_MASK
#define GL_CONTEXT_PROFILE_MASK 0x9126
#endif
#ifndef GL_CONTEXT_CORE_PROFILE_BIT
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#endif
#ifndef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#endif #endif
case QSurfaceFormat::OpenGLES:
default:
eglBindAPI(EGL_OPENGL_ES_API);
break;
}
}
QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display)
: m_eglDisplay(display) : m_eglDisplay(display)
@ -114,14 +131,55 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform
void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
{ {
m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig);
// m_format now has the renderableType() resolved (it cannot be Default anymore)
// but does not yet contain version, profile, options.
m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0; m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0;
QVector<EGLint> contextAttrs; QVector<EGLint> contextAttrs;
contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
contextAttrs.append(format.majorVersion()); contextAttrs.append(format.majorVersion());
const bool hasKHRCreateContext = q_hasEglExtension(m_eglDisplay, "EGL_KHR_create_context");
if (hasKHRCreateContext) {
contextAttrs.append(EGL_CONTEXT_MINOR_VERSION_KHR);
contextAttrs.append(format.minorVersion());
int flags = 0;
// The debug bit is supported both for OpenGL and OpenGL ES.
if (format.testOption(QSurfaceFormat::DebugContext))
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
// The fwdcompat bit is only for OpenGL 3.0+.
if (m_format.renderableType() == QSurfaceFormat::OpenGL
&& format.majorVersion() >= 3
&& !format.testOption(QSurfaceFormat::DeprecatedFunctions))
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (flags) {
contextAttrs.append(EGL_CONTEXT_FLAGS_KHR);
contextAttrs.append(flags);
}
// Profiles are OpenGL only and mandatory in 3.2+. The value is silently ignored for < 3.2.
if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
contextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
contextAttrs.append(format.profile() == QSurfaceFormat::CoreProfile
? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
: EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
}
}
contextAttrs.append(EGL_NONE); contextAttrs.append(EGL_NONE);
bindApi(m_format); switch (m_format.renderableType()) {
case QSurfaceFormat::OpenVG:
m_api = EGL_OPENVG_API;
break;
#ifdef EGL_VERSION_1_4
case QSurfaceFormat::OpenGL:
m_api = EGL_OPENGL_API;
break;
#endif // EGL_VERSION_1_4
default:
m_api = EGL_OPENGL_ES_API;
break;
}
eglBindAPI(m_api);
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData());
if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) {
m_shareContext = 0; m_shareContext = 0;
@ -133,6 +191,7 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont
return; return;
} }
#ifndef QT_NO_OPENGL
// Make the context current to ensure the GL version query works. This needs a surface too. // Make the context current to ensure the GL version query works. This needs a surface too.
const EGLint pbufferAttributes[] = { const EGLint pbufferAttributes[] = {
EGL_WIDTH, 1, EGL_WIDTH, 1,
@ -145,25 +204,52 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont
return; return;
if (eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) { if (eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) {
const GLubyte *s = glGetString(GL_VERSION); if (m_format.renderableType() == QSurfaceFormat::OpenGL
if (s) { || m_format.renderableType() == QSurfaceFormat::OpenGLES) {
QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); const GLubyte *s = glGetString(GL_VERSION);
int major, minor; if (s) {
if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
m_format.setMajorVersion(major); int major, minor;
m_format.setMinorVersion(minor); if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) {
m_format.setMajorVersion(major);
m_format.setMinorVersion(minor);
}
}
m_format.setProfile(QSurfaceFormat::NoProfile);
m_format.setOptions(QSurfaceFormat::FormatOptions());
if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
// Check profile and options.
if (m_format.majorVersion() < 3) {
m_format.setOption(QSurfaceFormat::DeprecatedFunctions);
} else {
GLint value = 0;
glGetIntegerv(GL_CONTEXT_FLAGS, &value);
if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
m_format.setOption(QSurfaceFormat::DeprecatedFunctions);
if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
m_format.setOption(QSurfaceFormat::DebugContext);
if (m_format.version() >= qMakePair(3, 2)) {
value = 0;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
if (value & GL_CONTEXT_CORE_PROFILE_BIT)
m_format.setProfile(QSurfaceFormat::CoreProfile);
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
m_format.setProfile(QSurfaceFormat::CompatibilityProfile);
}
}
} }
} }
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
} }
eglDestroySurface(m_eglDisplay, pbuffer); eglDestroySurface(m_eglDisplay, pbuffer);
#endif // QT_NO_OPENGL
} }
bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface)
{ {
Q_ASSERT(surface->surface()->supportsOpenGL()); Q_ASSERT(surface->surface()->supportsOpenGL());
bindApi(m_format); eglBindAPI(m_api);
EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface); EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
@ -231,7 +317,7 @@ QEGLPlatformContext::~QEGLPlatformContext()
void QEGLPlatformContext::doneCurrent() void QEGLPlatformContext::doneCurrent()
{ {
bindApi(m_format); eglBindAPI(m_api);
bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (!ok) if (!ok)
qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this); qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this);
@ -239,7 +325,7 @@ void QEGLPlatformContext::doneCurrent()
void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface) void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface)
{ {
bindApi(m_format); eglBindAPI(m_api);
EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface); EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
bool ok = eglSwapBuffers(m_eglDisplay, eglSurface); bool ok = eglSwapBuffers(m_eglDisplay, eglSurface);
if (!ok) if (!ok)
@ -248,7 +334,7 @@ void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface)
void (*QEGLPlatformContext::getProcAddress(const QByteArray &procName)) () void (*QEGLPlatformContext::getProcAddress(const QByteArray &procName)) ()
{ {
bindApi(m_format); eglBindAPI(m_api);
return eglGetProcAddress(procName.constData()); return eglGetProcAddress(procName.constData());
} }

View File

@ -80,6 +80,7 @@ private:
EGLDisplay m_eglDisplay; EGLDisplay m_eglDisplay;
EGLConfig m_eglConfig; EGLConfig m_eglConfig;
QSurfaceFormat m_format; QSurfaceFormat m_format;
EGLenum m_api;
int m_swapInterval; int m_swapInterval;
bool m_swapIntervalEnvChecked; bool m_swapIntervalEnvChecked;
int m_swapIntervalFromEnv; int m_swapIntervalFromEnv;