blob: 0d24f3f9d533d09d74ef1142d3c3c80b9364540c [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Data Visualization module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) 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.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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "glstatestore_p.h"
#include <QDebug>
#include <QColor>
#include <QFile>
#ifdef VERBOSE_STATE_STORE
static QFile *beforeFile = 0;
static QFile *afterFile = 0;
#endif
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 !defined(QT_OPENGL_ES_2)
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 !defined(QT_OPENGL_ES_2)
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 !defined(QT_OPENGL_ES_2)
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 !defined(QT_OPENGL_ES_2)
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 !defined(QT_OPENGL_ES_2)
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 !defined(QT_OPENGL_ES_2)
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;
}