From fbfe610150eb5c0a44fe2e7c037303761e5416e1 Mon Sep 17 00:00:00 2001 From: rachytski Date: Tue, 5 Jul 2011 00:37:56 +0300 Subject: [PATCH] Using all available CPU cores for tile rendering. --- base/base_tests/base_tests.pro | 3 +- base/base_tests/condition_test.cpp | 36 ++++++++++++++++++++ indexer/drawing_rules.hpp | 53 +++++++++++++++++++++++++----- iphone/Maps/Classes/EAGLView.mm | 4 +-- map/drawer_yg.cpp | 46 +++++++++++++++----------- map/drawer_yg.hpp | 8 +++-- map/framework.cpp | 12 ++++--- map/render_queue.cpp | 10 ++++-- map/render_queue.hpp | 2 ++ map/render_queue_routine.cpp | 18 +++++++--- omim.pro | 2 +- platform/platform.cpp | 10 ++++++ platform/platform.hpp | 6 ++++ qt/widgets.cpp | 2 +- qt_tstfrm/tstwidgets.cpp | 2 +- yg/tile_cache.cpp | 5 +++ yg/tile_cache.hpp | 2 ++ yg/tiler.cpp | 50 ++++++++++++++++++---------- yg/tiler.hpp | 15 +++++---- 19 files changed, 214 insertions(+), 72 deletions(-) create mode 100644 base/base_tests/condition_test.cpp diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro index b1c74d7eca..cf486b9946 100644 --- a/base/base_tests/base_tests.pro +++ b/base/base_tests/base_tests.pro @@ -32,6 +32,7 @@ SOURCES += \ assert_test.cpp \ timer_test.cpp \ mru_cache_test.cpp \ - threaded_list_test.cpp + threaded_list_test.cpp \ + condition_test.cpp HEADERS += diff --git a/base/base_tests/condition_test.cpp b/base/base_tests/condition_test.cpp new file mode 100644 index 0000000000..3bd28b0d34 --- /dev/null +++ b/base/base_tests/condition_test.cpp @@ -0,0 +1,36 @@ +#include "../../base/SRC_FIRST.hpp" +#include "../../testing/testing.hpp" + +#include "../thread.hpp" +#include "../threaded_list.hpp" +#include "../condition.hpp" + +#include "../../base/logging.hpp" + +struct ConditionThread : public threads::IRoutine +{ + ThreadedList * m_tl; + + ConditionThread(ThreadedList * tl) : m_tl(tl) + {} + + void Do() + { + m_tl->Front(true); + } +}; + +UNIT_TEST(Condition_Test) +{ + ThreadedList l; + + threads::Thread t0; + t0.Create(new ConditionThread(&l)); + + threads::Thread t1; + t1.Create(new ConditionThread(&l)); + + l.Cancel(); + t0.Join(); + t1.Join(); +} diff --git a/indexer/drawing_rules.hpp b/indexer/drawing_rules.hpp index 888e4178ae..bf710725a8 100644 --- a/indexer/drawing_rules.hpp +++ b/indexer/drawing_rules.hpp @@ -7,6 +7,7 @@ #include "../std/vector.hpp" #include "../std/array.hpp" #include "../std/string.hpp" +#include "../base/buffer_vector.hpp" class ReaderPtrStream; class FileWriterStream; @@ -18,25 +19,61 @@ namespace drule class BaseRule { string m_class; - mutable uint32_t m_id1, m_id2; + mutable buffer_vector m_id1, m_id2; char m_type; public: static uint32_t const empty_id = 0xFFFFFFFF; - BaseRule() : m_id1(empty_id), m_id2(empty_id) {} + BaseRule() + { + } virtual ~BaseRule() {} /// @todo Rewrite this. Make an array of IDs. //@{ - uint32_t GetID() const { return m_id1; } - void SetID(uint32_t id) const { m_id1 = id; } - void MakeEmptyID() { m_id1 = empty_id; } + void CheckSize(buffer_vector & v, size_t s) const + { + if (v.size() < s) + v.resize(s, empty_id); + } - uint32_t GetID2() const { return m_id2; } - void SetID2(uint32_t id) const { m_id2 = id; } - void MakeEmptyID2() { m_id2 = empty_id; } + uint32_t GetID(size_t threadID) const + { + CheckSize(m_id1, threadID + 1); + return m_id1[threadID]; + } + + void SetID(size_t threadID, uint32_t id) const + { + CheckSize(m_id1, threadID + 1); + m_id1[threadID] = id; + } + + void MakeEmptyID(size_t threadID) + { + CheckSize(m_id1, threadID + 1); + m_id1[threadID] = empty_id; + } + + uint32_t GetID2(size_t threadID) const + { + CheckSize(m_id2, threadID + 1); + return m_id2[threadID]; + } + + void SetID2(size_t threadID, uint32_t id) const + { + CheckSize(m_id2, threadID + 1); + m_id2[threadID] = id; + } + + void MakeEmptyID2(size_t threadID) + { + CheckSize(m_id2, threadID + 1); + m_id2[threadID] = empty_id; + } //@} void SetClassName(string const & cl) { m_class = cl; } diff --git a/iphone/Maps/Classes/EAGLView.mm b/iphone/Maps/Classes/EAGLView.mm index 7ed7a0c64b..0458c62392 100644 --- a/iphone/Maps/Classes/EAGLView.mm +++ b/iphone/Maps/Classes/EAGLView.mm @@ -102,11 +102,11 @@ blitVBSize, blitIBSize, 10, 512, 256, 6, 512, 256, 4, + 256, 256, 40, "unicode_blocks.txt", "fonts_whitelist.txt", "fonts_blacklist.txt", - 1 * 1024 * 1024, - 500 * 1024, + 1.5 * 1024 * 1024, fmt, !yg::gl::g_isBufferObjectsSupported, !pl.IsMultiSampled())); diff --git a/map/drawer_yg.cpp b/map/drawer_yg.cpp index cd810386bb..0d84a5b733 100644 --- a/map/drawer_yg.cpp +++ b/map/drawer_yg.cpp @@ -1,5 +1,7 @@ #include "drawer_yg.hpp" +#include "../std/bind.hpp" + #include "../indexer/drawing_rules.hpp" #include "../indexer/scales.hpp" @@ -18,21 +20,23 @@ DrawerYG::Params::Params() : m_dynamicPagesCount(2), - m_textPagesCount(2) + m_textPagesCount(2), + m_threadID(0) { } -uint32_t di::DrawRule::GetID() const +uint32_t di::DrawRule::GetID(size_t threadID) const { - return (m_transparent ? m_rule->GetID2() : m_rule->GetID()); + return (m_transparent ? m_rule->GetID2(threadID) : m_rule->GetID(threadID)); } -void di::DrawRule::SetID(uint32_t id) const +void di::DrawRule::SetID(size_t threadID, uint32_t id) const { - m_transparent ? m_rule->SetID2(id) : m_rule->SetID(id); + m_transparent ? m_rule->SetID2(threadID, id) : m_rule->SetID(threadID, id); } DrawerYG::DrawerYG(string const & skinName, params_t const & params) + : m_threadID(params.m_threadID) { m_pScreen = shared_ptr(new yg::gl::Screen(params)); m_pSkin = shared_ptr(loadSkin(params.m_resourceManager, @@ -42,31 +46,33 @@ DrawerYG::DrawerYG(string const & skinName, params_t const & params) m_pScreen->setSkin(m_pSkin); if (m_pSkin) - m_pSkin->addClearPageFn(&DrawerYG::ClearSkinPage, 0); + m_pSkin->addClearPageFn(bind(&DrawerYG::ClearSkinPage, m_threadID, _1), 0); } namespace { struct make_invalid { + size_t m_threadID; uint32_t m_pageIDMask; - make_invalid(uint8_t pageID) : m_pageIDMask(pageID << 24) + make_invalid(size_t threadID, uint8_t pageID) + : m_threadID(threadID), m_pageIDMask(pageID << 24) {} void operator() (int, int, drule::BaseRule * p) { - if ((p->GetID() & 0xFF000000) == m_pageIDMask) - p->MakeEmptyID(); - if ((p->GetID2() & 0xFF000000) == m_pageIDMask) - p->MakeEmptyID2(); + if ((p->GetID(m_threadID) & 0xFF000000) == m_pageIDMask) + p->MakeEmptyID(m_threadID); + if ((p->GetID2(m_threadID) & 0xFF000000) == m_pageIDMask) + p->MakeEmptyID2(m_threadID); } }; } -void DrawerYG::ClearSkinPage(uint8_t pageID) +void DrawerYG::ClearSkinPage(size_t threadID, uint8_t pageID) { - drule::rules().ForEachRule(make_invalid(pageID)); + drule::rules().ForEachRule(make_invalid(threadID, pageID)); } void DrawerYG::beginFrame() @@ -96,7 +102,7 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, string const & symbolName, yg:: void DrawerYG::drawCircle(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth) { - uint32_t id = pRule->GetID(); + uint32_t id = pRule->GetID(m_threadID); if (id == drule::BaseRule::empty_id) { double const radius = min(max(pRule->GetRadius() * m_scale, 3.0), 6.0) * m_visualScale; @@ -111,7 +117,7 @@ void DrawerYG::drawCircle(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition yg::Color::fromXRGB(lineC, alpha))); if (id != drule::BaseRule::empty_id) - pRule->SetID(id); + pRule->SetID(m_threadID, id); else { //ASSERT ( false, ("Can't find symbol by id = ", (name)) ); @@ -127,7 +133,7 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition // Use BaseRule::m_id to cache for point draw rule. // This rules doesn't mix with other rule-types. - uint32_t id = pRule->GetID(); + uint32_t id = pRule->GetID(m_threadID); if (id == drule::BaseRule::empty_id) { string name; @@ -135,7 +141,7 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition id = m_pSkin->mapSymbol(name.c_str()); if (id != drule::BaseRule::empty_id) - pRule->SetID(id); + pRule->SetID(m_threadID, id); else { //ASSERT ( false, ("Can't find symbol by id = ", (name)) ); @@ -152,7 +158,7 @@ void DrawerYG::drawPath(di::PathInfo const & info, di::DrawRule const * rules, s bool flag = false; for (size_t i = 0; i < count; ++i) { - if (rules[i].GetID() == drule::BaseRule::empty_id) + if (rules[i].GetID(m_threadID) == drule::BaseRule::empty_id) { flag = true; break; @@ -186,7 +192,7 @@ void DrawerYG::drawPath(di::PathInfo const & info, di::DrawRule const * rules, s if (m_pSkin->mapPenInfo(&penInfos[0], &styleIDs[0], count)) { for (size_t i = 0; i < count; ++i) - rules[i].SetID(styleIDs[i]); + rules[i].SetID(m_threadID, styleIDs[i]); } else { @@ -197,7 +203,7 @@ void DrawerYG::drawPath(di::PathInfo const & info, di::DrawRule const * rules, s // draw path with array of rules for (size_t i = 0; i < count; ++i) - m_pScreen->drawPath(&info.m_path[0], info.m_path.size(), -info.GetOffset(), rules[i].GetID(), rules[i].m_depth); + m_pScreen->drawPath(&info.m_path[0], info.m_path.size(), -info.GetOffset(), rules[i].GetID(m_threadID), rules[i].m_depth); } void DrawerYG::drawArea(vector const & pts, rule_ptr_t pRule, int depth) diff --git a/map/drawer_yg.hpp b/map/drawer_yg.hpp index f95104bb68..81cb70d288 100644 --- a/map/drawer_yg.hpp +++ b/map/drawer_yg.hpp @@ -54,8 +54,8 @@ namespace di DrawRule() : m_rule(0) {} DrawRule(rule_ptr_t p, int d, bool tr) : m_rule(p), m_depth(d), m_transparent(tr) {} - uint32_t GetID() const; - void SetID(uint32_t id) const; + uint32_t GetID(size_t threadID) const; + void SetID(size_t threadID, uint32_t id) const; }; } @@ -66,11 +66,12 @@ class DrawerYG double m_scale; double m_visualScale; int m_level; + size_t m_threadID; shared_ptr m_pScreen; shared_ptr m_pSkin; - static void ClearSkinPage(uint8_t pageID); + static void ClearSkinPage(size_t threadID, uint8_t pageID); protected: void drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth); @@ -92,6 +93,7 @@ public: { size_t m_dynamicPagesCount; size_t m_textPagesCount; + size_t m_threadID; Params(); }; diff --git a/map/framework.cpp b/map/framework.cpp index e717796955..3938a90c7a 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -338,13 +338,15 @@ void FrameWork::AddRedrawCommandSure() m_renderQueue(GetPlatform().SkinName(), GetPlatform().IsBenchmarking(), GetPlatform().ScaleEtalonSize(), + GetPlatform().MaxTilesCount(), + GetPlatform().CpuCores(), m_bgColor), m_isRedrawEnabled(true), m_metresMinWidth(20), m_minRulerWidth(97), m_centeringMode(EDoNothing), m_maxDuration(0), - m_tileSize(512) + m_tileSize(GetPlatform().TileSize()) { m_startTime = my::FormatCurrentTime(); @@ -916,7 +918,10 @@ void FrameWork::AddRedrawCommandSure() m_renderQueue.renderState().m_actualScreen, currentScreen);*/ - m_tiler.seed(currentScreen, m_tileSize); + m_tiler.seed(currentScreen, + currentScreen.GlobalRect().Center(), + m_tileSize, + GetPlatform().ScaleEtalonSize()); while (m_tiler.hasTile()) { @@ -924,10 +929,9 @@ void FrameWork::AddRedrawCommandSure() m_renderQueue.TileCache().lock(); - LOG(LINFO, ("Checking TileRect:", ri.m_rect)); - if (m_renderQueue.TileCache().hasTile(ri)) { + m_renderQueue.TileCache().touchTile(ri); yg::Tile tile = m_renderQueue.TileCache().getTile(ri); m_renderQueue.TileCache().unlock(); pDrawer->screen()->blit(tile.m_renderTarget, tile.m_tileScreen, currentScreen, true); diff --git a/map/render_queue.cpp b/map/render_queue.cpp index db13f0d060..35e603c5fe 100644 --- a/map/render_queue.cpp +++ b/map/render_queue.cpp @@ -5,14 +5,19 @@ #include "../yg/render_state.hpp" #include "../yg/rendercontext.hpp" +#include "../base/logging.hpp" + RenderQueue::RenderQueue( string const & skinName, bool isBenchmarking, unsigned scaleEtalonSize, + unsigned maxTilesCount, + unsigned tasksCount, yg::Color const & bgColor - ) : m_sequence(0), m_tileCache(39) + ) : m_sequence(0), m_tileCache(maxTilesCount - 1) { - m_tasksCount = 1; //< calculate from the CPU Cores Number + m_tasksCount = tasksCount; //< calculate from the CPU Cores Number + LOG(LINFO, ("initializing ", tasksCount, " rendering threads")); m_tasks = new Task[m_tasksCount]; for (unsigned i = 0; i < m_tasksCount; ++i) m_tasks[i].m_routine = new RenderQueueRoutine( @@ -43,6 +48,7 @@ RenderQueue::~RenderQueue() m_renderCommands.Cancel(); for (unsigned i = 0; i < m_tasksCount; ++i) m_tasks[i].m_thread.Cancel(); + delete [] m_tasks; } void RenderQueue::AddCommand(RenderQueueRoutine::render_fn_t const & fn, yg::Tiler::RectInfo const & rectInfo, size_t seqNum) diff --git a/map/render_queue.hpp b/map/render_queue.hpp index 120d9ad529..fc57381e1e 100644 --- a/map/render_queue.hpp +++ b/map/render_queue.hpp @@ -52,6 +52,8 @@ public: RenderQueue(string const & skinName, bool isBenchmarking, unsigned scaleEtalonSize, + unsigned maxTilesCount, + unsigned tasksCount, yg::Color const & bgColor); /// destructor. ~RenderQueue(); diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp index afea7118ab..03d8e0645d 100644 --- a/map/render_queue_routine.cpp +++ b/map/render_queue_routine.cpp @@ -83,6 +83,7 @@ void RenderQueueRoutine::Do() params.m_infoLayer = infoLayer; params.m_glyphCacheID = m_resourceManager->renderThreadGlyphCacheID(m_threadNum); params.m_useOverlay = true; + params.m_threadID = m_threadNum; /* params.m_isDebugging = true; params.m_drawPathes = false; params.m_drawAreas = false; @@ -103,8 +104,13 @@ void RenderQueueRoutine::Do() threads::MutexGuard guard(m_mutex); m_currentCommand = m_renderQueue->RenderCommands().Front(true); - if (IsCancelled()) + + if (m_renderQueue->RenderCommands().IsCancelled()) + { + LOG(LINFO, (m_threadNum, " cancelled on renderCommands")); break; + } + m_currentCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer)); /// commands from the previous sequence are ignored @@ -129,8 +135,12 @@ void RenderQueueRoutine::Do() shared_ptr tileTarget; tileTarget = m_resourceManager->renderTargets().Front(true); - if (IsCancelled()) + + if (m_resourceManager->renderTargets().IsCancelled()) + { + LOG(LINFO, (m_threadNum, " cancelled on renderTargets")); break; + } m_threadDrawer->screen()->setRenderTarget(tileTarget); @@ -140,13 +150,11 @@ void RenderQueueRoutine::Do() frameScreen.SetFromRect(m_currentCommand->m_rectInfo.m_rect); - int scaleLevel = scales::GetScaleLevel(m_currentCommand->m_rectInfo.m_rect); - m_currentCommand->m_renderFn( m_currentCommand->m_paintEvent, frameScreen, m_currentCommand->m_rectInfo.m_rect, - scaleLevel); + m_currentCommand->m_rectInfo.m_drawScale); /// rendering all collected texts // m_infoLayer->draw(m_threadDrawer->screen().get(), math::Identity()); diff --git a/omim.pro b/omim.pro index 8660590ecb..b2d690540f 100644 --- a/omim.pro +++ b/omim.pro @@ -36,8 +36,8 @@ SUBDIRS = 3party \ coding \ geometry \ platform \ - yg \ indexer \ + yg \ search \ version \ storage \ diff --git a/platform/platform.cpp b/platform/platform.cpp index 0bbf5bc1d7..512b66f55e 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -147,3 +147,13 @@ int BasePlatformImpl::ScaleEtalonSize() const { return 512 + 256; } + +int BasePlatformImpl::MaxTilesCount() const +{ + return 80; +} + +int BasePlatformImpl::TileSize() const +{ + return 256; +} diff --git a/platform/platform.hpp b/platform/platform.hpp index f856ea45de..624a4133bc 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -70,6 +70,10 @@ public: virtual bool IsBenchmarking() const = 0; + virtual int TileSize() const = 0; + + virtual int MaxTilesCount() const = 0; + virtual bool IsVisualLog() const = 0; virtual string DeviceID() const = 0; @@ -100,6 +104,8 @@ public: virtual bool IsBenchmarking() const; virtual bool IsVisualLog() const; virtual int ScaleEtalonSize() const; + virtual int TileSize() const; + virtual int MaxTilesCount() const; }; extern "C" Platform & GetPlatform(); diff --git a/qt/widgets.cpp b/qt/widgets.cpp index 2f31cc93cc..1b0d0c4fbf 100644 --- a/qt/widgets.cpp +++ b/qt/widgets.cpp @@ -52,7 +52,7 @@ namespace qt 10, 512, 256, 5, - 256, 256, 80, + GetPlatform().TileSize(), GetPlatform().TileSize(), GetPlatform().MaxTilesCount(), "unicode_blocks.txt", "fonts_whitelist.txt", "fonts_blacklist.txt", diff --git a/qt_tstfrm/tstwidgets.cpp b/qt_tstfrm/tstwidgets.cpp index 69b5814673..c0fe7fb400 100644 --- a/qt_tstfrm/tstwidgets.cpp +++ b/qt_tstfrm/tstwidgets.cpp @@ -56,7 +56,7 @@ void GLDrawWidget::initializeGL() 30, 512, 256, 10, 512, 256, 5, - 256, 256, 80, + GetPlatform().TileSize(), GetPlatform().TileSize(), GetPlatform().MaxTilesCount(), "unicode_blocks.txt", "fonts_whitelist.txt", "fonts_blacklist.txt", diff --git a/yg/tile_cache.cpp b/yg/tile_cache.cpp index b7b8efd4af..aeb092ff1f 100644 --- a/yg/tile_cache.cpp +++ b/yg/tile_cache.cpp @@ -35,6 +35,11 @@ namespace yg return m_cache.HasElem(key.toUInt64Cell()); } + void TileCache::touchTile(Tiler::RectInfo const & key) + { + m_cache.Touch(key.toUInt64Cell()); + } + Tile const & TileCache::getTile(Tiler::RectInfo const & key) { return m_cache.Find(key.toUInt64Cell()).m_tile; diff --git a/yg/tile_cache.hpp b/yg/tile_cache.hpp index 64e24d545d..0e10c5667d 100644 --- a/yg/tile_cache.hpp +++ b/yg/tile_cache.hpp @@ -46,6 +46,8 @@ namespace yg void addTile(Tiler::RectInfo const & key, Entry const & entry); /// check, whether we have some tile in the cache bool hasTile(Tiler::RectInfo const & key); + /// touch tile + void touchTile(Tiler::RectInfo const & key); /// get tile from the cache Tile const & getTile(Tiler::RectInfo const & key); }; diff --git a/yg/tiler.cpp b/yg/tiler.cpp index 7fe87e2dfe..5f4a659e84 100644 --- a/yg/tiler.cpp +++ b/yg/tiler.cpp @@ -11,30 +11,34 @@ namespace yg /// pack y in 0-16 bits /// pack x in 17-33 bits /// pack scale in 34-40 bits - return ((m_y & 0x1FF) | ((m_x & 0x1FF) << 17) | ((uint64_t)m_scale & 0x1F) << 34); + return ((m_y & 0x1FF) + | ((m_x & 0x1FF) << 17) + | ((uint64_t)m_tileScale & 0x1F) << 34) + | ((uint64_t)m_drawScale & 0x1F) << 40; } - void Tiler::RectInfo::fromUInt64Cell(uint64_t v, m2::RectD const & globRect) + void Tiler::RectInfo::fromUInt64Cell(uint64_t v, m2::RectD const & globRect, m2::PointD const & centerPt) { m_y = v & 0x1FF; m_x = (v >> 17) & 0x1FF; - m_scale = (v >> 34) & 0x1F; - init(globRect); + m_tileScale = (v >> 34) & 0x1F; + m_drawScale = (v >> 40) & 0x1F; + init(globRect, centerPt); } Tiler::RectInfo::RectInfo() - : m_scale(0), m_x(0), m_y(0), m_distance(0), m_coverage(0) + : m_drawScale(0), m_tileScale(0), m_x(0), m_y(0), m_distance(0), m_coverage(0) {} - Tiler::RectInfo::RectInfo(int scale, int x, int y, m2::RectD const & globRect) - : m_scale(scale), m_x(x), m_y(y) + Tiler::RectInfo::RectInfo(int drawScale, int tileScale, int x, int y, m2::RectD const & globRect, m2::PointD const & centerPt) + : m_drawScale(drawScale), m_tileScale(tileScale), m_x(x), m_y(y) { - init(globRect); + init(globRect, centerPt); } - void Tiler::RectInfo::init(m2::RectD const & globRect) + void Tiler::RectInfo::init(m2::RectD const & globRect, m2::PointD const & centerPt) { - int k = 1 << m_scale; + int k = 1 << m_tileScale; double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / k; double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / k; @@ -44,7 +48,7 @@ namespace yg m_rect.setMinY(m_y * rectSizeY); m_rect.setMaxY((m_y + 1) * rectSizeY); - m_distance = m_rect.Center().Length(globRect.Center()); + m_distance = m_rect.Center().Length(centerPt); m2::RectD r = globRect; if (r.Intersect(m_rect)) m_coverage = r.SizeX() * r.SizeY() / (m_rect.SizeX() * m_rect.SizeY()); @@ -69,7 +73,7 @@ namespace yg return l.m_distance > r.m_distance; } - void Tiler::seed(ScreenBase const & screen, int scaleEtalonSize) + void Tiler::seed(ScreenBase const & screen, m2::PointD const & centerPt, int tileSize, int scaleEtalonSize) { if (screen != m_screen) ++m_seqNum; @@ -80,13 +84,25 @@ namespace yg pxCenter + m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2)), glbRect); - m_scale = scales::GetScaleLevel(glbRect); + m_drawScale = scales::GetScaleLevel(glbRect); + m_screen = screen; m2::RectD const screenRect = m_screen.GlobalRect(); - double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / (1 << m_scale); - double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / (1 << m_scale); + /// slightly smaller than original to produce "antialiasing" effect using bilinear filtration. + tileSize /= 1.05; + + screen.PtoG(m2::RectD(pxCenter - m2::PointD(tileSize / 2, tileSize / 2), + pxCenter + m2::PointD(tileSize / 2, tileSize / 2)), + glbRect); + + double glbRectSize = min(glbRect.SizeX(), glbRect.SizeY()); + + m_tileScale = ceil(log((MercatorBounds::maxX - MercatorBounds::minX) / glbRectSize) / log(2)); + + double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / (1 << m_tileScale); + double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / (1 << m_tileScale); int minTileX = floor(screenRect.minX() / rectSizeX); int maxTileX = ceil(screenRect.maxX() / rectSizeX); @@ -103,11 +119,9 @@ namespace yg for (int tileY = minTileY; tileY < maxTileY; ++tileY) for (int tileX = minTileX; tileX < maxTileX; ++tileX) { - m_coverage.push(RectInfo(m_scale, tileX, tileY, screenRect)); + m_coverage.push(RectInfo(m_drawScale, m_tileScale, tileX, tileY, screenRect, centerPt)); ++rectCount; } - - LOG(LINFO, ("Tiler coverage contains ", rectCount, " rectangles")); } Tiler::Tiler() : m_seqNum(0) diff --git a/yg/tiler.hpp b/yg/tiler.hpp index 3bb479be25..e6a79912fe 100644 --- a/yg/tiler.hpp +++ b/yg/tiler.hpp @@ -13,7 +13,9 @@ namespace yg struct RectInfo { - int m_scale; + int m_drawScale; + + int m_tileScale; int m_x; int m_y; @@ -22,20 +24,21 @@ namespace yg double m_coverage; RectInfo(); - RectInfo(int scale, int x, int y, m2::RectD const & globRect); + RectInfo(int drawScale, int tileScale, int x, int y, m2::RectD const & globRect, m2::PointD const & centerPt); - void init(m2::RectD const & globRect); + void init(m2::RectD const & globRect, m2::PointD const & centerPt); /// pack scale, x, y into 64 bit word to use it as a hash-map key uint64_t toUInt64Cell() const; /// unpack 64bit integer and compute other parameters - void fromUInt64Cell(uint64_t v, m2::RectD const & globRect); + void fromUInt64Cell(uint64_t v, m2::RectD const & globRect, m2::PointD const & centerPt); }; private: ScreenBase m_screen; - int m_scale; + int m_drawScale; + int m_tileScale; size_t m_seqNum; priority_queue, greater > m_coverage; @@ -47,7 +50,7 @@ namespace yg /// seed tiler with new screenBase. /// if there are an existing tile sequence it is /// reorganized to reflect screen changes. - void seed(ScreenBase const & screenBase, int scaleEtalonSize); + void seed(ScreenBase const & screenBase, m2::PointD const & centerPt, int tileSize, int scaleEtalonSize); /// check whether the sequence has next tile bool hasTile();