pyramidal tiles pre-caching.

This commit is contained in:
rachytski 2012-02-15 15:42:54 +04:00 committed by Alex Zolotarev
parent d18fe08ce5
commit db6b2b07de
6 changed files with 157 additions and 150 deletions

View file

@ -17,42 +17,51 @@ public:
double const log2 = log(2.0);
// LOG(LINFO, ("width:", screenWidth, ", height:", screenHeight));
size_t ceiledScreenWidth = static_cast<int>(pow(2.0, ceil(log(double(screenWidth)) / log2)));
size_t ceiledScreenHeight = static_cast<int>(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<int>((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<int>(120 * k), m_maxTilesCount);
switch (densityDpi)
{

View file

@ -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<Tiler::RectInfo> allRects;
vector<Tiler::RectInfo> allPrevRects;
vector<Tiler::RectInfo> 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<Tiler::RectInfo> 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<Tiler::RectInfo> firstClassTiles;
vector<Tiler::RectInfo> 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<yg::gl::BlitInfo> 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

View file

@ -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<Tile const *, LessRectInfo> TileSet;
TileSet m_tiles;
TileSet m_prevTiles;
/// InfoLayer composed of infoLayers for visible tiles
scoped_ptr<yg::InfoLayer> 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;
};

View file

@ -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<RectInfo> & 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<int>(floor(clipRect.minX() / rectSizeX));
int maxTileX = static_cast<int>(ceil(clipRect.maxX() / rectSizeX));
int minTileY = static_cast<int>(floor(clipRect.minY() / rectSizeY));
int maxTileY = static_cast<int>(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<RectInfo> & tiles, int depth)
void Tiler::tiles(vector<RectInfo> & tiles, int depth)
{
if (m_tileScale == 0)
return;
@ -176,14 +125,14 @@ void Tiler::prevLevelTiles(vector<RectInfo> & 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<RectInfo> & 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<int>(floor(clipRect.minX() / rectSizeX));
int maxTileX = static_cast<int>(ceil(clipRect.maxX() / rectSizeX));
@ -234,12 +169,15 @@ void Tiler::prevLevelTiles(vector<RectInfo> & 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);
}

View file

@ -46,18 +46,19 @@ public:
/// seed tiler with new screenBase.
void seed(ScreenBase const & screenBase, m2::PointD const & centerPt);
void currentLevelTiles(vector<RectInfo> & tiles);
void prevLevelTiles(vector<RectInfo> & tiles, int depth);
void tiles(vector<RectInfo> & 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);
};

View file

@ -76,7 +76,7 @@ int Platform::MaxTilesCount() const
int Platform::PreCachingDepth() const
{
return 3;
return 5;
}
int Platform::TileSize() const