/* QQuickWindow does event compression and only delivers events just * before it is about to render the next frame. Since some tests * rely on events being delivered immediately AND that no other * event processing has occurred in the meanwhile, we flush the * event manually and immediately. */ void flush(QQuickWindow *window) { if (!window) return; QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); if (!wd || !wd->delayedTouch) return; wd->deliverDelayedTouchEvent(); }
/* QQuickWindow does event compression and only delivers events just * before it is about to render the next frame. Since some tests * rely on events being delivered immediately AND that no other * event processing has occurred in the meanwhile, we flush the * event manually and immediately. */ void flush(QQuickWindow *window) { if (!window) return; QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); if (!wd || !wd->delayedTouch) return; wd->reallyDeliverTouchEvent(wd->delayedTouch); delete wd->delayedTouch; wd->delayedTouch = 0; }
void QQuickTrivialWindowManager::hide(QQuickWindow *window) { if (!m_windows.contains(window)) return; m_windows.remove(window); QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); cd->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { sg->invalidate(); delete gl; gl = 0; } }
void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window) { m_windows.remove(window); delete m_backingStores[window]; m_backingStores.remove(window); hide(window); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); d->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { rc->invalidate(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); } }
QImage QSGWindowsRenderLoop::grab(QQuickWindow *window) { RLDEBUG("grab"); if (!m_gl) return QImage(); m_gl->makeCurrent(window); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); d->polishItems(); d->syncSceneGraph(); d->renderSceneGraph(window->size()); QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false); return image; }
QImage QSGWindowsRenderLoop::grab(QQuickWindow *window) { RLDEBUG("grab"); if (!m_gl) return QImage(); m_gl->makeCurrent(window); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); d->polishItems(); d->syncSceneGraph(); d->renderSceneGraph(window->size()); bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255; QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha); return image; }
void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) { RLDEBUG("windowDestroyed"); for (int i=0; i<m_windows.size(); ++i) { if (m_windows.at(i).window == window) { m_windows.removeAt(i); break; } } hide(window); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); bool current = false; QScopedPointer<QOffscreenSurface> offscreenSurface; if (m_gl) { QSurface *surface = window; // There may be no platform window if the window got closed. if (!window->handle()) { offscreenSurface.reset(new QOffscreenSurface); offscreenSurface->setFormat(m_gl->format()); offscreenSurface->create(); surface = offscreenSurface.data(); } current = m_gl->makeCurrent(surface); } if (Q_UNLIKELY(!current)) qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context"; QQuickShaderEffectMaterial::cleanupMaterialCache(); d->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { d->context->invalidate(); delete m_gl; m_gl = 0; } else if (m_gl && current) { m_gl->doneCurrent(); } delete d->animationController; }
void QSGWindowsRenderLoop::hide(QQuickWindow *window) { RLDEBUG("hide"); for (int i=0; i<m_windows.size(); ++i) { if (m_windows.at(i).window == window) { m_windows.removeAt(i); break; } } // The expose event is queued while hide is sent synchronously, so // the value might not be updated yet. (plus that the windows plugin // sends exposed=true when it goes to hidden, so it is doubly broken) // The check is made here, after the removal from m_windows, so // anyoneShowing will report the right value. if (window->isExposed()) handleObscurity(); if (!m_gl) return; QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); m_gl->makeCurrent(window); cd->cleanupNodesOnShutdown(); // If this is the last tracked window, check for persistent SG and GL and // potentially clean up. if (m_windows.size() == 0) { if (!cd->persistentSceneGraph) { QQuickWindowPrivate::get(window)->context->invalidate(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); if (!cd->persistentGLContext) { delete m_gl; m_gl = 0; } } } }
/* * 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)) return; QSG_RENDER_TIMING_SAMPLE(time_start); RLDEBUG(" - polishing"); d->polishItems(); QSG_RENDER_TIMING_SAMPLE(time_polished); RLDEBUG(" - syncing"); d->syncSceneGraph(); QSG_RENDER_TIMING_SAMPLE(time_synced); RLDEBUG(" - rendering"); d->renderSceneGraph(window->size()); QSG_RENDER_TIMING_SAMPLE(time_rendered); RLDEBUG(" - swapping"); m_gl->swapBuffers(window); QSG_RENDER_TIMING_SAMPLE(time_swapped); RLDEBUG(" - frameDone"); d->fireFrameSwapped(); #ifndef QSG_NO_RENDER_TIMING if (qsg_render_timing) { qDebug("WindowsRenderLoop(t=%d): window=%p, polish=%d ms, sync=%d ms, render=%d ms, swap=%d ms", int(qsg_render_timer.elapsed()), window, int((time_polished - time_start)/1000000), int((time_synced - time_polished)/1000000), int((time_rendered - time_synced)/1000000), int((time_swapped - time_rendered)/1000000)); } if (QQmlProfilerService::enabled) { QQmlProfilerService::sceneGraphFrame( QQmlProfilerService::SceneGraphWindowsPolishFrame, time_polished - time_start ); QQmlProfilerService::sceneGraphFrame( QQmlProfilerService::SceneGraphRenderLoopFrame, time_synced - time_polished, time_rendered - time_synced, time_swapped - time_rendered ); } #endif }
/* * 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 QQuickTrivialWindowManager::renderWindow(QQuickWindow *window) { bool renderWithoutShowing = QQuickWindowPrivate::get(window)->renderWithoutShowing; if ((!window->isExposed() && !renderWithoutShowing) || !m_windows.contains(window)) return; WindowData &data = const_cast<WindowData &>(m_windows[window]); QQuickWindow *masterWindow = 0; if (!window->isVisible() && !renderWithoutShowing) { // Find a "proper surface" to bind... for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin(); it != m_windows.constEnd() && !masterWindow; ++it) { if (it.key()->isVisible()) masterWindow = it.key(); } } else { masterWindow = window; } if (!masterWindow) return; if (!QQuickWindowPrivate::get(masterWindow)->isRenderable()) { qWarning().nospace() << "Unable to find a renderable master window " << masterWindow << "when trying to render" << window << " (" << window->geometry() << ")."; return; } if (!gl) { gl = new QOpenGLContext(); gl->setFormat(masterWindow->requestedFormat()); gl->create(); if (!gl->makeCurrent(masterWindow)) qWarning("QQuickWindow: makeCurrent() failed..."); sg->initialize(gl); } else { gl->makeCurrent(masterWindow); } bool alsoSwap = data.updatePending; data.updatePending = false; QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); cd->polishItems(); int renderTime = 0, syncTime = 0; QTime renderTimer; if (qquick_render_timing()) renderTimer.start(); cd->syncSceneGraph(); if (qquick_render_timing()) syncTime = renderTimer.elapsed(); cd->renderSceneGraph(window->size()); if (qquick_render_timing()) renderTime = renderTimer.elapsed() - syncTime; if (data.grabOnly) { grabContent = qt_gl_read_framebuffer(window->size(), false, false); data.grabOnly = false; } if (alsoSwap && window->isVisible()) { gl->swapBuffers(window); cd->fireFrameSwapped(); } if (qquick_render_timing()) { static QTime lastFrameTime = QTime::currentTime(); const int swapTime = renderTimer.elapsed() - renderTime - syncTime; qDebug() << "- Breakdown of frame time; sync:" << syncTime << "ms render:" << renderTime << "ms swap:" << swapTime << "ms total:" << swapTime + renderTime + syncTime << "ms time since last frame:" << (lastFrameTime.msecsTo(QTime::currentTime())) << "ms"; lastFrameTime = QTime::currentTime(); } // Might have been set during syncSceneGraph() if (data.updatePending) maybeUpdate(window); }
void QSGSoftwareRenderLoop::hide(QQuickWindow *window) { QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); cd->fireAboutToStop(); }
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); }