From dcea7e200b90a5ad5571a558d5a693165381c9fc Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 15 Jun 2020 16:48:42 +0800 Subject: [PATCH 03/17] Revert "Use a dedicated EGLContext for the decorations blitter" This reverts commit 7a69fc27a7cb5c5e9c70c1c56e534e6e59b46696. Somehow mali doesn't work well with this. Signed-off-by: Jeffy Chen --- .../client/wayland-egl/qwaylandglcontext.cpp | 205 +++++++++++++----- .../client/wayland-egl/qwaylandglcontext.h | 4 +- 2 files changed, 148 insertions(+), 61 deletions(-) diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp index 1a1c349..d076d9e 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp @@ -56,7 +56,6 @@ #include #include #include -#include #include @@ -139,10 +138,19 @@ public: qDebug() << "Shader Program link failed."; qDebug() << m_blitProgram->log(); } + } + ~DecorationsBlitter() + { + delete m_blitProgram; + } + void blit(QWaylandEglWindow *window) + { + Q_ASSERT(window->wlSurface()); + QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context()); - m_blitProgram->bind(); - m_blitProgram->enableAttributeArray(0); - m_blitProgram->enableAttributeArray(1); + QSize surfaceSize = window->surfaceSize(); + int scale = window->scale() ; + glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); @@ -151,8 +159,9 @@ public: glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - m_buffer.create(); - m_buffer.bind(); + m_context->mUseNativeDefaultFbo = true; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + m_context->mUseNativeDefaultFbo = false; static const GLfloat squareVertices[] = { -1.f, -1.f, @@ -160,12 +169,14 @@ 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, @@ -173,57 +184,44 @@ public: 1.0f, 1.0f, }; - m_squareVerticesOffset = 0; - m_inverseSquareVerticesOffset = sizeof(squareVertices); - m_textureVerticesOffset = sizeof(squareVertices) + sizeof(textureVertices); - - 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); + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_blitProgram->bind(); - m_textureWrap = m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; - } - ~DecorationsBlitter() - { - delete m_blitProgram; - } - void blit(QWaylandEglWindow *window) - { - Q_ASSERT(window->wlSurface()); - QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context()); + m_blitProgram->enableAttributeArray(0); + m_blitProgram->enableAttributeArray(1); + m_blitProgram->setAttributeArray(1, textureVertices, 2); - QSize surfaceSize = window->surfaceSize(); - int scale = window->scale() ; - glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale); + glActiveTexture(GL_TEXTURE0); //Draw Decoration - m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_inverseSquareVerticesOffset, 2); + 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); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_textureWrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_textureWrap); + 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); + } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); //Draw Content - m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_squareVerticesOffset, 2); + m_blitProgram->setAttributeArray(0, squareVertices, 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; }; @@ -310,13 +308,6 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis 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. - QVector eglDecorationsContextAttrs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - m_decorationsContext = eglCreateContext(m_eglDisplay, m_config, m_context, 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) || @@ -406,8 +397,6 @@ void QWaylandGLContext::updateGLFormat() QWaylandGLContext::~QWaylandGLContext() { delete m_blitter; - if (m_decorationsContext != EGL_NO_CONTEXT) - eglDestroyContext(m_eglDisplay, m_decorationsContext); eglDestroyContext(m_eglDisplay, m_context); } @@ -435,7 +424,12 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface) if (window->isExposed()) window->setCanResize(false); - if (m_decorationsContext != EGL_NO_CONTEXT && !window->decoration()) + // 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 (eglSurface == EGL_NO_SURFACE) { @@ -466,6 +460,102 @@ void QWaylandGLContext::doneCurrent() eglMakeCurrent(m_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(surface); @@ -473,23 +563,15 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) EGLSurface eglSurface = window->eglSurface(); if (window->decoration()) { - if (m_api != EGL_OPENGL_ES_API) - eglBindAPI(EGL_OPENGL_ES_API); + makeCurrent(surface); - // 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(m_eglDisplay, eglSurface, eglSurface, m_decorationsContext); + // Must save & restore all state. Applications are usually not prepared + // for random context state changes in a swapBuffers() call. + StateGuard stateGuard; 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 = m_supportNonBlockingSwap ? 0 : m_format.swapInterval(); @@ -507,6 +589,9 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) GLuint QWaylandGLContext::defaultFramebufferObject(QPlatformSurface *surface) const { + if (mUseNativeDefaultFbo) + return 0; + return static_cast(surface)->contentFBO(); } diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h index 93edaec..cacd909 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h @@ -87,13 +87,15 @@ private: QWaylandDisplay *m_display = nullptr; EGLContext m_context; EGLContext m_shareEGLContext; - EGLContext m_decorationsContext; EGLConfig m_config; QSurfaceFormat m_format; DecorationsBlitter *m_blitter = nullptr; + bool mUseNativeDefaultFbo = false; uint m_api; bool m_supportNonBlockingSwap = true; bool m_supportSurfaceLessContext = false; + + friend class DecorationsBlitter; }; } -- 2.20.1