From efe61b3b44c0c391d4c11bd061e531f03bf8fb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 1 Sep 2009 09:55:13 +0200 Subject: Fixed poor utilization of depth buffer range in GL 2 paint engine. Before this patch we were only able to do 20 or so IntersectClips before failing, this patch instead adapts to the fixed point nature of typical depth buffer implementations and lets us do ~2^15 IntersectClip operations before failing, which should be a reasonable limit for any real-world application. Using the following mapping of old floating point depths to integer depths: -1.0 -> 0, -0.5 -> 1, 0.0 -> 2, 0.25 -> 3, 0.5 -> 4, 0.625 -> 5, etc.. Reviewed-by: Tom --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 51 +++++++++++----------- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 19 ++++++-- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index a976a02..0c01263 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -380,7 +380,7 @@ void QGL2PaintEngineExPrivate::useSimpleShader() } if (simpleShaderDepthUniformDirty) { - shaderManager->simpleProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth); + shaderManager->simpleProgram()->setUniformValue("depth", normalizedDeviceDepth(q->state()->currentDepth)); simpleShaderDepthUniformDirty = false; } } @@ -731,7 +731,6 @@ void QGL2PaintEngineExPrivate::resetGLState() glActiveTexture(GL_TEXTURE0); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glDepthFunc(GL_LESS); glDepthMask(true); glClearDepth(1); } @@ -959,7 +958,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) } if (depthUniformDirty) { - shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), (GLfloat)q->state()->currentDepth); + shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), normalizedDeviceDepth(q->state()->currentDepth)); depthUniformDirty = false; } @@ -1351,7 +1350,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) if (!d->inRenderText) { glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LESS); glDepthMask(false); } @@ -1441,7 +1440,7 @@ void QGL2PaintEngineEx::ensureActive() if (d->needsSync) { glViewport(0, 0, d->width, d->height); glDepthMask(false); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LESS); setState(state()); d->needsSync = false; } @@ -1492,7 +1491,7 @@ void QGL2PaintEngineEx::clipEnabledChanged() d->regenerateDepthClip(); } else { if (d->use_system_clip) { - state()->currentDepth = -0.5f; + state()->currentDepth = 0; } else { state()->depthTestEnabled = false; } @@ -1501,7 +1500,7 @@ void QGL2PaintEngineEx::clipEnabledChanged() } } -void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) +void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint depth) { transferMode(BrushDrawingMode); @@ -1510,7 +1509,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) if (q->state()->needsDepthBufferClear) { glDepthMask(true); - glClearDepth(0.5); + glClearDepth(rawDepth(2)); glClear(GL_DEPTH_BUFFER_BIT); q->state()->needsDepthBufferClear = false; glDepthMask(false); @@ -1532,7 +1531,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) glColorMask(false, false, false, false); glDepthMask(true); - shaderManager->simpleProgram()->setUniformValue("depth", depth); + shaderManager->simpleProgram()->setUniformValue("depth", normalizedDeviceDepth(depth)); simpleShaderDepthUniformDirty = true; glEnable(GL_DEPTH_TEST); @@ -1596,12 +1595,12 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) glDepthFunc(GL_ALWAYS); - state()->maxDepth = 0.5f; + state()->maxDepth = 4; d->writeClip(qtVectorPathForPath(path), state()->maxDepth); - state()->currentDepth = 0.25f; + state()->currentDepth = 3; state()->depthTestEnabled = true; - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } @@ -1610,7 +1609,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) if (d->use_system_clip) { glEnable(GL_DEPTH_TEST); state()->depthTestEnabled = true; - state()->currentDepth = -0.5; + state()->currentDepth = 0; } else { glDisable(GL_DEPTH_TEST); state()->depthTestEnabled = false; @@ -1618,18 +1617,18 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) state()->canRestoreClip = false; break; case Qt::IntersectClip: - state()->maxDepth = (1.0f + state()->maxDepth) * 0.5; + ++state()->maxDepth; d->writeClip(path, state()->maxDepth); - state()->currentDepth = 1.5 * state()->maxDepth - 0.5f; + state()->currentDepth = state()->maxDepth - 1; state()->depthTestEnabled = true; break; case Qt::ReplaceClip: d->systemStateChanged(); state()->rectangleClip = QRect(); - state()->maxDepth = 0.5f; + state()->maxDepth = 4; glDepthFunc(GL_ALWAYS); d->writeClip(path, state()->maxDepth); - state()->currentDepth = 0.25f; + state()->currentDepth = 3; state()->canRestoreClip = false; state()->depthTestEnabled = true; break; @@ -1641,7 +1640,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) break; } - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LESS); if (state()->depthTestEnabled) { glEnable(GL_DEPTH_TEST); d->simpleShaderDepthUniformDirty = true; @@ -1672,8 +1671,8 @@ void QGL2PaintEngineExPrivate::systemStateChanged() glDisable(GL_SCISSOR_TEST); - q->state()->currentDepth = -0.5f; - q->state()->maxDepth = 0.5f; + q->state()->currentDepth = 1; + q->state()->maxDepth = 4; q->state()->rectangleClip = QRect(0, 0, width, height); @@ -1708,8 +1707,8 @@ void QGL2PaintEngineExPrivate::systemStateChanged() path.addRegion(systemClip); glDepthFunc(GL_ALWAYS); - writeClip(qtVectorPathForPath(path), 0.0f); - glDepthFunc(GL_LEQUAL); + writeClip(qtVectorPathForPath(path), 2); + glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); q->state()->depthTestEnabled = true; @@ -1718,7 +1717,7 @@ void QGL2PaintEngineExPrivate::systemStateChanged() q->transformChanged(); } - q->state()->currentDepth = -0.5f; + q->state()->currentDepth = 1; simpleShaderDepthUniformDirty = true; depthUniformDirty = true; } @@ -1757,7 +1756,7 @@ void QGL2PaintEngineEx::setState(QPainterState *new_state) if (old_state && old_state != s && old_state->canRestoreClip) { d->updateDepthScissorTest(); glDepthMask(false); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LESS); s->maxDepth = old_state->maxDepth; } else { d->regenerateDepthClip(); @@ -1802,8 +1801,8 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() needsDepthBufferClear = true; depthTestEnabled = false; scissorTestEnabled = false; - currentDepth = -0.5f; - maxDepth = 0.5f; + currentDepth = 1; + maxDepth = 4; canRestoreClip = true; hasRectangleClip = false; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 58fcde1..552e390 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -82,8 +82,8 @@ public: bool depthTestEnabled; bool scissorTestEnabled; - qreal currentDepth; - qreal maxDepth; + uint maxDepth; + uint currentDepth; bool canRestoreClip; QRect rectangleClip; @@ -230,13 +230,26 @@ public: QGLEngineShaderManager* shaderManager; - void writeClip(const QVectorPath &path, float depth); + void writeClip(const QVectorPath &path, uint depth); void updateDepthScissorTest(); void setScissor(const QRect &rect); void regenerateDepthClip(); void systemStateChanged(); uint use_system_clip : 1; + static inline GLfloat rawDepth(uint depth) + { + // assume at least 16 bits in the depth buffer, and + // use 2^15 depth levels to be safe with regard to + // rounding issues etc + return depth * (1.0f / GLfloat((1 << 15) - 1)); + } + + static inline GLfloat normalizedDeviceDepth(uint depth) + { + return 2.0f * rawDepth(depth) - 1.0f; + } + uint location(QGLEngineShaderManager::Uniform uniform) { return shaderManager->getUniformLocation(uniform); -- cgit v0.12