From b1e5fe5ce54f3fc387e26b55dec05e99ee430164 Mon Sep 17 00:00:00 2001 From: rachytski Date: Sun, 31 Jul 2011 01:23:26 +0300 Subject: [PATCH] added CoverageGenerator. --- base/mutex.hpp | 2 +- map/coverage_generator.cpp | 73 +++++++++++++++++++++++++++ map/coverage_generator.hpp | 88 +++++++++++++++++++++++++++++++++ map/map.pro | 6 ++- map/render_queue.cpp | 8 ++- map/render_queue.hpp | 5 +- map/render_queue_routine.cpp | 30 +++++++---- map/render_queue_routine.hpp | 11 +++-- map/tiling_render_policy_mt.cpp | 13 ++--- map/tiling_render_policy_st.cpp | 7 ++- yg/tile_cache.cpp | 10 ++++ yg/tile_cache.hpp | 4 ++ yg/tiler.cpp | 11 +++-- yg/tiler.hpp | 7 ++- 14 files changed, 239 insertions(+), 36 deletions(-) create mode 100644 map/coverage_generator.cpp create mode 100644 map/coverage_generator.hpp diff --git a/base/mutex.hpp b/base/mutex.hpp index d0f54d7028..25afb9d19b 100644 --- a/base/mutex.hpp +++ b/base/mutex.hpp @@ -22,7 +22,7 @@ namespace threads /// Mutex primitive, used only for synchronizing this process threads /// based on Critical Section under Win32 and pthreads under Linux /// @author Siarhei Rachytski - /// As the MacOS implementation doesn't support recursive mutexes we should emulate them by ourselves. + /// @deprecated As the MacOS implementation doesn't support recursive mutexes we should emulate them by ourselves. /// The code is taken from @a http://www.omnigroup.com/mailman/archive/macosx-dev/2002-March/036465.html class Mutex { diff --git a/map/coverage_generator.cpp b/map/coverage_generator.cpp new file mode 100644 index 0000000000..4eea2ed099 --- /dev/null +++ b/map/coverage_generator.cpp @@ -0,0 +1,73 @@ +#include "../base/SRC_FIRST.hpp" + +#include "coverage_generator.hpp" +#include "render_queue.hpp" + +#include "../std/bind.hpp" + +CoverageGenerator::CoverageGenerator( + size_t tileSize, + size_t scaleEtalonSize, + RenderPolicy::TRenderFn renderFn, + RenderQueue * renderQueue) + : m_tiler(tileSize, scaleEtalonSize), + m_sequenceID(0), + m_renderFn(renderFn), + m_renderQueue(renderQueue) +{ + m_routine = new Routine(this); + m_thread.Create(m_routine); +} + +void CoverageGenerator::Cancel() +{ + m_thread.Cancel(); +} + +void CoverageGenerator::AddCoverageTask(ScreenBase const & screen) +{ +} + +void CoverageGenerator::AddMergeTileTask(yg::Tiler::RectInfo const & rectInfo, yg::Tile const & tile) +{ +} + +CoverageGenerator::Routine::Routine(CoverageGenerator * parent) + : m_parent(parent) +{} + +void CoverageGenerator::Routine::Do() +{ + while (!IsCancelled()) + { + ScreenBase screen = m_parent->m_tasks.Front(true).m_screen; + + if (m_parent->m_tasks.IsCancelled()) + break; + + m_parent->m_tiler.seed(screen, screen.GlobalRect().Center()); + m_parent->m_sequenceID++; + + m_parent->m_workCoverage->Clear(); + + while (m_parent->m_tiler.hasTile()) + { + yg::Tiler::RectInfo rectInfo = m_parent->m_tiler.nextTile(); + + if (m_parent->m_renderQueue->TileCache().hasTile(rectInfo)) + + m_parent->m_renderQueue->AddCommand( + m_parent->m_renderFn, + m_parent->m_tiler.nextTile(), + m_parent->m_sequenceID, + bind(&CoverageGenerator::AddMergeTileTask, m_parent, _1, _2)); + } + + { + threads::MutexGuard g(m_parent->m_mutex); + swap(m_parent->m_currentCoverage, m_parent->m_workCoverage); + } + + m_parent->m_workCoverage->Clear(); + } +} diff --git a/map/coverage_generator.hpp b/map/coverage_generator.hpp new file mode 100644 index 0000000000..4f5decc03a --- /dev/null +++ b/map/coverage_generator.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include "render_policy.hpp" + +#include "../geometry/screenbase.hpp" + +#include "../yg/tiler.hpp" +#include "../yg/tile.hpp" +#include "../yg/info_layer.hpp" + +#include "../base/thread.hpp" +#include "../base/threaded_list.hpp" +#include "../base/mutex.hpp" + +#include "../std/vector.hpp" +#include "../std/shared_ptr.hpp" + +class RenderQueue; + +/// holds the tile coverage for a specific screen +struct ScreenCoverage +{ + ScreenBase m_screen; + vector m_tiles; + shared_ptr m_infoLayer; + + void Clear(); +}; + +class CoverageGenerator +{ +private: + + struct Task + { + enum EType + { + ECoverageTask, + EMergeTileTask + } m_type; + + int m_sequenceID; + ScreenBase m_screen; + yg::Tiler::RectInfo m_rectInfo; + yg::Tile m_tile; + }; + + ThreadedList m_tasks; + + struct Routine : public threads::IRoutine + { + CoverageGenerator * m_parent; + void Do(); + Routine(CoverageGenerator * parent); + }; + + friend struct Routine; + + Routine * m_routine; + threads::Thread m_thread; + + threads::Mutex m_mutex; + + yg::Tiler m_tiler; + + size_t m_sequenceID; + + RenderPolicy::TRenderFn m_renderFn; + RenderQueue * m_renderQueue; + + ScreenCoverage * m_workCoverage; + ScreenCoverage * m_currentCoverage; + +public: + + CoverageGenerator(size_t tileSize, + size_t scaleEtalonSize, + RenderPolicy::TRenderFn renderFn, + RenderQueue * renderQueue); + + void AddCoverageTask(ScreenBase const & screen); + + void AddMergeTileTask(yg::Tiler::RectInfo const & rectInfo, yg::Tile const & tile); + + void Cancel(); + + ScreenCoverage * CurrentCoverage(); +}; diff --git a/map/map.pro b/map/map.pro index e1c7482926..8e60688a24 100644 --- a/map/map.pro +++ b/map/map.pro @@ -30,7 +30,8 @@ HEADERS += \ tiling_render_policy.hpp \ benchmark_framework.hpp \ framework_factory.hpp \ - render_policy_st.hpp + render_policy_st.hpp \ + coverage_generator.hpp SOURCES += \ feature_vec_model.cpp \ @@ -50,7 +51,8 @@ SOURCES += \ tiling_render_policy.cpp \ benchmark_framework.cpp \ framework_factory.cpp \ - render_policy_st.cpp + render_policy_st.cpp \ + coverage_generator.cpp !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp diff --git a/map/render_queue.cpp b/map/render_queue.cpp index 4a6433ae34..7e4fb06c6a 100644 --- a/map/render_queue.cpp +++ b/map/render_queue.cpp @@ -51,10 +51,14 @@ RenderQueue::~RenderQueue() delete [] m_tasks; } -void RenderQueue::AddCommand(RenderQueueRoutine::TRenderFn const & fn, yg::Tiler::RectInfo const & rectInfo, size_t sequenceID) +void RenderQueue::AddCommand( + RenderQueueRoutine::TRenderFn const & renderFn, + yg::Tiler::RectInfo const & rectInfo, + size_t sequenceID, + RenderQueueRoutine::TCommandFinishedFn const & commandFinishedFn) { m_sequenceID = sequenceID; - m_renderCommands.PushBack(make_shared_ptr(new RenderQueueRoutine::Command(rectInfo, fn, sequenceID))); + m_renderCommands.PushBack(make_shared_ptr(new RenderQueueRoutine::Command(renderFn, rectInfo, sequenceID, commandFinishedFn))); } void RenderQueue::AddWindowHandle(shared_ptr const & windowHandle) diff --git a/map/render_queue.hpp b/map/render_queue.hpp index 16f634c991..638f5acffc 100644 --- a/map/render_queue.hpp +++ b/map/render_queue.hpp @@ -60,7 +60,10 @@ public: shared_ptr const & resourceManager, double visualScale); /// add command to the commands queue. - void AddCommand(RenderQueueRoutine::TRenderFn const & fn, yg::Tiler::RectInfo const & rectInfo, size_t seqNum); + void AddCommand(RenderQueueRoutine::TRenderFn const & renderFn, + yg::Tiler::RectInfo const & rectInfo, + size_t sequenceID, + RenderQueueRoutine::TCommandFinishedFn const & commandFinishedFn); /// add window handle to notify when rendering operation finishes void AddWindowHandle(shared_ptr const & windowHandle); /// free all possible memory caches. diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp index 525ed280ee..522c5d57c2 100644 --- a/map/render_queue_routine.cpp +++ b/map/render_queue_routine.cpp @@ -25,12 +25,14 @@ #include "render_queue_routine.hpp" #include "render_queue.hpp" -RenderQueueRoutine::Command::Command(yg::Tiler::RectInfo const & rectInfo, - TRenderFn renderFn, - size_t sequenceID) - : m_rectInfo(rectInfo), - m_renderFn(renderFn), - m_sequenceID(sequenceID) +RenderQueueRoutine::Command::Command(TRenderFn renderFn, + yg::Tiler::RectInfo const & rectInfo, + size_t sequenceID, + TCommandFinishedFn commandFinishedFn) + : m_renderFn(renderFn), + m_rectInfo(rectInfo), + m_sequenceID(sequenceID), + m_commandFinishedFn(commandFinishedFn) {} RenderQueueRoutine::RenderQueueRoutine(string const & skinName, @@ -172,18 +174,28 @@ void RenderQueueRoutine::Do() double duration = timer.ElapsedSeconds(); + TCommandFinishedFn fn; + yg::Tiler::RectInfo rectInfo; + yg::Tile tile; + if (!IsCancelled()) { { threads::MutexGuard guard(m_mutex); - if (!m_currentCommand->m_paintEvent->isCancelled()) - AddTile(m_currentCommand->m_rectInfo, yg::Tile(tileTarget, tileInfoLayer, frameScreen, m_currentCommand->m_rectInfo, duration)); + if (m_currentCommand->m_paintEvent->isCancelled()) + break; + + rectInfo = m_currentCommand->m_rectInfo; + tile = yg::Tile(tileTarget, tileInfoLayer, frameScreen, m_currentCommand->m_rectInfo, duration); + AddTile(rectInfo, tile); + + fn = m_currentCommand->m_commandFinishedFn; m_currentCommand.reset(); } - Invalidate(); + fn(rectInfo, tile); } } diff --git a/map/render_queue_routine.hpp b/map/render_queue_routine.hpp index 8fdc697afe..bfaafca195 100644 --- a/map/render_queue_routine.hpp +++ b/map/render_queue_routine.hpp @@ -45,17 +45,20 @@ class RenderQueueRoutine : public threads::IRoutine public: typedef RenderPolicy::TRenderFn TRenderFn; + typedef function TCommandFinishedFn; /// Single tile rendering command struct Command { + TRenderFn m_renderFn; yg::Tiler::RectInfo m_rectInfo; shared_ptr m_paintEvent; //< paintEvent is set later after construction - TRenderFn m_renderFn; size_t m_sequenceID; - Command(yg::Tiler::RectInfo const & rectInfo, - TRenderFn renderFn, - size_t sequenceID); + TCommandFinishedFn m_commandFinishedFn; + Command(TRenderFn renderFn, + yg::Tiler::RectInfo const & rectInfo, + size_t sequenceID, + TCommandFinishedFn commandFinishedFn); }; private: diff --git a/map/tiling_render_policy_mt.cpp b/map/tiling_render_policy_mt.cpp index 39e4120e73..40b9ce7177 100644 --- a/map/tiling_render_policy_mt.cpp +++ b/map/tiling_render_policy_mt.cpp @@ -3,11 +3,12 @@ #include "drawer_yg.hpp" #include "events.hpp" #include "tiling_render_policy_mt.hpp" +#include "window_handle.hpp" #include "../geometry/screenbase.hpp" #include "../platform/platform.hpp" - +#include "../std/bind.hpp" TilingRenderPolicyMT::TilingRenderPolicyMT(shared_ptr const & windowHandle, RenderPolicy::TRenderFn const & renderFn) @@ -17,7 +18,9 @@ TilingRenderPolicyMT::TilingRenderPolicyMT(shared_ptr const & wind GetPlatform().ScaleEtalonSize(), GetPlatform().MaxTilesCount(), GetPlatform().CpuCores(), - bgColor()) + bgColor()), + m_tiler(GetPlatform().TileSize(), + GetPlatform().ScaleEtalonSize()) { m_renderQueue.AddWindowHandle(windowHandle); } @@ -41,9 +44,7 @@ void TilingRenderPolicyMT::DrawFrame(shared_ptr const & e, ScreenBas m_infoLayer.clear(); m_tiler.seed(currentScreen, - currentScreen.GlobalRect().Center(), - GetPlatform().TileSize(), - GetPlatform().ScaleEtalonSize()); + currentScreen.GlobalRect().Center()); while (m_tiler.hasTile()) { @@ -70,7 +71,7 @@ void TilingRenderPolicyMT::DrawFrame(shared_ptr const & e, ScreenBas else { m_renderQueue.TileCache().unlock(); - m_renderQueue.AddCommand(renderFn(), ri, m_tiler.seqNum()); + m_renderQueue.AddCommand(renderFn(), ri, m_tiler.seqNum(), bind(&WindowHandle::invalidate, windowHandle())); } } diff --git a/map/tiling_render_policy_st.cpp b/map/tiling_render_policy_st.cpp index a00cb37851..bdf52c078b 100644 --- a/map/tiling_render_policy_st.cpp +++ b/map/tiling_render_policy_st.cpp @@ -16,7 +16,8 @@ TilingRenderPolicyST::TilingRenderPolicyST(shared_ptr const & windowHandle, RenderPolicy::TRenderFn const & renderFn) : RenderPolicy(windowHandle, renderFn), - m_tileCache(GetPlatform().MaxTilesCount() - 1) + m_tileCache(GetPlatform().MaxTilesCount() - 1), + m_tiler(GetPlatform().TileSize(), GetPlatform().ScaleEtalonSize()) {} void TilingRenderPolicyST::Initialize(shared_ptr const & primaryContext, @@ -62,9 +63,7 @@ void TilingRenderPolicyST::DrawFrame(shared_ptr const & e, ScreenBas m_infoLayer.clear(); m_tiler.seed(currentScreen, - currentScreen.GlobalRect().Center(), - GetPlatform().TileSize(), - GetPlatform().ScaleEtalonSize()); + currentScreen.GlobalRect().Center()); while (m_tiler.hasTile()) { diff --git a/yg/tile_cache.cpp b/yg/tile_cache.cpp index aeb092ff1f..b5fa7cabaf 100644 --- a/yg/tile_cache.cpp +++ b/yg/tile_cache.cpp @@ -35,6 +35,16 @@ namespace yg return m_cache.HasElem(key.toUInt64Cell()); } + void TileCache::lockTile(Tiler::RectInfo const & key) + { + return m_cache.LockElem(key.toUInt64Cell()); + } + + void TileCache::unlockTile(Tiler::RectInfo const & key) + { + return m_cache.UnlockElem(key.toUInt64Cell()); + } + void TileCache::touchTile(Tiler::RectInfo const & key) { m_cache.Touch(key.toUInt64Cell()); diff --git a/yg/tile_cache.hpp b/yg/tile_cache.hpp index 0e10c5667d..19dc688684 100644 --- a/yg/tile_cache.hpp +++ b/yg/tile_cache.hpp @@ -46,6 +46,10 @@ 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); + /// lock tile + void lockTile(Tiler::RectInfo const & key); + /// unlock tile + void unlockTile(Tiler::RectInfo const & key); /// touch tile void touchTile(Tiler::RectInfo const & key); /// get tile from the cache diff --git a/yg/tiler.cpp b/yg/tiler.cpp index 6db7958c60..85a64f8b24 100644 --- a/yg/tiler.cpp +++ b/yg/tiler.cpp @@ -73,15 +73,15 @@ namespace yg return l.m_distance > r.m_distance; } - void Tiler::seed(ScreenBase const & screen, m2::PointD const & centerPt, int tileSize, int scaleEtalonSize) + void Tiler::seed(ScreenBase const & screen, m2::PointD const & centerPt) { if (screen != m_screen) ++m_seqNum; m2::RectD glbRect; m2::PointD pxCenter = screen.PixelRect().Center(); - screen.PtoG(m2::RectD(pxCenter - m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2), - pxCenter + m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2)), + screen.PtoG(m2::RectD(pxCenter - m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2), + pxCenter + m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2)), glbRect); m_drawScale = scales::GetScaleLevel(glbRect); @@ -91,7 +91,7 @@ namespace yg m2::RectD const screenRect = m_screen.GlobalRect(); /// slightly smaller than original to produce "antialiasing" effect using bilinear filtration. - tileSize /= 1.05; + size_t tileSize = m_tileSize / 1.05; screen.PtoG(m2::RectD(pxCenter - m2::PointD(tileSize / 2, tileSize / 2), pxCenter + m2::PointD(tileSize / 2, tileSize / 2)), @@ -124,7 +124,8 @@ namespace yg } } - Tiler::Tiler() : m_seqNum(0) + Tiler::Tiler(size_t tileSize, size_t scaleEtalonSize) + : m_seqNum(0), m_tileSize(tileSize), m_scaleEtalonSize(scaleEtalonSize) {} bool Tiler::hasTile() diff --git a/yg/tiler.hpp b/yg/tiler.hpp index e6a79912fe..2ca78bfdab 100644 --- a/yg/tiler.hpp +++ b/yg/tiler.hpp @@ -43,14 +43,17 @@ namespace yg priority_queue, greater > m_coverage; + size_t m_tileSize; + size_t m_scaleEtalonSize; + public: - Tiler(); + Tiler(size_t tileSize, size_t scaleEtalonSize); /// seed tiler with new screenBase. /// if there are an existing tile sequence it is /// reorganized to reflect screen changes. - void seed(ScreenBase const & screenBase, m2::PointD const & centerPt, int tileSize, int scaleEtalonSize); + void seed(ScreenBase const & screenBase, m2::PointD const & centerPt); /// check whether the sequence has next tile bool hasTile();