diff options
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 69 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 1 |
2 files changed, 41 insertions, 29 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 5875124..b3638ff 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -391,7 +391,6 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) } -// Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray void QGL2PaintEngineExPrivate::useSimpleShader() { shaderManager->simpleProgram()->enable(); @@ -891,16 +890,26 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); - // Stencil the brush onto the dest buffer - glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); // Pass if stencil buff value != 0 - glStencilOp(GL_KEEP, GL_ZERO, GL_ZERO); - glStencilMask(GL_STENCIL_HIGH_BIT); + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + + if (q->state()->clipTestEnabled) { + // Pass when high bit is set, replace stencil value with current clip + glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); + } else if (path.hasWindingFill()) { + // Pass when any bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, 0xff); + } else { + // Pass when high bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); + } prepareForDraw(currentBrush->isOpaque()); if (inRenderText) prepareDepthRangeForRenderText(); + // Stencil the brush onto the dest buffer composite(vertexCoordinateArray.boundingRect()); if (inRenderText) @@ -916,7 +925,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); - glStencilMask(0xffff); // Enable stencil writes + glStencilMask(0xff); // Enable stencil writes if (dirtyStencilRegion.intersects(currentScissorBounds)) { QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects(); @@ -948,39 +957,30 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve if (useWindingFill) { if (q->state()->clipTestEnabled) { + // Flatten clip values higher than current clip, and set high bit to match current clip glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); composite(vertexArray.boundingRect()); glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); - } else { - glStencilFunc(GL_ALWAYS, 0, 0xffff); + } else if (!stencilClean) { + // Clear stencil buffer within bounding rect + glStencilFunc(GL_ALWAYS, 0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); composite(vertexArray.boundingRect()); } // Inc. for front-facing triangle glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); - //Dec. for back-facing "holes" + // Dec. for back-facing "holes" glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); glStencilMask(~GL_STENCIL_HIGH_BIT); drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); if (q->state()->clipTestEnabled) { - // clear high bit of stencil outside of path - glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); - glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); - glStencilMask(GL_STENCIL_HIGH_BIT); - composite(vertexArray.boundingRect()); - // reset lower bits of stencil inside path to current clip - glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, GL_STENCIL_HIGH_BIT); + // Clear high bit of stencil outside of path + glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - glStencilMask(~GL_STENCIL_HIGH_BIT); - composite(vertexArray.boundingRect()); - } else { - // set high bit of stencil inside path - glStencilFunc(GL_NOTEQUAL, 0, 0xffff); - glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); glStencilMask(GL_STENCIL_HIGH_BIT); composite(vertexArray.boundingRect()); } @@ -1020,7 +1020,7 @@ void QGL2PaintEngineExPrivate::resetClipIfNeeded() QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); // Set high bit on clip region - glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xffff); + glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); glStencilMask(GL_STENCIL_HIGH_BIT); composite(rect); @@ -1028,7 +1028,7 @@ void QGL2PaintEngineExPrivate::resetClipIfNeeded() // Reset clipping to 1 and everything else to zero glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); - glStencilMask(0xFFFF); + glStencilMask(0xff); composite(rect); q->state()->currentClip = 1; @@ -1636,6 +1636,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->use_system_clip = !systemClip().isEmpty(); d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); + d->stencilClean = true; // Calling begin paint should make the correct context current. So, any // code which calls into GL or otherwise needs a current context *must* @@ -1731,7 +1732,7 @@ void QGL2PaintEngineExPrivate::updateClipScissorTest() glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); } else { glDisable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0xffff); + glStencilFunc(GL_ALWAYS, 0, 0xff); } #ifdef QT_GL_NO_SCISSOR_TEST @@ -1787,7 +1788,7 @@ void QGL2PaintEngineExPrivate::clearClip(uint value) { dirtyStencilRegion -= currentScissorBounds; - glStencilMask(0xffff); + glStencilMask(0xff); glClearStencil(value); glClear(GL_STENCIL_BUFFER_BIT); glStencilMask(0x0); @@ -1802,6 +1803,8 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) if (matrixDirty) updateMatrix(); + stencilClean = false; + const bool singlePass = !path.hasWindingFill() && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled) || q->state()->needsClipBufferClear); @@ -1819,7 +1822,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) if (q->state()->clipTestEnabled) glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); else - glStencilFunc(GL_ALWAYS, 0, 0xffff); + glStencilFunc(GL_ALWAYS, 0, 0xff); vertexCoordinateArray.clear(); vertexCoordinateArray.addPath(path, inverseScale); @@ -1841,9 +1844,17 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); } else { - glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - glStencilMask(0xffff); + glStencilMask(0xff); + + if (!q->state()->clipTestEnabled && path.hasWindingFill()) { + // Pass when any clip bit is set, set high bit + glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); + composite(vertexCoordinateArray.boundingRect()); + } + + // Pass when high bit is set, replace stencil value with new clip value + glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); composite(vertexCoordinateArray.boundingRect()); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 28c972e..46be398 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -223,6 +223,7 @@ public: bool shaderMatrixUniformDirty; bool opacityUniformDirty; + bool stencilClean; // Has the stencil not been used for clipping so far? QRegion dirtyStencilRegion; QRect currentScissorBounds; uint maxClip; |