From 37fc30f41b9f4ada6276b2f9c01780ee9a8b8ffa Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Wed, 13 Mar 2019 10:29:39 +0300 Subject: [PATCH] [drape] Optimized route arrows preparation --- drape/drape_routine.hpp | 28 ++++++++-- drape_frontend/drape_engine.cpp | 2 +- drape_frontend/frontend_renderer.cpp | 40 ++++++++++---- drape_frontend/frontend_renderer.hpp | 5 +- drape_frontend/message.cpp | 3 +- drape_frontend/message.hpp | 3 +- drape_frontend/message_subclasses.hpp | 22 +++++++- drape_frontend/route_renderer.cpp | 80 +++++++++++++++++++-------- drape_frontend/route_renderer.hpp | 6 +- 9 files changed, 139 insertions(+), 50 deletions(-) diff --git a/drape/drape_routine.hpp b/drape/drape_routine.hpp index 210ce26df3..5d000ec2f5 100644 --- a/drape/drape_routine.hpp +++ b/drape/drape_routine.hpp @@ -19,8 +19,6 @@ namespace dp // OpenGL data), use FR/BR threads for that. class DrapeRoutine { - friend class Promise; - public: class Result { @@ -92,6 +90,23 @@ public: return result; } + // Asynchronous execution for tasks when execution order matters. + template + static ResultPtr RunSequential(Task && t) + { + ResultPtr result(new Result(Instance().GetNextId())); + bool const success = Instance().m_sequentialWorkerThread.Push([result, t]() mutable + { + t(); + Instance().Notify(result->Finish()); + }); + + if (!success) + return {}; + + return result; + } + private: static DrapeRoutine & Instance() { @@ -129,6 +144,7 @@ private: void FinishAll() { m_workerThread.ShutdownAndJoin(); + m_sequentialWorkerThread.ShutdownAndJoin(); std::lock_guard lock(m_mutex); m_finished = true; @@ -141,6 +157,7 @@ private: std::condition_variable m_condition; std::mutex m_mutex; base::thread_pool::delayed::ThreadPool m_workerThread; + base::thread_pool::delayed::ThreadPool m_sequentialWorkerThread; }; // This is a helper class, which aggregates logic of waiting for active @@ -179,10 +196,9 @@ public: void Remove(std::shared_ptr const & task) { std::lock_guard lock(m_mutex); - m_tasks.erase( - std::remove_if(m_tasks.begin(), m_tasks.end(), - [task](ActiveTask const & t) { return t.m_task == task; }), - m_tasks.end()); + m_tasks.erase(std::remove_if(m_tasks.begin(), m_tasks.end(), + [task](ActiveTask const & t) { return t.m_task == task; }), + m_tasks.end()); } void FinishAll() diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 7de05e166d..b51fd7e65e 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -147,7 +147,7 @@ void DrapeEngine::Update(int w, int h) RecacheMapShapes(); m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(), + make_unique_dp(), MessagePriority::Normal); ResizeImpl(w, h); diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 8cabcd64e3..5d14a9d793 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -474,8 +474,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) { m_routeRenderer->UpdateDistanceFromBegin(info.GetDistanceFromBegin()); // Here we have to recache route arrows. - m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(), - std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + m_routeRenderer->PrepareRouteArrows(m_userEventStream.GetCurrentScreen(), + std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2)); } break; @@ -514,8 +514,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) m_routeRenderer->AddSubrouteData(m_context, std::move(subrouteData), make_ref(m_gpuProgramManager)); // Here we have to recache route arrows. - m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(), - std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + m_routeRenderer->PrepareRouteArrows(m_userEventStream.GetCurrentScreen(), + std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2)); if (m_pendingFollowRoute != nullptr) { @@ -642,9 +642,18 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::Type::RecoverGLResources: + case Message::Type::PrepareSubrouteArrows: { - UpdateGLResources(); + ref_ptr msg = message; + m_routeRenderer->CacheRouteArrows(m_userEventStream.GetCurrentScreen(), + msg->GetSubrouteId(), msg->MoveBorders(), + std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + break; + } + + case Message::Type::RecoverContextDependentResources: + { + UpdateContextDependentResources(); break; } @@ -683,7 +692,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) blocker.Wait(); } - UpdateGLResources(); + UpdateContextDependentResources(); break; } @@ -996,7 +1005,7 @@ unique_ptr FrontendRenderer::CreateRoutine() return make_unique(*this); } -void FrontendRenderer::UpdateGLResources() +void FrontendRenderer::UpdateContextDependentResources() { ++m_lastRecacheRouteId; @@ -1011,7 +1020,7 @@ void FrontendRenderer::UpdateGLResources() m_trafficRenderer->ClearContextDependentResources(); - // In some cases UpdateGLResources can be called before the rendering of + // In some cases UpdateContextDependentResources can be called before the rendering of // the first frame. m_currentZoomLevel will be equal to -1, so ResolveTileKeys // could not be called. if (m_currentZoomLevel > 0) @@ -2406,7 +2415,7 @@ void FrontendRenderer::PrepareScene(ScreenBase const & modelView) RefreshPivotTransform(modelView); m_myPositionController->OnUpdateScreen(modelView); - m_routeRenderer->UpdateRoute(modelView, std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + m_routeRenderer->PrepareRouteArrows(modelView, std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2)); } void FrontendRenderer::UpdateScene(ScreenBase const & modelView) @@ -2448,10 +2457,17 @@ void FrontendRenderer::EmitModelViewChanged(ScreenBase const & modelView) const m_modelViewChangedFn(modelView); } -void FrontendRenderer::OnCacheRouteArrows(int routeIndex, std::vector const & borders) +void FrontendRenderer::OnPrepareRouteArrows(dp::DrapeID subrouteIndex, std::vector && borders) +{ + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(subrouteIndex, std::move(borders)), + MessagePriority::Normal); +} + +void FrontendRenderer::OnCacheRouteArrows(dp::DrapeID subrouteIndex, std::vector const & borders) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(routeIndex, borders, m_lastRecacheRouteId), + make_unique_dp(subrouteIndex, borders, m_lastRecacheRouteId), MessagePriority::Normal); } diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 447d365ab3..14227e6651 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -226,7 +226,7 @@ private: }; void ReleaseResources(); - void UpdateGLResources(); + void UpdateContextDependentResources(); void BeginUpdateOverlayTree(ScreenBase const & modelView); void UpdateOverlayTree(ScreenBase const & modelView, drape_ptr & renderGroup); @@ -255,7 +255,8 @@ private: void ProcessSelection(ref_ptr msg); - void OnCacheRouteArrows(int routeIndex, std::vector const & borders); + void OnPrepareRouteArrows(dp::DrapeID subrouteIndex, std::vector && borders); + void OnCacheRouteArrows(dp::DrapeID subrouteIndex, std::vector const & borders); void CollectShowOverlaysEvents(); diff --git a/drape_frontend/message.cpp b/drape_frontend/message.cpp index 89925e12a2..f2f170174b 100644 --- a/drape_frontend/message.cpp +++ b/drape_frontend/message.cpp @@ -37,6 +37,7 @@ std::string DebugPrint(Message::Type msgType) case Message::Type::SelectObject: return "SelectObject"; case Message::Type::AddSubroute: return "AddSubroute"; case Message::Type::RemoveSubroute: return "RemoveSubroute"; + case Message::Type::PrepareSubrouteArrows: return "PrepareSubrouteArrows"; case Message::Type::CacheSubrouteArrows: return "CacheSubrouteArrows"; case Message::Type::FlushSubroute: return "FlushSubroute"; case Message::Type::FlushSubrouteArrows: return "FlushSubrouteArrows"; @@ -64,7 +65,7 @@ std::string DebugPrint(Message::Type msgType) case Message::Type::SetDisplacementMode: return "SetDisplacementMode"; case Message::Type::AllowAutoZoom: return "AllowAutoZoom"; case Message::Type::RequestSymbolsSize: return "RequestSymbolsSize"; - case Message::Type::RecoverGLResources: return "RecoverGLResources"; + case Message::Type::RecoverContextDependentResources: return "RecoverContextDependentResources"; case Message::Type::SetVisibleViewport: return "SetVisibleViewport"; case Message::Type::EnableTraffic: return "EnableTraffic"; case Message::Type::FlushTrafficGeometry: return "FlushTrafficGeometry"; diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 9a1d1db343..49f4e6c84a 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -38,6 +38,7 @@ public: SelectObject, AddSubroute, RemoveSubroute, + PrepareSubrouteArrows, CacheSubrouteArrows, FlushSubroute, FlushSubrouteArrows, @@ -65,7 +66,7 @@ public: SetDisplacementMode, AllowAutoZoom, RequestSymbolsSize, - RecoverGLResources, + RecoverContextDependentResources, SetVisibleViewport, EnableTraffic, FlushTrafficGeometry, diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 6db408c2a7..a50e9fe921 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -561,6 +561,24 @@ private: int const m_recacheId; }; +class PrepareSubrouteArrowsMessage : public Message +{ +public: + PrepareSubrouteArrowsMessage(dp::DrapeID subrouteId, + std::vector && borders) + : m_subrouteId(subrouteId) + , m_borders(std::move(borders)) + {} + + Type GetType() const override { return Type::PrepareSubrouteArrows; } + dp::DrapeID GetSubrouteId() const { return m_subrouteId; } + std::vector && MoveBorders() { return std::move(m_borders); } + +private: + dp::DrapeID m_subrouteId; + std::vector m_borders; +}; + class CacheSubrouteArrowsMessage : public Message { public: @@ -711,10 +729,10 @@ public: Type GetType() const override { return Type::Invalidate; } }; -class RecoverGLResourcesMessage : public Message +class RecoverContextDependentResourcesMessage : public Message { public: - Type GetType() const override { return Type::RecoverGLResources; } + Type GetType() const override { return Type::RecoverContextDependentResources; } bool IsGraphicsContextDependent() const override { return true; } }; diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index 48fbe9568a..9171c3e95c 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -5,6 +5,7 @@ #include "shaders/programs.hpp" +#include "drape/drape_routine.hpp" #include "drape/glsl_func.hpp" #include "drape/utils/projection.hpp" #include "drape/vertex_array_buffer.hpp" @@ -145,17 +146,17 @@ bool AreEqualArrowBorders(std::vector const & borders1, return true; } -std::vector CalculateArrowBorders(ScreenBase const & screen, float currentHalfWidth, - RouteRenderer::SubrouteInfo const & subrouteInfo, - double distanceFromBegin) +std::vector CalculateArrowBorders(m2::RectD screenRect, double screenScale, + float currentHalfWidth, SubrouteConstPtr const & subroute, + double subrouteLength, double distanceFromBegin) { - auto const & turns = subrouteInfo.m_subroute->m_turns; + auto const & turns = subroute->m_turns; if (turns.empty()) return {}; // Calculate arrow mercator length. double glbHalfLen = 0.5 * kArrowSize; - double const glbHalfTextureWidth = currentHalfWidth * kArrowHeightFactor * screen.GetScale(); + double const glbHalfTextureWidth = currentHalfWidth * kArrowHeightFactor * screenScale; double const glbHalfTextureLen = glbHalfTextureWidth * kArrowAspect; if (glbHalfLen < glbHalfTextureLen) glbHalfLen = glbHalfTextureLen; @@ -164,20 +165,20 @@ std::vector CalculateArrowBorders(ScreenBase const & screen, float double const glbArrowTail = 2.0 * kArrowTailSize * glbHalfTextureLen; double const glbMinArrowSize = glbArrowHead + glbArrowTail; - double const kExtendCoef = 1.1; - m2::RectD screenRect = screen.ClipRect(); - screenRect.Scale(kExtendCoef); + double constexpr kExtentCoef = 1.1; + screenRect.Scale(kExtentCoef); // Calculate arrow borders. + size_t constexpr kAverageArrowsCount = 10; std::vector newArrowBorders; - newArrowBorders.reserve(turns.size()); - auto const & polyline = subrouteInfo.m_subroute->m_polyline; + newArrowBorders.reserve(kAverageArrowsCount); + auto const & polyline = subroute->m_polyline; for (size_t i = 0; i < turns.size(); i++) { ArrowBorders arrowBorders; arrowBorders.m_groupIndex = static_cast(i); arrowBorders.m_startDistance = std::max(0.0, turns[i] - glbHalfLen * 0.8); - arrowBorders.m_endDistance = std::min(subrouteInfo.m_length, turns[i] + glbHalfLen * 1.2); + arrowBorders.m_endDistance = std::min(subrouteLength, turns[i] + glbHalfLen * 1.2); if ((arrowBorders.m_endDistance - arrowBorders.m_startDistance) < glbMinArrowSize || arrowBorders.m_startDistance < distanceFromBegin) @@ -248,9 +249,9 @@ RouteRenderer::RouteRenderer(PreviewPointsRequestCallback && previewPointsReques ASSERT(m_previewPointsRequest != nullptr, ()); } -void RouteRenderer::UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback) +void RouteRenderer::PrepareRouteArrows(ScreenBase const & screen, + PrepareRouteArrowsCallback const & prepareCallback) { - ASSERT(callback != nullptr, ()); for (auto & subrouteInfo : m_subroutes) { // Interpolate values by zoom level. @@ -270,18 +271,49 @@ void RouteRenderer::UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallb double dist = kInvalidDistance; if (m_followingEnabled) dist = m_distanceFromBegin - subrouteInfo.m_subroute->m_baseDistance; - auto newArrowBorders = CalculateArrowBorders(screen, halfWidth, subrouteInfo, dist); - if (newArrowBorders.empty()) + + // We run asynchronous task to calculate new positions of route arrows. + auto subrouteId = subrouteInfo.m_subrouteId; + auto screenRect = screen.ClipRect(); + auto screenScale = screen.GetScale(); + auto subroute = subrouteInfo.m_subroute; + auto subrouteLength = subrouteInfo.m_length; + dp::DrapeRoutine::RunSequential([subrouteId, screenRect, screenScale, halfWidth, + subroute = std::move(subroute), subrouteLength, + dist, prepareCallback]() { - // Clear arrows. - subrouteInfo.m_arrowsData.reset(); - subrouteInfo.m_arrowBorders.clear(); - } - else if (!AreEqualArrowBorders(newArrowBorders, subrouteInfo.m_arrowBorders)) - { - subrouteInfo.m_arrowBorders = std::move(newArrowBorders); - callback(subrouteInfo.m_subrouteId, subrouteInfo.m_arrowBorders); - } + ASSERT(prepareCallback != nullptr, ()); + prepareCallback(subrouteId, CalculateArrowBorders(screenRect, screenScale, halfWidth, + subroute, subrouteLength, dist)); + }); + } +} + +void RouteRenderer::CacheRouteArrows(ScreenBase const & screen, dp::DrapeID subrouteId, + std::vector && arrowBorders, + CacheRouteArrowsCallback const & cacheCallback) +{ + ASSERT(cacheCallback != nullptr, ()); + auto const it = FindSubroute(m_subroutes, subrouteId); + if (it == m_subroutes.end()) + return; + + auto & subrouteInfo = *it; + + double zoom = 0.0; + float halfWidth = 0.0; + InterpolateByZoom(subrouteInfo.m_subroute, screen, halfWidth, zoom); + + if (arrowBorders.empty() || zoom < kArrowAppearingZoomLevel) + { + // Clear arrows. + subrouteInfo.m_arrowsData.reset(); + subrouteInfo.m_arrowBorders.clear(); + } + else if (!AreEqualArrowBorders(arrowBorders, subrouteInfo.m_arrowBorders)) + { + subrouteInfo.m_arrowBorders = std::move(arrowBorders); + cacheCallback(subrouteInfo.m_subrouteId, subrouteInfo.m_arrowBorders); } } diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp index e676c2c0d3..c2e83cd757 100644 --- a/drape_frontend/route_renderer.hpp +++ b/drape_frontend/route_renderer.hpp @@ -29,6 +29,7 @@ extern std::string const kTransitStopInnerMarkerColor; class RouteRenderer final { public: + using PrepareRouteArrowsCallback = std::function &&)>; using CacheRouteArrowsCallback = std::function const &)>; using PreviewPointsRequestCallback = std::function; @@ -55,7 +56,10 @@ public: explicit RouteRenderer(PreviewPointsRequestCallback && previewPointsRequest); - void UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback); + void PrepareRouteArrows(ScreenBase const & screen, PrepareRouteArrowsCallback const & prepareCallback); + void CacheRouteArrows(ScreenBase const & screen, dp::DrapeID subrouteId, + std::vector && arrowBorders, + CacheRouteArrowsCallback const & cacheCallback); void RenderRoute(ref_ptr context, ref_ptr mng, ScreenBase const & screen, bool trafficShown, FrameValues const & frameValues);