aboutsummaryrefslogtreecommitdiffstats
path: root/softwarecontext/renderloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'softwarecontext/renderloop.cpp')
-rw-r--r--softwarecontext/renderloop.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/softwarecontext/renderloop.cpp b/softwarecontext/renderloop.cpp
new file mode 100644
index 0000000000..fd5137e945
--- /dev/null
+++ b/softwarecontext/renderloop.cpp
@@ -0,0 +1,230 @@
+#include "renderloop.h"
+
+#include "context.h"
+#include <private/qquickwindow_p.h>
+#include <QElapsedTimer>
+#include <private/qquickprofiler_p.h>
+
+// Used for very high-level info about the renderering and gl context
+// Includes GL_VERSION, type of render loop, atlas size, etc.
+Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.info")
+
+// Used to debug the renderloop logic. Primarily useful for platform integrators
+// and when investigating the render loop logic.
+Q_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP, "qt.scenegraph.renderloop")
+
+
+// GLSL shader compilation
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION, "qt.scenegraph.time.compilation")
+
+// polish, animations, sync, render and swap in the render loop
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop")
+
+// Texture uploads and swizzling
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_TEXTURE, "qt.scenegraph.time.texture")
+
+// Glyph preparation (only for distance fields atm)
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
+
+// Timing inside the renderer base class
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
+
+RenderLoop::RenderLoop()
+ : eventPending(false)
+{
+ sg = QSGContext::createDefaultContext();
+ rc = sg->createRenderContext();
+}
+
+RenderLoop::~RenderLoop()
+{
+ delete rc;
+ delete sg;
+}
+
+void RenderLoop::show(QQuickWindow *window)
+{
+ WindowData data;
+ data.updatePending = false;
+ data.grabOnly = false;
+ m_windows[window] = data;
+
+ maybeUpdate(window);
+}
+
+void RenderLoop::hide(QQuickWindow *window)
+{
+ if (!m_windows.contains(window))
+ return;
+
+ m_windows.remove(window);
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ cd->fireAboutToStop();
+ cd->cleanupNodesOnShutdown();
+
+ if (m_windows.size() == 0) {
+ if (!cd->persistentSceneGraph) {
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+ }
+}
+
+void RenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ hide(window);
+ if (m_windows.size() == 0) {
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+}
+
+void RenderLoop::renderWindow(QQuickWindow *window)
+{
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (!cd->isRenderable() || !m_windows.contains(window))
+ return;
+
+ WindowData &data = const_cast<WindowData &>(m_windows[window]);
+
+ // ### create QPainter and set up pointer to current window/painter
+ static_cast<SoftwareContext::RenderContext*>(cd->context)->currentWindow = window;
+
+ bool alsoSwap = data.updatePending;
+ data.updatePending = false;
+
+ if (!data.grabOnly) {
+ cd->flushDelayedTouchEvent();
+ // 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_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::enabled;
+ if (profileFrames)
+ renderTimer.start();
+
+ cd->polishItems();
+
+ if (profileFrames) {
+ polishTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishFrame, (polishTime));
+ }
+
+ emit window->afterAnimating();
+
+ cd->syncSceneGraph();
+
+ if (profileFrames)
+ syncTime = renderTimer.nsecsElapsed();
+
+ cd->renderSceneGraph(window->size());
+
+ if (profileFrames)
+ renderTime = renderTimer.nsecsElapsed();
+
+ if (data.grabOnly) {
+ // #### grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
+ data.grabOnly = false;
+ }
+
+ if (alsoSwap && window->isVisible()) {
+// ### gl->swapBuffers(window);
+ cd->fireFrameSwapped();
+ }
+
+ qint64 swapTime = 0;
+ if (profileFrames)
+ swapTime = renderTimer.nsecsElapsed();
+
+ if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
+ static QTime lastFrameTime = QTime::currentTime();
+ qCDebug(QSG_LOG_TIME_RENDERLOOP,
+ "Frame rendered with 'basic' 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();
+ }
+
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, (
+ syncTime - polishTime,
+ renderTime - syncTime,
+ swapTime - renderTime));
+
+ // Might have been set during syncSceneGraph()
+ if (data.updatePending)
+ maybeUpdate(window);
+}
+
+void RenderLoop::exposureChanged(QQuickWindow *window)
+{
+ if (window->isExposed()) {
+ m_windows[window].updatePending = true;
+ renderWindow(window);
+ }
+}
+
+QImage RenderLoop::grab(QQuickWindow *window)
+{
+ if (!m_windows.contains(window))
+ return QImage();
+
+ m_windows[window].grabOnly = true;
+
+ renderWindow(window);
+
+ QImage grabbed = grabContent;
+ grabContent = QImage();
+ return grabbed;
+}
+
+
+
+void RenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ if (!m_windows.contains(window))
+ return;
+
+ m_windows[window].updatePending = true;
+
+ if (!eventPending) {
+ const int exhaust_delay = 5;
+ m_update_timer = startTimer(exhaust_delay, Qt::PreciseTimer);
+ eventPending = true;
+ }
+}
+
+QSurface::SurfaceType RenderLoop::windowSurfaceType() const
+{
+ return QSurface::RasterSurface;
+}
+
+
+
+QSGContext *RenderLoop::sceneGraphContext() const
+{
+ return sg;
+}
+
+
+bool RenderLoop::event(QEvent *e)
+{
+ if (e->type() == QEvent::Timer) {
+ eventPending = false;
+ killTimer(m_update_timer);
+ m_update_timer = 0;
+ for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
+ it != m_windows.constEnd(); ++it) {
+ const WindowData &data = it.value();
+ if (data.updatePending)
+ renderWindow(it.key());
+ }
+ return true;
+ }
+ return QObject::event(e);
+}