diff --git a/core/document.cpp b/core/document.cpp index dafcd5a6c..5c6894373 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -216,6 +216,7 @@ void DocumentPrivate::cleanupPixmapMemory( qulonglong /*sure? bytesOffset*/ ) int pagesFreed = 0; QLinkedList< AllocatedPixmap * >::iterator pIt = m_allocatedPixmapsFifo.begin(); QLinkedList< AllocatedPixmap * >::iterator pEnd = m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * > visiblePixmaps; while ( (pIt != pEnd) && (memoryToFree > 0) ) { AllocatedPixmap * p = *pIt; @@ -230,9 +231,35 @@ void DocumentPrivate::cleanupPixmapMemory( qulonglong /*sure? bytesOffset*/ ) m_pagesVector.at( p->page )->deletePixmap( p->id ); // delete allocation descriptor delete p; - } else + } + else + { + visiblePixmaps.append( p ); ++pIt; + } } + + // Delete hidden pages may not be enough + pIt = visiblePixmaps.begin(); + pEnd = visiblePixmaps.end(); + while ( (pIt != pEnd) && memoryToFree > 0 ) + { + AllocatedPixmap * p = *pIt; + + TilesManager *tilesManager = m_pagesVector.at( p->page )->tilesManager( p->id ); + if ( tilesManager ) + { + tilesManager->cleanupPixmapMemory( memoryToFree ); + m_allocatedPixmapsTotalMemory -= p->memory; + memoryToFree -= p->memory; + p->memory = tilesManager->totalMemory(); + memoryToFree += p->memory; + m_allocatedPixmapsTotalMemory += p->memory; + } + + ++pIt; + } + //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmapsFifo.count() + pagesFreed, pagesFreed, m_allocatedPixmapsFifo.count() ); } } diff --git a/core/tilesmanager.cpp b/core/tilesmanager.cpp index 75a225600..47cfb68c9 100644 --- a/core/tilesmanager.cpp +++ b/core/tilesmanager.cpp @@ -10,34 +10,53 @@ #include #include +#include #ifdef TILES_DEBUG #include #endif +#define RANGE_MAX 1073741823 +#define RANGE_MIN -1073741824 + using namespace Okular; +static bool rankedTilesLessThan( Tile *t1, Tile *t2 ) +{ + if ( t1->dirty ^ t2->dirty ) + return t1->miss < t2->miss; + + return !t1->dirty; +} + class TilesManager::Private { public: Private(); bool hasPixmap( const NormalizedRect &rect, const Tile &tile ) const; - void tilesAt( const NormalizedRect &rect, const Tile &tile, QList &result ) const; + void tilesAt( const NormalizedRect &rect, Tile &tile, QList &result ); void setPixmap( const QPixmap *pixmap, const NormalizedRect &rect, Tile &tile ); void markDirty( Tile &tile ); void deleteTiles( const Tile &tile ); + void onClearPixmap( const Tile &tile ); + void rankTiles( Tile &tile ); + Tile tiles[16]; int width; int height; long totalPixels; + + QList rankedTiles; + QSize tileSize; }; TilesManager::Private::Private() : width( 0 ) , height( 0 ) , totalPixels( 0 ) + , tileSize( QSize() ) { } @@ -128,6 +147,7 @@ void TilesManager::Private::setPixmap( const QPixmap *pixmap, const NormalizedRe if ( !tile.rect.intersects( rect ) ) return; + // the tile intersects an edge of the viewport if ( !((tile.rect & rect) == tile.rect) ) { // paint subtiles if applied @@ -175,8 +195,13 @@ void TilesManager::Private::setPixmap( const QPixmap *pixmap, const NormalizedRe tile.tiles[2].rect = NormalizedRect( tile.rect.left, vCenter, hCenter, tile.rect.bottom ); tile.tiles[3].rect = NormalizedRect( hCenter, vCenter, tile.rect.right, tile.rect.bottom ); + tileSize = tile.tiles[0].rect.geometry( width, height ).size(); + for ( int i = 0; i < tile.nTiles; ++i ) + { + tile.tiles[ i ].parent = &tile; setPixmap( pixmap, rect, tile.tiles[ i ] ); + } if ( tile.pixmap ) { @@ -214,6 +239,8 @@ void TilesManager::Private::setPixmap( const QPixmap *pixmap, const NormalizedRe tile.tiles[ i ].pixmap = 0; } + tileSize = tile.rect.geometry( width, height ).size(); + delete [] tile.tiles; tile.tiles = 0; tile.nTiles = 0; @@ -250,8 +277,7 @@ bool TilesManager::Private::hasPixmap( const NormalizedRect &rect, const Tile &t if ( tile.nTiles == 0 ) return tile.pixmap && !tile.dirty; - // XXX - // TODO: onClearPixmap -> if (!parent.dirty) { parent.dirty(); onClearPixmap(parent); } + // all children tiles are clean. doesn't need to go deeper if ( !tile.dirty ) return true; @@ -264,7 +290,7 @@ bool TilesManager::Private::hasPixmap( const NormalizedRect &rect, const Tile &t return true; } -QList TilesManager::tilesAt( const NormalizedRect &rect ) const +QList TilesManager::tilesAt( const NormalizedRect &rect ) { QList result; @@ -276,13 +302,18 @@ QList TilesManager::tilesAt( const NormalizedRect &rect ) const return result; } -void TilesManager::Private::tilesAt( const NormalizedRect &rect, const Tile &tile, QList &result ) const +void TilesManager::Private::tilesAt( const NormalizedRect &rect, Tile &tile, QList &result ) { if ( !tile.rect.intersects( rect ) ) + { + tile.miss = qMin( tile.miss+1, RANGE_MAX ); return; + } if ( tile.nTiles == 0 ) { + // TODO: check tile size + tile.miss = qMax( tile.miss-1, RANGE_MIN ); result.append( tile ); } else @@ -297,11 +328,71 @@ long TilesManager::totalMemory() const return 4*d->totalPixels; } +void TilesManager::cleanupPixmapMemory( qulonglong numberOfBytes ) +{ + d->rankedTiles.clear(); + for ( int i = 0; i < 16; ++i ) + { + d->rankTiles( d->tiles[ i ] ); + } + qSort( d->rankedTiles.begin(), d->rankedTiles.end(), rankedTilesLessThan ); + + while ( numberOfBytes > 0 && !d->rankedTiles.isEmpty() ) + { + Tile *tile = d->rankedTiles.takeLast(); + if ( !tile->pixmap ) + continue; + + long pixels = tile->pixmap->width()*tile->pixmap->height(); + d->totalPixels -= pixels; + numberOfBytes -= 4*pixels; + + tile->miss = 0; + delete tile->pixmap; + tile->pixmap = 0; + + d->onClearPixmap( *tile ); + } +} + +void TilesManager::Private::onClearPixmap( const Tile &tile ) +{ + if ( !tile.parent ) + return; + + if ( !tile.parent->dirty ) + { + tile.parent->dirty = true; + onClearPixmap( *tile.parent ); + } +} + +void TilesManager::Private::rankTiles( Tile &tile ) +{ + if ( tile.parent ) + tile.miss = qBound( RANGE_MIN, tile.miss + tile.parent->miss, RANGE_MAX ); + + if ( tile.pixmap ) + { + rankedTiles.append( &tile ); + } + else + { + for ( int i = 0; i < tile.nTiles; ++i ) + { + rankTiles( tile.tiles[ i ] ); + } + tile.miss = 0; + } +} + Tile::Tile() : pixmap( 0 ) , dirty ( true ) , tiles( 0 ) , nTiles( 0 ) + , parent( 0 ) + , miss( 0 ) { } diff --git a/core/tilesmanager.h b/core/tilesmanager.h index d02e66901..f2ededef3 100644 --- a/core/tilesmanager.h +++ b/core/tilesmanager.h @@ -31,6 +31,9 @@ class OKULAR_EXPORT Tile Tile *tiles; int nTiles; + + Tile *parent; + int miss; }; class OKULAR_EXPORT TilesManager @@ -41,8 +44,9 @@ class OKULAR_EXPORT TilesManager void setPixmap( const QPixmap *pixmap, const NormalizedRect &rect ); bool hasPixmap( const NormalizedRect &rect ); - QList tilesAt( const NormalizedRect &rect ) const; + QList tilesAt( const NormalizedRect &rect ); long totalMemory() const; + void cleanupPixmapMemory( qulonglong numberOfBytes = 1 ); int width() const; void setWidth( int width );