1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Data Visualization module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "glstatestore_p.h"
31#include <QDebug>
32#include <QColor>
33#include <QFile>
34
35#ifdef VERBOSE_STATE_STORE
36static QFile *beforeFile = 0;
37static QFile *afterFile = 0;
38#endif
39
40GLStateStore::GLStateStore(QOpenGLContext *context, QObject *parent) :
41 QObject(parent),
42 QOpenGLFunctions(context)
43 #ifdef VERBOSE_STATE_STORE
44 , m_map(EnumToStringMap::newInstance())
45 #endif
46{
47 GLint maxVertexAttribs;
48 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, params: &maxVertexAttribs);
49
50#ifdef VERBOSE_STATE_STORE
51 qDebug() << "GL_MAX_VERTEX_ATTRIBS: " << maxVertexAttribs;
52 if (!beforeFile) {
53 beforeFile = new QFile(QStringLiteral("state_before.txt"));
54 afterFile = new QFile(QStringLiteral("state_after.txt"));
55 beforeFile->open(QIODevice::WriteOnly);
56 afterFile->open(QIODevice::WriteOnly);
57 QDebug beforeInit(beforeFile);
58 QDebug afterInit(afterFile);
59 beforeInit << "GL states before 'context switch'" << endl;
60 afterInit << "GL states after 'context switch'" << endl;
61 }
62#endif
63
64 m_maxVertexAttribs = qMin(a: maxVertexAttribs, b: 2); // Datavis only uses 2 attribs max
65 m_vertexAttribArrayEnabledStates.reset(other: new GLint[maxVertexAttribs]);
66 m_vertexAttribArrayBoundBuffers.reset(other: new GLint[maxVertexAttribs]);
67 m_vertexAttribArraySizes.reset(other: new GLint[maxVertexAttribs]);
68 m_vertexAttribArrayTypes.reset(other: new GLint[maxVertexAttribs]);
69 m_vertexAttribArrayNormalized.reset(other: new GLint[maxVertexAttribs]);
70 m_vertexAttribArrayStrides.reset(other: new GLint[maxVertexAttribs]);
71 m_vertexAttribArrayOffsets.reset(other: new void *[maxVertexAttribs]);
72
73 initGLDefaultState();
74}
75
76GLStateStore::~GLStateStore()
77{
78#ifdef VERBOSE_STATE_STORE
79 EnumToStringMap::deleteInstance();
80 m_map = 0;
81#endif
82}
83
84void GLStateStore::storeGLState()
85{
86#ifdef VERBOSE_STATE_STORE
87 printCurrentState(true);
88#endif
89
90#if !defined(QT_OPENGL_ES_2)
91 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, params: &m_drawFramebuffer);
92 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, params: &m_readFramebuffer);
93 glGetIntegerv(GL_RENDERBUFFER_BINDING, params: &m_renderbuffer);
94#endif
95 glGetFloatv(GL_COLOR_CLEAR_VALUE, params: m_clearColor);
96 m_isBlendingEnabled = glIsEnabled(GL_BLEND);
97 m_isDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
98 glGetBooleanv(GL_DEPTH_WRITEMASK, params: &m_isDepthWriteEnabled);
99 glGetFloatv(GL_DEPTH_CLEAR_VALUE, params: &m_clearDepth);
100 glGetIntegerv(GL_DEPTH_FUNC, params: &m_depthFunc);
101 glGetBooleanv(GL_POLYGON_OFFSET_FILL, params: &m_polygonOffsetFillEnabled);
102 glGetFloatv(GL_POLYGON_OFFSET_FACTOR, params: &m_polygonOffsetFactor);
103 glGetFloatv(GL_POLYGON_OFFSET_UNITS, params: &m_polygonOffsetUnits);
104
105 glGetIntegerv(GL_CURRENT_PROGRAM, params: &m_currentProgram);
106 glGetIntegerv(GL_ACTIVE_TEXTURE, params: &m_activeTexture);
107 glGetIntegerv(GL_TEXTURE_BINDING_2D, params: &m_texBinding2D);
108 glGetIntegerv(GL_FRONT_FACE, params: &m_frontFace);
109 m_isCullFaceEnabled = glIsEnabled(GL_CULL_FACE);
110 glGetIntegerv(GL_CULL_FACE_MODE, params: &m_cullFaceMode);
111 glGetIntegerv(GL_BLEND_EQUATION_RGB, params: &m_blendEquationRGB);
112 glGetIntegerv(GL_BLEND_EQUATION_ALPHA, params: &m_blendEquationAlpha);
113 glGetIntegerv(GL_BLEND_DST_ALPHA, params: &m_blendDestAlpha);
114 glGetIntegerv(GL_BLEND_DST_RGB, params: &m_blendDestRGB);
115 glGetIntegerv(GL_BLEND_SRC_ALPHA, params: &m_blendSrcAlpha);
116 glGetIntegerv(GL_BLEND_SRC_RGB, params: &m_blendSrcRGB);
117 glGetIntegerv(GL_SCISSOR_BOX, params: m_scissorBox);
118 m_isScissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
119
120 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, params: &m_boundArrayBuffer);
121 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, params: &m_boundElementArrayBuffer);
122
123 for (int i = 0; i < m_maxVertexAttribs;i++) {
124 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
125 params: &m_vertexAttribArrayEnabledStates[i]);
126 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
127 params: &m_vertexAttribArrayBoundBuffers[i]);
128 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_SIZE, params: &m_vertexAttribArraySizes[i]);
129 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_TYPE, params: &m_vertexAttribArrayTypes[i]);
130 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
131 params: &m_vertexAttribArrayNormalized[i]);
132 glGetVertexAttribiv(index: i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, params: &m_vertexAttribArrayStrides[i]);
133 }
134}
135
136#ifdef VERBOSE_STATE_STORE
137void GLStateStore::printCurrentState(bool in)
138{
139 QFile *file;
140 if (in)
141 file = beforeFile;
142 else
143 file = afterFile;
144
145 if (file->isOpen()) {
146 QDebug msg(file);
147#if !defined(QT_OPENGL_ES_2)
148 GLint drawFramebuffer;
149 GLint readFramebuffer;
150 GLint renderbuffer;
151#endif
152 GLfloat clearColor[4];
153 GLfloat clearDepth;
154 GLboolean isBlendingEnabled = glIsEnabled(GL_BLEND);
155 GLboolean isDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
156 GLint depthFunc;
157 GLboolean isDepthWriteEnabled;
158 GLint currentProgram;
159 GLint *vertexAttribArrayEnabledStates = new GLint[m_maxVertexAttribs];
160 GLint *vertexAttribArrayBoundBuffers = new GLint[m_maxVertexAttribs];
161 GLint *vertexAttribArraySizes = new GLint[m_maxVertexAttribs];
162 GLint *vertexAttribArrayTypes = new GLint[m_maxVertexAttribs];
163 GLint *vertexAttribArrayNormalized = new GLint[m_maxVertexAttribs];
164 GLint *vertexAttribArrayStrides = new GLint[m_maxVertexAttribs];
165 GLint activeTexture;
166 GLint texBinding2D;
167 GLint arrayBufferBinding;
168 GLint frontFace;
169 GLboolean isCullFaceEnabled = glIsEnabled(GL_CULL_FACE);
170 GLint cullFaceMode;
171 GLint blendEquationRGB;
172 GLint blendEquationAlpha;
173
174 GLint blendDestAlpha;
175 GLint blendDestRGB;
176 GLint blendSrcAlpha;
177 GLint blendSrcRGB;
178 GLint scissorBox[4];
179 GLboolean isScissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
180 GLint boundElementArrayBuffer;
181 GLboolean polygonOffsetFillEnabled;
182 GLfloat polygonOffsetFactor;
183 GLfloat polygonOffsetUnits;
184
185 glGetBooleanv(GL_DEPTH_WRITEMASK, &isDepthWriteEnabled);
186#if !defined(QT_OPENGL_ES_2)
187 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer);
188 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer);
189 glGetIntegerv(GL_RENDERBUFFER_BINDING, &renderbuffer);
190#endif
191 glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
192 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
193 glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
194 glGetBooleanv(GL_POLYGON_OFFSET_FILL, &polygonOffsetFillEnabled);
195 glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &polygonOffsetFactor);
196 glGetFloatv(GL_POLYGON_OFFSET_UNITS, &polygonOffsetUnits);
197
198 glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
199 glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
200 glGetIntegerv(GL_TEXTURE_BINDING_2D, &texBinding2D );
201 glGetIntegerv(GL_FRONT_FACE, &frontFace);
202 glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode);
203 glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB);
204 glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
205 glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
206 glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRGB);
207 glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
208 glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRGB);
209 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
210 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &boundElementArrayBuffer);
211 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBufferBinding);
212
213 for (int i = 0; i < m_maxVertexAttribs;i++) {
214 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
215 &vertexAttribArrayEnabledStates[i]);
216 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
217 &vertexAttribArrayBoundBuffers[i]);
218 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertexAttribArraySizes[i]);
219 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertexAttribArrayTypes[i]);
220 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
221 &vertexAttribArrayNormalized[i]);
222 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertexAttribArrayStrides[i]);
223 }
224
225 QColor color;
226 color.setRgbF(clearColor[0], clearColor[1], clearColor[2]);
227 color.setAlphaF(clearColor[3]);
228
229#if !defined(QT_OPENGL_ES_2)
230 msg << "---" << endl;
231 msg << " GL_DRAW_FRAMEBUFFER_BINDING "<< drawFramebuffer << endl;
232 msg << " GL_READ_FRAMEBUFFER_BINDING "<< readFramebuffer << endl;
233 msg << " GL_RENDERBUFFER_BINDING " << renderbuffer << endl;
234#endif
235 msg << " GL_SCISSOR_TEST " << bool(isScissorTestEnabled) << endl;
236 msg << " GL_SCISSOR_BOX " << m_scissorBox[0] << m_scissorBox[1] << m_scissorBox[2]
237 << m_scissorBox[3] << endl;
238 msg << " GL_COLOR_CLEAR_VALUE "<< color << endl;
239 msg << " GL_DEPTH_CLEAR_VALUE "<< clearDepth << endl;
240 msg << " GL_BLEND "<< bool(isBlendingEnabled) << endl;
241 msg << " GL_BLEND_EQUATION_RGB" << m_map->lookUp(blendEquationRGB) << endl;
242 msg << " GL_BLEND_EQUATION_ALPHA" << m_map->lookUp(blendEquationAlpha) << endl;
243 msg << " GL_BLEND_DST_ALPHA" << m_map->lookUp(blendDestAlpha) << endl;
244 msg << " GL_BLEND_DST_RGB" << m_map->lookUp(blendDestRGB) << endl;
245 msg << " GL_BLEND_SRC_ALPHA" << m_map->lookUp(blendSrcAlpha) << endl;
246 msg << " GL_BLEND_SRC_RGB" << m_map->lookUp(blendSrcRGB) << endl;
247 msg << " GL_DEPTH_TEST "<< bool(isDepthTestEnabled) << endl;
248 msg << " GL_DEPTH_WRITEMASK "<< bool(isDepthWriteEnabled) << endl;
249 msg << " GL_POLYGON_OFFSET_FILL" << bool(polygonOffsetFillEnabled) << endl;
250 msg << " GL_POLYGON_OFFSET_FACTOR "<< polygonOffsetFactor << endl;
251 msg << " GL_POLYGON_OFFSET_UNITS "<< polygonOffsetUnits << endl;
252 msg << " GL_CULL_FACE "<< bool(isCullFaceEnabled) << endl;
253 msg << " GL_CULL_FACE_MODE "<< m_map->lookUp(cullFaceMode) << endl;
254 msg << " GL_DEPTH_FUNC "<< m_map->lookUp(depthFunc) << endl;
255 msg << " GL_FRONT_FACE "<< m_map->lookUp(frontFace) << endl;
256 msg << " GL_CURRENT_PROGRAM "<< currentProgram << endl;
257 msg << " GL_ACTIVE_TEXTURE "<< QString("0x%1").arg(activeTexture, 0, 16) << endl;
258 msg << " GL_TEXTURE_BINDING_2D "<< texBinding2D << endl;
259 msg << " GL_ELEMENT_ARRAY_BUFFER_BINDING "<< boundElementArrayBuffer << endl;
260 msg << " GL_ARRAY_BUFFER_BINDING "<< arrayBufferBinding << endl;
261 for (int i = 0; i < m_maxVertexAttribs;i++) {
262 msg << " GL_VERTEX_ATTRIB_ARRAY_ENABLED "<< i << " = "
263 << bool(vertexAttribArrayEnabledStates[i]) << endl;
264 msg << " GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"<< i << " = "
265 << vertexAttribArrayBoundBuffers[i] << endl;
266 msg << " GL_VERTEX_ATTRIB_ARRAY_SIZE"<< i << " = "
267 << vertexAttribArraySizes[i] << endl;
268 msg << " GL_VERTEX_ATTRIB_ARRAY_TYPE"<< i << " = "
269 << vertexAttribArrayTypes[i] << endl;
270 msg << " GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"<< i << " = "
271 << vertexAttribArrayNormalized[i] << endl;
272 msg << " GL_VERTEX_ATTRIB_ARRAY_STRIDE"<< i << " = "
273 << vertexAttribArrayStrides[i] << endl;
274 }
275 }
276}
277#endif
278
279void GLStateStore::restoreGLState()
280{
281#if !defined(QT_OPENGL_ES_2)
282 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer: m_readFramebuffer);
283 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: m_drawFramebuffer);
284 glBindRenderbuffer(GL_RENDERBUFFER_BINDING, renderbuffer: m_renderbuffer);
285#endif
286
287 if (m_isScissorTestEnabled)
288 glEnable(GL_SCISSOR_TEST);
289 else
290 glDisable(GL_SCISSOR_TEST);
291
292 glScissor(x: m_scissorBox[0], y: m_scissorBox[1], width: m_scissorBox[2], height: m_scissorBox[3]);
293 glClearColor(red: m_clearColor[0], green: m_clearColor[1], blue: m_clearColor[2], alpha: m_clearColor[3]);
294 glClearDepthf(depth: m_clearDepth);
295 if (m_isBlendingEnabled)
296 glEnable(GL_BLEND);
297 else
298 glDisable(GL_BLEND);
299
300 if (m_isDepthTestEnabled)
301 glEnable(GL_DEPTH_TEST);
302 else
303 glDisable(GL_DEPTH_TEST);
304
305 if (m_isCullFaceEnabled)
306 glEnable(GL_CULL_FACE);
307 else
308 glDisable(GL_CULL_FACE);
309
310 glCullFace(mode: m_cullFaceMode);
311
312 glBlendEquationSeparate(modeRGB: m_blendEquationRGB, modeAlpha: m_blendEquationAlpha);
313 glBlendFuncSeparate(srcRGB: m_blendSrcRGB, dstRGB: m_blendDestRGB, srcAlpha: m_blendSrcAlpha, dstAlpha: m_blendDestAlpha);
314
315 glDepthMask(flag: m_isDepthWriteEnabled);
316 glDepthFunc(func: m_depthFunc);
317 glFrontFace(mode: m_frontFace);
318
319 if (m_polygonOffsetFillEnabled)
320 glEnable(GL_POLYGON_OFFSET_FILL);
321 else
322 glDisable(GL_POLYGON_OFFSET_FILL);
323
324 glPolygonOffset(factor: m_polygonOffsetFactor, units: m_polygonOffsetUnits);
325
326 glUseProgram(program: m_currentProgram);
327
328 glActiveTexture(texture: m_activeTexture);
329 glBindTexture(GL_TEXTURE_2D, texture: m_texBinding2D);
330
331 // Restore bound element array buffer and array buffers
332 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_boundElementArrayBuffer);
333 for (int i = 0; i < m_maxVertexAttribs; i++) {
334 if (m_vertexAttribArrayEnabledStates[i])
335 glEnableVertexAttribArray(index: i);
336 else
337 glDisableVertexAttribArray(index: i);
338
339 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_vertexAttribArrayBoundBuffers[i]);
340 glVertexAttribPointer(indx: i, size: m_vertexAttribArraySizes[i],
341 type: m_vertexAttribArrayTypes[i],
342 normalized: m_vertexAttribArrayNormalized[i],
343 stride: m_vertexAttribArrayStrides[i],
344 ptr: m_vertexAttribArrayOffsets[i]);
345 }
346
347 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_boundArrayBuffer);
348
349#ifdef VERBOSE_STATE_STORE
350 printCurrentState(false);
351#endif
352}
353
354void GLStateStore::initGLDefaultState()
355{
356#if !defined(QT_OPENGL_ES_2)
357 m_drawFramebuffer = 0;
358 m_readFramebuffer = 0;
359 m_renderbuffer = 0;
360#endif
361 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 1.0f;
362 m_clearDepth = 1.0f;
363 m_isBlendingEnabled = GL_FALSE;
364 m_isDepthTestEnabled = GL_FALSE;
365 m_depthFunc = GL_LESS;
366 m_isDepthWriteEnabled = GL_TRUE;
367 m_currentProgram = 0;
368 m_texBinding2D = 0;
369 for (int i = 0; i < m_maxVertexAttribs;i++) {
370 m_vertexAttribArrayEnabledStates[i] = GL_FALSE;
371 m_vertexAttribArrayBoundBuffers[i] = 0;
372 m_vertexAttribArraySizes[i] = 4;
373 m_vertexAttribArrayTypes[i] = GL_FLOAT;
374 m_vertexAttribArrayNormalized[i] = GL_FALSE;
375 m_vertexAttribArrayStrides[i] = 0;
376 m_vertexAttribArrayOffsets[i] = 0;
377 }
378 m_activeTexture = GL_TEXTURE0;
379 m_frontFace = GL_CCW;
380 m_isCullFaceEnabled = false;
381 m_cullFaceMode = GL_BACK;
382 m_blendEquationRGB = GL_FUNC_ADD;
383 m_blendEquationAlpha = GL_FUNC_ADD;
384 m_scissorBox[0] = 0;
385 m_scissorBox[1] = 0;
386 m_scissorBox[2] = 0;
387 m_scissorBox[3] = 0;
388 m_isScissorTestEnabled = GL_FALSE;
389
390 m_polygonOffsetFillEnabled = GL_FALSE;
391 m_polygonOffsetFactor = 0.0;
392 m_polygonOffsetUnits = 0.0;
393}
394

source code of qtdatavis3d/src/datavisualizationqml2/glstatestore.cpp