void QSGDistanceFieldGlyphCache::update() { m_populatingGlyphs.clear(); if (m_pendingGlyphs.isEmpty()) return; bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled(); if (profileFrames) qsg_render_timer.start(); Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame); QList<QDistanceField> distanceFields; for (int i = 0; i < m_pendingGlyphs.size(); ++i) { GlyphData &gd = glyphData(m_pendingGlyphs.at(i)); distanceFields.append(QDistanceField(gd.path, m_pendingGlyphs.at(i), m_doubleGlyphResolution)); gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path } qint64 renderTime = 0; int count = m_pendingGlyphs.size(); if (profileFrames) renderTime = qsg_render_timer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame); m_pendingGlyphs.reset(); storeGlyphs(distanceFields); #if defined(QSG_DISTANCEFIELD_CACHE_DEBUG) foreach (Texture texture, m_textures) saveTexture(texture.textureId, texture.size.width(), texture.size.height()); #endif if (QSG_LOG_TIME_GLYPH().isDebugEnabled()) { quint64 now = qsg_render_timer.elapsed(); qCDebug(QSG_LOG_TIME_GLYPH, "distancefield: %d glyphs prepared in %dms, rendering=%d, upload=%d", count, (int) now, int(renderTime / 1000000), int((now - (renderTime / 1000000)))); } Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame, (qint64)count); }
/* * Go through all windows we control and render them in turn. * Then tick animations if active. */ void QSGWindowsRenderLoop::render() { RLDEBUG("render"); bool rendered = false; foreach (const WindowData &wd, m_windows) { if (wd.pendingUpdate) { const_cast<WindowData &>(wd).pendingUpdate = false; renderWindow(wd.window); rendered = true; } } if (!rendered) { RLDEBUG("no changes, sleep"); QThread::msleep(m_vsyncDelta); } if (m_animationDriver->isRunning()) { RLDEBUG("advancing animations"); QSG_LOG_TIME_SAMPLE(time_start); Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphWindowsAnimations); m_animationDriver->advance(); RLDEBUG("animations advanced"); qCDebug(QSG_LOG_TIME_RENDERLOOP, "animations ticked in %dms", int((qsg_render_timer.nsecsElapsed() - time_start)/1000000)); Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphWindowsAnimations); // It is not given that animations triggered another maybeUpdate() // and thus another render pass, so to keep things running, // make sure there is another frame pending. maybePostUpdateTimer(); emit timeToIncubate(); } }
/* * Render the contents of this window. First polish, then sync, render * then finally swap. * * Note: This render function does not implement aborting * the render call when sync step results in no scene graph changes, * like the threaded renderer does. */ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window) { RLDEBUG("renderWindow"); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); if (!d->isRenderable()) return; if (!m_gl->makeCurrent(window)) { // Check for context loss. if (!m_gl->isValid()) { d->cleanupNodesOnShutdown(); m_rc->invalidate(); if (m_gl->create() && m_gl->makeCurrent(window)) m_rc->initialize(m_gl); else return; } } d->flushDelayedTouchEvent(); // Event delivery or processing has caused the window to stop rendering. if (!windowData(window)) return; QSG_LOG_TIME_SAMPLE(time_start); Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame); RLDEBUG(" - polishing"); d->polishItems(); QSG_LOG_TIME_SAMPLE(time_polished); Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame, QQuickProfiler::SceneGraphRenderLoopFrame); emit window->afterAnimating(); RLDEBUG(" - syncing"); d->syncSceneGraph(); QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_synced); RLDEBUG(" - rendering"); d->renderSceneGraph(window->size()); QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_rendered); RLDEBUG(" - swapping"); if (!d->customRenderStage || !d->customRenderStage->swap()) m_gl->swapBuffers(window); QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_swapped); RLDEBUG(" - frameDone"); d->fireFrameSwapped(); qCDebug(QSG_LOG_TIME_RENDERLOOP()).nospace() << "Frame rendered with 'windows' renderloop in: " << (time_swapped - time_start) / 1000000 << "ms" << ", polish=" << (time_polished - time_start) / 1000000 << ", sync=" << (time_synced - time_polished) / 1000000 << ", render=" << (time_rendered - time_synced) / 1000000 << ", swap=" << (time_swapped - time_rendered) / 1000000 << " - " << window; Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphRenderLoopFrame); }
void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose) { QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); if (!m_windows.contains(window)) return; WindowData &data = const_cast<WindowData &>(m_windows[window]); //If were not in grabOnly mode, dont render a non-renderable window if (!data.grabOnly && !cd->isRenderable()) return; //Resize the backing store if necessary if (m_backingStores[window]->size() != window->size()) { m_backingStores[window]->resize(window->size()); } // ### create QPainter and set up pointer to current window/painter QSGSoftwareRenderContext *ctx = static_cast<QSGSoftwareRenderContext*>(cd->context); ctx->initializeIfNeeded(); bool alsoSwap = data.updatePending; data.updatePending = false; if (!data.grabOnly) { cd->flushFrameSynchronousEvents(); // Event delivery/processing triggered the window to be deleted or stop rendering. if (!m_windows.contains(window)) return; } QElapsedTimer renderTimer; qint64 renderTime = 0, syncTime = 0, polishTime = 0; bool profileFrames = QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled(); if (profileFrames) renderTimer.start(); Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame); cd->polishItems(); if (profileFrames) polishTime = renderTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame, QQuickProfiler::SceneGraphRenderLoopFrame, QQuickProfiler::SceneGraphPolishPolish); emit window->afterAnimating(); cd->syncSceneGraph(); rc->endSync(); if (profileFrames) syncTime = renderTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame, QQuickProfiler::SceneGraphRenderLoopSync); //Tell the renderer about the windows backing store auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer); if (softwareRenderer) softwareRenderer->setBackingStore(m_backingStores[window]); cd->renderSceneGraph(window->size()); if (profileFrames) renderTime = renderTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame, QQuickProfiler::SceneGraphRenderLoopRender); if (data.grabOnly) { grabContent = m_backingStores[window]->handle()->toImage(); data.grabOnly = false; } if (alsoSwap && window->isVisible()) { //Flush backingstore to window if (!isNewExpose) m_backingStores[window]->flush(softwareRenderer->flushRegion()); else m_backingStores[window]->flush(QRegion(QRect(QPoint(0,0), window->size()))); cd->fireFrameSwapped(); } qint64 swapTime = 0; if (profileFrames) swapTime = renderTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame, QQuickProfiler::SceneGraphRenderLoopSwap); if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) { static QTime lastFrameTime = QTime::currentTime(); qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP, "Frame rendered with 'software' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d", int(swapTime / 1000000), int(polishTime / 1000000), int((syncTime - polishTime) / 1000000), int((renderTime - syncTime) / 1000000), int((swapTime - renderTime) / 10000000), int(lastFrameTime.msecsTo(QTime::currentTime()))); lastFrameTime = QTime::currentTime(); } // Might have been set during syncSceneGraph() if (data.updatePending) maybeUpdate(window); }