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.
*/
static inline void bindApi(const QSurfaceFormat &format)
{
switch (format.renderableType()) {
case QSurfaceFormat::OpenVG:
eglBindAPI(EGL_OPENVG_API);
break;
#ifdef EGL_VERSION_1_4
case QSurfaceFormat::DefaultRenderableType:
#ifndef QT_NO_OPENGL
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL)
eglBindAPI(EGL_OPENGL_API);
else
#endif // QT_NO_OPENGL
eglBindAPI(EGL_OPENGL_ES_API);
break;
case QSurfaceFormat::OpenGL:
eglBindAPI(EGL_OPENGL_API);
break;
// Constants from EGL_KHR_create_context
#ifndef EGL_CONTEXT_MINOR_VERSION_KHR
#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
#endif
#ifndef EGL_CONTEXT_FLAGS_KHR
#define EGL_CONTEXT_FLAGS_KHR 0x30FC
#endif
#ifndef EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
#endif
#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
#endif
#ifndef EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
#endif
#ifndef EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
#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
case QSurfaceFormat::OpenGLES:
default:
eglBindAPI(EGL_OPENGL_ES_API);
break;
}
}
QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display)
: m_eglDisplay(display)
@ -114,14 +131,55 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform
void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
{
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;
QVector<EGLint> contextAttrs;
contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
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);
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());
if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) {
m_shareContext = 0;
@ -133,6 +191,7 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont
return;
}
#ifndef QT_NO_OPENGL
// Make the context current to ensure the GL version query works. This needs a surface too.
const EGLint pbufferAttributes[] = {
EGL_WIDTH, 1,
@ -145,25 +204,52 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont
return;
if (eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) {
const GLubyte *s = glGetString(GL_VERSION);
if (s) {
QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
int major, minor;
if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) {
m_format.setMajorVersion(major);
m_format.setMinorVersion(minor);
if (m_format.renderableType() == QSurfaceFormat::OpenGL
|| m_format.renderableType() == QSurfaceFormat::OpenGLES) {
const GLubyte *s = glGetString(GL_VERSION);
if (s) {
QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
int major, 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);
}
eglDestroySurface(m_eglDisplay, pbuffer);
#endif // QT_NO_OPENGL
}
bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface->surface()->supportsOpenGL());
bindApi(m_format);
eglBindAPI(m_api);
EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
@ -231,7 +317,7 @@ QEGLPlatformContext::~QEGLPlatformContext()
void QEGLPlatformContext::doneCurrent()
{
bindApi(m_format);
eglBindAPI(m_api);
bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (!ok)
qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this);
@ -239,7 +325,7 @@ void QEGLPlatformContext::doneCurrent()
void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface)
{
bindApi(m_format);
eglBindAPI(m_api);
EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
bool ok = eglSwapBuffers(m_eglDisplay, eglSurface);
if (!ok)
@ -248,7 +334,7 @@ void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface)
void (*QEGLPlatformContext::getProcAddress(const QByteArray &procName)) ()
{
bindApi(m_format);
eglBindAPI(m_api);
return eglGetProcAddress(procName.constData());
}

View File

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