diff --git a/anim/anim.pro b/anim/anim.pro index 0e328c422f..a7954cbf5a 100644 --- a/anim/anim.pro +++ b/anim/anim.pro @@ -15,5 +15,7 @@ HEADERS += \ SOURCES += \ controller.cpp \ + task.cpp + diff --git a/anim/controller.cpp b/anim/controller.cpp index 6737105e85..a68955d216 100644 --- a/anim/controller.cpp +++ b/anim/controller.cpp @@ -8,20 +8,16 @@ namespace anim { Controller::Controller() { - m_animStep = 10; - m_thread.Create(this); + m_LockCount = 0; } Controller::~Controller() { - m_tasks.Cancel(); - m_newTasks.Cancel(); - m_thread.Cancel(); } void Controller::AddTask(shared_ptr const & task) { - m_newTasks.PushBack(task); + m_tasks.PushBack(task); } void Controller::CopyTasks(TTasks & from, TTasks & to) @@ -30,54 +26,50 @@ namespace anim swap(from, to); } - void Controller::Do() + bool Controller::HasTasks() { - while (true) + return !m_tasks.Empty(); + } + + void Controller::Lock() + { + ++m_LockCount; + } + + void Controller::Unlock() + { + --m_LockCount; + } + + int Controller::LockCount() + { + if (m_LockCount < 0) + LOG(LWARNING, ("Lock/Unlock is unbalanced! LockCount < 0!")); + + return m_LockCount; + } + + void Controller::PerformStep() + { + m_tasks.ProcessList(bind(&Controller::CopyTasks, this, _1, ref(m_tasksList))); + + double ts = my::Timer::LocalTime(); + + TTasks l; + + for (TTasks::const_iterator it = m_tasksList.begin(); it != m_tasksList.end(); ++it) { - // making synchronized copy of tasks to process - // them without intervention from other threads. - m_newTasks.ProcessList(bind(&Controller::CopyTasks, this, _1, ref(m_newTasksList))); - m_tasks.ProcessList(bind(&Controller::CopyTasks, this, _1, ref(m_tasksList))); - - // checking for thread cancellation - if (m_newTasks.IsCancelled() - || m_tasks.IsCancelled() - || IsCancelled()) - break; - - // current animation step timestamp - double timeStamp = my::Timer::LocalTime(); - - // starting new tasks and adding them to the pool. - // they we'll be processed in the next animation step - for (TTasks::const_iterator it = m_newTasksList.begin(); - it != m_newTasksList.end(); - ++it) - { - shared_ptr task = *it; - task->OnStart(timeStamp); - m_tasks.PushBack(task); - } - - m_newTasksList.clear(); - - // processing current tasks - for (TTasks::const_iterator it = m_tasksList.begin(); - it != m_tasksList.end(); - ++it) - { - shared_ptr task = *it; - task->OnStep(timeStamp); - if (!task->IsFinished()) - m_tasks.PushBack(task); - else - task->OnEnd(timeStamp); - } - - m_tasksList.clear(); - - // sleeping till the next animation step. - threads::Sleep(m_animStep); + shared_ptr const & task = *it; + if (task->State() == Task::EWaitStart) + task->OnStart(ts); + if (task->State() == Task::EInProgress) + task->OnStep(ts); + if (task->State() == Task::EWaitEnd) + task->OnEnd(ts); + else + l.push_back(task); } + + m_tasks.ProcessList(bind(&Controller::CopyTasks, this, ref(l), _1)); } } diff --git a/anim/controller.hpp b/anim/controller.hpp index bf77e7766e..a46c9032c9 100644 --- a/anim/controller.hpp +++ b/anim/controller.hpp @@ -10,11 +10,7 @@ namespace anim class Task; // Animation controller class. - // - Creates and manages the separate thread. - // - Using ThreadedList to manage the list of active commands. - // - CPU efficient, which means that when there are no commands - // the thread is sleeping and doesn't consume CPU - class Controller : public threads::IRoutine + class Controller { private: @@ -25,17 +21,7 @@ namespace anim // Task for the current step. TTasks m_tasksList; - ThreadedList > m_newTasks; - // Added, but not started tasks. - // They'll be started in the next animation step. - TTasks m_newTasksList; - - // Animation thread. - threads::Thread m_thread; - // Animation step in miliseconds. - unsigned m_animStep; - // MainLoop method - void Do(); + int m_LockCount; void CopyTasks(list > & from, list > & to); @@ -46,5 +32,17 @@ namespace anim ~Controller(); // Adding animation task to the controller void AddTask(shared_ptr const & task); + // Do we have animation tasks, which are currently running? + bool HasTasks(); + // Lock/Unlock controller. Locked controller + // is considered to be in "transition" mode from one task to another + // and this situation is taken into account into RenderPolicy when + // checking for "need redraw" status. + void Lock(); + void Unlock(); + // Getting current lock count + int LockCount(); + // Perform single animation step + void PerformStep(); }; } diff --git a/anim/task.hpp b/anim/task.hpp index 16adf3231c..3853b27fce 100644 --- a/anim/task.hpp +++ b/anim/task.hpp @@ -6,12 +6,34 @@ namespace anim class Task { public: - virtual void OnStart(double ts) = 0; - virtual void OnStep(double ts) = 0; - virtual void OnEnd(double ts) = 0; - virtual bool IsFinished() = 0; - virtual void Finish() = 0; - virtual ~Task() {}; + enum EState + { + EWaitStart, + EInProgress, + EWaitEnd + }; + + private: + + EState m_State; + + protected: + + void SetState(EState state); + + public: + + Task(); + virtual ~Task(); + + EState State() const; + + virtual void OnStart(double ts); + virtual void OnStep(double ts); + virtual void OnEnd(double ts); + + void Finish(); + bool IsFinished() const; }; } diff --git a/map/basic_render_policy.cpp b/map/basic_render_policy.cpp index 042363ad76..c61673aabe 100644 --- a/map/basic_render_policy.cpp +++ b/map/basic_render_policy.cpp @@ -45,6 +45,8 @@ m2::RectI const BasicRenderPolicy::OnSize(int w, int h) void BasicRenderPolicy::BeginFrame(shared_ptr const & e, ScreenBase const & s) { + RenderPolicy::BeginFrame(e, s); + if (m_QueuedRenderer) m_QueuedRenderer->BeginFrame(); } diff --git a/map/basic_tiling_render_policy.cpp b/map/basic_tiling_render_policy.cpp index 40ce667cf8..06901adc00 100644 --- a/map/basic_tiling_render_policy.cpp +++ b/map/basic_tiling_render_policy.cpp @@ -52,6 +52,8 @@ BasicTilingRenderPolicy::BasicTilingRenderPolicy(Params const & p, void BasicTilingRenderPolicy::BeginFrame(shared_ptr const & e, ScreenBase const & s) { + RenderPolicy::BeginFrame(e, s); + if (m_QueuedRenderer) m_QueuedRenderer->BeginFrame(); } diff --git a/map/location_state.cpp b/map/location_state.cpp index aa28cc0106..1664252296 100644 --- a/map/location_state.cpp +++ b/map/location_state.cpp @@ -215,6 +215,8 @@ namespace location if (!m_fw->GetNavigator().DoSupportRotation()) return; + m_fw->GetRenderPolicy()->GetAnimController()->Lock(); + StopAnimation(); double startAngle = m_fw->GetNavigator().Screen().GetAngle(); @@ -235,8 +237,10 @@ namespace location endAngle, 1)); - m_fw->GetAnimController()->AddTask(m_rotateScreenTask); + m_fw->GetRenderPolicy()->GetAnimController()->AddTask(m_rotateScreenTask); } + + m_fw->GetRenderPolicy()->GetAnimController()->Unlock(); } void State::StopAnimation() diff --git a/map/render_policy.cpp b/map/render_policy.cpp index a62425e61b..d8dd3b5883 100644 --- a/map/render_policy.cpp +++ b/map/render_policy.cpp @@ -1,9 +1,6 @@ #include "../base/SRC_FIRST.hpp" #include "render_policy.hpp" - -#include "../indexer/drawing_rules.hpp" - #include "window_handle.hpp" #include "test_render_policy.hpp" #include "basic_render_policy.hpp" @@ -13,9 +10,13 @@ #include "tiling_render_policy_st.hpp" #include "tiling_render_policy_mt.hpp" +#include "../anim/controller.hpp" +#include "../anim/task.hpp" + #include "../yg/internal/opengl.hpp" #include "../indexer/scales.hpp" +#include "../indexer/drawing_rules.hpp" #include "../platform/video_timer.hpp" #include "../platform/settings.hpp" @@ -37,7 +38,7 @@ RenderPolicy::RenderPolicy(Params const & p, m_doForceUpdate(false), m_visualScale(p.m_visualScale), m_skinName(p.m_skinName), - m_isAnimating(false) + m_controller(new anim::Controller()) { LOG(LDEBUG, ("each BaseRule will hold up to", idCacheSize, "cached values")); drule::rules().ResizeCaches(idCacheSize); @@ -98,7 +99,10 @@ void RenderPolicy::StopRotate(double a, double) } void RenderPolicy::BeginFrame(shared_ptr const & e, ScreenBase const & s) -{} +{ + /// processing animations at the beginning of the frame + m_controller->PerformStep(); +} void RenderPolicy::EndFrame(shared_ptr const & e, ScreenBase const & s) {} @@ -110,7 +114,14 @@ bool RenderPolicy::DoSupportRotation() const bool RenderPolicy::NeedRedraw() const { - return m_windowHandle->needRedraw(); + return m_windowHandle->needRedraw() + || IsAnimating(); +} + +bool RenderPolicy::IsAnimating() const +{ + return (m_controller->HasTasks() + || (m_controller->LockCount() > 0)); } bool RenderPolicy::IsTiling() const @@ -209,14 +220,9 @@ void RenderPolicy::JoinBenchmarkFence(int fenceID) { } -void RenderPolicy::SetIsAnimating(bool flag) +shared_ptr const & RenderPolicy::GetAnimController() const { - m_isAnimating = flag; -} - -bool RenderPolicy::IsAnimating() const -{ - return m_isAnimating; + return m_controller; } RenderPolicy * CreateRenderPolicy(RenderPolicy::Params const & params) diff --git a/map/render_policy.hpp b/map/render_policy.hpp index 30fd8bf4df..2ad7504b6f 100644 --- a/map/render_policy.hpp +++ b/map/render_policy.hpp @@ -24,6 +24,12 @@ namespace yg class ResourceManager; } +namespace anim +{ + class Controller; + class Task; +} + class WindowHandle; class RenderPolicy @@ -54,7 +60,7 @@ protected: m2::AnyRectD m_invalidRect; double m_visualScale; string m_skinName; - bool m_isAnimating; + shared_ptr m_controller; public: @@ -114,7 +120,7 @@ public: bool DoForceUpdate() const; void SetForceUpdate(bool flag); - void SetIsAnimating(bool flag); + shared_ptr const & GetAnimController() const; bool IsAnimating() const; void SetInvalidRect(m2::AnyRectD const & glbRect); diff --git a/map/rotate_screen_task.cpp b/map/rotate_screen_task.cpp index 7a4de48a3d..8a757dfb94 100644 --- a/map/rotate_screen_task.cpp +++ b/map/rotate_screen_task.cpp @@ -11,21 +11,20 @@ RotateScreenTask::RotateScreenTask(Framework * framework, m_interval(interval) { m_startTime = 0; - m_isFinished = false; } void RotateScreenTask::OnStart(double ts) { m_startTime = ts; m_curAngle = m_startAngle; - m_framework->GetRenderPolicy()->SetIsAnimating(true); + anim::Task::OnStart(ts); } void RotateScreenTask::OnStep(double ts) { if (ts - m_startTime > m_interval) { - m_isFinished = true; + Finish(); return; } @@ -37,21 +36,4 @@ void RotateScreenTask::OnStep(double ts) m_framework->GetNavigator().Rotate(angle - m_curAngle); m_curAngle = angle; - - m_framework->GetRenderPolicy()->GetWindowHandle()->invalidate(); -} - -void RotateScreenTask::OnEnd(double ts) -{ - m_framework->GetRenderPolicy()->SetIsAnimating(false); -} - -bool RotateScreenTask::IsFinished() -{ - return m_isFinished; -} - -void RotateScreenTask::Finish() -{ - m_isFinished = true; } diff --git a/map/rotate_screen_task.hpp b/map/rotate_screen_task.hpp index f1a8c86337..8d8ec8ec77 100644 --- a/map/rotate_screen_task.hpp +++ b/map/rotate_screen_task.hpp @@ -16,8 +16,6 @@ private: double m_interval; double m_curAngle; - bool m_isFinished; - public: RotateScreenTask(Framework * framework, @@ -27,8 +25,4 @@ public: void OnStart(double ts); void OnStep(double ts); - void OnEnd(double ts); - - bool IsFinished(); - void Finish(); };