summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Rahn <rahn@kde.org>2016-11-09 17:26:44 (GMT)
committerTorsten Rahn <trahn@testo.de>2016-11-09 18:02:37 (GMT)
commit0d3aedbb8a37a40d64ec158823604bbd0e0ace36 (patch)
treecf7e3f57aa953e8135d70c73742a6f5733812666
parent76edbd38835e4a81cf55cdaa628374a9c439a300 (diff)
Batch Rendering for placemark symbol pixmaps:
- Actually share identical pixmaps in memory - Cache them inside a dedicated QPixmapCache - Render identical symbols in a batch using QPainter::drawPixmapFragments() Batch rendering can be disabled via the BATCH_RENDERING define. The "O"-keystroke-debug mode is now extended by displaying a background color for each placemark. Placemarks rendered in parallel share the same background color. This should benefit rendering of huge amounts of pixmaps of the same kind (e.g. trees).
-rw-r--r--src/lib/marble/PlacemarkLayout.cpp2
-rw-r--r--src/lib/marble/VisiblePlacemark.cpp17
-rw-r--r--src/lib/marble/VisiblePlacemark.h12
-rw-r--r--src/lib/marble/layers/PlacemarkLayer.cpp83
-rw-r--r--src/lib/marble/layers/PlacemarkLayer.h9
5 files changed, 112 insertions, 11 deletions
diff --git a/src/lib/marble/PlacemarkLayout.cpp b/src/lib/marble/PlacemarkLayout.cpp
index b6cfb5c..fb933e6 100644
--- a/src/lib/marble/PlacemarkLayout.cpp
+++ b/src/lib/marble/PlacemarkLayout.cpp
@@ -290,7 +290,7 @@ void PlacemarkLayout::resetCacheData()
QSet<TileId> PlacemarkLayout::visibleTiles( const ViewportParams *viewport )
{
- int zoomLevel = qLn( viewport->radius() *4 / 256 ) / qLn( 2.0 );
+ int zoomLevel = qLn( viewport->radius()/64.0 ) / qLn( 2.0 );
/*
* rely on m_placemarkCache to find the placemarks for the tiles which
diff --git a/src/lib/marble/VisiblePlacemark.cpp b/src/lib/marble/VisiblePlacemark.cpp
index 15dd6c7..6280a9f 100644
--- a/src/lib/marble/VisiblePlacemark.cpp
+++ b/src/lib/marble/VisiblePlacemark.cpp
@@ -47,9 +47,20 @@ const GeoDataPlacemark* VisiblePlacemark::placemark() const
const QPixmap& VisiblePlacemark::symbolPixmap() const
{
+ if (!m_symbolId.isEmpty() && m_symbolPixmap.isNull()) {
+ if ( !m_symbolCache.find( m_symbolId, &m_symbolPixmap ) ) {
+ m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon());
+ m_symbolCache.insert( m_symbolId, m_symbolPixmap);
+ }
+ }
return m_symbolPixmap;
}
+const QString& VisiblePlacemark::symbolId() const
+{
+ return m_symbolId;
+}
+
bool VisiblePlacemark::selected() const
{
return m_selected;
@@ -120,7 +131,11 @@ const QPixmap& VisiblePlacemark::labelPixmap()
void VisiblePlacemark::setSymbolPixmap()
{
if (m_style) {
- m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon() );
+ m_symbolId = m_style->iconStyle().iconPath() + QString::number(m_style->iconStyle().scale());
+ if (m_style->iconStyle().iconPath().isEmpty()) {
+ m_symbolId.clear();
+ m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon());
+ }
emit updateNeeded();
}
else {
diff --git a/src/lib/marble/VisiblePlacemark.h b/src/lib/marble/VisiblePlacemark.h
index f0eff24..0dd109a 100644
--- a/src/lib/marble/VisiblePlacemark.h
+++ b/src/lib/marble/VisiblePlacemark.h
@@ -20,6 +20,7 @@
#include <QPixmap>
#include <QPoint>
#include <QRectF>
+#include <QPixmapCache>
#include <GeoDataStyle.h>
#include <GeoDataCoordinates.h>
@@ -56,6 +57,11 @@ class VisiblePlacemark : public QObject
const QPixmap& symbolPixmap() const;
/**
+ * Returns the id for the place mark symbol.
+ */
+ const QString& symbolId() const;
+
+ /**
* Returns the state of the place mark.
*/
bool selected() const;
@@ -130,9 +136,13 @@ private Q_SLOTS:
bool m_labelDirty;
QRectF m_labelRect; // bounding box of label
- mutable QPixmap m_symbolPixmap; // cached value
GeoDataStyle::ConstPtr m_style;
GeoDataCoordinates m_coordinates;
+
+ mutable QPixmap m_symbolPixmap; // cached value
+ QString m_symbolId;
+
+ QPixmapCache m_symbolCache;
};
}
diff --git a/src/lib/marble/layers/PlacemarkLayer.cpp b/src/lib/marble/layers/PlacemarkLayer.cpp
index 9492d53..e92d23b 100644
--- a/src/lib/marble/layers/PlacemarkLayer.cpp
+++ b/src/lib/marble/layers/PlacemarkLayer.cpp
@@ -25,6 +25,8 @@
#include "VisiblePlacemark.h"
#include "RenderState.h"
+#define BATCH_RENDERING
+
using namespace Marble;
bool PlacemarkLayer::m_useXWorkaround = false;
@@ -69,8 +71,14 @@ bool PlacemarkLayer::render( GeoPainter *geoPainter, ViewportParams *viewport,
QVector<VisiblePlacemark*>::const_iterator itEnd = visiblePlacemarks.constBegin();
QPainter *const painter = geoPainter;
+
bool const repeatableX = viewport->currentProjection()->repeatableX();
int const radius4 = 4 * viewport->radius();
+
+#ifdef BATCH_RENDERING
+ QHash <QString, Fragment> hash;
+#endif
+
while ( visit != itEnd ) {
--visit;
@@ -78,7 +86,8 @@ bool PlacemarkLayer::render( GeoPainter *geoPainter, ViewportParams *viewport,
// Intentionally converting positions from floating point to pixel aligned screen grid below
QRect labelRect( mark->labelRect().toRect() );
- QPoint symbolPos(mark->symbolPosition().toPoint());
+ QPoint symbolPos( mark->symbolPosition().toPoint());
+ struct Fragment fragment;
// when the map is such zoomed out that a given place
// appears many times, we draw one placemark at each
@@ -90,16 +99,74 @@ bool PlacemarkLayer::render( GeoPainter *geoPainter, ViewportParams *viewport,
labelRect.moveLeft(i - symbolX + textX);
symbolPos.setX(i);
+ if (!mark->symbolPixmap().isNull()) {
+#ifdef BATCH_RENDERING
+ QRect symbolRect = mark->symbolPixmap().rect();
+ QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect));
+
+ QHash<QString, Fragment>::iterator i = hash.find(mark->symbolId());
+ if (i == hash.end()) {
+ fragment.count = 1;
+ fragment.pixmap = mark->symbolPixmap();
+ }
+ else {
+ fragment = i.value();
+ ++fragment.count;
+ }
+ fragment.fragments.append(pixmapFragment);
+ hash.insert(mark->symbolId(), fragment);
+#else
+ painter->drawPixmap( symbolPos, mark->symbolPixmap() );
+#endif
+ }
+ if (!mark->labelPixmap().isNull()) {
+ painter->drawPixmap( labelRect, mark->labelPixmap() );
+ }
+ }
+ } else { // simple case, one draw per placemark
+
+ if (!mark->symbolPixmap().isNull()) {
+#ifdef BATCH_RENDERING
+ QRect symbolRect = mark->symbolPixmap().rect();
+ QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect));
+
+ QHash<QString, Fragment>::iterator i = hash.find(mark->symbolId());
+ if (i == hash.end()) {
+ fragment.count = 1;
+ fragment.pixmap = mark->symbolPixmap();
+ }
+ else {
+ fragment = i.value();
+ ++fragment.count;
+ }
+ fragment.fragments.append(pixmapFragment);
+ hash.insert(mark->symbolId(), fragment);
+#else
painter->drawPixmap( symbolPos, mark->symbolPixmap() );
+#endif
+ }
+ if (!mark->labelPixmap().isNull()) {
painter->drawPixmap( labelRect, mark->labelPixmap() );
}
- } else {
- // simple case, one draw per placemark
- painter->drawPixmap(symbolPos, mark->symbolPixmap());
- painter->drawPixmap(labelRect, mark->labelPixmap());
}
}
+#ifdef BATCH_RENDERING
+ for (auto& val : hash.values()) {
+ if (m_debugModeEnabled) {
+// qDebug() << "Batches" << val.count;
+ QPixmap debugPixmap(val.pixmap.size());
+ debugPixmap.fill((quint64)(&val));
+ QPainter pixpainter;
+ pixpainter.begin(&debugPixmap);
+ pixpainter.drawPixmap(0, 0, val.pixmap);
+ pixpainter.end();
+ val.pixmap = debugPixmap;
+ }
+ painter->drawPixmapFragments(val.fragments.data(), val.count, val.pixmap);
+ }
+#endif
+
if (m_debugModeEnabled) {
renderDebug(geoPainter, viewport, visiblePlacemarks);
}
@@ -173,9 +240,9 @@ void PlacemarkLayer::requestStyleReset()
}
-// Test if there a bug in the X server which makes
-// text fully transparent if it gets written on
-// QPixmaps that were initialized by filling them
+// Test if there a bug in the X server which makes
+// text fully transparent if it gets written on
+// QPixmaps that were initialized by filling them
// with Qt::transparent
bool PlacemarkLayer::testXBug()
diff --git a/src/lib/marble/layers/PlacemarkLayer.h b/src/lib/marble/layers/PlacemarkLayer.h
index f90ea73..3bb3bd6 100644
--- a/src/lib/marble/layers/PlacemarkLayer.h
+++ b/src/lib/marble/layers/PlacemarkLayer.h
@@ -22,6 +22,7 @@
#include "LayerInterface.h"
#include <QVector>
+#include <QPainter>
#include "PlacemarkLayout.h"
@@ -38,6 +39,14 @@ class MarbleClock;
class ViewportParams;
class StyleBuilder;
+
+struct Fragment
+{
+ QVarLengthArray<QPainter::PixmapFragment, 16> fragments;
+ int count;
+ QPixmap pixmap;
+};
+
class PlacemarkLayer : public QObject, public LayerInterface
{
Q_OBJECT