void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) { if (fboId) { QSGBindableFboId bindable(fboId); renderer->renderScene(bindable); } else { renderer->renderScene(); } }
bool SemanticsVisitor::applicable(TypeDescriptorList formalParams, TypeDescriptorList actualParams) { if (formalParams.size() == 0 && actualParams.size() == 0) return true; else if (formalParams.size() == 0 || actualParams.size() == 0) return false; else { if (bindable(formalParams.front(), actualParams.front())) return applicable( TypeDescriptorList(++formalParams.begin(), formalParams.end()), TypeDescriptorList(++actualParams.begin(), actualParams.end()) ); return false; } }
QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip) { if (!clip) { glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); return NoClip; } bool stencilEnabled = false; bool scissorEnabled = false; glDisable(GL_SCISSOR_TEST); int clipDepth = 0; QRect clipRect; while (clip) { QMatrix4x4 m = m_current_projection_matrix; if (clip->matrix()) m *= *clip->matrix(); // TODO: Check for multisampling and pixel grid alignment. bool canUseScissor = clip->isRectangular() && qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(0, 2)) && qFuzzyIsNull(m(1, 0)) && qFuzzyIsNull(m(1, 2)); if (canUseScissor) { QRectF bbox = clip->clipRect(); qreal invW = 1 / m(3, 3); qreal fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW; qreal fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW; qreal fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW; qreal fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW; GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5)); GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5)); GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5)); GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5)); if (!scissorEnabled) { clipRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); glEnable(GL_SCISSOR_TEST); scissorEnabled = true; } else { clipRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); } clipRect = clipRect.normalized(); glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()); } else { if (!stencilEnabled) { if (!m_clip_program.isLinked()) { m_clip_program.addShaderFromSourceCode(QGLShader::Vertex, "attribute highp vec4 vCoord; \n" "uniform highp mat4 matrix; \n" "void main() { \n" " gl_Position = matrix * vCoord; \n" "}"); m_clip_program.addShaderFromSourceCode(QGLShader::Fragment, "void main() { \n" " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw! "}"); m_clip_program.bindAttributeLocation("vCoord", 0); m_clip_program.link(); m_clip_matrix_id = m_clip_program.uniformLocation("matrix"); } glStencilMask(0xff); // write mask glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); glEnable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); m_clip_program.bind(); m_clip_program.enableAttributeArray(0); stencilEnabled = true; } glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass const QSGGeometry *geometry = clip->geometry(); Q_ASSERT(geometry->attributeCount() > 0); const QSGGeometry::Attribute *a = geometry->attributes(); glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData()); m_clip_program.setUniformValue(m_clip_matrix_id, m); draw(clip); ++clipDepth; } clip = clip->clipList(); } if (stencilEnabled) { m_clip_program.disableAttributeArray(0); glEnable(GL_DEPTH_TEST); glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass glStencilMask(0); // write mask bindable()->reactivate(); //glDepthMask(GL_TRUE); // must be reset correctly by caller. } else { glDisable(GL_STENCIL_TEST); } if (!scissorEnabled) glDisable(GL_SCISSOR_TEST); return stencilEnabled ? StencilClip : ScissorClip; }
void QSGDefaultRenderer::render() { #if defined (QML_RUNTIME_TESTING) static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree")); if (dumpTree) { printf("\n\n"); QSGNodeDumper::dump(rootNode()); } #endif #ifdef RENDERER_DEBUG debugTimer.invalidate(); debugTimer.start(); geometryNodesDrawn = 0; materialChanges = 0; #endif glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glFrontFace(isMirrored() ? GL_CW : GL_CCW); glDisable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(true); glDepthFunc(GL_GREATER); #if defined(QT_OPENGL_ES) glClearDepthf(0); #else glClearDepth(0); #endif glDisable(GL_SCISSOR_TEST); glClearColor(m_clear_color.redF(), m_clear_color.greenF(), m_clear_color.blueF(), m_clear_color.alphaF()); #ifdef RENDERER_DEBUG int debugtimeSetup = debugTimer.elapsed(); #endif bindable()->clear(clearMode()); #ifdef RENDERER_DEBUG int debugtimeClear = debugTimer.elapsed(); #endif QRect r = viewportRect(); glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); m_current_projection_matrix = projectionMatrix(); m_current_model_view_matrix.setToIdentity(); m_currentClip = 0; glDisable(GL_STENCIL_TEST); m_currentMaterial = 0; m_currentProgram = 0; m_currentMatrix = 0; if (m_rebuild_lists) { m_opaqueNodes.reset(); m_transparentNodes.reset(); m_currentRenderOrder = 1; buildLists(rootNode()); m_rebuild_lists = false; } #ifdef RENDERER_DEBUG int debugtimeLists = debugTimer.elapsed(); #endif if (m_needs_sorting) { if (!m_opaqueNodes.isEmpty()) { qSort(&m_opaqueNodes.first(), &m_opaqueNodes.first() + m_opaqueNodes.size(), m_sort_front_to_back ? nodeLessThanWithRenderOrder : nodeLessThan); } m_needs_sorting = false; } #ifdef RENDERER_DEBUG int debugtimeSorting = debugTimer.elapsed(); #endif m_renderOrderMatrix.setToIdentity(); m_renderOrderMatrix.scale(1, 1, qreal(1) / m_currentRenderOrder); glDisable(GL_BLEND); glDepthMask(true); #ifdef QML_RUNTIME_TESTING if (m_render_opaque_nodes) #endif { #if defined (QML_RUNTIME_TESTING) if (dumpTree) qDebug() << "Opaque Nodes:"; #endif renderNodes(m_opaqueNodes); } #ifdef RENDERER_DEBUG int debugtimeOpaque = debugTimer.elapsed(); int opaqueNodes = geometryNodesDrawn; int opaqueMaterialChanges = materialChanges; #endif glEnable(GL_BLEND); glDepthMask(false); #ifdef QML_RUNTIME_TESTING if (m_render_alpha_nodes) #endif { #if defined (QML_RUNTIME_TESTING) if (dumpTree) qDebug() << "Alpha Nodes:"; #endif renderNodes(m_transparentNodes); } #ifdef RENDERER_DEBUG int debugtimeAlpha = debugTimer.elapsed(); #endif if (m_currentProgram) m_currentProgram->deactivate(); #ifdef RENDERER_DEBUG if (debugTimer.elapsed() > DEBUG_THRESHOLD) { printf(" --- Renderer breakdown:\n" " - setup=%d, clear=%d, building=%d, sorting=%d, opaque=%d, alpha=%d\n" " - material changes: opaque=%d, alpha=%d, total=%d\n" " - geometry ndoes: opaque=%d, alpha=%d, total=%d\n", debugtimeSetup, debugtimeClear - debugtimeSetup, debugtimeLists - debugtimeClear, debugtimeSorting - debugtimeLists, debugtimeOpaque - debugtimeSorting, debugtimeAlpha - debugtimeOpaque, opaqueMaterialChanges, materialChanges - opaqueMaterialChanges, materialChanges, opaqueNodes, geometryNodesDrawn - opaqueNodes, geometryNodesDrawn); } #endif }
QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip) { if (!clip) { glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); return NoClip; } ClipType clipType = NoClip; glDisable(GL_SCISSOR_TEST); m_current_stencil_value = 0; m_current_scissor_rect = 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); GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5)); GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5)); GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5)); GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5)); if (!(clipType & ScissorClip)) { m_current_scissor_rect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); glEnable(GL_SCISSOR_TEST); clipType |= ScissorClip; } else { m_current_scissor_rect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1); } glScissor(m_current_scissor_rect.x(), m_current_scissor_rect.y(), m_current_scissor_rect.width(), m_current_scissor_rect.height()); } else { if (!(clipType & StencilClip)) { if (!m_clip_program.isLinked()) { m_clip_program.addShaderFromSourceCode(QOpenGLShader::Vertex, "attribute highp vec4 vCoord; \n" "uniform highp mat4 matrix; \n" "void main() { \n" " gl_Position = matrix * vCoord; \n" "}"); m_clip_program.addShaderFromSourceCode(QOpenGLShader::Fragment, "void main() { \n" " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw! "}"); m_clip_program.bindAttributeLocation("vCoord", 0); m_clip_program.link(); m_clip_matrix_id = m_clip_program.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); if (m_vertex_buffer_bound) { glBindBuffer(GL_ARRAY_BUFFER, 0); m_vertex_buffer_bound = false; } if (m_index_buffer_bound) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); m_index_buffer_bound = false; } m_clip_program.bind(); m_clip_program.enableAttributeArray(0); clipType |= StencilClip; } glStencilFunc(GL_EQUAL, m_current_stencil_value, 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_clip_program.setUniformValue(m_clip_matrix_id, m); if (g->indexCount()) { glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); } else { glDrawArrays(g->drawingMode(), 0, g->vertexCount()); } ++m_current_stencil_value; } clip = clip->clipList(); } if (clipType & StencilClip) { m_clip_program.disableAttributeArray(0); glStencilFunc(GL_EQUAL, m_current_stencil_value, 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; }