From db6b2b07ded3792622a3df82148d99fb56c55911 Mon Sep 17 00:00:00 2001 From: rachytski Date: Wed, 15 Feb 2012 15:42:54 +0400 Subject: [PATCH] pyramidal tiles pre-caching. --- .../jni/com/mapswithme/platform/Platform.cpp | 27 ++-- map/screen_coverage.cpp | 129 ++++++++++++------ map/screen_coverage.hpp | 12 +- map/tiler.cpp | 126 +++++------------ map/tiler.hpp | 11 +- platform/platform_qt.cpp | 2 +- 6 files changed, 157 insertions(+), 150 deletions(-) diff --git a/android/jni/com/mapswithme/platform/Platform.cpp b/android/jni/com/mapswithme/platform/Platform.cpp index b56fd54f73..2bbf5dea1c 100644 --- a/android/jni/com/mapswithme/platform/Platform.cpp +++ b/android/jni/com/mapswithme/platform/Platform.cpp @@ -17,42 +17,51 @@ public: double const log2 = log(2.0); +// LOG(LINFO, ("width:", screenWidth, ", height:", screenHeight)); + size_t ceiledScreenWidth = static_cast(pow(2.0, ceil(log(double(screenWidth)) / log2))); size_t ceiledScreenHeight = static_cast(pow(2.0, ceil(log(double(screenHeight)) / log2))); size_t ceiledScreenSize = max(ceiledScreenWidth, ceiledScreenHeight); +// LOG(LINFO, ("ceiledScreenSize=", ceiledScreenSize)); + m_tileSize = min(max(ceiledScreenSize / 2, (size_t)128), (size_t)512); - int k = static_cast((256.0 / m_tileSize) * (256.0 / m_tileSize)); + double k = (256.0 / m_tileSize) * (256.0 / m_tileSize); + + LOG(LINFO, ("tileSize=", m_tileSize)); /// calculating how much tiles we need for the screen of such size m_maxTilesCount = 0; - m_preCachingDepth = 3; + m_preCachingDepth = 6; /// calculating for non-rotated screen for (unsigned i = 0; i < m_preCachingDepth; ++i) { +// LOG(LINFO, ("calculating", i, "level")); /// minimum size of tile on the screen - int minTileSize = floor((m_tileSize << i) / 1.05 / 2.0) - 1; + float minTileSize = floor((m_tileSize << i) / 1.05 / 2.0) - 1; +// LOG(LINFO, ("minTileSize:", minTileSize)); int tilesOnXSide = ceil(screenWidth / minTileSize) + 1; +// LOG(LINFO, ("tilesOnXSide:", tilesOnXSide)); int tilesOnYSide = ceil(screenHeight / minTileSize) + 1; +// LOG(LINFO, ("tilesOnYSide:", tilesOnYSide)); /// tiles in the single screen int singleScreenTilesCount = tilesOnXSide * tilesOnYSide; - - int curLevelTilesCount = singleScreenTilesCount * 2; - +// LOG(LINFO, ("singleScreenTilesCount:", singleScreenTilesCount)); + int curLevelTilesCount = singleScreenTilesCount * 3; +// LOG(LINFO, ("curLevelTilesCount:", curLevelTilesCount)); m_maxTilesCount += curLevelTilesCount; - - LOG(LINFO, ("on", i, "depth we need", curLevelTilesCount, "tiles")); +// LOG(LINFO, ("on", i, "depth we need", curLevelTilesCount, "tiles")); } LOG(LINFO, ("minimum amount of tiles needed is", m_maxTilesCount)); - m_maxTilesCount = max(120 * k, m_maxTilesCount); + m_maxTilesCount = max(static_cast(120 * k), m_maxTilesCount); switch (densityDpi) { diff --git a/map/screen_coverage.cpp b/map/screen_coverage.cpp index b6a3cfacd5..f48caff83c 100644 --- a/map/screen_coverage.cpp +++ b/map/screen_coverage.cpp @@ -17,8 +17,8 @@ ScreenCoverage::ScreenCoverage() : m_tiler(0, 0), m_infoLayer(new yg::InfoLayer()), - m_drawScale(0), m_isEmptyDrawingCoverage(false), + m_leavesCount(0), m_stylesCache(0) { m_infoLayer->setCouldOverlap(false); @@ -31,8 +31,8 @@ ScreenCoverage::ScreenCoverage(TileRenderer * tileRenderer, : m_tileRenderer(tileRenderer), m_tiler(tileSize, scaleEtalonSize), m_infoLayer(new yg::InfoLayer()), - m_drawScale(0), m_isEmptyDrawingCoverage(false), + m_leavesCount(0), m_coverageGenerator(coverageGenerator), m_stylesCache(0) { @@ -49,8 +49,9 @@ ScreenCoverage * ScreenCoverage::Clone() res->m_coverageGenerator = m_coverageGenerator; res->m_tileRects = m_tileRects; res->m_newTileRects = m_newTileRects; - res->m_drawScale = m_drawScale; + res->m_newLeafTileRects = m_newLeafTileRects; res->m_isEmptyDrawingCoverage = m_isEmptyDrawingCoverage; + res->m_leavesCount = m_leavesCount; TileCache * tileCache = &m_tileRenderer->GetTileCache(); @@ -119,8 +120,13 @@ void ScreenCoverage::Merge(Tiler::RectInfo const & ri) m_tiles.insert(tile); m_tileRects.erase(ri); m_newTileRects.erase(ri); + m_newLeafTileRects.erase(ri); - m_isEmptyDrawingCoverage &= tile->m_isEmptyDrawing; + if (m_tiler.isLeaf(ri)) + { + m_isEmptyDrawingCoverage &= tile->m_isEmptyDrawing; + m_leavesCount--; + } } } @@ -128,12 +134,14 @@ void ScreenCoverage::Merge(Tiler::RectInfo const & ri) if (addTile) { - yg::InfoLayer * tileInfoLayerCopy = tile->m_infoLayer->clone(); + if (m_tiler.isLeaf(ri)) + { + yg::InfoLayer * tileInfoLayerCopy = tile->m_infoLayer->clone(); + m_infoLayer->merge(*tileInfoLayerCopy, + tile->m_tileScreen.PtoGMatrix() * m_screen.GtoPMatrix()); - m_infoLayer->merge(*tileInfoLayerCopy, - tile->m_tileScreen.PtoGMatrix() * m_screen.GtoPMatrix()); - - delete tileInfoLayerCopy; + delete tileInfoLayerCopy; + } } } @@ -167,41 +175,45 @@ void ScreenCoverage::SetScreen(ScreenBase const & screen) m_screen = screen; m_newTileRects.clear(); + m_tiler.seed(m_screen, m_screen.GlobalRect().GlobalCenter()); vector allRects; vector allPrevRects; vector newRects; TileSet tiles; - TileSet prevTiles; - m_tiler.currentLevelTiles(allRects); - m_tiler.prevLevelTiles(allPrevRects, GetPlatform().PreCachingDepth()); + m_tiler.tiles(allRects, GetPlatform().PreCachingDepth()); TileCache * tileCache = &m_tileRenderer->GetTileCache(); tileCache->writeLock(); - m_drawScale = m_tiler.drawScale(); - m_isEmptyDrawingCoverage = true; + m_leavesCount = 0; for (unsigned i = 0; i < allRects.size(); ++i) { m_tileRects.insert(allRects[i]); Tiler::RectInfo ri = allRects[i]; + if (tileCache->hasTile(ri)) { tileCache->touchTile(ri); Tile const * tile = &tileCache->getTile(ri); ASSERT(tiles.find(tile) == tiles.end(), ()); - m_isEmptyDrawingCoverage &= tile->m_isEmptyDrawing; + if (m_tiler.isLeaf(allRects[i])) + m_isEmptyDrawingCoverage &= tile->m_isEmptyDrawing; tiles.insert(tile); } else + { newRects.push_back(ri); + if (m_tiler.isLeaf(ri)) + ++m_leavesCount; + } } for (TileSet::const_iterator it = m_prevTiles.begin(); it != m_prevTiles.end(); ++it) @@ -260,12 +272,58 @@ void ScreenCoverage::SetScreen(ScreenBase const & screen) for (TileSet::const_iterator it = m_tiles.begin(); it != m_tiles.end(); ++it) { - yg::InfoLayer * tileInfoLayerCopy = (*it)->m_infoLayer->clone(); - m_infoLayer->merge(*tileInfoLayerCopy, (*it)->m_tileScreen.PtoGMatrix() * screen.GtoPMatrix()); - delete tileInfoLayerCopy; + Tiler::RectInfo ri = (*it)->m_rectInfo; + if (m_tiler.isLeaf(ri)) + { + yg::InfoLayer * tileInfoLayerCopy = (*it)->m_infoLayer->clone(); + m_infoLayer->merge(*tileInfoLayerCopy, (*it)->m_tileScreen.PtoGMatrix() * screen.GtoPMatrix()); + delete tileInfoLayerCopy; + } } + m_newLeafTileRects.clear(); + + for (unsigned i = 0; i < newRects.size(); ++i) + if (m_tiler.isLeaf(newRects[i])) + m_newLeafTileRects.insert(newRects[i]); + copy(newRects.begin(), newRects.end(), inserter(m_newTileRects, m_newTileRects.end())); + + set drawnTiles; + + for (TileSet::const_iterator it = m_tiles.begin(); it != m_tiles.end(); ++it) + { + Tiler::RectInfo ri = (*it)->m_rectInfo; + drawnTiles.insert(Tiler::RectInfo(0, ri.m_tileScale, ri.m_x, ri.m_y)); + } + + vector firstClassTiles; + vector secondClassTiles; + + for (unsigned i = 0; i < newRects.size(); ++i) + { + Tiler::RectInfo nr = newRects[i]; + + Tiler::RectInfo cr[4] = + { + Tiler::RectInfo(0, nr.m_tileScale + 1, nr.m_x * 2, nr.m_y * 2), + Tiler::RectInfo(0, nr.m_tileScale + 1, nr.m_x * 2 + 1, nr.m_y * 2), + Tiler::RectInfo(0, nr.m_tileScale + 1, nr.m_x * 2 + 1, nr.m_y * 2 + 1), + Tiler::RectInfo(0, nr.m_tileScale + 1, nr.m_x * 2, nr.m_y * 2 + 1) + }; + + int childTilesToDraw = 4; + + for (int i = 0; i < 4; ++i) + if (drawnTiles.count(cr[i]) || !m_screen.GlobalRect().IsIntersect(m2::AnyRectD(cr[i].m_rect))) + --childTilesToDraw; + + if (childTilesToDraw > 1) + firstClassTiles.push_back(nr); + else + secondClassTiles.push_back(nr); + } + /// clearing all old commands m_tileRenderer->ClearCommands(); /// setting new sequenceID @@ -273,11 +331,16 @@ void ScreenCoverage::SetScreen(ScreenBase const & screen) m_tileRenderer->CancelCommands(); - /// adding commands for tiles which aren't in cache - for (size_t i = 0; i < newRects.size(); ++i) - m_tileRenderer->AddCommand(newRects[i], m_tiler.sequenceID(), - bind(&CoverageGenerator::AddMergeTileTask, m_coverageGenerator, newRects[i])); + // filtering out rects that are fully covered by its descedants + // adding commands for tiles which aren't in cache + for (size_t i = 0; i < firstClassTiles.size(); ++i) + m_tileRenderer->AddCommand(firstClassTiles[i], m_tiler.sequenceID(), + bind(&CoverageGenerator::AddMergeTileTask, m_coverageGenerator, + firstClassTiles[i])); + + for (size_t i = 0; i < secondClassTiles.size(); ++i) + m_tileRenderer->AddCommand(secondClassTiles[i], m_tiler.sequenceID()); } ScreenCoverage::~ScreenCoverage() @@ -308,23 +371,7 @@ void ScreenCoverage::Draw(yg::gl::Screen * s, ScreenBase const & screen) { vector infos; - for (TileSet::const_iterator it = m_prevTiles.begin(); it != m_prevTiles.end(); ++it) - { - Tile const * tile = *it; - - size_t tileWidth = tile->m_renderTarget->width(); - size_t tileHeight = tile->m_renderTarget->height(); - - yg::gl::BlitInfo bi; - - bi.m_matrix = tile->m_tileScreen.PtoGMatrix() * screen.GtoPMatrix(); - - bi.m_srcRect = m2::RectI(0, 0, tileWidth - 2, tileHeight - 2); - bi.m_texRect = m2::RectU(1, 1, tileWidth - 1, tileHeight - 1); - bi.m_srcSurface = tile->m_renderTarget; - - infos.push_back(bi); - } +// LOG(LINFO, ("drawing", m_tiles.size(), "tiles")); for (TileSet::const_iterator it = m_tiles.begin(); it != m_tiles.end(); ++it) { @@ -369,12 +416,12 @@ void ScreenCoverage::EndFrame(yg::gl::Screen *s) int ScreenCoverage::GetDrawScale() const { - return m_drawScale; + return m_tiler.drawScale(); } bool ScreenCoverage::IsEmptyDrawingCoverage() const { - return m_isEmptyDrawingCoverage; + return (m_leavesCount <= 0) && m_isEmptyDrawingCoverage; } bool ScreenCoverage::IsPartialCoverage() const diff --git a/map/screen_coverage.hpp b/map/screen_coverage.hpp index 9d50af86a4..73753f453b 100644 --- a/map/screen_coverage.hpp +++ b/map/screen_coverage.hpp @@ -44,20 +44,19 @@ private: TileRectSet m_tileRects; /// Only rects, that should be drawn TileRectSet m_newTileRects; + /// Only leaf rects, that should be drawn + TileRectSet m_newLeafTileRects; /// Typedef for a set of tiles, that are visible for the m_screen typedef set TileSet; TileSet m_tiles; TileSet m_prevTiles; /// InfoLayer composed of infoLayers for visible tiles scoped_ptr m_infoLayer; - /// Primary scale, which is used to draw tiles in m_screen. - /// Not all tiles could correspond to this value, as there could be tiles from - /// lower and higher level in the coverage to provide a smooth - /// scale transition experience - int m_drawScale; bool m_isEmptyDrawingCoverage; + int m_leavesCount; + CoverageGenerator * m_coverageGenerator; yg::StylesCache * m_stylesCache; @@ -96,5 +95,8 @@ public: /// perform end frame void EndFrame(yg::gl::Screen * s); /// get draw scale for the tiles in the current coverage + /// Not all tiles in coverage could correspond to this value, + /// as there could be tiles from lower and higher level in the + /// coverage to provide a smooth scale transition experience int GetDrawScale() const; }; diff --git a/map/tiler.cpp b/map/tiler.cpp index b315ec8211..b4c9a0a9e2 100644 --- a/map/tiler.cpp +++ b/map/tiler.cpp @@ -28,26 +28,31 @@ void Tiler::RectInfo::initRect() m_rect.setMaxY((m_y + 1) * rectSizeY); } -LessByDistance::LessByDistance(m2::PointD const & pt) +LessByScaleAndDistance::LessByScaleAndDistance(m2::PointD const & pt) : m_pt(pt) { } -bool LessByDistance::operator()(Tiler::RectInfo const & l, Tiler::RectInfo const & r) +bool LessByScaleAndDistance::operator()(Tiler::RectInfo const & l, Tiler::RectInfo const & r) { + if (l.m_drawScale != r.m_drawScale) + return l.m_drawScale < r.m_drawScale; + if (l.m_tileScale != r.m_tileScale) + return l.m_tileScale < r.m_tileScale; + return l.m_rect.Center().Length(m_pt) < r.m_rect.Center().Length(m_pt); } bool operator<(Tiler::RectInfo const & l, Tiler::RectInfo const & r) { - if (l.m_y != r.m_y) - return l.m_y < r.m_y; - if (l.m_x != r.m_x) - return l.m_x < r.m_x; if (l.m_drawScale != r.m_drawScale) return l.m_drawScale < r.m_drawScale; if (l.m_tileScale != r.m_tileScale) return l.m_tileScale < r.m_tileScale; + if (l.m_y != r.m_y) + return l.m_y < r.m_y; + if (l.m_x != r.m_x) + return l.m_x < r.m_x; return false; } @@ -112,63 +117,7 @@ void Tiler::seed(ScreenBase const & screen, m2::PointD const & centerPt) m_tileScale = getTileScale(screen, m_tileSize); } -void Tiler::currentLevelTiles(vector & tiles) -{ - int tileSize = m_tileSize; - - int drawScale = getDrawScale(m_screen, tileSize, 1); - int tileScale = getTileScale(m_screen, tileSize); - - double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / (1 << tileScale); - double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / (1 << tileScale); - - /// calculating coverage on the global rect, which corresponds to the - /// pixel rect, which in ceiled to tileSize and enlarged by 1 tile on each side - /// to produce an effect of simple precaching. - - m2::RectD pxRect = m_screen.PixelRect(); - - int pxWidthInTiles = (pxRect.SizeX() + tileSize - 1) / tileSize; - int pxHeightInTiles = (pxRect.SizeY() + tileSize - 1) / tileSize; - - m2::PointD pxCenter = pxRect.Center(); - - double glbHalfSizeX = m_screen.PtoG(pxCenter - m2::PointD(pxWidthInTiles * tileSize / 2, 0)).Length(m_screen.PtoG(pxCenter)); - double glbHalfSizeY = m_screen.PtoG(pxCenter - m2::PointD(0, pxHeightInTiles * tileSize / 2)).Length(m_screen.PtoG(pxCenter)); - - m2::AnyRectD globalRect(m_screen.PtoG(pxCenter), - m_screen.GlobalRect().angle(), - m2::RectD(-glbHalfSizeX, -glbHalfSizeY, glbHalfSizeX, glbHalfSizeY)); - - m2::RectD const clipRect = globalRect.GetGlobalRect(); - - int minTileX = static_cast(floor(clipRect.minX() / rectSizeX)); - int maxTileX = static_cast(ceil(clipRect.maxX() / rectSizeX)); - int minTileY = static_cast(floor(clipRect.minY() / rectSizeY)); - int maxTileY = static_cast(ceil(clipRect.maxY() / rectSizeY)); - - /// clearing previous coverage - tiles.clear(); - - /// generating new coverage - - for (int tileY = minTileY; tileY < maxTileY; ++tileY) - for (int tileX = minTileX; tileX < maxTileX; ++tileX) - { - m2::RectD tileRect(tileX * rectSizeX, - tileY * rectSizeY, - (tileX + 1) * rectSizeX, - (tileY + 1) * rectSizeY); - - if (globalRect.IsIntersect(m2::AnyRectD(tileRect))) - tiles.push_back(RectInfo(drawScale, tileScale, tileX, tileY)); - } - - /// sorting coverage elements - sort(tiles.begin(), tiles.end(), LessByDistance(m_centerPt)); -} - -void Tiler::prevLevelTiles(vector & tiles, int depth) +void Tiler::tiles(vector & tiles, int depth) { if (m_tileScale == 0) return; @@ -176,14 +125,14 @@ void Tiler::prevLevelTiles(vector & tiles, int depth) /// clearing previous coverage tiles.clear(); - int lowerBound = m_tileScale > depth ? m_tileScale - depth : 0; - int higherBound = m_tileScale; + if (m_tileScale - depth < 0) + depth = m_tileScale; - for (unsigned i = lowerBound; i < higherBound; ++i) + for (unsigned i = 0; i < depth; ++i) { - int pow = m_tileScale - i - 1; + int pow = depth - 1 - i; - int scale = 2 << pow; + int scale = 1 << pow; int tileSize = m_tileSize * scale; @@ -194,24 +143,10 @@ void Tiler::prevLevelTiles(vector & tiles, int depth) double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / (1 << tileScale); /// calculating coverage on the global rect, which corresponds to the - /// pixel rect, which in ceiled to tileSize and enlarged by 1 tile on each side - /// to produce an effect of simple precaching. + /// pixel rect, which in ceiled to tileSize - m2::RectD pxRect = m_screen.PixelRect(); - - int pxWidthInTiles = (pxRect.SizeX() + tileSize - 1) / tileSize; - int pxHeightInTiles = (pxRect.SizeY() + tileSize - 1) / tileSize; - - m2::PointD pxCenter = pxRect.Center(); - - double glbHalfSizeX = m_screen.PtoG(pxCenter - m2::PointD(pxWidthInTiles * tileSize / 2, 0)).Length(m_screen.PtoG(pxCenter)); - double glbHalfSizeY = m_screen.PtoG(pxCenter - m2::PointD(0, pxHeightInTiles * tileSize / 2)).Length(m_screen.PtoG(pxCenter)); - - m2::AnyRectD globalRect(m_screen.PtoG(pxCenter), - m_screen.GlobalRect().angle(), - m2::RectD(-glbHalfSizeX, -glbHalfSizeY, glbHalfSizeX, glbHalfSizeY)); - - m2::RectD const clipRect = globalRect.GetGlobalRect(); + m2::AnyRectD const & globalRect = m_screen.GlobalRect(); + m2::RectD const clipRect = m_screen.GlobalRect().GetGlobalRect(); int minTileX = static_cast(floor(clipRect.minX() / rectSizeX)); int maxTileX = static_cast(ceil(clipRect.maxX() / rectSizeX)); @@ -234,12 +169,15 @@ void Tiler::prevLevelTiles(vector & tiles, int depth) } /// sorting coverage elements - sort(tiles.begin(), tiles.end(), LessByDistance(m_centerPt)); + sort(tiles.begin(), tiles.end(), LessByScaleAndDistance(m_centerPt)); } - Tiler::Tiler(size_t tileSize, size_t scaleEtalonSize) - : m_sequenceID(0), m_tileSize(tileSize), m_scaleEtalonSize(scaleEtalonSize) + : m_drawScale(0), + m_tileScale(0), + m_sequenceID(0), + m_tileSize(tileSize), + m_scaleEtalonSize(scaleEtalonSize) {} size_t Tiler::sequenceID() const @@ -247,7 +185,17 @@ size_t Tiler::sequenceID() const return m_sequenceID; } -double Tiler::drawScale() const +int Tiler::drawScale() const { return m_drawScale; } + +int Tiler::tileScale() const +{ + return m_tileScale; +} + +bool Tiler::isLeaf(RectInfo const & ri) const +{ + return (ri.m_drawScale == m_drawScale) && (ri.m_tileScale == m_tileScale); +} diff --git a/map/tiler.hpp b/map/tiler.hpp index a20d5fc4b2..596286be1b 100644 --- a/map/tiler.hpp +++ b/map/tiler.hpp @@ -46,18 +46,19 @@ public: /// seed tiler with new screenBase. void seed(ScreenBase const & screenBase, m2::PointD const & centerPt); - void currentLevelTiles(vector & tiles); - void prevLevelTiles(vector & tiles, int depth); + void tiles(vector & tiles, int depth); + bool isLeaf(RectInfo const & ri) const; size_t sequenceID() const; - double drawScale() const; + int drawScale() const; + int tileScale() const; }; -struct LessByDistance +struct LessByScaleAndDistance { m2::PointD m_pt; - LessByDistance(m2::PointD const & pt); + LessByScaleAndDistance(m2::PointD const & pt); bool operator()(Tiler::RectInfo const & l, Tiler::RectInfo const & r); }; diff --git a/platform/platform_qt.cpp b/platform/platform_qt.cpp index 92f987b467..bddad826a1 100644 --- a/platform/platform_qt.cpp +++ b/platform/platform_qt.cpp @@ -76,7 +76,7 @@ int Platform::MaxTilesCount() const int Platform::PreCachingDepth() const { - return 3; + return 5; } int Platform::TileSize() const