Optimizations of tiles tree and small bugfixes

This commit is contained in:
r.kuznetsov 2015-03-31 09:38:06 +03:00
parent 0f239e8852
commit c14d67c567
4 changed files with 150 additions and 139 deletions

View file

@ -50,12 +50,17 @@ FrontendRenderer::FrontendRenderer(dp::RefPointer<ThreadsCommutator> commutator,
RefreshProjection();
RefreshModelView();
m_tileTree.SetHandlers(bind(&FrontendRenderer::OnAddRenderGroup, this, _1, _2, _3),
bind(&FrontendRenderer::OnDeferRenderGroup, this, _1, _2, _3),
bind(&FrontendRenderer::OnAddDeferredTile, this, _1, _2),
bind(&FrontendRenderer::OnRemoveTile, this, _1, _2));
StartThread();
}
FrontendRenderer::~FrontendRenderer()
{
StopThread();
m_tileTree.ResetHandlers();
}
#ifdef DRAW_INFO
@ -131,7 +136,11 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
program->Bind();
bucket->GetBuffer()->Build(program);
if (!IsUserMarkLayer(key))
CreateTileRenderGroup(state, bucket, key);
{
bool const result = m_tileTree.ProcessTile(key, state, bucket);
if (!result)
bucket.Destroy();
}
else
{
unique_ptr<UserMarkRenderGroup> & group = FindUserMarkRenderGroup(key, true);
@ -146,7 +155,7 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
TileReadEndMessage * msg = df::CastMessage<TileReadEndMessage>(message);
TileKey const & key = msg->GetKey();
if (!IsUserMarkLayer(key))
FinishTileRenderGroup(key);
m_tileTree.FinishTile(key);
break;
}
@ -238,51 +247,6 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
}
}
void FrontendRenderer::CreateTileRenderGroup(dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket,
TileKey const & newTile)
{
// adding tiles to render
auto onAddTile = [&state, &renderBucket, this](TileKey const & tileKey, TileStatus tileStatus)
{
if (tileStatus == TileStatus::Rendered)
AddToRenderGroup(m_renderGroups, state, renderBucket, tileKey);
else if (tileStatus == TileStatus::Deferred)
OnAddDeferredTile(tileKey, tileStatus);
else
ASSERT(false, ());
};
// deferring tiles
auto onDeferTile = [&state, &renderBucket, this](TileKey const & tileKey, TileStatus tileStatus)
{
AddToRenderGroup(m_deferredRenderGroups, state, renderBucket, tileKey);
};
// removing tiles
auto onRemoveTile = [this](TileKey const & tileKey, TileStatus tileStatus)
{
OnRemoveTile(tileKey, tileStatus);
};
bool const result = m_tileTree.ProcessTile(newTile, onAddTile, onRemoveTile, onDeferTile);
if (!result)
renderBucket.Destroy();
}
void FrontendRenderer::FinishTileRenderGroup(TileKey const & newTile)
{
auto onRemoveTile = [this](TileKey const & tileKey, TileStatus tileStatus)
{
OnRemoveTile(tileKey, tileStatus);
};
auto onAddDeferredTile = [this](TileKey const & tileKey, TileStatus tileStatus)
{
OnAddDeferredTile(tileKey, tileStatus);
};
m_tileTree.FinishTile(newTile, onAddDeferredTile, onRemoveTile);
}
void FrontendRenderer::AddToRenderGroup(vector<unique_ptr<RenderGroup>> & groups,
dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket,
@ -293,6 +257,18 @@ void FrontendRenderer::AddToRenderGroup(vector<unique_ptr<RenderGroup>> & groups
groups.emplace_back(move(group));
}
void FrontendRenderer::OnAddRenderGroup(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket)
{
AddToRenderGroup(m_renderGroups, state, renderBucket, tileKey);
}
void FrontendRenderer::OnDeferRenderGroup(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket)
{
AddToRenderGroup(m_deferredRenderGroups, state, renderBucket, tileKey);
}
void FrontendRenderer::OnAddDeferredTile(TileKey const & tileKey, TileStatus tileStatus)
{
ASSERT(tileStatus == TileStatus::Deferred, ());
@ -463,18 +439,10 @@ void FrontendRenderer::ResolveTileKeys(int tileScale)
int const maxTileY = static_cast<int>(ceil(clipRect.maxY() / rectSize));
// clip all tiles which are out of viewport
auto onRemoveTile = [this](TileKey const & tileKey, TileStatus tileStatus)
{
OnRemoveTile(tileKey, tileStatus);
};
auto onAddDeferredTile = [this](TileKey const & tileKey, TileStatus tileStatus)
{
OnAddDeferredTile(tileKey, tileStatus);
};
m_tileTree.ClipByRect(clipRect, onAddDeferredTile, onRemoveTile);
m_tileTree.ClipByRect(clipRect);
// request new tiles
m_tileTree.BeginRequesting(tileScale, onRemoveTile);
m_tileTree.BeginRequesting(tileScale);
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
{
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
@ -484,7 +452,7 @@ void FrontendRenderer::ResolveTileKeys(int tileScale)
m_tileTree.RequestTile(key);
}
}
m_tileTree.EndRequesting(onRemoveTile);
m_tileTree.EndRequesting();
}
void FrontendRenderer::StartThread()

View file

@ -96,14 +96,14 @@ private:
// it applies new model-view matrix to the scene (this matrix will be used on next frame)
void UpdateScene();
void CreateTileRenderGroup(dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket,
TileKey const & newTile);
void FinishTileRenderGroup(TileKey const & newTile);
void AddToRenderGroup(vector<unique_ptr<RenderGroup>> & groups,
dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket,
TileKey const & newTile);
void OnAddRenderGroup(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket);
void OnDeferRenderGroup(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & renderBucket);
void OnAddDeferredTile(TileKey const & tileKey, TileStatus tileStatus);
void OnRemoveTile(TileKey const & tileKey, TileStatus tileStatus);

130
drape_frontend/tile_tree.cpp Normal file → Executable file
View file

@ -14,6 +14,26 @@ TileTree::TileTree()
TileTree::~TileTree()
{
m_root.reset();
ResetHandlers();
}
void TileTree::SetHandlers(TRenderGroupHandler const & addRenderGroup,
TRenderGroupHandler const & deferRenderGroup,
TTileHandler const & addDeferredTile,
TTileHandler const & removeTile)
{
m_addRenderGroup = addRenderGroup;
m_deferRenderGroup = deferRenderGroup;
m_addDeferredTile = addDeferredTile;
m_removeTile = removeTile;
}
void TileTree::ResetHandlers()
{
m_addRenderGroup = nullptr;
m_deferRenderGroup = nullptr;
m_addDeferredTile = nullptr;
m_removeTile = nullptr;
}
void TileTree::Clear()
@ -21,9 +41,9 @@ void TileTree::Clear()
m_root.reset(new Node());
}
void TileTree::BeginRequesting(int const zoomLevel, TTileHandler const & removeTile)
void TileTree::BeginRequesting(int const zoomLevel)
{
AbortTiles(m_root, zoomLevel, removeTile);
AbortTiles(m_root, zoomLevel);
}
void TileTree::RequestTile(TileKey const & tileKey)
@ -31,9 +51,9 @@ void TileTree::RequestTile(TileKey const & tileKey)
InsertToNode(m_root, tileKey);
}
void TileTree::EndRequesting(TTileHandler const & removeTile)
void TileTree::EndRequesting()
{
SimplifyTree(removeTile);
SimplifyTree();
}
void TileTree::GetTilesCollection(TTilesCollection & tiles, int const zoomLevel)
@ -41,31 +61,29 @@ void TileTree::GetTilesCollection(TTilesCollection & tiles, int const zoomLevel)
FillTilesCollection(m_root, tiles, zoomLevel);
}
void TileTree::ClipByRect(m2::RectD const & rect, TTileHandler const & addDeferredTile,
TTileHandler const & removeTile)
void TileTree::ClipByRect(m2::RectD const & rect)
{
ClipNode(m_root, rect, removeTile);
CheckDeferredTiles(m_root, addDeferredTile, removeTile);
SimplifyTree(removeTile);
ClipNode(m_root, rect);
CheckDeferredTiles(m_root);
SimplifyTree();
}
bool TileTree::ProcessTile(TileKey const & tileKey, TTileHandler const & addTile,
TTileHandler const & removeTile, TTileHandler const & deferTile)
bool TileTree::ProcessTile(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & bucket)
{
bool const result = ProcessNode(m_root, tileKey, addTile, removeTile, deferTile);
bool const result = ProcessNode(m_root, tileKey, state, bucket);
if (result)
SimplifyTree(removeTile);
SimplifyTree();
return result;
}
void TileTree::FinishTile(TileKey const & tileKey, TTileHandler const & addDeferredTile,
TTileHandler const & removeTile)
void TileTree::FinishTile(TileKey const & tileKey)
{
if (FinishNode(m_root, tileKey))
{
CheckDeferredTiles(m_root, addDeferredTile, removeTile);
SimplifyTree(removeTile);
CheckDeferredTiles(m_root);
SimplifyTree();
}
}
@ -153,7 +171,7 @@ void TileTree::InsertToNode(TNodePtr const & node, TileKey const & tileKey)
}
}
void TileTree::AbortTiles(TNodePtr const & node, int const zoomLevel, TTileHandler const & removeTile)
void TileTree::AbortTiles(TNodePtr const & node, int const zoomLevel)
{
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
{
@ -162,10 +180,10 @@ void TileTree::AbortTiles(TNodePtr const & node, int const zoomLevel, TTileHandl
if ((*it)->m_tileStatus == TileStatus::Requested)
(*it)->m_tileStatus = TileStatus::Unknown;
else if ((*it)->m_tileStatus == TileStatus::Deferred)
RemoveTile(*it, removeTile);
RemoveTile(*it);
}
AbortTiles(*it, zoomLevel, removeTile);
AbortTiles(*it, zoomLevel);
}
}
@ -180,37 +198,36 @@ void TileTree::FillTilesCollection(TNodePtr const & node, TTilesCollection & til
}
}
void TileTree::ClipNode(TNodePtr const & node, m2::RectD const & rect, TTileHandler const & removeTile)
void TileTree::ClipNode(TNodePtr const & node, m2::RectD const & rect)
{
for (auto it = node->m_children.begin(); it != node->m_children.end();)
{
m2::RectD const tileRect = (*it)->m_tileKey.GetGlobalRect();
if(rect.IsIntersect(tileRect))
{
ClipNode(*it, rect, removeTile);
ClipNode(*it, rect);
++it;
}
else
{
RemoveTile(*it, removeTile);
ClipNode(*it, rect, removeTile);
RemoveTile(*it);
ClipNode(*it, rect);
it = node->m_children.erase(it);
}
}
}
void TileTree::RemoveTile(TNodePtr const & node, TTileHandler const & removeTile)
void TileTree::RemoveTile(TNodePtr const & node)
{
if (removeTile != nullptr && !node->m_isRemoved)
removeTile(node->m_tileKey, node->m_tileStatus);
if (m_removeTile != nullptr && !node->m_isRemoved)
m_removeTile(node->m_tileKey, node->m_tileStatus);
node->m_isRemoved = true;
node->m_tileStatus = TileStatus::Unknown;
}
bool TileTree::ProcessNode(TNodePtr const & node, TileKey const & tileKey,
TTileHandler const & addTile, TTileHandler const & removeTile,
TTileHandler const & deferTile)
dp::GLState const & state, dp::MasterPointer<dp::RenderBucket> & bucket)
{
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
{
@ -219,28 +236,28 @@ bool TileTree::ProcessNode(TNodePtr const & node, TileKey const & tileKey,
if ((*it)->m_tileStatus == TileStatus::Unknown)
return false;
DeleteTilesBelow(*it, removeTile);
DeleteTilesBelow(*it);
if (node->m_tileStatus == TileStatus::Rendered)
{
(*it)->m_tileStatus = TileStatus::Deferred;
if (deferTile != nullptr)
deferTile((*it)->m_tileKey, (*it)->m_tileStatus);
if (m_deferRenderGroup != nullptr)
m_deferRenderGroup((*it)->m_tileKey, state, bucket);
(*it)->m_isRemoved = false;
}
else
{
(*it)->m_tileStatus = TileStatus::Rendered;
if (addTile != nullptr)
addTile((*it)->m_tileKey, (*it)->m_tileStatus);
if (m_addRenderGroup != nullptr)
m_addRenderGroup((*it)->m_tileKey, state, bucket);
(*it)->m_isRemoved = false;
}
DeleteTilesAbove(node, addTile, removeTile);
DeleteTilesAbove(node);
return true;
}
else if (IsTileBelow((*it)->m_tileKey, tileKey))
return ProcessNode(*it, tileKey, addTile, removeTile, deferTile);
return ProcessNode(*it, tileKey, state, bucket);
}
return false;
}
@ -252,7 +269,10 @@ bool TileTree::FinishNode(TNodePtr const & node, TileKey const & tileKey)
{
if ((*it)->m_tileKey == tileKey && (*it)->m_tileStatus == TileStatus::Requested)
{
// here a tile has finished, but we hadn't got any data from BR. It means that
// this tile is empty, so we remove all his descendants and him
(*it)->m_tileStatus = TileStatus::Unknown;
DeleteTilesBelow(*it);
changed = true;
}
@ -261,17 +281,17 @@ bool TileTree::FinishNode(TNodePtr const & node, TileKey const & tileKey)
return changed;
}
void TileTree::DeleteTilesBelow(TNodePtr const & node, TTileHandler const & removeTile)
void TileTree::DeleteTilesBelow(TNodePtr const & node)
{
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
{
RemoveTile(*it, removeTile);
DeleteTilesBelow(*it, removeTile);
RemoveTile(*it);
DeleteTilesBelow(*it);
}
node->m_children.clear();
}
void TileTree::DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addTile, TTileHandler const & removeTile)
void TileTree::DeleteTilesAbove(TNodePtr const & node)
{
if (node->m_tileStatus == TileStatus::Requested || node->m_children.empty())
return;
@ -286,8 +306,8 @@ void TileTree::DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addT
{
if ((*it)->m_tileStatus == TileStatus::Deferred)
{
if (addTile != nullptr)
addTile((*it)->m_tileKey, (*it)->m_tileStatus);
if (m_addDeferredTile != nullptr)
m_addDeferredTile((*it)->m_tileKey, (*it)->m_tileStatus);
(*it)->m_tileStatus = TileStatus::Rendered;
(*it)->m_isRemoved = false;
@ -296,16 +316,16 @@ void TileTree::DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addT
// remove current tile
if (node != m_root)
RemoveTile(node, removeTile);
RemoveTile(node);
}
void TileTree::SimplifyTree(TTileHandler const & removeTile)
void TileTree::SimplifyTree()
{
ClearEmptyLevels(m_root, removeTile);
ClearObsoleteTiles(m_root, removeTile);
ClearEmptyLevels(m_root);
ClearObsoleteTiles(m_root);
}
void TileTree::ClearEmptyLevels(TNodePtr const & node, TTileHandler const & removeTile)
void TileTree::ClearEmptyLevels(TNodePtr const & node)
{
if (HaveChildrenSameStatus(node, TileStatus::Unknown))
{
@ -317,26 +337,26 @@ void TileTree::ClearEmptyLevels(TNodePtr const & node, TTileHandler const & remo
list<TNodePtr> newChildren;
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
{
RemoveTile(*it, removeTile);
RemoveTile(*it);
newChildren.splice(newChildren.begin(), (*it)->m_children);
}
node->m_children.swap(newChildren);
}
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
ClearEmptyLevels(*it, removeTile);
ClearEmptyLevels(*it);
}
bool TileTree::ClearObsoleteTiles(TNodePtr const & node, TTileHandler const & removeTile)
bool TileTree::ClearObsoleteTiles(TNodePtr const & node)
{
bool canClear = true;
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
canClear &= ClearObsoleteTiles(*it, removeTile);
canClear &= ClearObsoleteTiles(*it);
if (canClear)
{
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
RemoveTile(*it, removeTile);
RemoveTile(*it);
node->m_children.clear();
}
@ -375,12 +395,12 @@ bool TileTree::HaveGrandchildrenSameZoomLevel(TNodePtr const & node) const
return true;
}
void TileTree::CheckDeferredTiles(TNodePtr const & node, TTileHandler const & addTile, TTileHandler const & removeTile)
void TileTree::CheckDeferredTiles(TNodePtr const & node)
{
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
{
DeleteTilesAbove(*it, addTile, removeTile);
CheckDeferredTiles(*it, addTile, removeTile);
DeleteTilesAbove(*it);
CheckDeferredTiles(*it);
}
}

67
drape_frontend/tile_tree.hpp Normal file → Executable file
View file

@ -1,7 +1,10 @@
#pragma once
#include "tile_utils.hpp"
#include "render_group.hpp"
#include "../drape/glstate.hpp"
#include "../drape/pointers.hpp"
#include "../geometry/rect2d.hpp"
#include "../std/function.hpp"
@ -12,6 +15,7 @@
namespace df
{
/// this class implements K-d tree of visible tiles
class TileTree
{
public:
@ -19,21 +23,40 @@ public:
~TileTree();
using TTileHandler = function<void(TileKey const &, TileStatus)>;
using TRenderGroupHandler = function<void(TileKey const &, dp::GLState const &,
dp::MasterPointer<dp::RenderBucket> &)>;
void BeginRequesting(int const zoomLevel, TTileHandler const & removeTile);
/// addRenderGroup is called when render group can be created by a tile and rendered at once
/// deferRenderGroup is called when render group can be created by a tile but has to be deferred
/// addDeferredTile is called when previously deferred tile can be rendered
/// removeTile is called when a tile must be removed from rendering
void SetHandlers(TRenderGroupHandler const & addRenderGroup,
TRenderGroupHandler const & deferRenderGroup,
TTileHandler const & addDeferredTile,
TTileHandler const & removeTile);
void ResetHandlers();
/// this method must be called before requesting bunch of tiles
void BeginRequesting(int const zoomLevel);
/// request a new tile
void RequestTile(TileKey const & tileKey);
void EndRequesting(TTileHandler const & removeTile);
/// this method must be called after requesting bunch of tiles
void EndRequesting();
bool ProcessTile(TileKey const & tileKey, TTileHandler const & addTile,
TTileHandler const & removeTile, TTileHandler const & deferTile);
/// this method processes received from BR tile
bool ProcessTile(TileKey const & tileKey, dp::GLState const & state,
dp::MasterPointer<dp::RenderBucket> & bucket);
/// this method processes a message about finishing tile on BR
void FinishTile(TileKey const & tileKey);
void FinishTile(TileKey const & tileKey, TTileHandler const & addDeferredTile,
TTileHandler const & removeTile);
/// this method performs clipping by rectangle
void ClipByRect(m2::RectD const & rect);
void ClipByRect(m2::RectD const & rect, TTileHandler const & addDeferredTile,
TTileHandler const & removeTile);
/// clear all entire structure of tree. DO NOT call removeTile handlers,
/// so all external storages of tiles must be cleared manually
void Clear();
/// it returns actual tile collection to send to BR
void GetTilesCollection(TTilesCollection & tiles, int const zoomLevel);
private:
@ -41,29 +64,25 @@ private:
using TNodePtr = unique_ptr<Node>;
void InsertToNode(TNodePtr const & node, TileKey const & tileKey);
void AbortTiles(TNodePtr const & node, int const zoomLevel, TTileHandler const & removeTile);
void AbortTiles(TNodePtr const & node, int const zoomLevel);
void FillTilesCollection(TNodePtr const & node, TTilesCollection & tiles, int const zoomLevel);
void ClipNode(TNodePtr const & node, m2::RectD const & rect,
TTileHandler const & removeTile);
void CheckDeferredTiles(TNodePtr const & node, TTileHandler const & addTile,
TTileHandler const & removeTile);
void ClipNode(TNodePtr const & node, m2::RectD const & rect);
void CheckDeferredTiles(TNodePtr const & node);
void RemoveTile(TNodePtr const & node, TTileHandler const & removeTile);
void RemoveTile(TNodePtr const & node);
bool ProcessNode(TNodePtr const & node, TileKey const & tileKey,
TTileHandler const & addTile, TTileHandler const & removeTile,
TTileHandler const & deferTile);
dp::GLState const & state, dp::MasterPointer<dp::RenderBucket> & bucket);
bool FinishNode(TNodePtr const & node, TileKey const & tileKey);
void DeleteTilesBelow(TNodePtr const & node, TTileHandler const & removeTile);
void DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addTile,
TTileHandler const & removeTile);
void DeleteTilesBelow(TNodePtr const & node);
void DeleteTilesAbove(TNodePtr const & node);
void SimplifyTree(TTileHandler const & removeTile);
void ClearEmptyLevels(TNodePtr const & node, TTileHandler const & removeTile);
bool ClearObsoleteTiles(TNodePtr const & node, TTileHandler const & removeTile);
void SimplifyTree();
void ClearEmptyLevels(TNodePtr const & node);
bool ClearObsoleteTiles(TNodePtr const & node);
bool HaveChildrenSameStatus(TNodePtr const & node, TileStatus tileStatus) const;
bool HaveGrandchildrenSameZoomLevel(TNodePtr const & node) const;
@ -83,6 +102,10 @@ private:
};
TNodePtr m_root;
TRenderGroupHandler m_addRenderGroup;
TRenderGroupHandler m_deferRenderGroup;
TTileHandler m_addDeferredTile;
TTileHandler m_removeTile;
private:
friend void DebugPrintNode(TileTree::TNodePtr const & node, ostringstream & out, string const & offset);