diff options
author | Samuel Rødal <sroedal@trolltech.com> | 2009-09-17 08:52:05 (GMT) |
---|---|---|
committer | Samuel Rødal <sroedal@trolltech.com> | 2009-09-21 14:37:50 (GMT) |
commit | 32c3de3d02193c994c701f085cd64d864563bac0 (patch) | |
tree | 3f763c49f5e8f1bb3949abd45d139216d927f649 /src/opengl/gl2paintengineex | |
parent | c6d2ec67384d5b0a4f9108277888d4aaf0e2f6d2 (diff) | |
download | Qt-32c3de3d02193c994c701f085cd64d864563bac0.zip Qt-32c3de3d02193c994c701f085cd64d864563bac0.tar.gz Qt-32c3de3d02193c994c701f085cd64d864563bac0.tar.bz2 |
Optimized GL2 engine to use scissor clipping more aggressively.
There's no reason to stop using a scissor clip when a more complex clip
is set. Instead, we can use a combination of scissoring and depth
clipping to represent the final clip. When intersecting with a new clip
path, if the clip path is a rectangle we simply intersect it against the
scissor clip, and otherwise we intersect its bounding rect against the
scissor clip and write the actual path to the depth buffer.
The patch simplifies the logic in clip() quite a bit, except in the
UniteClip case in which we don't care about performance anyways.
It also fixes a bug which could cause rendering errors if the stencil
buffer contains junk before painting.
Reviewed-by: Gunnar Sletta
Diffstat (limited to 'src/opengl/gl2paintengineex')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 163 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 4 |
2 files changed, 72 insertions, 95 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ba2a0ea..fb493e6 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -750,6 +750,7 @@ void QGL2PaintEngineEx::beginNativePainting() #endif d->lastTexture = GLuint(-1); + d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); d->resetGLState(); d->needsSync = true; @@ -894,12 +895,12 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); glStencilMask(0xFFFF); // Enable stencil writes - if (stencilBufferDirty) { + if (dirtyStencilRegion.intersects(currentScissorBounds)) { // Clear the stencil buffer to zeros glDisable(GL_STENCIL_TEST); glClearStencil(0); // Clear to zero glClear(GL_STENCIL_BUFFER_BIT); - stencilBufferDirty = false; + dirtyStencilRegion -= currentScissorBounds; } glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes @@ -1419,13 +1420,14 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->brushUniformsDirty = true; d->matrixDirty = true; d->compositionModeDirty = true; - d->stencilBufferDirty = true; d->simpleShaderDepthUniformDirty = true; d->depthUniformDirty = true; d->opacityUniformDirty = true; d->needsSync = true; d->use_system_clip = !systemClip().isEmpty(); + d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); + // Calling begin paint should make the correct context current. So, any // code which calls into GL or otherwise needs a current context *must* // go after beginPaint: @@ -1521,19 +1523,26 @@ void QGL2PaintEngineExPrivate::updateDepthScissorTest() else glDisable(GL_DEPTH_TEST); - if (q->state()->scissorTestEnabled) { - QRect bounds = q->state()->rectangleClip; - if (bounds.isNull() || !q->painter()->hasClipping()) { - if (use_system_clip) - bounds = systemClip.boundingRect(); - else - bounds = QRect(0, 0, width, height); - } + QRect bounds = q->state()->rectangleClip; + if (!q->state()->clipEnabled) { + if (use_system_clip) + bounds = systemClip.boundingRect(); + else + bounds = QRect(0, 0, width, height); + } else { + if (use_system_clip) + bounds = bounds.intersected(systemClip.boundingRect()); + else + bounds = bounds.intersected(QRect(0, 0, width, height)); + } + currentScissorBounds = bounds; + + if (bounds == QRect(0, 0, width, height)) { + glDisable(GL_SCISSOR_TEST); + } else { glEnable(GL_SCISSOR_TEST); setScissor(bounds); - } else { - glDisable(GL_SCISSOR_TEST); } } @@ -1573,7 +1582,6 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint depth) if (matrixDirty) updateMatrix(); - if (q->state()->needsDepthBufferClear) { glDepthMask(true); glClearDepth(rawDepth(2)); @@ -1624,90 +1632,81 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) ensureActive(); - if (op == Qt::ReplaceClip && !d->hasClipOperations()) + if (op == Qt::ReplaceClip) { op = Qt::IntersectClip; + if (d->hasClipOperations()) { + d->systemStateChanged(); + state()->canRestoreClip = false; + } + } if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) { const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); QRectF rect(points[0], points[2]); if (state()->matrix.type() <= QTransform::TxScale) { - rect = state()->matrix.mapRect(rect); - - if ((d->use_system_clip && rect.contains(d->systemClip.boundingRect())) - || rect.contains(QRect(0, 0, d->width, d->height))) - return; - - if (state()->rectangleClip.isValid()) { - state()->rectangleClip = state()->rectangleClip.intersected(rect.toRect()); - - state()->hasRectangleClip = true; - state()->scissorTestEnabled = true; - - glEnable(GL_SCISSOR_TEST); - d->setScissor(state()->rectangleClip); - - return; - } + state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect()); + d->updateDepthScissorTest(); + return; } } - if (!state()->hasRectangleClip) - state()->rectangleClip = QRect(); - - if (state()->rectangleClip.isValid() && op != Qt::NoClip && op != Qt::ReplaceClip) { - QPainterPath path; - path.addRect(state()->rectangleClip); - path = state()->matrix.inverted().map(path); - - state()->rectangleClip = QRect(); - d->updateDepthScissorTest(); - - glDepthFunc(GL_ALWAYS); - - state()->maxDepth = 4; - d->writeClip(qtVectorPathForPath(path), state()->maxDepth); - state()->currentDepth = 3; - state()->depthTestEnabled = true; - - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - } + const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect(); switch (op) { case Qt::NoClip: if (d->use_system_clip) { - glEnable(GL_DEPTH_TEST); state()->depthTestEnabled = true; state()->currentDepth = 0; } else { - glDisable(GL_DEPTH_TEST); state()->depthTestEnabled = false; } + state()->rectangleClip = QRect(0, 0, d->width, d->height); state()->canRestoreClip = false; + d->updateDepthScissorTest(); break; case Qt::IntersectClip: + state()->rectangleClip = state()->rectangleClip.intersected(pathRect); + d->updateDepthScissorTest(); ++state()->maxDepth; d->writeClip(path, state()->maxDepth); state()->currentDepth = state()->maxDepth - 1; state()->depthTestEnabled = true; break; - case Qt::ReplaceClip: - d->systemStateChanged(); - state()->rectangleClip = QRect(); - state()->maxDepth = 4; - glDepthFunc(GL_ALWAYS); - d->writeClip(path, state()->maxDepth); - state()->currentDepth = 3; - state()->canRestoreClip = false; - state()->depthTestEnabled = true; - break; - case Qt::UniteClip: + case Qt::UniteClip: { + if (state()->rectangleClip.isValid()) { + ++state()->maxDepth; + + QPainterPath path; + path.addRect(state()->rectangleClip); + + // flush the existing clip rectangle to the depth buffer + d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), state()->maxDepth); + } + + QRect oldRectangleClip = state()->rectangleClip; + + state()->rectangleClip = state()->rectangleClip.united(pathRect); + d->updateDepthScissorTest(); + + QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip; + glDepthFunc(GL_ALWAYS); + if (!extendRegion.isEmpty()) { + QPainterPath extendPath; + extendPath.addRegion(extendRegion); + + // first clear the depth buffer in the extended region + d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0); + } + + // now write the clip path d->writeClip(path, state()->maxDepth); state()->canRestoreClip = false; + state()->currentDepth = state()->maxDepth - 1; state()->depthTestEnabled = true; break; + } } glDepthFunc(GL_LESS); @@ -1739,39 +1738,22 @@ void QGL2PaintEngineExPrivate::systemStateChanged() } } - glDisable(GL_DEPTH_TEST); q->state()->depthTestEnabled = false; - q->state()->scissorTestEnabled = false; q->state()->needsDepthBufferClear = true; - q->state()->hasRectangleClip = false; - - glDisable(GL_SCISSOR_TEST); q->state()->currentDepth = 1; q->state()->maxDepth = 4; - q->state()->rectangleClip = QRect(0, 0, width, height); + q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height); + updateDepthScissorTest(); if (use_system_clip) { if (systemClip.numRects() == 1) { - QRect bounds = systemClip.boundingRect(); - if (bounds == QRect(0, 0, width, height)) { + if (q->state()->rectangleClip == QRect(0, 0, width, height)) { use_system_clip = false; return; } - - q->state()->rectangleClip = bounds; - q->state()->scissorTestEnabled = true; - updateDepthScissorTest(); } else { - q->state()->rectangleClip = QRect(); - q->state()->scissorTestEnabled = true; - updateDepthScissorTest(); - - QTransform transform = q->state()->matrix; - q->state()->matrix = QTransform(); - q->transformChanged(); - q->state()->needsDepthBufferClear = false; glDepthMask(true); @@ -1783,17 +1765,13 @@ void QGL2PaintEngineExPrivate::systemStateChanged() path.addRegion(systemClip); glDepthFunc(GL_ALWAYS); - writeClip(qtVectorPathForPath(path), 2); + writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 2); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); q->state()->depthTestEnabled = true; - - q->state()->matrix = transform; - q->transformChanged(); } - q->state()->currentDepth = 1; simpleShaderDepthUniformDirty = true; depthUniformDirty = true; } @@ -1870,18 +1848,15 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &oth maxDepth = other.maxDepth; canRestoreClip = other.canRestoreClip; rectangleClip = other.rectangleClip; - hasRectangleClip = other.hasRectangleClip; } QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() { needsDepthBufferClear = true; depthTestEnabled = false; - scissorTestEnabled = false; currentDepth = 1; maxDepth = 4; canRestoreClip = true; - hasRectangleClip = false; } QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 8b09f41..049994f 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -217,11 +217,13 @@ public: bool brushUniformsDirty; bool simpleShaderMatrixUniformDirty; bool shaderMatrixUniformDirty; - bool stencilBufferDirty; bool depthUniformDirty; bool simpleShaderDepthUniformDirty; bool opacityUniformDirty; + QRegion dirtyStencilRegion; + QRect currentScissorBounds; + const QBrush* currentBrush; // May not be the state's brush! GLfloat inverseScale; |