/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc ** All rights reserved. ** For any questions to Digia, please use contact form at http://qt.digia.com ** ** This file is part of the QtDataVisualization module. ** ** Licensees holding valid Qt Enterprise licenses may use this file in ** accordance with the Qt Enterprise License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. ** ** If you have questions regarding the use of this file, please use ** contact form at http://qt.digia.com ** ****************************************************************************/ #include "glstatestore_p.h" #include #include #include #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 GLint[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); #else glGetIntegerv(GL_RENDERBUFFER, &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; #endif GLint renderbuffer; 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); #else glGetIntegerv(GL_RENDERBUFFER, &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, ¤tProgram); 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; #endif msg << " GL_RENDERBUFFER_BINDING " << renderbuffer << endl; 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); #else glBindRenderbuffer(GL_RENDERBUFFER, 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], (void *) 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; #endif m_renderbuffer = 0; 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; }