Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "glstatestore_p.h"
++ #include <QDebug>
++ #include <QColor>
++ #include <QFile>
++
++ #ifdef VERBOSE_STATE_STORE
++ static QFile *beforeFile = 0;
++ static QFile *afterFile = 0;
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ GLStateStore::GLStateStore(QOpenGLContext *context, QObject *parent) :
++ QObject(parent),
++ QOpenGLFunctions(context)
++ #ifdef VERBOSE_STATE_STORE
++ , m_map(EnumToStringMap::newInstance())
++ #endif
++ {
++ GLint maxVertexAttribs;
++ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
++
++ #ifdef VERBOSE_STATE_STORE
++ qDebug() << "GL_MAX_VERTEX_ATTRIBS: " << maxVertexAttribs;
++ if (!beforeFile) {
++ beforeFile = new QFile(QStringLiteral("state_before.txt"));
++ afterFile = new QFile(QStringLiteral("state_after.txt"));
++ beforeFile->open(QIODevice::WriteOnly);
++ afterFile->open(QIODevice::WriteOnly);
++ QDebug beforeInit(beforeFile);
++ QDebug afterInit(afterFile);
++ beforeInit << "GL states before 'context switch'" << endl;
++ afterInit << "GL states after 'context switch'" << endl;
++ }
++ #endif
++
++ m_maxVertexAttribs = qMin(maxVertexAttribs, 2); // Datavis only uses 2 attribs max
++ m_vertexAttribArrayEnabledStates.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArrayBoundBuffers.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArraySizes.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArrayTypes.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArrayNormalized.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArrayStrides.reset(new GLint[maxVertexAttribs]);
++ m_vertexAttribArrayOffsets.reset(new void *[maxVertexAttribs]);
++
++ initGLDefaultState();
++ }
++
++ GLStateStore::~GLStateStore()
++ {
++ #ifdef VERBOSE_STATE_STORE
++ EnumToStringMap::deleteInstance();
++ m_map = 0;
++ #endif
++ }
++
++ void GLStateStore::storeGLState()
++ {
++ #ifdef VERBOSE_STATE_STORE
++ printCurrentState(true);
++ #endif
++
++ #if !QT_CONFIG(opengles2)
++ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &m_drawFramebuffer);
++ glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &m_readFramebuffer);
++ glGetIntegerv(GL_RENDERBUFFER_BINDING, &m_renderbuffer);
++ #endif
++ glGetFloatv(GL_COLOR_CLEAR_VALUE, m_clearColor);
++ m_isBlendingEnabled = glIsEnabled(GL_BLEND);
++ m_isDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
++ glGetBooleanv(GL_DEPTH_WRITEMASK, &m_isDepthWriteEnabled);
++ glGetFloatv(GL_DEPTH_CLEAR_VALUE, &m_clearDepth);
++ glGetIntegerv(GL_DEPTH_FUNC, &m_depthFunc);
++ glGetBooleanv(GL_POLYGON_OFFSET_FILL, &m_polygonOffsetFillEnabled);
++ glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &m_polygonOffsetFactor);
++ glGetFloatv(GL_POLYGON_OFFSET_UNITS, &m_polygonOffsetUnits);
++
++ glGetIntegerv(GL_CURRENT_PROGRAM, &m_currentProgram);
++ glGetIntegerv(GL_ACTIVE_TEXTURE, &m_activeTexture);
++ glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_texBinding2D);
++ glGetIntegerv(GL_FRONT_FACE, &m_frontFace);
++ m_isCullFaceEnabled = glIsEnabled(GL_CULL_FACE);
++ glGetIntegerv(GL_CULL_FACE_MODE, &m_cullFaceMode);
++ glGetIntegerv(GL_BLEND_EQUATION_RGB, &m_blendEquationRGB);
++ glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &m_blendEquationAlpha);
++ glGetIntegerv(GL_BLEND_DST_ALPHA, &m_blendDestAlpha);
++ glGetIntegerv(GL_BLEND_DST_RGB, &m_blendDestRGB);
++ glGetIntegerv(GL_BLEND_SRC_ALPHA, &m_blendSrcAlpha);
++ glGetIntegerv(GL_BLEND_SRC_RGB, &m_blendSrcRGB);
++ glGetIntegerv(GL_SCISSOR_BOX, m_scissorBox);
++ m_isScissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
++
++ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &m_boundArrayBuffer);
++ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &m_boundElementArrayBuffer);
++
++ for (int i = 0; i < m_maxVertexAttribs;i++) {
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
++ &m_vertexAttribArrayEnabledStates[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
++ &m_vertexAttribArrayBoundBuffers[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &m_vertexAttribArraySizes[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &m_vertexAttribArrayTypes[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
++ &m_vertexAttribArrayNormalized[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &m_vertexAttribArrayStrides[i]);
++ }
++ }
++
++ #ifdef VERBOSE_STATE_STORE
++ void GLStateStore::printCurrentState(bool in)
++ {
++ QFile *file;
++ if (in)
++ file = beforeFile;
++ else
++ file = afterFile;
++
++ if (file->isOpen()) {
++ QDebug msg(file);
++ #if !QT_CONFIG(opengles2)
++ GLint drawFramebuffer;
++ GLint readFramebuffer;
++ GLint renderbuffer;
++ #endif
++ GLfloat clearColor[4];
++ GLfloat clearDepth;
++ GLboolean isBlendingEnabled = glIsEnabled(GL_BLEND);
++ GLboolean isDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
++ GLint depthFunc;
++ GLboolean isDepthWriteEnabled;
++ GLint currentProgram;
++ GLint *vertexAttribArrayEnabledStates = new GLint[m_maxVertexAttribs];
++ GLint *vertexAttribArrayBoundBuffers = new GLint[m_maxVertexAttribs];
++ GLint *vertexAttribArraySizes = new GLint[m_maxVertexAttribs];
++ GLint *vertexAttribArrayTypes = new GLint[m_maxVertexAttribs];
++ GLint *vertexAttribArrayNormalized = new GLint[m_maxVertexAttribs];
++ GLint *vertexAttribArrayStrides = new GLint[m_maxVertexAttribs];
++ GLint activeTexture;
++ GLint texBinding2D;
++ GLint arrayBufferBinding;
++ GLint frontFace;
++ GLboolean isCullFaceEnabled = glIsEnabled(GL_CULL_FACE);
++ GLint cullFaceMode;
++ GLint blendEquationRGB;
++ GLint blendEquationAlpha;
++
++ GLint blendDestAlpha;
++ GLint blendDestRGB;
++ GLint blendSrcAlpha;
++ GLint blendSrcRGB;
++ GLint scissorBox[4];
++ GLboolean isScissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
++ GLint boundElementArrayBuffer;
++ GLboolean polygonOffsetFillEnabled;
++ GLfloat polygonOffsetFactor;
++ GLfloat polygonOffsetUnits;
++
++ glGetBooleanv(GL_DEPTH_WRITEMASK, &isDepthWriteEnabled);
++ #if !QT_CONFIG(opengles2)
++ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer);
++ glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer);
++ glGetIntegerv(GL_RENDERBUFFER_BINDING, &renderbuffer);
++ #endif
++ glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
++ glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
++ glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
++ glGetBooleanv(GL_POLYGON_OFFSET_FILL, &polygonOffsetFillEnabled);
++ glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &polygonOffsetFactor);
++ glGetFloatv(GL_POLYGON_OFFSET_UNITS, &polygonOffsetUnits);
++
++ glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
++ glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
++ glGetIntegerv(GL_TEXTURE_BINDING_2D, &texBinding2D );
++ glGetIntegerv(GL_FRONT_FACE, &frontFace);
++ glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode);
++ glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB);
++ glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
++ glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
++ glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRGB);
++ glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
++ glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRGB);
++ glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
++ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &boundElementArrayBuffer);
++ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBufferBinding);
++
++ for (int i = 0; i < m_maxVertexAttribs;i++) {
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
++ &vertexAttribArrayEnabledStates[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
++ &vertexAttribArrayBoundBuffers[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertexAttribArraySizes[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertexAttribArrayTypes[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
++ &vertexAttribArrayNormalized[i]);
++ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertexAttribArrayStrides[i]);
++ }
++
++ QColor color;
++ color.setRgbF(clearColor[0], clearColor[1], clearColor[2]);
++ color.setAlphaF(clearColor[3]);
++
++ #if !QT_CONFIG(opengles2)
++ msg << "---" << endl;
++ msg << " GL_DRAW_FRAMEBUFFER_BINDING "<< drawFramebuffer << endl;
++ msg << " GL_READ_FRAMEBUFFER_BINDING "<< readFramebuffer << endl;
++ msg << " GL_RENDERBUFFER_BINDING " << renderbuffer << endl;
++ #endif
++ msg << " GL_SCISSOR_TEST " << bool(isScissorTestEnabled) << endl;
++ msg << " GL_SCISSOR_BOX " << m_scissorBox[0] << m_scissorBox[1] << m_scissorBox[2]
++ << m_scissorBox[3] << endl;
++ msg << " GL_COLOR_CLEAR_VALUE "<< color << endl;
++ msg << " GL_DEPTH_CLEAR_VALUE "<< clearDepth << endl;
++ msg << " GL_BLEND "<< bool(isBlendingEnabled) << endl;
++ msg << " GL_BLEND_EQUATION_RGB" << m_map->lookUp(blendEquationRGB) << endl;
++ msg << " GL_BLEND_EQUATION_ALPHA" << m_map->lookUp(blendEquationAlpha) << endl;
++ msg << " GL_BLEND_DST_ALPHA" << m_map->lookUp(blendDestAlpha) << endl;
++ msg << " GL_BLEND_DST_RGB" << m_map->lookUp(blendDestRGB) << endl;
++ msg << " GL_BLEND_SRC_ALPHA" << m_map->lookUp(blendSrcAlpha) << endl;
++ msg << " GL_BLEND_SRC_RGB" << m_map->lookUp(blendSrcRGB) << endl;
++ msg << " GL_DEPTH_TEST "<< bool(isDepthTestEnabled) << endl;
++ msg << " GL_DEPTH_WRITEMASK "<< bool(isDepthWriteEnabled) << endl;
++ msg << " GL_POLYGON_OFFSET_FILL" << bool(polygonOffsetFillEnabled) << endl;
++ msg << " GL_POLYGON_OFFSET_FACTOR "<< polygonOffsetFactor << endl;
++ msg << " GL_POLYGON_OFFSET_UNITS "<< polygonOffsetUnits << endl;
++ msg << " GL_CULL_FACE "<< bool(isCullFaceEnabled) << endl;
++ msg << " GL_CULL_FACE_MODE "<< m_map->lookUp(cullFaceMode) << endl;
++ msg << " GL_DEPTH_FUNC "<< m_map->lookUp(depthFunc) << endl;
++ msg << " GL_FRONT_FACE "<< m_map->lookUp(frontFace) << endl;
++ msg << " GL_CURRENT_PROGRAM "<< currentProgram << endl;
++ msg << " GL_ACTIVE_TEXTURE "<< QString("0x%1").arg(activeTexture, 0, 16) << endl;
++ msg << " GL_TEXTURE_BINDING_2D "<< texBinding2D << endl;
++ msg << " GL_ELEMENT_ARRAY_BUFFER_BINDING "<< boundElementArrayBuffer << endl;
++ msg << " GL_ARRAY_BUFFER_BINDING "<< arrayBufferBinding << endl;
++ for (int i = 0; i < m_maxVertexAttribs;i++) {
++ msg << " GL_VERTEX_ATTRIB_ARRAY_ENABLED "<< i << " = "
++ << bool(vertexAttribArrayEnabledStates[i]) << endl;
++ msg << " GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"<< i << " = "
++ << vertexAttribArrayBoundBuffers[i] << endl;
++ msg << " GL_VERTEX_ATTRIB_ARRAY_SIZE"<< i << " = "
++ << vertexAttribArraySizes[i] << endl;
++ msg << " GL_VERTEX_ATTRIB_ARRAY_TYPE"<< i << " = "
++ << vertexAttribArrayTypes[i] << endl;
++ msg << " GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"<< i << " = "
++ << vertexAttribArrayNormalized[i] << endl;
++ msg << " GL_VERTEX_ATTRIB_ARRAY_STRIDE"<< i << " = "
++ << vertexAttribArrayStrides[i] << endl;
++ }
++ }
++ }
++ #endif
++
++ void GLStateStore::restoreGLState()
++ {
++ #if !QT_CONFIG(opengles2)
++ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebuffer);
++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebuffer);
++ glBindRenderbuffer(GL_RENDERBUFFER_BINDING, m_renderbuffer);
++ #endif
++
++ if (m_isScissorTestEnabled)
++ glEnable(GL_SCISSOR_TEST);
++ else
++ glDisable(GL_SCISSOR_TEST);
++
++ glScissor(m_scissorBox[0], m_scissorBox[1], m_scissorBox[2], m_scissorBox[3]);
++ glClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3]);
++ glClearDepthf(m_clearDepth);
++ if (m_isBlendingEnabled)
++ glEnable(GL_BLEND);
++ else
++ glDisable(GL_BLEND);
++
++ if (m_isDepthTestEnabled)
++ glEnable(GL_DEPTH_TEST);
++ else
++ glDisable(GL_DEPTH_TEST);
++
++ if (m_isCullFaceEnabled)
++ glEnable(GL_CULL_FACE);
++ else
++ glDisable(GL_CULL_FACE);
++
++ glCullFace(m_cullFaceMode);
++
++ glBlendEquationSeparate(m_blendEquationRGB, m_blendEquationAlpha);
++ glBlendFuncSeparate(m_blendSrcRGB, m_blendDestRGB, m_blendSrcAlpha, m_blendDestAlpha);
++
++ glDepthMask(m_isDepthWriteEnabled);
++ glDepthFunc(m_depthFunc);
++ glFrontFace(m_frontFace);
++
++ if (m_polygonOffsetFillEnabled)
++ glEnable(GL_POLYGON_OFFSET_FILL);
++ else
++ glDisable(GL_POLYGON_OFFSET_FILL);
++
++ glPolygonOffset(m_polygonOffsetFactor, m_polygonOffsetUnits);
++
++ glUseProgram(m_currentProgram);
++
++ glActiveTexture(m_activeTexture);
++ glBindTexture(GL_TEXTURE_2D, m_texBinding2D);
++
++ // Restore bound element array buffer and array buffers
++ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_boundElementArrayBuffer);
++ for (int i = 0; i < m_maxVertexAttribs; i++) {
++ if (m_vertexAttribArrayEnabledStates[i])
++ glEnableVertexAttribArray(i);
++ else
++ glDisableVertexAttribArray(i);
++
++ glBindBuffer(GL_ARRAY_BUFFER, m_vertexAttribArrayBoundBuffers[i]);
++ glVertexAttribPointer(i, m_vertexAttribArraySizes[i],
++ m_vertexAttribArrayTypes[i],
++ m_vertexAttribArrayNormalized[i],
++ m_vertexAttribArrayStrides[i],
++ m_vertexAttribArrayOffsets[i]);
++ }
++
++ glBindBuffer(GL_ARRAY_BUFFER, m_boundArrayBuffer);
++
++ #ifdef VERBOSE_STATE_STORE
++ printCurrentState(false);
++ #endif
++ }
++
++ void GLStateStore::initGLDefaultState()
++ {
++ #if !QT_CONFIG(opengles2)
++ m_drawFramebuffer = 0;
++ m_readFramebuffer = 0;
++ m_renderbuffer = 0;
++ #endif
++ m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 1.0f;
++ m_clearDepth = 1.0f;
++ m_isBlendingEnabled = GL_FALSE;
++ m_isDepthTestEnabled = GL_FALSE;
++ m_depthFunc = GL_LESS;
++ m_isDepthWriteEnabled = GL_TRUE;
++ m_currentProgram = 0;
++ m_texBinding2D = 0;
++ for (int i = 0; i < m_maxVertexAttribs;i++) {
++ m_vertexAttribArrayEnabledStates[i] = GL_FALSE;
++ m_vertexAttribArrayBoundBuffers[i] = 0;
++ m_vertexAttribArraySizes[i] = 4;
++ m_vertexAttribArrayTypes[i] = GL_FLOAT;
++ m_vertexAttribArrayNormalized[i] = GL_FALSE;
++ m_vertexAttribArrayStrides[i] = 0;
++ m_vertexAttribArrayOffsets[i] = 0;
++ }
++ m_activeTexture = GL_TEXTURE0;
++ m_frontFace = GL_CCW;
++ m_isCullFaceEnabled = false;
++ m_cullFaceMode = GL_BACK;
++ m_blendEquationRGB = GL_FUNC_ADD;
++ m_blendEquationAlpha = GL_FUNC_ADD;
++ m_scissorBox[0] = 0;
++ m_scissorBox[1] = 0;
++ m_scissorBox[2] = 0;
++ m_scissorBox[3] = 0;
++ m_isScissorTestEnabled = GL_FALSE;
++
++ m_polygonOffsetFillEnabled = GL_FALSE;
++ m_polygonOffsetFactor = 0.0;
++ m_polygonOffsetUnits = 0.0;
++ }
++
++ QT_END_NAMESPACE