diff options
Diffstat (limited to 'src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp')
-rw-r--r-- | src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp | 503 |
1 files changed, 148 insertions, 355 deletions
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp index 6b9776e9c..02789b305 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp @@ -1,61 +1,26 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwaylandglcontext.h" +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwaylandglcontext_p.h" #include <QtWaylandClient/private/qwaylanddisplay_p.h> #include <QtWaylandClient/private/qwaylandwindow_p.h> #include <QtWaylandClient/private/qwaylandsubsurface_p.h> #include <QtWaylandClient/private/qwaylandabstractdecoration_p.h> #include <QtWaylandClient/private/qwaylandintegration_p.h> -#include "qwaylandeglwindow.h" +#include "qwaylandeglwindow_p.h" #include <QDebug> -#include <QtEglSupport/private/qeglconvenience_p.h> +#include <QtGui/private/qeglconvenience_p.h> #include <QtGui/private/qopenglcontext_p.h> -#include <QtGui/private/qopengltexturecache_p.h> +#include <QtOpenGL/private/qopengltexturecache_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformopenglcontext.h> #include <QtGui/QSurfaceFormat> -#include <QtGui/QOpenGLShaderProgram> +#include <QtOpenGL/QOpenGLShaderProgram> #include <QtGui/QOpenGLFunctions> +#include <QOpenGLBuffer> #include <QtCore/qmutex.h> @@ -138,19 +103,10 @@ public: qDebug() << "Shader Program link failed."; qDebug() << m_blitProgram->log(); } - } - ~DecorationsBlitter() - { - delete m_blitProgram; - } - void blit(QWaylandEglWindow *window) - { - Q_ASSERT(window->wl_surface::isInitialized()); - QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context()); - QRect windowRect = window->window()->frameGeometry(); - int scale = window->scale() ; - glViewport(0, 0, windowRect.width() * scale, windowRect.height() * scale); + m_blitProgram->bind(); + m_blitProgram->enableAttributeArray(0); + m_blitProgram->enableAttributeArray(1); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); @@ -159,9 +115,8 @@ public: glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - m_context->mUseNativeDefaultFbo = true; - glBindFramebuffer(GL_FRAMEBUFFER, 0); - m_context->mUseNativeDefaultFbo = false; + m_buffer.create(); + m_buffer.bind(); static const GLfloat squareVertices[] = { -1.f, -1.f, @@ -169,14 +124,12 @@ public: -1.f, 1.0f, 1.0f, 1.0f }; - static const GLfloat inverseSquareVertices[] = { -1.f, 1.f, 1.f, 1.f, -1.f, -1.f, 1.f, -1.f }; - static const GLfloat textureVertices[] = { 0.0f, 0.0f, 1.0f, 0.0f, @@ -184,212 +137,159 @@ public: 1.0f, 1.0f, }; - glBindBuffer(GL_ARRAY_BUFFER, 0); - m_blitProgram->bind(); + m_squareVerticesOffset = 0; + m_inverseSquareVerticesOffset = sizeof(squareVertices); + m_textureVerticesOffset = sizeof(squareVertices) + sizeof(textureVertices); - m_blitProgram->enableAttributeArray(0); - m_blitProgram->enableAttributeArray(1); - m_blitProgram->setAttributeArray(1, textureVertices, 2); + m_buffer.allocate(sizeof(squareVertices) + sizeof(inverseSquareVertices) + sizeof(textureVertices)); + m_buffer.write(m_squareVerticesOffset, squareVertices, sizeof(squareVertices)); + m_buffer.write(m_inverseSquareVerticesOffset, inverseSquareVertices, sizeof(inverseSquareVertices)); + m_buffer.write(m_textureVerticesOffset, textureVertices, sizeof(textureVertices)); + + m_blitProgram->setAttributeBuffer(1, GL_FLOAT, m_textureVerticesOffset, 2); + + m_textureWrap = m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; + } + ~DecorationsBlitter() + { + delete m_blitProgram; + } + void blit(QWaylandEglWindow *window) + { + QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context()); - glActiveTexture(GL_TEXTURE0); + QSize surfaceSize = window->surfaceSize(); + qreal scale = window->scale() ; + glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale); //Draw Decoration - m_blitProgram->setAttributeArray(0, inverseSquareVertices, 2); - QImage decorationImage = window->decoration()->contentImage(); - cache->bindTexture(m_context->context(), decorationImage); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - if (m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (auto *decoration = window->decoration()) { + m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_inverseSquareVerticesOffset, 2); + QImage decorationImage = decoration->contentImage(); + cache->bindTexture(m_context->context(), decorationImage); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_textureWrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_textureWrap); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); //Draw Content - m_blitProgram->setAttributeArray(0, squareVertices, 2); + m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_squareVerticesOffset, 2); glBindTexture(GL_TEXTURE_2D, window->contentTexture()); QRect r = window->contentsRect(); glViewport(r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - //Cleanup - m_blitProgram->disableAttributeArray(0); - m_blitProgram->disableAttributeArray(1); } QOpenGLShaderProgram *m_blitProgram = nullptr; QWaylandGLContext *m_context = nullptr; + QOpenGLBuffer m_buffer; + int m_squareVerticesOffset; + int m_inverseSquareVerticesOffset; + int m_textureVerticesOffset; + int m_textureWrap; }; - - -QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *display, const QSurfaceFormat &format, QPlatformOpenGLContext *share) - : QPlatformOpenGLContext() - , m_eglDisplay(eglDisplay) - , m_display(display) +QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *display, + const QSurfaceFormat &fmt, QPlatformOpenGLContext *share) + : QEGLPlatformContext(fmt, share, eglDisplay), m_display(display) { - QSurfaceFormat fmt = format; - if (static_cast<QWaylandIntegration *>(QGuiApplicationPrivate::platformIntegration())->display()->supportsWindowDecoration()) - fmt.setAlphaBufferSize(8); - m_config = q_configFromGLFormat(m_eglDisplay, fmt); - m_format = q_glFormatFromConfig(m_eglDisplay, m_config, fmt); - m_shareEGLContext = share ? static_cast<QWaylandGLContext *>(share)->eglContext() : EGL_NO_CONTEXT; - - QVector<EGLint> eglContextAttrs; - eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); - eglContextAttrs.append(format.majorVersion()); - const bool hasKHRCreateContext = q_hasEglExtension(m_eglDisplay, "EGL_KHR_create_context"); - if (hasKHRCreateContext) { - eglContextAttrs.append(EGL_CONTEXT_MINOR_VERSION_KHR); - eglContextAttrs.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) { - eglContextAttrs.append(EGL_CONTEXT_FLAGS_KHR); - eglContextAttrs.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) { - switch (format.profile()) { - case QSurfaceFormat::NoProfile: - break; - case QSurfaceFormat::CoreProfile: - eglContextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); - eglContextAttrs.append(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR); - break; - case QSurfaceFormat::CompatibilityProfile: - eglContextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); - eglContextAttrs.append(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); - break; - } - } - } - eglContextAttrs.append(EGL_NONE); + m_reconnectionWatcher = QObject::connect(m_display, &QWaylandDisplay::connected, + m_display, [this] { invalidateContext(); }); - switch (m_format.renderableType()) { + switch (format().renderableType()) { case QSurfaceFormat::OpenVG: m_api = EGL_OPENVG_API; break; #ifdef EGL_VERSION_1_4 -# if !defined(QT_OPENGL_ES_2) - case QSurfaceFormat::DefaultRenderableType: -# endif case QSurfaceFormat::OpenGL: m_api = EGL_OPENGL_API; break; -#endif - case QSurfaceFormat::OpenGLES: +#endif // EGL_VERSION_1_4 default: m_api = EGL_OPENGL_ES_API; break; } - eglBindAPI(m_api); - - m_context = eglCreateContext(m_eglDisplay, m_config, m_shareEGLContext, eglContextAttrs.constData()); - - if (m_context == EGL_NO_CONTEXT) { - m_context = eglCreateContext(m_eglDisplay, m_config, EGL_NO_CONTEXT, eglContextAttrs.constData()); - m_shareEGLContext = EGL_NO_CONTEXT; - } - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - qWarning("QWaylandGLContext: failed to create EGLContext, error=%x", error); - return; - } + // Create an EGL context for the decorations blitter. By using a dedicated context we don't need to make sure to not + // change the context state and we also use OpenGL ES 2 API independently to what the app is using to draw. + QList<EGLint> eglDecorationsContextAttrs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + m_decorationsContext = eglCreateContext(eglDisplay, eglConfig(), eglContext(), + eglDecorationsContextAttrs.constData()); + if (m_decorationsContext == EGL_NO_CONTEXT) + qWarning("QWaylandGLContext: Failed to create the decorations EGLContext. Decorations will not be drawn."); EGLint a = EGL_MIN_SWAP_INTERVAL; EGLint b = EGL_MAX_SWAP_INTERVAL; - if (!eglGetConfigAttrib(m_eglDisplay, m_config, a, &a) || - !eglGetConfigAttrib(m_eglDisplay, m_config, b, &b) || - a > 0) { - mSupportNonBlockingSwap = false; + if (!eglGetConfigAttrib(eglDisplay, eglConfig(), a, &a) + || !eglGetConfigAttrib(eglDisplay, eglConfig(), b, &b) || a > 0) { + m_supportNonBlockingSwap = false; + } + { + bool ok; + int supportNonBlockingSwap = qEnvironmentVariableIntValue("QT_WAYLAND_FORCE_NONBLOCKING_SWAP_SUPPORT", &ok); + if (ok) + m_supportNonBlockingSwap = supportNonBlockingSwap != 0; } - if (!mSupportNonBlockingSwap) { + if (!m_supportNonBlockingSwap) { qWarning(lcQpaWayland) << "Non-blocking swap buffers not supported." << "Subsurface rendering can be affected." << "It may also cause the event loop to freeze in some situations"; } +} - updateGLFormat(); +EGLSurface QWaylandGLContext::createTemporaryOffscreenSurface() +{ + m_wlSurface = m_display->createSurface(nullptr); + m_eglWindow = wl_egl_window_create(m_wlSurface, 1, 1); +#if QT_CONFIG(egl_extension_platform_wayland) + EGLSurface eglSurface = + eglCreatePlatformWindowSurface(eglDisplay(), eglConfig(), m_eglWindow, nullptr); +#else + EGLSurface eglSurface = eglCreateWindowSurface(eglDisplay(), eglConfig(), m_eglWindow, nullptr); +#endif + return eglSurface; } -void QWaylandGLContext::updateGLFormat() +void QWaylandGLContext::destroyTemporaryOffscreenSurface(EGLSurface eglSurface) { - // Have to save & restore to prevent QOpenGLContext::currentContext() from becoming - // inconsistent after QOpenGLContext::create(). - EGLDisplay prevDisplay = eglGetCurrentDisplay(); - if (prevDisplay == EGL_NO_DISPLAY) // when no context is current - prevDisplay = m_eglDisplay; - EGLContext prevContext = eglGetCurrentContext(); - EGLSurface prevSurfaceDraw = eglGetCurrentSurface(EGL_DRAW); - EGLSurface prevSurfaceRead = eglGetCurrentSurface(EGL_READ); - - wl_surface *wlSurface = m_display->createSurface(nullptr); - wl_egl_window *eglWindow = wl_egl_window_create(wlSurface, 1, 1); - EGLSurface eglSurface = eglCreateWindowSurface(m_eglDisplay, m_config, eglWindow, 0); - - if (eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_context)) { - 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(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext); - } - eglDestroySurface(m_eglDisplay, eglSurface); - wl_egl_window_destroy(eglWindow); - wl_surface_destroy(wlSurface); + eglDestroySurface(eglDisplay(), eglSurface); + wl_egl_window_destroy(m_eglWindow); + m_eglWindow = nullptr; + wl_surface_destroy(m_wlSurface); + m_wlSurface = nullptr; } QWaylandGLContext::~QWaylandGLContext() { + QObject::disconnect(m_reconnectionWatcher); delete m_blitter; - eglDestroyContext(m_eglDisplay, m_context); + m_blitter = nullptr; + if (m_decorationsContext != EGL_NO_CONTEXT) + eglDestroyContext(eglDisplay(), m_decorationsContext); +} + +void QWaylandGLContext::beginFrame() +{ + Q_ASSERT(m_currentWindow != nullptr); + if (m_supportNonBlockingSwap) + m_currentWindow->beginFrame(); +} + +void QWaylandGLContext::endFrame() +{ + Q_ASSERT(m_currentWindow != nullptr); + if (m_supportNonBlockingSwap) + m_currentWindow->endFrame(); } bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) { + if (!isValid()) { + return false; + } + // in QWaylandGLContext() we called eglBindAPI with the correct value. However, // eglBindAPI's documentation says: // "eglBindAPI defines the current rendering API for EGL in the thread it is called from" @@ -399,147 +299,44 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) eglBindAPI(m_api); } - QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface); - EGLSurface eglSurface = window->eglSurface(); + m_currentWindow = static_cast<QWaylandEglWindow *>(surface); + EGLSurface eglSurface = m_currentWindow->eglSurface(); - if (!window->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) { - if (!eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_context)) { - qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); + if (!m_currentWindow->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) { + if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) { + qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this); return false; } return true; } - if (window->isExposed()) - window->setCanResize(false); - // Core profiles mandate the use of VAOs when rendering. We would then need to use one - // in DecorationsBlitter, but for that we would need a QOpenGLFunctions_3_2_Core instead - // of the QOpenGLFunctions we use, but that would break when using a lower version context. - // Instead of going crazy, just disable decorations for core profiles until we use - // subsurfaces for them. - if (m_format.profile() != QSurfaceFormat::CoreProfile && !window->decoration()) - window->createDecoration(); + if (m_currentWindow->isExposed()) + m_currentWindow->setCanResize(false); if (eglSurface == EGL_NO_SURFACE) { - window->updateSurface(true); - eglSurface = window->eglSurface(); + m_currentWindow->updateSurface(true); + eglSurface = m_currentWindow->eglSurface(); } - if (!eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_context)) { - qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); - window->setCanResize(true); + if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) { + qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this); + m_currentWindow->setCanResize(true); return false; } //### setCurrentContext will be called in QOpenGLContext::makeCurrent after this function // returns, but that's too late, as we need a current context in order to bind the content FBO. QOpenGLContextPrivate::setCurrentContext(context()); - window->bindContentFBO(); + m_currentWindow->bindContentFBO(); return true; } void QWaylandGLContext::doneCurrent() { - eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglMakeCurrent(eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -#define STATE_GUARD_VERTEX_ATTRIB_COUNT 2 - -class StateGuard -{ -public: - StateGuard() { - QOpenGLFunctions glFuncs(QOpenGLContext::currentContext()); - - glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &m_program); - glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &m_activeTextureUnit); - glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &m_texture); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &m_fbo); - glGetIntegerv(GL_VIEWPORT, m_viewport); - glGetIntegerv(GL_DEPTH_WRITEMASK, &m_depthWriteMask); - glGetIntegerv(GL_COLOR_WRITEMASK, m_colorWriteMask); - m_blend = glIsEnabled(GL_BLEND); - m_depth = glIsEnabled(GL_DEPTH_TEST); - m_cull = glIsEnabled(GL_CULL_FACE); - m_scissor = glIsEnabled(GL_SCISSOR_TEST); - for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) { - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *) &m_vertexAttribs[i].enabled); - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *) &m_vertexAttribs[i].arrayBuffer); - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &m_vertexAttribs[i].size); - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &m_vertexAttribs[i].stride); - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *) &m_vertexAttribs[i].type); - glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *) &m_vertexAttribs[i].normalized); - glFuncs.glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &m_vertexAttribs[i].pointer); - } - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint *) &m_minFilter); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint *) &m_magFilter); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (GLint *) &m_wrapS); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (GLint *) &m_wrapT); - } - - ~StateGuard() { - QOpenGLFunctions glFuncs(QOpenGLContext::currentContext()); - - glFuncs.glUseProgram(m_program); - glActiveTexture(m_activeTextureUnit); - glBindTexture(GL_TEXTURE_2D, m_texture); - glFuncs.glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]); - glDepthMask(m_depthWriteMask); - glColorMask(m_colorWriteMask[0], m_colorWriteMask[1], m_colorWriteMask[2], m_colorWriteMask[3]); - if (m_blend) - glEnable(GL_BLEND); - if (m_depth) - glEnable(GL_DEPTH_TEST); - if (m_cull) - glEnable(GL_CULL_FACE); - if (m_scissor) - glEnable(GL_SCISSOR_TEST); - for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) { - if (m_vertexAttribs[i].enabled) - glFuncs.glEnableVertexAttribArray(i); - GLuint prevBuf; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint *) &prevBuf); - glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_vertexAttribs[i].arrayBuffer); - glFuncs.glVertexAttribPointer(i, m_vertexAttribs[i].size, m_vertexAttribs[i].type, - m_vertexAttribs[i].normalized, m_vertexAttribs[i].stride, - m_vertexAttribs[i].pointer); - glFuncs.glBindBuffer(GL_ARRAY_BUFFER, prevBuf); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); - } - -private: - GLuint m_program; - GLenum m_activeTextureUnit; - GLuint m_texture; - GLuint m_fbo; - GLint m_depthWriteMask; - GLint m_colorWriteMask[4]; - GLboolean m_blend; - GLboolean m_depth; - GLboolean m_cull; - GLboolean m_scissor; - GLint m_viewport[4]; - struct VertexAttrib { - bool enabled; - GLuint arrayBuffer; - GLint size; - GLint stride; - GLenum type; - bool normalized; - void *pointer = nullptr; - } m_vertexAttribs[STATE_GUARD_VERTEX_ATTRIB_COUNT]; - GLenum m_minFilter; - GLenum m_magFilter; - GLenum m_wrapS; - GLenum m_wrapT; -}; - void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) { QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface); @@ -547,48 +344,44 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) EGLSurface eglSurface = window->eglSurface(); if (window->decoration()) { - makeCurrent(surface); + if (m_api != EGL_OPENGL_ES_API) + eglBindAPI(EGL_OPENGL_ES_API); - // Must save & restore all state. Applications are usually not prepared - // for random context state changes in a swapBuffers() call. - StateGuard stateGuard; + // save the current EGL content and surface to set it again after the blitter is done + EGLDisplay currentDisplay = eglGetCurrentDisplay(); + EGLContext currentContext = eglGetCurrentContext(); + EGLSurface currentSurfaceDraw = eglGetCurrentSurface(EGL_DRAW); + EGLSurface currentSurfaceRead = eglGetCurrentSurface(EGL_READ); + eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, m_decorationsContext); if (!m_blitter) m_blitter = new DecorationsBlitter(this); m_blitter->blit(window); + + if (m_api != EGL_OPENGL_ES_API) + eglBindAPI(m_api); + eglMakeCurrent(currentDisplay, currentSurfaceDraw, currentSurfaceRead, currentContext); } - int swapInterval = mSupportNonBlockingSwap ? 0 : m_format.swapInterval(); - eglSwapInterval(m_eglDisplay, swapInterval); - if (swapInterval == 0 && m_format.swapInterval() > 0) { + int swapInterval = m_supportNonBlockingSwap ? 0 : format().swapInterval(); + eglSwapInterval(eglDisplay(), swapInterval); + if (swapInterval == 0 && format().swapInterval() > 0) { // Emulating a blocking swap glFlush(); // Flush before waiting so we can swap more quickly when the frame event arrives window->waitForFrameSync(100); } window->handleUpdate(); - eglSwapBuffers(m_eglDisplay, eglSurface); + if (!eglSwapBuffers(eglDisplay(), eglSurface)) + qCWarning(lcQpaWayland, "eglSwapBuffers failed with %#x, surface: %p", eglGetError(), eglSurface); window->setCanResize(true); } GLuint QWaylandGLContext::defaultFramebufferObject(QPlatformSurface *surface) const { - if (mUseNativeDefaultFbo) - return 0; - return static_cast<QWaylandEglWindow *>(surface)->contentFBO(); } -bool QWaylandGLContext::isSharing() const -{ - return m_shareEGLContext != EGL_NO_CONTEXT; -} - -bool QWaylandGLContext::isValid() const -{ - return m_context != EGL_NO_CONTEXT; -} - QFunctionPointer QWaylandGLContext::getProcAddress(const char *procName) { QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName); @@ -597,9 +390,9 @@ QFunctionPointer QWaylandGLContext::getProcAddress(const char *procName) return proc; } -EGLConfig QWaylandGLContext::eglConfig() const +EGLSurface QWaylandGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { - return m_config; + return static_cast<QWaylandEglWindow *>(surface)->eglSurface(); } } |