summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-07-29 12:43:05 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-08-06 07:30:50 +0000
commit4d39da87349d4930a4fd97af3afaacc1fd838c9f (patch)
tree2609063517063ab38d3a7caf95d917f35423f1e6 /src/plugins/platforms/eglfs
parent752362b0fa48ae9be15757aff7eb3dce6665b41a (diff)
eglfs: save state in the cursor
Running an example like hellogles3 with eglfs and the mouse cursor visible breaks due to the cursor implementation not being aware of vertex array objects. The cursor drawing code uses client side pointers and having a VAO bound breaks this. Instead, the VAO should be reset to 0. In addition, the same applies to all touched state: naive applications doing custom OpenGL rendering expect the state to be unchanged between frames and this is not unreasonable. So introduce saving and restoring for all touched state, with the exception of Quick where there is no need to waste time with this. Change-Id: Ib79039e80993ab5fc8368357fc1147ee7863d055 Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/eglfs')
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp129
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.h2
2 files changed, 115 insertions, 16 deletions
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
index d81aa2eaf2..eea130a754 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp
@@ -43,6 +43,11 @@
#include <QtCore/QJsonObject>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qopenglvertexarrayobject_p.h>
+
+#ifndef GL_VERTEX_ARRAY_BINDING
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#endif
QT_BEGIN_NAMESPACE
@@ -50,8 +55,6 @@ QEglFSCursor::QEglFSCursor(QPlatformScreen *screen)
: m_visible(true),
m_screen(static_cast<QEglFSScreen *>(screen)),
m_program(0),
- m_vertexCoordEntry(0),
- m_textureCoordEntry(0),
m_textureEntry(0),
m_deviceListener(0),
m_updateRequested(false)
@@ -134,10 +137,10 @@ void QEglFSCursor::createShaderPrograms()
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
+ m_program->bindAttributeLocation("vertexCoordEntry", 0);
+ m_program->bindAttributeLocation("textureCoordEntry", 1);
m_program->link();
- m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry");
- m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry");
m_textureEntry = m_program->uniformLocation("texture");
}
@@ -322,8 +325,105 @@ void QEglFSCursor::paintOnScreen()
draw(r);
}
+// In order to prevent breaking code doing custom OpenGL rendering while
+// expecting the state in the context unchanged, save and restore all the state
+// we touch. The exception is Qt Quick where the scenegraph is known to be able
+// to deal with the changes we make.
+struct StateSaver
+{
+ StateSaver() {
+ f = QOpenGLContext::currentContext()->functions();
+ vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext());
+
+ static bool windowsChecked = false;
+ static bool shouldSave = true;
+ if (!windowsChecked) {
+ windowsChecked = true;
+ QWindowList windows = QGuiApplication::allWindows();
+ if (!windows.isEmpty() && windows[0]->inherits("QQuickWindow"))
+ shouldSave = false;
+ }
+ saved = shouldSave;
+ if (!shouldSave)
+ return;
+
+ f->glGetIntegerv(GL_CURRENT_PROGRAM, &program);
+ f->glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
+ f->glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
+ f->glGetIntegerv(GL_FRONT_FACE, &frontFace);
+ cull = f->glIsEnabled(GL_CULL_FACE);
+ depthTest = f->glIsEnabled(GL_DEPTH_TEST);
+ blend = f->glIsEnabled(GL_BLEND);
+ f->glGetIntegerv(GL_BLEND_SRC_RGB, blendFunc);
+ f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1);
+ f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2);
+ f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3);
+ f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf);
+ if (vaoHelper->isValid())
+ f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao);
+ for (int i = 0; i < 2; ++i) {
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &va[i].enabled);
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &va[i].size);
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &va[i].type);
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &va[i].normalized);
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &va[i].stride);
+ f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &va[i].buffer);
+ f->glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &va[i].pointer);
+ }
+ }
+ ~StateSaver() {
+ if (saved) {
+ f->glUseProgram(program);
+ f->glBindTexture(GL_TEXTURE_2D, texture);
+ f->glActiveTexture(activeTexture);
+ f->glFrontFace(frontFace);
+ if (cull)
+ f->glEnable(GL_CULL_FACE);
+ else
+ f->glDisable(GL_CULL_FACE);
+ if (depthTest)
+ f->glEnable(GL_DEPTH_TEST);
+ else
+ f->glDisable(GL_DEPTH_TEST);
+ if (blend)
+ f->glEnable(GL_BLEND);
+ else
+ f->glDisable(GL_BLEND);
+ f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]);
+ f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf);
+ if (vaoHelper->isValid())
+ vaoHelper->glBindVertexArray(vao);
+ for (int i = 0; i < 2; ++i) {
+ if (va[i].enabled)
+ f->glEnableVertexAttribArray(i);
+ else
+ f->glDisableVertexAttribArray(i);
+ f->glBindBuffer(GL_ARRAY_BUFFER, va[i].buffer);
+ f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer);
+ }
+ }
+ delete vaoHelper;
+ }
+ QOpenGLFunctions *f;
+ QOpenGLVertexArrayObjectHelper *vaoHelper;
+ bool saved;
+ GLint program;
+ GLint texture;
+ GLint activeTexture;
+ GLint frontFace;
+ bool cull;
+ bool depthTest;
+ bool blend;
+ GLint blendFunc[4];
+ GLint vao;
+ GLint arrayBuf;
+ struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2];
+};
+
void QEglFSCursor::draw(const QRectF &r)
{
+ StateSaver stateSaver;
+
if (!m_program) {
// one time initialization
initializeOpenGLFunctions();
@@ -373,13 +473,16 @@ void QEglFSCursor::draw(const QRectF &r)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_cursor.texture);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- m_program->enableAttributeArray(m_vertexCoordEntry);
- m_program->enableAttributeArray(m_textureCoordEntry);
+ if (stateSaver.vaoHelper->isValid())
+ stateSaver.vaoHelper->glBindVertexArray(0);
- m_program->setAttributeArray(m_vertexCoordEntry, cursorCoordinates, 2);
- m_program->setAttributeArray(m_textureCoordEntry, textureCoordinates, 2);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ m_program->enableAttributeArray(0);
+ m_program->enableAttributeArray(1);
+ m_program->setAttributeArray(0, cursorCoordinates, 2);
+ m_program->setAttributeArray(1, textureCoordinates, 2);
m_program->setUniformValue(m_textureEntry, 0);
@@ -388,13 +491,11 @@ void QEglFSCursor::draw(const QRectF &r)
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- glDisable(GL_BLEND);
- glBindTexture(GL_TEXTURE_2D, 0);
- m_program->disableAttributeArray(m_textureCoordEntry);
- m_program->disableAttributeArray(m_vertexCoordEntry);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ m_program->disableAttributeArray(0);
+ m_program->disableAttributeArray(1);
m_program->release();
}
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h
index 048f276137..be5db41b37 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.h
+++ b/src/plugins/platforms/eglfs/qeglfscursor.h
@@ -131,8 +131,6 @@ private:
bool m_visible;
QEglFSScreen *m_screen;
QOpenGLShaderProgram *m_program;
- int m_vertexCoordEntry;
- int m_textureCoordEntry;
int m_textureEntry;
QEglFSCursorDeviceListener *m_deviceListener;
bool m_updateRequested;