void QuickSceneGraphModel::populateFromNode(QSGNode *node, bool emitSignals) { if (!node) { return; } QVector<QSGNode*> &childList = m_parentChildMap[node]; QVector<QSGNode*> newChildList; newChildList.reserve(node->childCount()); for (QSGNode *childNode = node->firstChild(); childNode; childNode = childNode->nextSibling()) { newChildList.append(childNode); } QModelIndex myIndex; // don't call indexForNode(node) here yet, in the common case of few changes we waste a lot of time here bool hasMyIndex = false; std::sort(newChildList.begin(), newChildList.end()); QVector<QSGNode*>::iterator i = childList.begin(); QVector<QSGNode*>::const_iterator j = newChildList.constBegin(); while (i != childList.end() && j != newChildList.constEnd()) { if (*i < *j) { // handle deleted node emit nodeDeleted(*i); GET_INDEX if (emitSignals) { const auto idx = std::distance(childList.begin(), i); beginRemoveRows(myIndex, idx, idx); } pruneSubTree(*i); i = childList.erase(i); if (emitSignals) endRemoveRows(); } else if (*i > *j) { // handle added node
void QSGRenderer::removeNodesToPreprocess(QSGNode *node) { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) removeNodesToPreprocess(c); if (node->flags() & QSGNode::UsePreprocess) m_nodes_to_preprocess.remove(node); }
void QSGRenderer::preprocess() { Q_ASSERT(m_root_node); // We need to take a copy here, in case any of the preprocess calls deletes a node that // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs // For the default case, when this does not happen, the cost is neglishible. QSet<QSGNode *> items = m_nodes_to_preprocess; for (QSet<QSGNode *>::const_iterator it = items.constBegin(); it != items.constEnd(); ++it) { QSGNode *n = *it; if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) { n->preprocess(); } } #ifdef QSG_RENDERER_TIMING preprocessTime = frameTimer.elapsed(); #endif nodeUpdater()->setToplevelOpacity(context()->renderAlpha()); nodeUpdater()->updateStates(m_root_node); #ifdef QSG_RENDERER_TIMING updatePassTime = frameTimer.elapsed(); #endif }
void SatellitesItem::update() { if( ! m_satComp->selected() ) { hide(); return; } QSGNode *n = firstChild(); while(n != 0) { SatelliteNode *satNode = static_cast<SatelliteNode *>(n); Satellite *sat = satNode->sat(); if ( sat->selected() ) { if ( Options::showVisibleSatellites() ) { if ( sat->isVisible() ) { satNode->update(); } else { satNode->hide(); } } else { satNode->update(); } } else { satNode->hide(); } n = n->nextSibling(); } }
QVariant QuickSceneGraphModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QSGNode *node = reinterpret_cast<QSGNode*>(index.internalPointer()); if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::addressToString(node); } else if (index.column() == 1) { switch (node->type()) { case QSGNode::BasicNodeType: return "Node"; case QSGNode::GeometryNodeType: return "Geometry Node"; case QSGNode::TransformNodeType: return "Transform Node"; case QSGNode::ClipNodeType: return "Clip Node"; case QSGNode::OpacityNodeType: return "Opacity Node"; case QSGNode::RootNodeType: return "Root Node"; case QSGNode::RenderNodeType: return "Render Node"; } } } else if (role == ObjectModel::ObjectRole) { return QVariant::fromValue(node); } return QVariant(); }
void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller) { QQuickAnimatorJob::initialize(controller); QQuickItemPrivate *d = QQuickItemPrivate::get(m_target); if (d->extra.isAllocated() && d->extra->layer && d->extra->layer->enabled()) { d = QQuickItemPrivate::get(d->extra->layer->m_effectSource); } m_opacityNode = d->opacityNode(); if (!m_opacityNode) { m_opacityNode = new QSGOpacityNode(); d->extra.value().opacityNode = m_opacityNode; QSGNode *child = d->clipNode(); if (!child) child = d->rootNode(); if (!child) child = d->groupNode; if (child) { if (child->parent()) child->parent()->removeChildNode(child); m_opacityNode->appendChildNode(child); } d->itemNode()->appendChildNode(m_opacityNode); } }
void MultiTrackPlotter::setChannelData( int channel, float *data ) { Q_ASSERT(channel >= 0 && channel < m_channel_count); QSGNode *transformNode = childAtIndex(channel); PlotNode1D *plotNode = static_cast<PlotNode1D*>( transformNode->childAtIndex(0) ); plotNode->setData(data, m_frame_count); }
void deleteContent() { QSGNode *subnode = firstChild(); while (subnode) { // We can't delete the node now as it might be in the preprocess list // It will be deleted in the next preprocess m_nodes_to_delete.append(subnode); subnode = subnode->nextSibling(); } removeAllChildNodes(); }
void QSGNodeVisitorEx::visitChildren(QSGNode *node) { for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) { switch (child->type()) { case QSGNode::ClipNodeType: { QSGClipNode *c = static_cast<QSGClipNode*>(child); if (visit(c)) visitChildren(c); endVisit(c); break; } case QSGNode::TransformNodeType: { QSGTransformNode *c = static_cast<QSGTransformNode*>(child); if (visit(c)) visitChildren(c); endVisit(c); break; } case QSGNode::OpacityNodeType: { QSGOpacityNode *c = static_cast<QSGOpacityNode*>(child); if (visit(c)) visitChildren(c); endVisit(c); break; } case QSGNode::GeometryNodeType: { if (child->flags() & QSGNode::IsVisitableNode) { QSGVisitableNode *v = static_cast<QSGVisitableNode*>(child); v->accept(this); } else { QSGGeometryNode *c = static_cast<QSGGeometryNode*>(child); if (visit(c)) visitChildren(c); endVisit(c); } break; } case QSGNode::RootNodeType: { QSGRootNode *root = static_cast<QSGRootNode*>(child); if (visit(root)) visitChildren(root); endVisit(root); break; } case QSGNode::BasicNodeType: { visitChildren(child); break; } default: Q_UNREACHABLE(); break; } } }
BindingLoopsRenderPassState::BindingLoopsRenderPassState(const QmlProfilerRangeModel *model) : m_indexFrom(std::numeric_limits<int>::max()), m_indexTo(-1) { m_collapsedOverlay = new QSGNode; m_collapsedOverlay->setFlag(QSGNode::OwnedByParent, false); m_expandedRows.reserve(model->expandedRowCount()); for (int i = 0; i < model->expandedRowCount(); ++i) { QSGNode *node = new QSGNode; node->setFlag(QSGNode::OwnedByParent, false); m_expandedRows << node; } }
QSGNode *QuickSceneGraphModel::currentRootNode() const { if (!m_window) return nullptr; QQuickItem *item = m_window->contentItem(); QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); QSGNode *root = itemPriv->itemNode(); while (root->parent()) // Ensure that we really get the very root node. root = root->parent(); return root; }
/* Search through the node set and remove nodes that are leaves of other nodes in the same set. */ QSet<QSGNode *> qsg_simplerenderer_updateRoots(const QSet<QSGNode *> &nodes, QSGRootNode *root) { QSet<QSGNode *> result = nodes; foreach (QSGNode *node, nodes) { QSGNode *n = node; while (n != root) { if (result.contains(n)) { result.remove(node); break; } n = n->parent(); } }
void QSGNode::removeAllChildNodes() { while (m_firstChild) { QSGNode *node = m_firstChild; m_firstChild = node->m_nextSibling; node->m_nextSibling = 0; if (m_firstChild) m_firstChild->m_previousSibling = 0; else m_lastChild = 0; node->markDirty(DirtyNodeRemoved); node->m_parent = 0; } }
QSGNode *QQuickTextField::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) { QQuickDefaultClipNode *clipNode = static_cast<QQuickDefaultClipNode *>(oldNode); if (!clipNode) clipNode = new QQuickDefaultClipNode(QRectF()); clipNode->setRect(clipRect().adjusted(leftPadding(), topPadding(), -rightPadding(), -bottomPadding())); clipNode->update(); QSGNode *textNode = QQuickTextInput::updatePaintNode(clipNode->firstChild(), data); if (!textNode->parent()) clipNode->appendChildNode(textNode); return clipNode; }
void QSGNode::destroy() { if (m_parent) { m_parent->removeChildNode(this); Q_ASSERT(m_parent == 0); } while (m_firstChild) { QSGNode *child = m_firstChild; removeChildNode(child); Q_ASSERT(child->m_parent == 0); if (child->flags() & OwnedByParent) delete child; } Q_ASSERT(m_firstChild == 0 && m_lastChild == 0); }
QSGNode* Graph::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) { QSGNode* rootNode = QQuickItem::updatePaintNode(oldNode, data); if (rootNode == NULL) { rootNode = new QSGNode(); rootNode->setFlag(QSGNode::OwnedByParent, true); } else { rootNode->removeAllChildNodes(); } DrawAxes(rootNode); return rootNode; }
void SupernovaeItem::update() { if( ! m_snovaComp->selected() ) { hide(); return; } show(); QSGNode *n = firstChild(); while(n != 0) { SupernovaNode *sNode = static_cast<SupernovaNode *>(n); sNode->update(); n = n->nextSibling(); } }
void TimelineRenderState::updateExpandedRowHeights(const TimelineModel *model, int defaultRowHeight, int defaultRowOffset) { Q_D(TimelineRenderState); int row = 0; qreal offset = 0; for (QSGNode *rowNode = d->expandedRowRoot->firstChild(); rowNode != 0; rowNode = rowNode->nextSibling()) { qreal rowHeight = model->expandedRowHeight(row++); QMatrix4x4 matrix; matrix.translate(0, offset, 0); matrix.scale(1, rowHeight / defaultRowHeight, 1); offset += defaultRowOffset * rowHeight / defaultRowHeight; static_cast<QSGTransformNode *>(rowNode)->setMatrix(matrix); } }
void QSGNode::markDirty(DirtyState bits) { int renderableCountDiff = 0; if (bits & DirtyNodeAdded) renderableCountDiff += m_subtreeRenderableCount; if (bits & DirtyNodeRemoved) renderableCountDiff -= m_subtreeRenderableCount; QSGNode *p = m_parent; while (p) { p->m_subtreeRenderableCount += renderableCountDiff; if (p->type() == RootNodeType) static_cast<QSGRootNode *>(p)->notifyNodeChange(this, bits); p = p->m_parent; } }
void QuickSceneGraphModel::updateSGTree() { QQuickItem *item = m_window->contentItem(); QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); QSGNode *rootNode = itemPriv->itemNode(); while(rootNode->parent()) // Ensure that we really get the very root node. rootNode = rootNode->parent(); m_oldChildParentMap = m_childParentMap; m_oldParentChildMap = m_parentChildMap; m_childParentMap = QHash<QSGNode*, QSGNode*>(); m_parentChildMap = QHash<QSGNode*, QVector<QSGNode*> >(); m_childParentMap[m_rootNode] = 0; m_parentChildMap[0].append(m_rootNode); populateFromNode(m_rootNode); collectItemNodes(m_window->contentItem()); }
void QQuickTextNode::setColor(const QColor &color) { if (m_usePixmapCache) { setUpdateFlag(UpdateNodes); } else { for (QSGNode *childNode = firstChild(); childNode; childNode = childNode->nextSibling()) { if (childNode->subType() == GlyphNodeSubType) { QSGGlyphNode *glyphNode = static_cast<QSGGlyphNode *>(childNode); if (glyphNode->color() == m_color) glyphNode->setColor(color); } else if (childNode->subType() == SolidRectNodeSubType) { QSGSimpleRectNode *solidRectNode = static_cast<QSGSimpleRectNode *>(childNode); if (solidRectNode->color() == m_color) solidRectNode->setColor(color); } } } m_color = color; }
void QSGAbstractSoftwareRenderer::nodeRemoved(QSGNode *node) { qCDebug(lc2DRender) << "nodeRemoved" << (void*)node; auto renderable = renderableNode(node); // remove mapping if (renderable != nullptr) { // Need to mark this region dirty in the other nodes QRegion dirtyRegion = renderable->previousDirtyRegion(true); if (dirtyRegion.isEmpty()) dirtyRegion = renderable->boundingRectMax(); m_dirtyRegion += dirtyRegion; m_nodes.remove(node); delete renderable; } // Remove all children nodes as well for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) { nodeRemoved(child); } m_nodeUpdater->updateNodes(node, true); }
QSGNode *Renderer::paintNode(const QRectF& viewport) const { if (m_tiles.isEmpty()) { return 0; } QSGNode *parentNode = new QSGNode; for (const Tile& tile : m_tiles) { if (tile.visible) { QRectF rect = m_view->tileRect(tile); QSGSimpleTextureNode *node = new SimpleTextureNode; node->setFlag(QSGNode::OwnedByParent, true); node->setTexture(m_view->window()->createTextureFromImage(tile.image)); node->setRect(rect); node->setFiltering(QSGTexture::Nearest); // node->setOwnsTexture(true); // TODO: Qt 5.4 qreal dx1 = rect.left() < viewport.left() ? viewport.left() - rect.left() : 0.0f; qreal dy1 = 0.0f; qreal dx2 = rect.right() > viewport.right() ? viewport.right() - rect.right() : 0.0f; qreal dy2 = rect.bottom() > viewport.bottom() ? viewport.bottom() - rect.bottom() : 0.0f; if (dx1 != 0.0f || dx2 != 0.0f || dy2 != 0.0f) { QSGClipNode *clip = new QSGClipNode; clip->setIsRectangular(true); clip->setClipRect(rect.adjusted(dx1, dy1, dx2, dy2)); parentNode->appendChildNode(clip); clip->appendChildNode(node); // qDebug() << "Clipping"; } else { parentNode->appendChildNode(node); } } } return parentNode; }
void MultiTrackPlotter::setChannelColor( int channel, const QColor & color ) { QSGNode *transformNode = childAtIndex(channel); PlotNode1D *plotNode = static_cast<PlotNode1D*>( transformNode->childAtIndex(0) ); plotNode->setColor(color); }
QSGNode* AudioBarSpectrumItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) { if (!m_analyzer) return oldNode; if (!isVisible()) return oldNode; const std::vector<double>& points = m_analyzer->getSimplifiedSpectrum(); const double gain = m_agcEnabled ? m_analyzer->getAgcValue() : m_manualGain; const int pointCount = points.size(); if (pointCount < 2) return oldNode; // -------------------- Prepare QSG Nodes: QSGNode* parentNode = nullptr; if (oldNode) { parentNode = static_cast<QSGNode*>(oldNode); } else { parentNode = new QSGNode; } // adapt child count: int childCount = parentNode->childCount(); if (childCount != 2) { parentNode->removeAllChildNodes(); QSGGeometryNode* node = new QSGGeometryNode; QSGGeometry* geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3); geometry->setDrawingMode(GL_TRIANGLE_STRIP); node->setGeometry(geometry); node->setFlag(QSGNode::OwnsGeometry); QSGFlatColorMaterial* material = new QSGFlatColorMaterial; material->setColor("#fff"); node->setMaterial(material); node->setFlag(QSGNode::OwnsMaterial); parentNode->appendChildNode(node); // Attention: TODO: colors are swapped! node = new QSGGeometryNode; geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3); geometry->setDrawingMode(GL_TRIANGLE_STRIP); node->setGeometry(geometry); node->setFlag(QSGNode::OwnsGeometry); material = new QSGFlatColorMaterial; material->setColor(m_color); node->setMaterial(material); node->setFlag(QSGNode::OwnsMaterial); parentNode->appendChildNode(node); } QSGGeometryNode* const qsgNode = static_cast<QSGGeometryNode*>(parentNode->childAtIndex(0)); QSGGeometryNode* const qsgNodeOutline = static_cast<QSGGeometryNode*>(parentNode->childAtIndex(1)); if (!qsgNode || !qsgNodeOutline) { qCritical() << "[SpectrumItem] Could not get QSG Node."; return nullptr; } QSGGeometry* const geometry = qsgNode->geometry(); QSGGeometry* const geometryOutline = qsgNodeOutline->geometry(); if (!geometry || !geometryOutline) { qCritical() << "[SpectrumItem] Could not get QSG Geometry."; return nullptr; } const int verticesCount = pointCount * 7; const int outlineVerticesCount = pointCount * 7; geometry->allocate(verticesCount); geometryOutline->allocate(outlineVerticesCount); QSGGeometry::Point2D* const vertices = geometry->vertexDataAsPoint2D(); QSGGeometry::Point2D* const verticesOutline = geometryOutline->vertexDataAsPoint2D(); if (! vertices || !verticesOutline) { qCritical() << "[SpectrumItem] Could not get QSG vertices."; return nullptr; } const double itemWidth = width(); const double itemHeight = height(); const double barWidth = (itemWidth / pointCount) * 0.4; const double spaceWidth = (itemWidth / pointCount) * 0.6; const double endLineHeight = itemHeight / 100.0; // draw spectrum: for (int i = 0; i < pointCount; ++i) { const float x = itemWidth * (i / float(pointCount)); const float y = itemHeight * (1 - points[i] * gain); vertices[i*7].set(x, itemHeight); vertices[i*7+1].set(x, y); vertices[i*7+2].set(x + barWidth, itemHeight); vertices[i*7+3].set(x + barWidth, y); vertices[i*7+4].set(x + barWidth, itemHeight); vertices[i*7+5].set(x + barWidth, itemHeight); vertices[i*7+6].set(x + barWidth + spaceWidth, itemHeight); const float y2 = qMin(itemHeight, itemHeight * (1 - points[i] * gain) + endLineHeight); verticesOutline[i*7].set(x, itemHeight); verticesOutline[i*7+1].set(x, y2); verticesOutline[i*7+2].set(x + barWidth, itemHeight); verticesOutline[i*7+3].set(x + barWidth, y2); verticesOutline[i*7+4].set(x + barWidth, itemHeight); verticesOutline[i*7+5].set(x + barWidth, itemHeight); verticesOutline[i*7+6].set(x + barWidth + spaceWidth, itemHeight); } // tell Scene Graph that this items needs to be drawn: qsgNode->markDirty(QSGNode::DirtyGeometry); qsgNodeOutline->markDirty(QSGNode::DirtyGeometry); return parentNode; }
void QSGDefaultRenderer::buildLists(QSGNode *node) { if (node->isSubtreeBlocked()) return; if (node->type() == QSGNode::GeometryNodeType) { QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(node); qreal opacity = geomNode->inheritedOpacity(); QSGMaterial *m = geomNode->activeMaterial(); #ifdef FORCE_NO_REORDER if (true) { #else if ((m->flags() & QSGMaterial::Blending) || opacity < 1) { #endif geomNode->setRenderOrder(m_currentRenderOrder - 1); m_transparentNodes.add(geomNode); } else { geomNode->setRenderOrder(m_currentRenderOrder); m_opaqueNodes.add(geomNode); m_currentRenderOrder += 2; } } if (!node->firstChild()) return; #ifdef FORCE_NO_REORDER static bool reorder = false; #else static bool reorder = !qApp->arguments().contains(QLatin1String("--no-reorder")); #endif if (reorder && node->firstChild() != node->lastChild() && (node->flags() & QSGNode::ChildrenDoNotOverlap)) { QVarLengthArray<int, 16> beginIndices; QVarLengthArray<int, 16> endIndices; int baseCount = m_transparentNodes.size(); int count = 0; for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) { beginIndices.append(m_transparentNodes.size()); buildLists(c); endIndices.append(m_transparentNodes.size()); ++count; } int childNodeCount = m_transparentNodes.size() - baseCount; if (childNodeCount) { m_tempNodes.reset(); m_tempNodes.reserve(childNodeCount); while (childNodeCount) { for (int i = 0; i < count; ++i) { if (beginIndices[i] != endIndices[i]) m_heap.insert(IndexGeometryNodePair(i, m_transparentNodes.at(beginIndices[i]++))); } while (!m_heap.isEmpty()) { IndexGeometryNodePair pair = m_heap.pop(); m_tempNodes.add(pair.second); --childNodeCount; int i = pair.first; if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), pair.second)) m_heap.insert(IndexGeometryNodePair(i, m_transparentNodes.at(beginIndices[i]++))); } } Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount); qMemCopy(&m_transparentNodes.at(baseCount), &m_tempNodes.at(0), m_tempNodes.size() * sizeof(QSGGeometryNode *)); } } else { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) buildLists(c); } } void QSGDefaultRenderer::renderNodes(const QDataBuffer<QSGGeometryNode *> &list) { const float scale = 1.0f / m_currentRenderOrder; int count = list.size(); int currentRenderOrder = 0x80000000; m_current_projection_matrix.setColumn(2, scale * projectionMatrix().column(2)); //int clipChangeCount = 0; //int programChangeCount = 0; //int materialChangeCount = 0; for (int i = 0; i < count; ++i) { QSGGeometryNode *geomNode = list.at(i); QSGMaterialShader::RenderState::DirtyStates updates; #if defined (QML_RUNTIME_TESTING) static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree")); if (dumpTree) qDebug() << geomNode; #endif bool changeMatrix = m_currentMatrix != geomNode->matrix(); if (changeMatrix) { m_currentMatrix = geomNode->matrix(); if (m_currentMatrix) m_current_model_view_matrix = *m_currentMatrix; else m_current_model_view_matrix.setToIdentity(); updates |= QSGMaterialShader::RenderState::DirtyMatrix; } bool changeOpacity = m_current_opacity != geomNode->inheritedOpacity(); if (changeOpacity) { updates |= QSGMaterialShader::RenderState::DirtyOpacity; m_current_opacity = geomNode->inheritedOpacity(); } Q_ASSERT(geomNode->activeMaterial()); QSGMaterial *material = geomNode->activeMaterial(); QSGMaterialShader *program = m_context->prepareMaterial(material); Q_ASSERT(program->program()->isLinked()); bool changeClip = geomNode->clipList() != m_currentClip; QSGRenderer::ClipType clipType = QSGRenderer::NoClip; if (changeClip) { clipType = updateStencilClip(geomNode->clipList()); m_currentClip = geomNode->clipList(); #ifdef FORCE_NO_REORDER glDepthMask(false); #else glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_current_opacity == 1); #endif //++clipChangeCount; } bool changeProgram = (changeClip && clipType == QSGRenderer::StencilClip) || m_currentProgram != program; if (changeProgram) { if (m_currentProgram) m_currentProgram->deactivate(); m_currentProgram = program; m_currentProgram->activate(); //++programChangeCount; updates |= (QSGMaterialShader::RenderState::DirtyMatrix | QSGMaterialShader::RenderState::DirtyOpacity); #ifdef RENDERER_DEBUG materialChanges++; #endif } bool changeRenderOrder = currentRenderOrder != geomNode->renderOrder(); if (changeRenderOrder) { currentRenderOrder = geomNode->renderOrder(); m_current_projection_matrix.setColumn(3, projectionMatrix().column(3) + currentRenderOrder * m_current_projection_matrix.column(2)); updates |= QSGMaterialShader::RenderState::DirtyMatrix; } if (changeProgram || m_currentMaterial != material) { program->updateState(state(updates), material, changeProgram ? 0 : m_currentMaterial); m_currentMaterial = material; //++materialChangeCount; } //glDepthRange((geomNode->renderOrder() + 0.1) * scale, (geomNode->renderOrder() + 0.9) * scale); const QSGGeometry *g = geomNode->geometry(); bindGeometry(program, g); draw(geomNode); #ifdef RENDERER_DEBUG geometryNodesDrawn++; #endif } //qDebug("Clip: %i, shader program: %i, material: %i times changed while drawing %s items", // clipChangeCount, programChangeCount, materialChangeCount, // &list == &m_transparentNodes ? "transparent" : "opaque"); } QT_END_NAMESPACE
QSGNode* BrowserUtils::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData) { Q_UNUSED(updatePaintNodeData); if (!(m_webview && (flags() & QQuickItem::ItemHasContents))) { return oldNode; } setFlag(QQuickItem::ItemHasContents, false); #if 0 QQuickWebPage* page = m_webview->page(); qreal xmin = qMin(page->width(), m_webview->width()); qreal ymin = qMin(m_webview->height(), page->height()); #else // Here the screenshot of the page might be too large if the page is tiny qreal xmin = m_webview->width(); qreal ymin = m_webview->height(); #endif ymin = qMin(static_cast<int>(ymin), m_imageSize.height()); xmin = qMin(static_cast<int>(xmin), m_imageSize.width()); QSize size(xmin, ymin); QSGNode* node = QQuickItemPrivate::get(m_webview)->itemNode(); QSGNode* parent = node->QSGNode::parent(); QSGNode* previousSibling = node->previousSibling(); if (parent) { parent->removeChildNode(node); } QSGRootNode root; root.appendChildNode(node); QSGRenderer* renderer; #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) renderer = QQuickItemPrivate::get(this)->sceneGraphContext()->createRenderer(); #else renderer = QQuickItemPrivate::get(this)->sceneGraphRenderContext()->createRenderer(); #endif renderer->setRootNode(static_cast<QSGRootNode*>(&root)); QOpenGLFramebufferObject fbo(size); renderer->setDeviceRect(size); renderer->setViewportRect(size); renderer->setProjectionMatrixToRect(QRectF(QPointF(), size)); renderer->setClearColor(Qt::transparent); renderer->renderScene(BindableFbo(&fbo)); fbo.release(); QImage image = fbo.toImage().scaled(m_imageSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); QFileInfo imageInfo(m_outFile); QDir imageDir(imageInfo.path()); if (!imageDir.exists()) { imageDir.mkpath("."); } bool saved = image.save(m_outFile); root.removeChildNode(node); renderer->setRootNode(0); delete renderer; if (parent) { if (previousSibling) { parent->insertChildNodeAfter(node, previousSibling); } else { parent->prependChildNode(node); } } Q_EMIT webViewSaved(saved, m_outFile); return oldNode; }
void HsQMLCanvasBackEnd::doRendering() { if (!mGL) { mGL = mWindow->openglContext(); QObject::connect( mGL, SIGNAL(aboutToBeDestroyed()), this, SLOT(doCleanup())); HsQMLGLCanvasType ctype; QSurfaceFormat format = mGL->format(); switch (format.renderableType()) { case QSurfaceFormat::OpenGL: ctype = HSQML_GL_DESKTOP; break; case QSurfaceFormat::OpenGLES: ctype = HSQML_GL_ES; break; default: setStatus(HsQMLCanvas::BadConfig); return; } mGLViewportFn = reinterpret_cast<GLViewportFn>( mGL->getProcAddress("glViewport")); mGLClearColorFn = reinterpret_cast<GLClearColorFn>( mGL->getProcAddress("glClearColor")); mGLClearFn = reinterpret_cast<GLClearFn>( mGL->getProcAddress("glClear")); if (!mGLViewportFn || !mGLClearColorFn || !mGLClearFn) { setStatus(HsQMLCanvas::BadProcs); return; } mGLCallbacks->mSetupCb( ctype, format.majorVersion(), format.minorVersion()); } // Reset OpenGL state before rendering #if QT_VERSION >= 0x050200 mWindow->resetOpenGLState(); #else #warning Resetting OpenGL state requires Qt 5.2 or later #endif // Clear window if painting below the scenegraph if (mWinInfo.needsBelowClear()) { QColor bg = mWindow->color(); mGLClearColorFn(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); mGLClearFn(GL_COLOR_BUFFER_BIT); } // Setup prior to paint callback QMatrix4x4 matrix; bool inlineMode = HsQMLCanvas::Inline == mDisplayMode; if (inlineMode) { if (!mFBO->bind()) { setStatus(HsQMLCanvas::BadBind); return; } mGLViewportFn(0, 0, qCeil(mCanvasWidth), qCeil(mCanvasHeight)); // Clear FBO to transparent mGLClearColorFn(0, 0, 0, 0); mGLClearFn(GL_COLOR_BUFFER_BIT); } else { // Calculate matrix for non-inline display modes QMatrix4x4 smatrix; QSGNode* node = mTransformNode; while (node) { if (QSGNode::TransformNodeType == node->type()) { QSGTransformNode* tnode = static_cast<QSGTransformNode*>(node); smatrix = tnode->matrix() * smatrix; } node = node->parent(); } matrix.translate(-1, 1); matrix.scale(2.0f/mWindow->width(), -2.0f/mWindow->height()); matrix *= smatrix; matrix.scale(mItemWidth/2.0f, mItemHeight/2.0f); matrix.translate(1, 1); mGLViewportFn(0, 0, mWindow->width(), mWindow->height()); } setStatus(HsQMLCanvas::Okay); mGLCallbacks->mPaintCb(matrix.data(), mItemWidth, mItemHeight); if (inlineMode) { mFBO->release(); } }
void QSGNodeVisitor::visitChildren(QSGNode *n) { for (QSGNode *c = n->firstChild(); c; c = c->nextSibling()) visitNode(c); }
void SSGQuickLayer::grab() { if (!m_item || m_size.isNull()) { delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_depthStencilBuffer.clear(); m_dirtyTexture = false; return; } QSGNode *root = m_item; while (root->firstChild() && root->type() != QSGNode::RootNodeType) root = root->firstChild(); if (root->type() != QSGNode::RootNodeType) return; if (!m_renderer) { m_renderer = m_context->createRenderer(); connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture())); } m_renderer->setDevicePixelRatio(m_device_pixel_ratio); m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); bool deleteFboLater = false; if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format || (!m_fbo->format().mipmap() && m_mipmap)) { if (!m_multisamplingChecked) { if (m_context->openglContext()->format().samples() <= 1) { m_multisampling = false; } else { const QSet<QByteArray> extensions = m_context->openglContext()->extensions(); m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample")) && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit")); } m_multisamplingChecked = true; } if (m_multisampling) { // Don't delete the FBO right away in case it is used recursively. deleteFboLater = true; delete m_secondaryFbo; QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo); } } } if (m_recursive && !m_secondaryFbo) { // m_fbo already created, m_recursive was just set. Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } // Render texture. root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update. m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update. #ifdef QSG_DEBUG_FBO_OVERLAY if (qmlFboOverlay()) { if (!m_debugOverlay) m_debugOverlay = new QSGSimpleRectNode(); m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height())); m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40)); root->appendChildNode(m_debugOverlay); } #endif m_dirtyTexture = false; m_renderer->setDeviceRect(m_size); m_renderer->setViewportRect(m_size); QRectF mirrored(m_mirrorHorizontal ? m_rect.right() : m_rect.left(), m_mirrorVertical ? m_rect.bottom() : m_rect.top(), m_mirrorHorizontal ? -m_rect.width() : m_rect.width(), m_mirrorVertical ? -m_rect.height() : m_rect.height()); m_renderer->setProjectionMatrixToRect(mirrored); m_renderer->setClearColor(Qt::transparent); if (m_multisampling) { m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setAttachment(QOpenGLFramebufferObject::NoAttachment); format.setMipmap(m_mipmap); format.setSamples(0); m_fbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } QRect r(QPoint(), m_size); QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r); } else { if (m_recursive) { m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); m_fbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } qSwap(m_fbo, m_secondaryFbo); } else { m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data())); } } if (m_mipmap) { funcs->glBindTexture(GL_TEXTURE_2D, textureId()); funcs->glGenerateMipmap(GL_TEXTURE_2D); } root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update. #ifdef QSG_DEBUG_FBO_OVERLAY if (qmlFboOverlay()) root->removeChildNode(m_debugOverlay); #endif if (m_recursive) markDirtyTexture(); // Continuously update if 'live' and 'recursive'. }