From 4b3d11efc04c9fb2bf8bb43d841a9f05b34a8c84 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 7 Mar 2014 16:50:22 +0100 Subject: Add EGL_KHR_create_context support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog] GLES3 and desktop OpenGL are now fully supported with EGL Task-number: QTBUG-37332 Change-Id: Ic695db573d90b3a204941d105a370f5c63182b63 Reviewed-by: Jørgen Lind --- .../eglconvenience/qeglplatformcontext.cpp | 158 ++++++++++++++++----- .../eglconvenience/qeglplatformcontext_p.h | 1 + 2 files changed, 123 insertions(+), 36 deletions(-) (limited to 'src/platformsupport/eglconvenience') diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index ace83289c9..9c3b9b539c 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -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(share)->m_eglContext : 0; QVector 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(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(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()); } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index b4734fb22a..714633c3bc 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -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; -- cgit v1.2.3