Marble

StackedTileLoader.cpp
1 /*
2  SPDX-FileCopyrightText: 2005-2007 Torsten Rahn <[email protected]>
3  SPDX-FileCopyrightText: 2007 Inge Wallin <[email protected]>
4  SPDX-FileCopyrightText: 2008, 2009, 2010 Jens-Michael Hoffmann <[email protected]>
5  SPDX-FileCopyrightText: 2010-2012 Bernhard Beschow <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "StackedTileLoader.h"
11 
12 #include "MarbleDebug.h"
13 #include "MergedLayerDecorator.h"
14 #include "StackedTile.h"
15 #include "TileLoader.h"
16 #include "TileLoaderHelper.h"
17 #include "MarbleGlobal.h"
18 
19 #include <QCache>
20 #include <QHash>
21 #include <QReadWriteLock>
22 #include <QImage>
23 
24 
25 namespace Marble
26 {
27 
28 class StackedTileLoaderPrivate
29 {
30 public:
31  explicit StackedTileLoaderPrivate( MergedLayerDecorator *mergedLayerDecorator )
32  : m_layerDecorator( mergedLayerDecorator )
33  {
34  m_tileCache.setMaxCost( 20000 * 1024 ); // Cache size measured in bytes
35  }
36 
37  MergedLayerDecorator *const m_layerDecorator;
38  QHash <TileId, StackedTile*> m_tilesOnDisplay;
39  QCache <TileId, StackedTile> m_tileCache;
40  QReadWriteLock m_cacheLock;
41 };
42 
43 StackedTileLoader::StackedTileLoader( MergedLayerDecorator *mergedLayerDecorator, QObject *parent )
44  : QObject( parent ),
45  d( new StackedTileLoaderPrivate( mergedLayerDecorator ) )
46 {
47 }
48 
49 StackedTileLoader::~StackedTileLoader()
50 {
51  qDeleteAll( d->m_tilesOnDisplay );
52  delete d;
53 }
54 
55 int StackedTileLoader::tileColumnCount( int level ) const
56 {
57  return d->m_layerDecorator->tileColumnCount( level );
58 }
59 
60 int StackedTileLoader::tileRowCount( int level ) const
61 {
62  return d->m_layerDecorator->tileRowCount( level );
63 }
64 
65 const GeoSceneAbstractTileProjection *StackedTileLoader::tileProjection() const
66 {
67  return d->m_layerDecorator->tileProjection();
68 }
69 
70 QSize StackedTileLoader::tileSize() const
71 {
72  return d->m_layerDecorator->tileSize();
73 }
74 
76 {
77  QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
78  QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
79  for (; it != end; ++it ) {
80  Q_ASSERT( it.value()->used() && "contained in m_tilesOnDisplay should imply used()" );
81  it.value()->setUsed( false );
82  }
83 }
84 
86 {
87  // Make sure that tiles which haven't been used during the last
88  // rendering of the map at all get removed from the tile hash.
89 
90  QHashIterator<TileId, StackedTile*> it( d->m_tilesOnDisplay );
91  while ( it.hasNext() ) {
92  it.next();
93  if ( !it.value()->used() ) {
94  // If insert call result is false then the cache is too small to store the tile
95  // but the item will get deleted nevertheless and the pointer we have
96  // doesn't get set to zero (so don't delete it in this case or it will crash!)
97  d->m_tileCache.insert( it.key(), it.value(), it.value()->byteCount() );
98  d->m_tilesOnDisplay.remove( it.key() );
99  }
100  }
101 }
102 
103 const StackedTile* StackedTileLoader::loadTile( TileId const & stackedTileId )
104 {
105  // check if the tile is in the hash
106  d->m_cacheLock.lockForRead();
107  StackedTile * stackedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
108  d->m_cacheLock.unlock();
109  if ( stackedTile ) {
110  stackedTile->setUsed( true );
111  return stackedTile;
112  }
113  // here ends the performance critical section of this method
114 
115  d->m_cacheLock.lockForWrite();
116 
117  // has another thread loaded our tile due to a race condition?
118  stackedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
119  if ( stackedTile ) {
120  Q_ASSERT( stackedTile->used() && "other thread should have marked tile as used" );
121  d->m_cacheLock.unlock();
122  return stackedTile;
123  }
124 
125  // the tile was not in the hash so check if it is in the cache
126  stackedTile = d->m_tileCache.take( stackedTileId );
127  if ( stackedTile ) {
128  Q_ASSERT( !stackedTile->used() && "tiles in m_tileCache are invisible and should thus be marked as unused" );
129  stackedTile->setUsed( true );
130  d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
131  d->m_cacheLock.unlock();
132  return stackedTile;
133  }
134 
135  // tile (valid) has not been found in hash or cache, so load it from disk
136  // and place it in the hash from where it will get transferred to the cache
137 
138  mDebug() << "load tile from disk:" << stackedTileId;
139 
140  stackedTile = d->m_layerDecorator->loadTile( stackedTileId );
141  Q_ASSERT( stackedTile );
142  stackedTile->setUsed( true );
143 
144  d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
145  d->m_cacheLock.unlock();
146 
147  emit tileLoaded( stackedTileId );
148 
149  return stackedTile;
150 }
151 
153 {
154  return d->m_tileCache.maxCost() / 1024;
155 }
156 
158 {
159  return d->m_tilesOnDisplay.keys();
160 }
161 
163 {
164  return d->m_tileCache.count() + d->m_tilesOnDisplay.count();
165 }
166 
168 {
169  mDebug() << QString("Setting tile cache to %1 kilobytes.").arg( kiloBytes );
170  d->m_tileCache.setMaxCost( kiloBytes * 1024 );
171 }
172 
173 void StackedTileLoader::updateTile( TileId const &tileId, QImage const &tileImage )
174 {
175  const TileId stackedTileId( 0, tileId.zoomLevel(), tileId.x(), tileId.y() );
176 
177  StackedTile * displayedTile = d->m_tilesOnDisplay.take( stackedTileId );
178  if ( displayedTile ) {
179  Q_ASSERT( !d->m_tileCache.contains( stackedTileId ) );
180 
181  StackedTile *const stackedTile = d->m_layerDecorator->updateTile( *displayedTile, tileId, tileImage );
182  stackedTile->setUsed( true );
183  d->m_tilesOnDisplay.insert( stackedTileId, stackedTile );
184 
185  delete displayedTile;
186  displayedTile = nullptr;
187 
188  emit tileLoaded( stackedTileId );
189  } else {
190  d->m_tileCache.remove( stackedTileId );
191  }
192 }
193 
194 RenderState StackedTileLoader::renderState() const
195 {
196  RenderState renderState( "Stacked Tiles" );
197  QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
198  QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
199  for (; it != end; ++it ) {
200  renderState.addChild( d->m_layerDecorator->renderState( it.key() ) );
201  }
202  return renderState;
203 }
204 
206 {
207  qDeleteAll( d->m_tilesOnDisplay );
208  d->m_tilesOnDisplay.clear();
209  d->m_tileCache.clear(); // clear the tile cache in physical memory
210 
211  emit cleared();
212 }
213 
214 }
215 
216 #include "moc_StackedTileLoader.cpp"
StackedTileLoader(MergedLayerDecorator *mergedLayerDecorator, QObject *parent=nullptr)
Creates a new tile loader.
quint64 volatileCacheLimit() const
Returns the limit of the volatile (in RAM) cache.
A single tile that consists of a stack of Tile layers.
Definition: StackedTile.h:50
const StackedTile * loadTile(TileId const &stackedTileId)
Loads a tile and returns it.
int tileCount() const
Return the number of tiles in the cache.
void cleanupTilehash()
Cleans up the internal tile hash.
const T & value() const const
QHashIterator::Item next()
void clear()
Effectively triggers a reload of all tiles that are currently in use and clears the tile cache in phy...
QList< TileId > visibleTiles() const
Reloads the tiles that are currently displayed.
Binds a QML item to a specific geodetic location in screen coordinates.
bool hasNext() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setVolatileCacheLimit(quint64 kiloBytes)
Set the limit of the volatile (in RAM) cache.
void resetTilehash()
Resets the internal tile hash.
const Key & key() const const
const QList< QKeySequence > & end()
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Sep 27 2023 04:09:07 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.