← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~mrqtros/ubuntu-docviewer-app/docviewer-sg-rendering into lp:ubuntu-docviewer-app/reboot

 

Roman Shchekin has proposed merging lp:~mrqtros/ubuntu-docviewer-app/docviewer-sg-rendering into lp:ubuntu-docviewer-app/reboot.

Commit message:
Multithreaded rendering.

Requested reviews:
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)

For more details, see:
https://code.launchpad.net/~mrqtros/ubuntu-docviewer-app/docviewer-sg-rendering/+merge/270157

SceneGraph rendering (via QQuickItem and QSGSimpleTextureNode) instead of direct painting (via QQuickPaintedItem). 
-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~mrqtros/ubuntu-docviewer-app/docviewer-sg-rendering into lp:ubuntu-docviewer-app/reboot.
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot	2015-08-04 16:01:37 +0000
+++ po/com.ubuntu.docviewer.pot	2015-09-04 10:33:13 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-07-12 21:23+0200\n"
+"POT-Creation-Date: 2015-09-02 14:29+0300\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -33,7 +33,7 @@
 msgstr ""
 
 #: ../src/app/docviewer-application.cpp:171
-#: /home/stefano/Progetti/docviewer/Libreoffice/build-lo-tiled-rendering-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+#: /home/qtros/dev/build-DocViewer-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
 msgid "Document Viewer"
 msgstr ""
 
@@ -149,32 +149,33 @@
 msgid "%1 byte"
 msgstr ""
 
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:28
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:36
 msgid "Delete file"
 msgstr ""
 
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:29
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:37
 #, qt-format
 msgid "Delete %1 file"
 msgid_plural "Delete %1 files"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:30
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:31
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:38
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:39
 msgid "Are you sure you want to permanently delete this file?"
 msgid_plural "Are you sure you want to permanently delete these files?"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:36
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:44
 #: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:27
 #: ../src/app/qml/loView/LOViewGotoDialog.qml:52
 #: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:52
 msgid "Cancel"
 msgstr ""
 
-#: ../src/app/qml/documentPage/DeleteFileDialog.qml:41
+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:49
+#: ../src/app/qml/documentPage/DocumentDelegateActions.qml:25
 #: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:82
 msgid "Delete"
 msgstr ""
@@ -191,47 +192,35 @@
 
 #. TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
 #. http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
-#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:35
+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:32
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:37
 #, qt-format
 msgid "Today, %1"
 msgstr ""
 
 #. TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
 #. http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
-#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:40
+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:37
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:42
 #, qt-format
 msgid "Yesterday, %1"
 msgstr ""
 
 #. TRANSLATORS: this is a datetime formatting string,
 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:45
+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:42
 #: ../src/app/qml/documentPage/DocumentListDelegate.qml:58
 msgid "dddd, hh:mm"
 msgstr ""
 
 #. TRANSLATORS: this is a datetime formatting string,
 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:49
+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:46
 #: ../src/app/qml/documentPage/DocumentListDelegate.qml:47
 #: ../src/app/qml/documentPage/DocumentListDelegate.qml:63
 msgid "dd-MM-yyyy hh:mm"
 msgstr ""
 
-#. TRANSLATORS: this is a datetime formatting string, and the
-#. singlequote is an escape character.
-#. See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:36
-msgid "'Today', hh:mm"
-msgstr ""
-
-#. TRANSLATORS: this is a datetime formatting string, and the
-#. singlequote is an escape character.
-#. See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:42
-msgid "'Yesterday', hh:mm"
-msgstr ""
-
 #: ../src/app/qml/documentPage/DocumentListView.qml:157
 msgid "Today"
 msgstr ""
@@ -414,6 +403,6 @@
 msgid "Open"
 msgstr ""
 
-#: /home/stefano/Progetti/docviewer/Libreoffice/build-lo-tiled-rendering-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+#: /home/qtros/dev/build-DocViewer-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
 msgid "documents;viewer;pdf;reader;"
 msgstr ""

=== modified file 'src/app/CMakeLists.txt'
--- src/app/CMakeLists.txt	2015-04-29 16:06:32 +0000
+++ src/app/CMakeLists.txt	2015-09-04 10:33:13 +0000
@@ -19,7 +19,7 @@
 
 add_executable(ubuntu-docviewer-app ${docviewer_SRCS})
 
-qt5_use_modules(ubuntu-docviewer-app Widgets Gui Qml Quick DBus)
+qt5_use_modules(ubuntu-docviewer-app Widgets Gui Qml Quick DBus Concurrent)
 
 target_link_libraries( ubuntu-docviewer-app
     ${CONTENTHUB_LIBRARIES}

=== modified file 'src/app/command-line-parser.cpp'
--- src/app/command-line-parser.cpp	2015-04-29 15:23:32 +0000
+++ src/app/command-line-parser.cpp	2015-09-04 10:33:13 +0000
@@ -30,8 +30,8 @@
 
 CommandLineParser::CommandLineParser()
     : m_pickMode(false),
+      m_isFullscreen(false),
       m_testability(false),
-      m_isFullscreen(false),
       m_documentFile(""),
       m_documentsDir("")
 {

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt'
--- src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt	2015-08-25 22:35:28 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/CMakeLists.txt	2015-09-04 10:33:13 +0000
@@ -13,6 +13,7 @@
     lodocument.cpp
     loview.cpp
     tileitem.cpp
+    sgtileitem.cpp
     ${QML_SRCS}
 )
 
@@ -20,6 +21,7 @@
 set(libreofficetoolkitqmlplugin_HDRS
     twips.h
     config.h
+    sgtileitem.h
 )
 
 add_library(libreofficetoolkitqmlplugin MODULE

=== added file 'src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml	1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml	2015-09-04 10:33:13 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.4
+import DocumentViewer.LibreOffice 1.0 as LibreOffice
+
+Flickable {
+    id: rootFlickable
+
+    property alias document:    view.document
+    property alias zoomFactor:  view.zoomFactor
+    property alias cacheBuffer: view.cacheBuffer
+
+    contentHeight: view.height * view.zoomFactor
+    contentWidth: view.width * view.zoomFactor
+
+    boundsBehavior: Flickable.StopAtBounds
+
+    LibreOffice.View {
+        id: view
+
+        parentFlickable: rootFlickable
+    }
+}

=== removed file 'src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml'
--- src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml	2015-07-26 17:33:51 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/LOViewer.qml	1970-01-01 00:00:00 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-import QtQuick 2.4
-import DocumentViewer.LibreOffice 1.0 as LibreOffice
-
-Flickable {
-    id: rootFlickable
-
-    property alias document:    view.document
-    property alias zoomFactor:  view.zoomFactor
-    property alias cacheBuffer: view.cacheBuffer
-
-    contentHeight: view.height * view.zoomFactor
-    contentWidth: view.width * view.zoomFactor
-
-    boundsBehavior: Flickable.StopAtBounds
-
-    LibreOffice.View {
-        id: view
-
-        parentFlickable: rootFlickable
-    }
-}

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp	2015-07-23 01:05:20 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp	2015-09-04 10:33:13 +0000
@@ -28,6 +28,10 @@
 
 // TODO: Error management
 
+#ifdef DEBUG_TILE_BENCHMARK
+#include <QElapsedTimer>
+#endif
+
 lok::Office *LODocument::s_office = nullptr;
 
 LODocument::LODocument()
@@ -105,6 +109,12 @@
 QImage LODocument::paintTile(QSize canvasSize, QRect tileSize)
 {
     QImage result = QImage(canvasSize.width(), canvasSize.height(),  QImage::Format_RGB32);
+
+#ifdef DEBUG_TILE_BENCHMARK
+    QElapsedTimer renderTimer;
+    renderTimer.start();
+#endif
+
     m_document->paintTile(result.bits(),
                           canvasSize.width(), canvasSize.height(),
                           Twips::convertPixelsToTwips(tileSize.x()),
@@ -112,6 +122,10 @@
                           Twips::convertPixelsToTwips(tileSize.width()),
                           Twips::convertPixelsToTwips(tileSize.height()));
 
+#ifdef DEBUG_TILE_BENCHMARK
+    qDebug() << "Time to render the tile:" << renderTimer.elapsed() << "ms";
+#endif
+
     return result.rgbSwapped();
 }
 

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-07-26 17:33:51 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-09-04 10:33:13 +0000
@@ -17,6 +17,7 @@
 #include "loview.h"
 #include "lodocument.h"
 #include "tileitem.h"
+#include "sgtileitem.h"
 #include "twips.h"
 #include "config.h"
 
@@ -29,7 +30,7 @@
 // updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * data)
 
 LOView::LOView(QQuickItem *parent)
-    : QQuickPaintedItem(parent)
+    : QQuickItem(parent) //QQuickPaintedItem(parent)
     , m_parentFlickable(nullptr)
     , m_document(nullptr)
     , m_zoomFactor(1.0)
@@ -46,17 +47,17 @@
     connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateVisibleRect()));
 }
 
-void LOView::paint(QPainter *painter)
-{
-    Q_FOREACH(TileItem* tile, m_tiles) {
-        painter->drawImage(tile->area(), tile->texture());
-        tile->setPainted(true);
+//void LOView::paint(QPainter *painter)
+//{
+//    Q_FOREACH(TileItem* tile, m_tiles) {
+//        painter->drawImage(tile->area(), tile->texture());
+//        tile->setPainted(true);
 
-#ifdef DEBUG_SHOW_TILE_BORDER
-        painter->drawRect(tile->area());
-#endif
-    }
-}
+//#ifdef DEBUG_SHOW_TILE_BORDER
+//        painter->drawRect(tile->area());
+//#endif
+//    }
+//}
 
 // Returns the parent QML Flickable
 QQuickItem* LOView::parentFlickable() const
@@ -170,18 +171,21 @@
     if (!m_tiles.isEmpty()) {
         auto i = m_tiles.begin();
         while (i != m_tiles.end()) {
-            TileItem* tile = i.value();
-
-            if (!m_bufferArea.intersects(tile->area())) {
-                tile->releaseTexture();
-                i = m_tiles.erase(i);
-
-#ifdef DEBUG_VERBOSE
-                qDebug() << "Removing tile indexed as" << i.key();
-#endif
-            } else {
-                ++i;
+            SGTileItem* sgtile = i.value();
+
+            // Ok - we still need this item.
+            if (m_bufferArea.intersects(sgtile->area())) {
+                i++;
+                continue;
             }
+
+            // Out of buffer - we should delete this item.
+#ifdef DEBUG_VERBOSE
+            qDebug() << "Removing tile indexed as" << i.key();
+#endif
+
+            sgtile->dispose();
+            i = m_tiles.erase(i);
         }
     }
 
@@ -223,9 +227,9 @@
         qDebug() << "Creating tile indexed as" << index;
 #endif
 
-        auto tile = new TileItem(rect, m_document);
-        connect(tile, SIGNAL(textureChanged()), this, SLOT(update()));
-        tile->requestTexture();
+        auto tile = new SGTileItem(rect, m_document, this);
+        // TODO When we should update with SG?
+        // connect(tile, SIGNAL(textureChanged()), this, SLOT(update()));
 
         // Append the tile in the map
         m_tiles.insert(index, tile);

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.h'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-07-26 17:33:51 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-09-04 10:33:13 +0000
@@ -18,12 +18,14 @@
 #define LOVIEW_H
 
 #include <QQuickPaintedItem>
+#include <QQuickItem>
 #include <QTimer>
 
 class LODocument;
 class TileItem;
+class SGTileItem;
 
-class LOView : public QQuickPaintedItem
+class LOView : public QQuickItem // QQuickPaintedItem
 {
     Q_OBJECT
     Q_PROPERTY(QQuickItem* parentFlickable READ parentFlickable WRITE setParentFlickable NOTIFY parentFlickableChanged)
@@ -37,7 +39,7 @@
     LOView(QQuickItem *parent = 0);
     ~LOView();
 
-    void        paint(QPainter *painter);
+//    void        paint(QPainter *painter);
 
     QQuickItem* parentFlickable() const;
     void        setParentFlickable(QQuickItem* flickable);
@@ -74,7 +76,7 @@
 
     QTimer                  m_updateTimer;
 
-    QMap<int, TileItem*>    m_tiles;
+    QMap<int, SGTileItem*>    m_tiles;
 
     void                    generateTiles(int x1, int y1, int x2, int y2, int tilesPerWidth);
     void                    createTile(int index, QRect rect);

=== added file 'src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp	1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.cpp	2015-09-04 10:33:13 +0000
@@ -0,0 +1,73 @@
+#include "sgtileitem.h"
+
+#include "lodocument.h"
+#include "config.h"
+
+SGTileItem::SGTileItem(const QRect &area, LODocument *document, QQuickItem *parent)
+    : QQuickItem(parent)
+    , m_area(area)
+    , m_document(document)
+    , m_state(SgstInitial)
+{
+    setFlag(ItemHasContents, true);
+}
+
+SGTileItem::~SGTileItem()
+{ }
+
+void SGTileItem::dispose()
+{
+    if (m_state.loadAcquire() != SgstRendering)
+        deleteLater();
+    m_state.storeRelease(SgstDisposed);
+    // qDebug() << "---- dispose called: " << this << m_state;
+}
+
+QSGNode *SGTileItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+    QSGSimpleTextureNode* node = static_cast<QSGSimpleTextureNode*>(oldNode);
+    QQuickWindow* wnd = window();
+
+    if (!node && wnd) {
+        if (this->m_state.loadAcquire() == SgstInitial) {
+            m_state.storeRelease(SgstRendering);
+            QtConcurrent::run( [=] {
+
+                QImage img;
+
+                // By this time already can be disposed, so it's better to ckeck again.
+                if (this->m_state.loadAcquire() == SgstRendering)
+                    img = m_document->paintTile(this->area().size(), this->area());
+
+                if (this->m_state.loadAcquire() == SgstDisposed)
+                    qDebug() << "Already disposed:" << m_state.loadAcquire();
+                QMetaObject::invokeMethod(this, "renderCallback", Q_ARG(QImage, img));
+
+            });
+        } else if (m_state.loadAcquire() == SgstActive) {
+            QImage image = m_data;
+            auto texture = wnd->createTextureFromImage(image);
+            node = new QSGSimpleTextureNode();
+            node->setTexture(texture);
+            node->setOwnsTexture(true);
+            node->setRect(m_area);
+        }
+    }
+
+    return node;
+}
+
+void SGTileItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+    QQuickItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void SGTileItem::renderCallback(QImage image)
+{
+    if (m_state.loadAcquire() == SgstRendering) {
+        m_data = image;
+        m_state.storeRelease(SgstActive);
+        update();
+    } else deleteLater();
+}
+

=== added file 'src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h'
--- src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h	1970-01-01 00:00:00 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/sgtileitem.h	2015-09-04 10:33:13 +0000
@@ -0,0 +1,54 @@
+#ifndef SGTILEITEM_H
+#define SGTILEITEM_H
+
+#include <QQuickItem>
+#include <QQuickWindow>
+#include <QSGSimpleTextureNode>
+#include <QImage>
+#include <QtConcurrent/QtConcurrent>
+#include <QAtomicInteger>
+
+enum SGTileItemState
+{
+    SgstInitial = 1,
+    SgstRendering,
+    SgstActive,
+    SgstDisposed
+};
+
+class LODocument;
+
+class SGTileItem : public QQuickItem
+{
+    Q_OBJECT
+public:
+    SGTileItem(const QRect &area, LODocument *document, QQuickItem *parent = 0);
+    ~SGTileItem();
+
+    inline QRect area() const { return m_area; }
+    inline void setArea(const QRect &area) { m_area = area; }
+
+    inline LODocument* document() const { return m_document; }
+    inline void setDocument(LODocument* document) { m_document = document; }
+
+    void dispose();
+
+protected:
+    virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+    virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+
+private:
+    Q_INVOKABLE void renderCallback(QImage image);
+
+signals:
+
+private:
+    QRect m_area;
+    LODocument* m_document;
+    QImage m_data;
+    QAtomicInteger<int> m_state;
+
+public slots:
+};
+
+#endif // SGTILEITEM_H

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/tileitem.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/tileitem.cpp	2015-07-22 16:44:39 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/tileitem.cpp	2015-09-04 10:33:13 +0000
@@ -160,12 +160,16 @@
 // Render the texture for this tile.
 void RenderTask::run()
 {
+    // Can cause crash if document is nullptr.
+    if (!m_document)
+        return;
+
 #ifdef DEBUG_TILE_BENCHMARK
     QElapsedTimer renderTimer;
     renderTimer.start();
 #endif
 
-    QImage render = this->document()->paintTile(this->area().size(),
+    QImage render = m_document->paintTile(this->area().size(),
                                                 this->area());
 
     Q_EMIT renderCompleted(render);


Follow ups