From ffc715a2e6382fe9e331557c35fafc426507b8f5 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Fri, 5 Nov 2010 08:12:51 -0400 Subject: Use a fixed number of BaseTiles per TiledPage. This CL ensures that the TiledPage only keeps track of BaseTiles that are backed by a texture. In order to avoid unecessary allocations on the stack we pre-allocate the memory for the tiles and reuse tiles. Change-Id: I894cf4d5c6b564169ccf7a967629f5d670a5426d --- WebCore/platform/graphics/android/BaseTile.cpp | 16 ++- WebCore/platform/graphics/android/BaseTile.h | 5 +- .../platform/graphics/android/GLWebViewState.cpp | 8 +- WebCore/platform/graphics/android/TiledPage.cpp | 140 +++++++++++---------- WebCore/platform/graphics/android/TiledPage.h | 12 +- WebCore/platform/graphics/android/TilesManager.cpp | 23 ++-- WebCore/platform/graphics/android/TilesManager.h | 5 +- 7 files changed, 121 insertions(+), 88 deletions(-) diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp index ff5d9ca..6fd9e89 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -66,10 +66,10 @@ int BaseTile::count() } #endif -BaseTile::BaseTile(TiledPage* page, int x, int y) - : m_page(page) - , m_x(x) - , m_y(y) +BaseTile::BaseTile() + : m_page(0) + , m_x(-1) + , m_y(-1) , m_texture(0) , m_scale(1) , m_dirty(true) @@ -91,6 +91,14 @@ BaseTile::~BaseTile() // All the following functions must be called from the main GL thread. +void BaseTile::setContents(TiledPage* page, int x, int y) +{ + android::AutoMutex lock(m_atomicSync); + m_page = page; + m_x = x; + m_y = y; +} + void BaseTile::reserveTexture() { BackedDoubleBufferedTexture* texture = TilesManager::instance()->getAvailableTexture(this); diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h index 8870cbf..8f095e3 100644 --- a/WebCore/platform/graphics/android/BaseTile.h +++ b/WebCore/platform/graphics/android/BaseTile.h @@ -64,9 +64,12 @@ public: #ifdef DEBUG_COUNT static int count(); #endif - BaseTile(TiledPage* page, int x, int y); + BaseTile(); ~BaseTile(); + void setContents(TiledPage* page, int x, int y); + bool isAvailable() const { return !m_texture; } + void reserveTexture(); void removeTexture(); void setUsedLevel(int); diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp index 4ad22d8..617690c 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -217,9 +217,9 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale) return; m_viewport = viewport; - float fnbw = m_viewport.width() * scale / TilesManager::instance()->tileWidth(); + float fnbw = m_viewport.width() * scale / TilesManager::tileWidth(); int nbw = static_cast(ceilf(fnbw)); - float fnbh = m_viewport.height() * scale / TilesManager::instance()->tileHeight(); + float fnbh = m_viewport.height() * scale / TilesManager::tileHeight(); int nbh = static_cast(ceilf(fnbh)); m_nbTilesWidth = nbw + 1; m_nbTilesHeight = nbh + 1; @@ -227,8 +227,8 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale) m_viewport.fLeft, m_viewport.fTop, m_viewport.fRight, m_viewport.fBottom, m_viewport.width(), m_viewport.height(), scale, m_nbTilesWidth, m_nbTilesHeight); - m_firstTileX = static_cast(m_viewport.fLeft * scale / TilesManager::instance()->tileWidth()); - m_firstTileY = static_cast(m_viewport.fTop * scale / TilesManager::instance()->tileHeight()); + m_firstTileX = static_cast(m_viewport.fLeft * scale / TilesManager::tileWidth()); + m_firstTileY = static_cast(m_viewport.fTop * scale / TilesManager::tileHeight()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/android/TiledPage.cpp b/WebCore/platform/graphics/android/TiledPage.cpp index 358c1a8..eb500ac 100644 --- a/WebCore/platform/graphics/android/TiledPage.cpp +++ b/WebCore/platform/graphics/android/TiledPage.cpp @@ -67,41 +67,47 @@ TiledPage::TiledPage(int id, GLWebViewState* state) , m_glWebViewState(state) , m_latestPictureInval(0) { + // This value must be at least 1 greater than the max number of allowed + // textures. This is because prepare() asks for a tile before it reserves + // a texture for that tile. If all textures are currently in use by the + // page then there will be no available tile and having the extra tile + // ensures that this does not happen. After claiming the extra tile the call + // to reserveTexture() will cause some other tile in the page to lose it's + // texture and become available, thus ensuring that we always have at least + // one tile that is available. + m_baseTileSize = TilesManager::maxTextureCount() + 1; + m_baseTiles = new BaseTile[m_baseTileSize]; + #ifdef DEBUG_COUNT gTilePageCount++; #endif } TiledPage::~TiledPage() { - // Stop any pixmap generation - if (m_baseTiles.size()) { - TilesManager::instance()->removeSetsWithPage(this); - } - m_glWebViewState = 0; - // At this point, we can safely deallocate the BaseTiles, as - // there is no more BaseTile painting or scheduled to be painted - // by the TextureGenerator, and as we did reset the BaseLayer in GLWebViewState, - // in WebView's destructor (so no additional painting can be scheduled) - deleteAllValues(m_baseTiles); + // In order to delete the page we must ensure that none of its BaseTiles are + // currently painting or scheduled to be painted by the TextureGenerator + TilesManager::instance()->removeSetsWithPage(this); + delete[] m_baseTiles; #ifdef DEBUG_COUNT gTilePageCount--; #endif } -BaseTile* TiledPage::getBaseTile(int x, int y) +BaseTile* TiledPage::getBaseTile(int x, int y) const { - // if (x,y) is (0,0) the HashMap will treat the key as a null value and will - // not store the tile so we increment the key values by 1 - TileKey key(x+1, y+1); - return m_baseTiles.get(key); + for (int j = 0; j < m_baseTileSize; j++) { + BaseTile& tile = m_baseTiles[j]; + if (tile.x() == x && tile.y() == y && !tile.isAvailable()) + return &tile; + } + return 0; } void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureCount) { // Given the current scale level we need to mark the appropriate tiles as dirty - TilesManager* manager = TilesManager::instance(); - const float invTileContentWidth = m_scale / manager->tileWidth(); - const float invTileContentHeight = m_scale / manager->tileHeight(); + const float invTileContentWidth = m_scale / TilesManager::tileWidth(); + const float invTileContentHeight = m_scale / TilesManager::tileHeight(); const int firstDirtyTileX = static_cast(floorf(inval.x() * invTileContentWidth)); const int firstDirtyTileY = static_cast(floorf(inval.y() * invTileContentHeight)); @@ -131,20 +137,31 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y else x += (tilesInRow - 1) - i; - TileKey key(x+1, y+1); - BaseTile* tile = 0; - if (!m_baseTiles.contains(key)) { - tile = new BaseTile(this, x, y); - m_baseTiles.set(key, tile); + + BaseTile* currentTile = 0; + BaseTile* availableTile = 0; + for (int j = 0; j < m_baseTileSize; j++) { + BaseTile& tile = m_baseTiles[j]; + if (tile.x() == x && tile.y() == y) { + currentTile = &tile; + break; + } + if (!availableTile && tile.isAvailable()) + availableTile = &tile; + } + + if (!currentTile) { + currentTile = availableTile; + currentTile->setContents(this, x, y); } - tile = m_baseTiles.get(key); - tile->setScale(m_scale); + + currentTile->setScale(m_scale); // ensure there is a texture associated with the tile and then check to // see if the texture is dirty and in need of repainting - tile->reserveTexture(); - if(tile->isDirty()) - set->add(tile); + currentTile->reserveTexture(); + if(currentTile->isDirty()) + set->add(currentTile); } } @@ -156,35 +173,36 @@ void TiledPage::updateTileState(int firstTileX, int firstTileY) const int nbTilesWidth = m_glWebViewState->nbTilesWidth(); const int nbTilesHeight = m_glWebViewState->nbTilesHeight(); - TileMap::const_iterator end = m_baseTiles.end(); - for (TileMap::const_iterator it = m_baseTiles.begin(); it != end; ++it) { - BaseTile* tile = it->second; + for (int x = 0; x < m_baseTileSize; x++) { + + BaseTile& tile = m_baseTiles[x]; - if(!tile) + // if the tile no longer has a texture then proceed to the next tile + if (tile.isAvailable()) continue; // if the tile is in the dirty region then we must invalidate it - if (m_invalRegion.contains(tile->x(), tile->y())) - tile->markAsDirty(m_latestPictureInval); + if (m_invalRegion.contains(tile.x(), tile.y())) + tile.markAsDirty(m_latestPictureInval); // set the used level of the tile (e.g. distance from the viewport) int dx = 0; int dy = 0; - if (firstTileX > tile->x()) - dx = firstTileX - tile->x(); - else if (firstTileX + (nbTilesWidth - 1) < tile->x()) - dx = tile->x() - firstTileX - (nbTilesWidth - 1); + if (firstTileX > tile.x()) + dx = firstTileX - tile.x(); + else if (firstTileX + (nbTilesWidth - 1) < tile.x()) + dx = tile.x() - firstTileX - (nbTilesWidth - 1); - if (firstTileY > tile->y()) - dy = firstTileY - tile->y(); - else if (firstTileY + (nbTilesHeight - 1) < tile->y()) - dy = tile->y() - firstTileY - (nbTilesHeight - 1); + if (firstTileY > tile.y()) + dy = firstTileY - tile.y(); + else if (firstTileY + (nbTilesHeight - 1) < tile.y()) + dy = tile.y() - firstTileY - (nbTilesHeight - 1); int d = std::max(dx, dy); XLOG("setTileLevel tile: %x, fxy(%d, %d), level: %d", tile, firstTileX, firstTileY, d); - tile->setUsedLevel(d); + tile.setUsedLevel(d); } // clear the invalidated region as all tiles within that region have now @@ -245,32 +263,28 @@ void TiledPage::draw(float transparency, SkRect& viewport, int firstTileX, int f if (!m_glWebViewState) return; - float w = TilesManager::instance()->tileWidth() * m_invScale; - float h = TilesManager::instance()->tileHeight() * m_invScale; - int nbTilesWidth = m_glWebViewState->nbTilesWidth(); - int nbTilesHeight = m_glWebViewState->nbTilesHeight(); - - XLOG("WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency); - for (int i = 0; i < nbTilesHeight; i++) { - for (int j = 0; j < nbTilesWidth; j++) { - int x = j + firstTileX; - int y = i + firstTileY; + const float tileWidth = TilesManager::tileWidth() * m_invScale; + const float tileHeight = TilesManager::tileHeight() * m_invScale; - BaseTile* tile = getBaseTile(x, y); + SkIRect viewportTilesRect; + viewportTilesRect.fLeft = firstTileX; + viewportTilesRect.fTop = firstTileY; + viewportTilesRect.fRight = firstTileY + m_glWebViewState->nbTilesWidth() + 1; + viewportTilesRect.fBottom = firstTileY + m_glWebViewState->nbTilesHeight() + 1; - if (!tile) { - XLOG("NO TILE AT %d, %d", x, y); - continue; - } + XLOG("WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency); + for (int j = 0; j < m_baseTileSize; j++) { + BaseTile& tile = m_baseTiles[j]; + if(viewportTilesRect.contains(tile.x(), tile.y())) { SkRect rect; - rect.fLeft = x * w; - rect.fTop = y * h; - rect.fRight = rect.fLeft + w; - rect.fBottom = rect.fTop + h; + rect.fLeft = tile.x() * tileWidth; + rect.fTop = tile.y() * tileHeight; + rect.fRight = rect.fLeft + tileWidth; + rect.fBottom = rect.fTop + tileHeight; TilesManager::instance()->shader()->setViewport(viewport); - tile->draw(transparency, rect); + tile.draw(transparency, rect); } } diff --git a/WebCore/platform/graphics/android/TiledPage.h b/WebCore/platform/graphics/android/TiledPage.h index b532033..1edf5b4 100644 --- a/WebCore/platform/graphics/android/TiledPage.h +++ b/WebCore/platform/graphics/android/TiledPage.h @@ -38,9 +38,6 @@ namespace WebCore { class GLWebViewState; class IntRect; -typedef std::pair TileKey; -typedef HashMap TileMap; - /** * The TiledPage represents a map of BaseTiles covering the viewport. Each * GLWebViewState contains two TiledPages, one to display the page at the @@ -83,9 +80,14 @@ private: void updateTileState(int firstTileX, int firstTileY); void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set); - BaseTile* getBaseTile(int x, int y); + BaseTile* getBaseTile(int x, int y) const; - TileMap m_baseTiles; + // array of tiles used to compose a page. The tiles are allocated in the + // constructor to prevent them from potentially being allocated on the stack + BaseTile* m_baseTiles; + // stores the number of tiles in the m_baseTiles array. This enables us to + // quickly iterate over the array without have to check it's size + int m_baseTileSize; int m_id; float m_scale; float m_invScale; diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp index 9ebfe02..38dd282 100644 --- a/WebCore/platform/graphics/android/TilesManager.cpp +++ b/WebCore/platform/graphics/android/TilesManager.cpp @@ -55,17 +55,17 @@ // second page used when scaling. // In our case, we use 300x300 textures. On the tablet, this equals to // at least 24 (6 * 4) textures, hence 48. -#define DEFAULT_TEXTURES_ALLOCATION 48 -#define DEFAULT_TEXTURE_SIZE_WIDTH 300 -#define DEFAULT_TEXTURE_SIZE_HEIGHT 300 +#define MAX_TEXTURE_ALLOCATION 48 +#define TILE_WIDTH 300 +#define TILE_HEIGHT 300 namespace WebCore { TilesManager::TilesManager() : m_generatorReady(false) { - m_textures.reserveCapacity(DEFAULT_TEXTURES_ALLOCATION); - for (int i = 0; i < DEFAULT_TEXTURES_ALLOCATION; i++) { + m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); + for (int i = 0; i < MAX_TEXTURE_ALLOCATION; i++) { BackedDoubleBufferedTexture* texture = new BackedDoubleBufferedTexture( tileWidth(), tileHeight()); // the atomic load ensures that the texture has been fully initialized @@ -217,14 +217,19 @@ BackedDoubleBufferedTexture* TilesManager::getAvailableTexture(BaseTile* owner) return 0; } -float TilesManager::tileWidth() const +int TilesManager::maxTextureCount() { - return DEFAULT_TEXTURE_SIZE_WIDTH; + return MAX_TEXTURE_ALLOCATION; } -float TilesManager::tileHeight() const +float TilesManager::tileWidth() { - return DEFAULT_TEXTURE_SIZE_HEIGHT; + return TILE_WIDTH; +} + +float TilesManager::tileHeight() +{ + return TILE_HEIGHT; } TilesManager* TilesManager::instance() diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h index 1f9cd38..86f6ce0 100644 --- a/WebCore/platform/graphics/android/TilesManager.h +++ b/WebCore/platform/graphics/android/TilesManager.h @@ -69,8 +69,9 @@ public: void resetTextureUsage(TiledPage* page); void paintTexturesDefault(); - float tileWidth() const; - float tileHeight() const; + static int maxTextureCount(); + static float tileWidth(); + static float tileHeight(); private: -- cgit v1.1