diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-07-02 16:56:26 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-07-29 17:54:43 +0200 |
commit | 9c67029ee5aca18ae02e740afbf6d0f883799ebd (patch) | |
tree | 76479e72ce3b9b0f993ddbc8a11c0d02775cbcc6 /src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | |
parent | 4c58d2a83736545f473559cb3e04133343b6194a (diff) |
Move QSGRenderer::updateStencilClip down to QSGBatchRenderer
This convenience method is currently only used by the batch renderer.
Moving it allows removing the QOpenGLFunction inheritance of
QSGRenderer and unbinding it slightly from the rendering implementation.
Change-Id: I4322952f843de8d950ced32885feee8d6c4a2730
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 133 |
1 files changed, 131 insertions, 2 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index e68b001ad1..4119dfb530 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -750,11 +750,14 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_renderOrderRebuildUpper(-1) , m_currentMaterial(0) , m_currentShader(0) + , m_currentStencilValue(0) + , m_clipMatrixId(0) , m_currentClip(0) , m_currentClipType(NoClip) , m_vao(0) , m_visualizeMode(VisualizeNothing) { + initializeOpenGLFunctions(); setNodeUpdater(new Updater(this)); m_shaderManager = ctx->findChild<ShaderManager *>(QStringLiteral("__qt_ShaderManager"), Qt::FindDirectChildrenOnly); @@ -1912,6 +1915,132 @@ void Renderer::uploadBatch(Batch *b) b->uploadedThisFrame = true; } +/*! + * Convenience function to set up the stencil buffer for clipping based on \a clip. + * + * If the clip is a pixel aligned rectangle, this function will use glScissor instead + * of stencil. + */ +Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) +{ + if (!clip) { + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + return NoClip; + } + + ClipType clipType = NoClip; + + glDisable(GL_SCISSOR_TEST); + + m_currentStencilValue = 0; + m_currentScissorRect = QRect(); + while (clip) { + QMatrix4x4 m = m_current_projection_matrix; + if (clip->matrix()) + m *= *clip->matrix(); + + // TODO: Check for multisampling and pixel grid alignment. + bool isRectangleWithNoPerspective = clip->isRectangular() + && qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1)); + bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0)); + bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1)); + + if (isRectangleWithNoPerspective && (noRotate || isRotate90)) { + QRectF bbox = clip->clipRect(); + qreal invW = 1 / m(3, 3); + qreal fx1, fy1, fx2, fy2; + if (noRotate) { + fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW; + fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW; + fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW; + fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW; + } else { + Q_ASSERT(isRotate90); + fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW; + fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW; + fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW; + fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW; + } + + if (fx1 > fx2) + qSwap(fx1, fx2); + if (fy1 > fy2) + qSwap(fy1, fy2); + + QRect deviceRect = this->deviceRect(); + + GLint ix1 = qRound((fx1 + 1) * deviceRect.width() * qreal(0.5)); + GLint iy1 = qRound((fy1 + 1) * deviceRect.height() * qreal(0.5)); + GLint ix2 = qRound((fx2 + 1) * deviceRect.width() * qreal(0.5)); + GLint iy2 = qRound((fy2 + 1) * deviceRect.height() * qreal(0.5)); + + if (!(clipType & ScissorClip)) { + m_currentScissorRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); + glEnable(GL_SCISSOR_TEST); + clipType |= ScissorClip; + } else { + m_currentScissorRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); + } + glScissor(m_currentScissorRect.x(), m_currentScissorRect.y(), + m_currentScissorRect.width(), m_currentScissorRect.height()); + } else { + if (!(clipType & StencilClip)) { + if (!m_clipProgram.isLinked()) { + QSGShaderSourceBuilder::initializeProgramFromFiles( + &m_clipProgram, + QStringLiteral(":/scenegraph/shaders/stencilclip.vert"), + QStringLiteral(":/scenegraph/shaders/stencilclip.frag")); + m_clipProgram.bindAttributeLocation("vCoord", 0); + m_clipProgram.link(); + m_clipMatrixId = m_clipProgram.uniformLocation("matrix"); + } + + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + glEnable(GL_STENCIL_TEST); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glDepthMask(GL_FALSE); + + m_clipProgram.bind(); + m_clipProgram.enableAttributeArray(0); + + clipType |= StencilClip; + } + + glStencilFunc(GL_EQUAL, m_currentStencilValue, 0xff); // stencil test, ref, test mask + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass + + const QSGGeometry *g = clip->geometry(); + Q_ASSERT(g->attributeCount() > 0); + const QSGGeometry::Attribute *a = g->attributes(); + glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->sizeOfVertex(), g->vertexData()); + + m_clipProgram.setUniformValue(m_clipMatrixId, m); + if (g->indexCount()) { + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + } else { + glDrawArrays(g->drawingMode(), 0, g->vertexCount()); + } + + ++m_currentStencilValue; + } + + clip = clip->clipList(); + } + + if (clipType & StencilClip) { + m_clipProgram.disableAttributeArray(0); + glStencilFunc(GL_EQUAL, m_currentStencilValue, 0xff); // stencil test, ref, test mask + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass + bindable()->reactivate(); + } else { + glDisable(GL_STENCIL_TEST); + } + + return clipType; +} + void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) { if (clipList != m_currentClip && Q_LIKELY(!debug_noclip)) { @@ -2485,8 +2614,8 @@ void Renderer::renderRenderNode(Batch *batch) state.projectionMatrix = ± state.scissorEnabled = m_currentClipType & ScissorClip; state.stencilEnabled = m_currentClipType & StencilClip; - state.scissorRect = m_current_scissor_rect; - state.stencilValue = m_current_stencil_value; + state.scissorRect = m_currentScissorRect; + state.stencilValue = m_currentStencilValue; QSGNode *xform = e->renderNode->parent(); QMatrix4x4 matrix; |