1From dcea7e200b90a5ad5571a558d5a693165381c9fc Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Mon, 15 Jun 2020 16:48:42 +0800
4Subject: [PATCH 03/17] Revert "Use a dedicated EGLContext for the decorations
5 blitter"
6
7This reverts commit 7a69fc27a7cb5c5e9c70c1c56e534e6e59b46696.
8
9Somehow mali doesn't work well with this.
10
11Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
12---
13 .../client/wayland-egl/qwaylandglcontext.cpp  | 205 +++++++++++++-----
14 .../client/wayland-egl/qwaylandglcontext.h    |   4 +-
15 2 files changed, 148 insertions(+), 61 deletions(-)
16
17diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
18index 1a1c349..d076d9e 100644
19--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
20+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
21@@ -56,7 +56,6 @@
22 #include <QtGui/QSurfaceFormat>
23 #include <QtGui/QOpenGLShaderProgram>
24 #include <QtGui/QOpenGLFunctions>
25-#include <QOpenGLBuffer>
26
27 #include <QtCore/qmutex.h>
28
29@@ -139,10 +138,19 @@ public:
30             qDebug() << "Shader Program link failed.";
31             qDebug() << m_blitProgram->log();
32         }
33+    }
34+    ~DecorationsBlitter()
35+    {
36+        delete m_blitProgram;
37+    }
38+    void blit(QWaylandEglWindow *window)
39+    {
40+        Q_ASSERT(window->wlSurface());
41+        QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
42
43-        m_blitProgram->bind();
44-        m_blitProgram->enableAttributeArray(0);
45-        m_blitProgram->enableAttributeArray(1);
46+        QSize surfaceSize = window->surfaceSize();
47+        int scale = window->scale() ;
48+        glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
49
50         glDisable(GL_DEPTH_TEST);
51         glDisable(GL_BLEND);
52@@ -151,8 +159,9 @@ public:
53         glDepthMask(GL_FALSE);
54         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
55
56-        m_buffer.create();
57-        m_buffer.bind();
58+        m_context->mUseNativeDefaultFbo = true;
59+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
60+        m_context->mUseNativeDefaultFbo = false;
61
62         static const GLfloat squareVertices[] = {
63             -1.f, -1.f,
64@@ -160,12 +169,14 @@ public:
65             -1.f,  1.0f,
66             1.0f,  1.0f
67         };
68+
69         static const GLfloat inverseSquareVertices[] = {
70             -1.f, 1.f,
71             1.f, 1.f,
72             -1.f, -1.f,
73             1.f, -1.f
74         };
75+
76         static const GLfloat textureVertices[] = {
77             0.0f,  0.0f,
78             1.0f,  0.0f,
79@@ -173,57 +184,44 @@ public:
80             1.0f,  1.0f,
81         };
82
83-        m_squareVerticesOffset = 0;
84-        m_inverseSquareVerticesOffset = sizeof(squareVertices);
85-        m_textureVerticesOffset = sizeof(squareVertices) + sizeof(textureVertices);
86-
87-        m_buffer.allocate(sizeof(squareVertices) + sizeof(inverseSquareVertices) + sizeof(textureVertices));
88-        m_buffer.write(m_squareVerticesOffset, squareVertices, sizeof(squareVertices));
89-        m_buffer.write(m_inverseSquareVerticesOffset, inverseSquareVertices, sizeof(inverseSquareVertices));
90-        m_buffer.write(m_textureVerticesOffset, textureVertices, sizeof(textureVertices));
91-
92-        m_blitProgram->setAttributeBuffer(1, GL_FLOAT, m_textureVerticesOffset, 2);
93+        glBindBuffer(GL_ARRAY_BUFFER, 0);
94+        m_blitProgram->bind();
95
96-        m_textureWrap = m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE;
97-    }
98-    ~DecorationsBlitter()
99-    {
100-        delete m_blitProgram;
101-    }
102-    void blit(QWaylandEglWindow *window)
103-    {
104-        Q_ASSERT(window->wlSurface());
105-        QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
106+        m_blitProgram->enableAttributeArray(0);
107+        m_blitProgram->enableAttributeArray(1);
108+        m_blitProgram->setAttributeArray(1, textureVertices, 2);
109
110-        QSize surfaceSize = window->surfaceSize();
111-        int scale = window->scale() ;
112-        glViewport(0, 0, surfaceSize.width() * scale, surfaceSize.height() * scale);
113+        glActiveTexture(GL_TEXTURE0);
114
115         //Draw Decoration
116-        m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_inverseSquareVerticesOffset, 2);
117+        m_blitProgram->setAttributeArray(0, inverseSquareVertices, 2);
118         QImage decorationImage = window->decoration()->contentImage();
119         cache->bindTexture(m_context->context(), decorationImage);
120         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
121         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
122-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_textureWrap);
123-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_textureWrap);
124+        if (m_context->context()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) {
125+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
126+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
127+        } else {
128+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
129+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
130+        }
131         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
132
133         //Draw Content
134-        m_blitProgram->setAttributeBuffer(0, GL_FLOAT, m_squareVerticesOffset, 2);
135+        m_blitProgram->setAttributeArray(0, squareVertices, 2);
136         glBindTexture(GL_TEXTURE_2D, window->contentTexture());
137         QRect r = window->contentsRect();
138         glViewport(r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale);
139         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
140+
141+        //Cleanup
142+        m_blitProgram->disableAttributeArray(0);
143+        m_blitProgram->disableAttributeArray(1);
144     }
145
146     QOpenGLShaderProgram *m_blitProgram = nullptr;
147     QWaylandGLContext *m_context = nullptr;
148-    QOpenGLBuffer m_buffer;
149-    int m_squareVerticesOffset;
150-    int m_inverseSquareVerticesOffset;
151-    int m_textureVerticesOffset;
152-    int m_textureWrap;
153 };
154
155
156@@ -310,13 +308,6 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis
157         return;
158     }
159
160-    // Create an EGL context for the decorations blitter. By using a dedicated context we don't need to make sure to not
161-    // change the context state and we also use OpenGL ES 2 API independently to what the app is using to draw.
162-    QVector<EGLint> eglDecorationsContextAttrs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
163-    m_decorationsContext = eglCreateContext(m_eglDisplay, m_config, m_context, eglDecorationsContextAttrs.constData());
164-    if (m_decorationsContext == EGL_NO_CONTEXT)
165-        qWarning("QWaylandGLContext: Failed to create the decorations EGLContext. Decorations will not be drawn.");
166-
167     EGLint a = EGL_MIN_SWAP_INTERVAL;
168     EGLint b = EGL_MAX_SWAP_INTERVAL;
169     if (!eglGetConfigAttrib(m_eglDisplay, m_config, a, &a) ||
170@@ -406,8 +397,6 @@ void QWaylandGLContext::updateGLFormat()
171 QWaylandGLContext::~QWaylandGLContext()
172 {
173     delete m_blitter;
174-    if (m_decorationsContext != EGL_NO_CONTEXT)
175-        eglDestroyContext(m_eglDisplay, m_decorationsContext);
176     eglDestroyContext(m_eglDisplay, m_context);
177 }
178
179@@ -435,7 +424,12 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
180
181     if (window->isExposed())
182         window->setCanResize(false);
183-    if (m_decorationsContext != EGL_NO_CONTEXT && !window->decoration())
184+    // Core profiles mandate the use of VAOs when rendering. We would then need to use one
185+    // in DecorationsBlitter, but for that we would need a QOpenGLFunctions_3_2_Core instead
186+    // of the QOpenGLFunctions we use, but that would break when using a lower version context.
187+    // Instead of going crazy, just disable decorations for core profiles until we use
188+    // subsurfaces for them.
189+    if (m_format.profile() != QSurfaceFormat::CoreProfile && !window->decoration())
190         window->createDecoration();
191
192     if (eglSurface == EGL_NO_SURFACE) {
193@@ -466,6 +460,102 @@ void QWaylandGLContext::doneCurrent()
194     eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
195 }
196
197+#define STATE_GUARD_VERTEX_ATTRIB_COUNT 2
198+
199+class StateGuard
200+{
201+public:
202+    StateGuard() {
203+        QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
204+
205+        glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &m_program);
206+        glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &m_activeTextureUnit);
207+        glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &m_texture);
208+        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &m_fbo);
209+        glGetIntegerv(GL_VIEWPORT, m_viewport);
210+        glGetIntegerv(GL_DEPTH_WRITEMASK, &m_depthWriteMask);
211+        glGetIntegerv(GL_COLOR_WRITEMASK, m_colorWriteMask);
212+        m_blend = glIsEnabled(GL_BLEND);
213+        m_depth = glIsEnabled(GL_DEPTH_TEST);
214+        m_cull = glIsEnabled(GL_CULL_FACE);
215+        m_scissor = glIsEnabled(GL_SCISSOR_TEST);
216+        for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) {
217+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *) &m_vertexAttribs[i].enabled);
218+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *) &m_vertexAttribs[i].arrayBuffer);
219+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &m_vertexAttribs[i].size);
220+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &m_vertexAttribs[i].stride);
221+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *) &m_vertexAttribs[i].type);
222+            glFuncs.glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *) &m_vertexAttribs[i].normalized);
223+            glFuncs.glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &m_vertexAttribs[i].pointer);
224+        }
225+        glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint *) &m_minFilter);
226+        glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint *) &m_magFilter);
227+        glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (GLint *) &m_wrapS);
228+        glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (GLint *) &m_wrapT);
229+    }
230+
231+    ~StateGuard() {
232+        QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
233+
234+        glFuncs.glUseProgram(m_program);
235+        glActiveTexture(m_activeTextureUnit);
236+        glBindTexture(GL_TEXTURE_2D, m_texture);
237+        glFuncs.glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
238+        glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
239+        glDepthMask(m_depthWriteMask);
240+        glColorMask(m_colorWriteMask[0], m_colorWriteMask[1], m_colorWriteMask[2], m_colorWriteMask[3]);
241+        if (m_blend)
242+            glEnable(GL_BLEND);
243+        if (m_depth)
244+            glEnable(GL_DEPTH_TEST);
245+        if (m_cull)
246+            glEnable(GL_CULL_FACE);
247+        if (m_scissor)
248+            glEnable(GL_SCISSOR_TEST);
249+        for (int i = 0; i < STATE_GUARD_VERTEX_ATTRIB_COUNT; ++i) {
250+            if (m_vertexAttribs[i].enabled)
251+                glFuncs.glEnableVertexAttribArray(i);
252+            GLuint prevBuf;
253+            glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint *) &prevBuf);
254+            glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_vertexAttribs[i].arrayBuffer);
255+            glFuncs.glVertexAttribPointer(i, m_vertexAttribs[i].size, m_vertexAttribs[i].type,
256+                                          m_vertexAttribs[i].normalized, m_vertexAttribs[i].stride,
257+                                          m_vertexAttribs[i].pointer);
258+            glFuncs.glBindBuffer(GL_ARRAY_BUFFER, prevBuf);
259+        }
260+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
261+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
262+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
263+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
264+    }
265+
266+private:
267+    GLuint m_program;
268+    GLenum m_activeTextureUnit;
269+    GLuint m_texture;
270+    GLuint m_fbo;
271+    GLint m_depthWriteMask;
272+    GLint m_colorWriteMask[4];
273+    GLboolean m_blend;
274+    GLboolean m_depth;
275+    GLboolean m_cull;
276+    GLboolean m_scissor;
277+    GLint m_viewport[4];
278+    struct VertexAttrib {
279+        bool enabled;
280+        GLuint arrayBuffer;
281+        GLint size;
282+        GLint stride;
283+        GLenum type;
284+        bool normalized;
285+        void *pointer = nullptr;
286+    } m_vertexAttribs[STATE_GUARD_VERTEX_ATTRIB_COUNT];
287+    GLenum m_minFilter;
288+    GLenum m_magFilter;
289+    GLenum m_wrapS;
290+    GLenum m_wrapT;
291+};
292+
293 void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
294 {
295     QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface);
296@@ -473,23 +563,15 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
297     EGLSurface eglSurface = window->eglSurface();
298
299     if (window->decoration()) {
300-        if (m_api != EGL_OPENGL_ES_API)
301-            eglBindAPI(EGL_OPENGL_ES_API);
302+        makeCurrent(surface);
303
304-        // save the current EGL content and surface to set it again after the blitter is done
305-        EGLDisplay currentDisplay = eglGetCurrentDisplay();
306-        EGLContext currentContext = eglGetCurrentContext();
307-        EGLSurface currentSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
308-        EGLSurface currentSurfaceRead = eglGetCurrentSurface(EGL_READ);
309-        eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_decorationsContext);
310+        // Must save & restore all state. Applications are usually not prepared
311+        // for random context state changes in a swapBuffers() call.
312+        StateGuard stateGuard;
313
314         if (!m_blitter)
315             m_blitter = new DecorationsBlitter(this);
316         m_blitter->blit(window);
317-
318-        if (m_api != EGL_OPENGL_ES_API)
319-            eglBindAPI(m_api);
320-        eglMakeCurrent(currentDisplay, currentSurfaceDraw, currentSurfaceRead, currentContext);
321     }
322
323     int swapInterval = m_supportNonBlockingSwap ? 0 : m_format.swapInterval();
324@@ -507,6 +589,9 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
325
326 GLuint QWaylandGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
327 {
328+    if (mUseNativeDefaultFbo)
329+        return 0;
330+
331     return static_cast<QWaylandEglWindow *>(surface)->contentFBO();
332 }
333
334diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h
335index 93edaec..cacd909 100644
336--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h
337+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.h
338@@ -87,13 +87,15 @@ private:
339     QWaylandDisplay *m_display = nullptr;
340     EGLContext m_context;
341     EGLContext m_shareEGLContext;
342-    EGLContext m_decorationsContext;
343     EGLConfig m_config;
344     QSurfaceFormat m_format;
345     DecorationsBlitter *m_blitter = nullptr;
346+    bool mUseNativeDefaultFbo = false;
347     uint m_api;
348     bool m_supportNonBlockingSwap = true;
349     bool m_supportSurfaceLessContext = false;
350+
351+    friend class DecorationsBlitter;
352 };
353
354 }
355--
3562.20.1
357
358