diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 4e11713605..cf0ff3c133 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -63,6 +63,7 @@ enum MultiTouchAction Framework::Framework() : m_lastCompass(0.0) + , m_isContextDestroyed(false) , m_currentMode(location::PendingPosition) , m_isCurrentModeInitialized(false) , m_isChoosePositionMode(false) @@ -143,23 +144,9 @@ bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi m_work.CreateDrapeEngine(make_ref(m_contextFactory), move(p)); m_work.EnterForeground(); - // Execute drape tasks which set up custom state. - { - lock_guard lock(m_drapeQueueMutex); - if (!m_drapeTasksQueue.empty()) - ExecuteDrapeTasks(); - } - return true; } -void Framework::DeleteDrapeEngine() -{ - m_work.EnterBackground(); - - m_work.DestroyDrapeEngine(); -} - bool Framework::IsDrapeEngineCreated() { return m_work.IsDrapeEngineCreated(); @@ -171,9 +158,16 @@ void Framework::Resize(int w, int h) m_work.OnSize(w, h); } -void Framework::DetachSurface() +void Framework::DetachSurface(bool destroyContext) { - m_work.SetRenderingEnabled(false); + LOG(LWARNING, ("Detach surface")); + if (destroyContext) + { + LOG(LWARNING, ("Destroy context")); + m_isContextDestroyed = true; + m_work.EnterBackground(); + } + m_work.SetRenderingDisabled(destroyContext); ASSERT(m_contextFactory != nullptr, ()); AndroidOGLContextFactory * factory = m_contextFactory->CastFactory(); @@ -182,11 +176,24 @@ void Framework::DetachSurface() void Framework::AttachSurface(JNIEnv * env, jobject jSurface) { + LOG(LWARNING, ("Attach surface")); + ASSERT(m_contextFactory != nullptr, ()); AndroidOGLContextFactory * factory = m_contextFactory->CastFactory(); factory->SetSurface(env, jSurface); - m_work.SetRenderingEnabled(true); + ASSERT(!m_guiPositions.empty(), ("GUI elements must be set-up before engine is created")); + + m_work.SetRenderingEnabled(factory); + + if (m_isContextDestroyed) + { + LOG(LWARNING, ("Recover resources, size:", factory->GetWidth(), factory->GetHeight())); + m_work.UpdateDrapeEngine(factory->GetWidth(), factory->GetHeight()); + m_isContextDestroyed = false; + + m_work.EnterForeground(); + } } void Framework::SetMapStyle(MapStyle mapStyle) @@ -196,6 +203,7 @@ void Framework::SetMapStyle(MapStyle mapStyle) void Framework::MarkMapStyle(MapStyle mapStyle) { + LOG(LWARNING, ("MarkMapStyle")); m_work.MarkMapStyle(mapStyle); } @@ -437,23 +445,6 @@ void Framework::SetupMeasurementSystem() m_work.SetupMeasurementSystem(); } -void Framework::PostDrapeTask(TDrapeTask && task) -{ - ASSERT(task != nullptr, ()); - lock_guard lock(m_drapeQueueMutex); - if (IsDrapeEngineCreated()) - task(); - else - m_drapeTasksQueue.push_back(move(task)); -} - -void Framework::ExecuteDrapeTasks() -{ - for (auto & task : m_drapeTasksQueue) - task(); - m_drapeTasksQueue.clear(); -} - void Framework::SetPlacePageInfo(place_page::Info const & info) { m_info = info; @@ -803,20 +794,15 @@ Java_com_mapswithme_maps_Framework_nativeBuildRoute(JNIEnv * env, jclass, jdouble startLat, jdouble startLon, jdouble finishLat, jdouble finishLon) { - g_framework->PostDrapeTask([startLat, startLon, finishLat, finishLon]() - { - frm()->BuildRoute(MercatorBounds::FromLatLon(startLat, startLon), - MercatorBounds::FromLatLon(finishLat, finishLon), 0 /* timeoutSec */); - }); + frm()->BuildRoute(MercatorBounds::FromLatLon(startLat, startLon), + MercatorBounds::FromLatLon(finishLat, finishLon), 0 /* timeoutSec */); + } JNIEXPORT void JNICALL Java_com_mapswithme_maps_Framework_nativeFollowRoute(JNIEnv * env, jclass) { - g_framework->PostDrapeTask([]() - { - frm()->FollowRoute(); - }); + frm()->FollowRoute(); } JNIEXPORT void JNICALL @@ -1013,10 +999,7 @@ Java_com_mapswithme_maps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolea bool const allow3dBuildings = static_cast(allowBuildings); g_framework->Save3dMode(allow3d, allow3dBuildings); - g_framework->PostDrapeTask([allow3d, allow3dBuildings]() - { - g_framework->Set3dMode(allow3d, allow3dBuildings); - }); + g_framework->Set3dMode(allow3d, allow3dBuildings); } JNIEXPORT void JNICALL @@ -1040,10 +1023,7 @@ Java_com_mapswithme_maps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass { bool const autoZoomEnabled = static_cast(enabled); frm()->SaveAutoZoom(autoZoomEnabled); - g_framework->PostDrapeTask([autoZoomEnabled]() - { - frm()->AllowAutoZoom(autoZoomEnabled); - }); + frm()->AllowAutoZoom(autoZoomEnabled); } JNIEXPORT jboolean JNICALL diff --git a/android/jni/com/mapswithme/maps/Framework.hpp b/android/jni/com/mapswithme/maps/Framework.hpp index a9b719a4f4..332606de49 100644 --- a/android/jni/com/mapswithme/maps/Framework.hpp +++ b/android/jni/com/mapswithme/maps/Framework.hpp @@ -45,6 +45,8 @@ namespace android string m_searchQuery; + bool m_isContextDestroyed; + map m_guiPositions; void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive); @@ -73,10 +75,9 @@ namespace android void Invalidate(); bool CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi, bool firstLaunch); - void DeleteDrapeEngine(); bool IsDrapeEngineCreated(); - void DetachSurface(); + void DetachSurface(bool destroyContext); void AttachSurface(JNIEnv * env, jobject jSurface); void SetMapStyle(MapStyle mapStyle); @@ -151,10 +152,6 @@ namespace android void ApplyWidgets(); void CleanWidgets(); - using TDrapeTask = function; - // Posts a task which must be executed when Drape Engine is alive. - void PostDrapeTask(TDrapeTask && task); - void SetPlacePageInfo(place_page::Info const & info); place_page::Info & GetPlacePageInfo(); void RequestBookingMinPrice(string const & hotelId, string const & currency, function const & callback); @@ -167,13 +164,6 @@ namespace android bool IsAutoRetryDownloadFailed(); bool IsDownloadOn3gEnabled(); void EnableDownloadOn3g(); - - private: - vector m_drapeTasksQueue; - mutex m_drapeQueueMutex; - - // This method must be executed under mutex m_drapeQueueMutex. - void ExecuteDrapeTasks(); }; } diff --git a/android/jni/com/mapswithme/maps/MapFragment.cpp b/android/jni/com/mapswithme/maps/MapFragment.cpp index 54c057c639..9b32591850 100644 --- a/android/jni/com/mapswithme/maps/MapFragment.cpp +++ b/android/jni/com/mapswithme/maps/MapFragment.cpp @@ -69,12 +69,6 @@ Java_com_mapswithme_maps_MapFragment_nativeCreateEngine(JNIEnv * env, jclass cla return g_framework->CreateDrapeEngine(env, surface, density, firstLaunch); } -JNIEXPORT void JNICALL -Java_com_mapswithme_maps_MapFragment_nativeDestroyEngine(JNIEnv * env, jclass clazz) -{ - g_framework->DeleteDrapeEngine(); -} - JNIEXPORT jboolean JNICALL Java_com_mapswithme_maps_MapFragment_nativeIsEngineCreated(JNIEnv * env, jclass clazz) { @@ -88,9 +82,9 @@ Java_com_mapswithme_maps_MapFragment_nativeAttachSurface(JNIEnv * env, jclass cl } JNIEXPORT void JNICALL -Java_com_mapswithme_maps_MapFragment_nativeDetachSurface(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_MapFragment_nativeDetachSurface(JNIEnv * env, jclass clazz, jboolean destroyContext) { - g_framework->DetachSurface(); + g_framework->DetachSurface(destroyContext); } JNIEXPORT void JNICALL diff --git a/android/jni/com/mapswithme/maps/SearchEngine.cpp b/android/jni/com/mapswithme/maps/SearchEngine.cpp index 0c04e4e2bb..63d6384a0b 100644 --- a/android/jni/com/mapswithme/maps/SearchEngine.cpp +++ b/android/jni/com/mapswithme/maps/SearchEngine.cpp @@ -240,21 +240,14 @@ extern "C" { lock_guard guard(g_resultsMutex); Result const & result = g_results.GetResult(index); - g_framework->PostDrapeTask([result]() - { - g_framework->NativeFramework()->ShowSearchResult(result); - }); + g_framework->NativeFramework()->ShowSearchResult(result); } JNIEXPORT void JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeShowAllResults(JNIEnv * env, jclass clazz) { lock_guard guard(g_resultsMutex); - auto const & results = g_results; - g_framework->PostDrapeTask([results]() - { - g_framework->NativeFramework()->ShowSearchResults(results); - }); + g_framework->NativeFramework()->ShowSearchResults(g_results); } JNIEXPORT void JNICALL diff --git a/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp index ec87921647..a31f86cae2 100644 --- a/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp +++ b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp @@ -37,10 +37,7 @@ Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeShowBookmarkOnMap( JNIEnv * env, jobject thiz, jint c, jint b) { BookmarkAndCategory bnc = BookmarkAndCategory(c,b); - g_framework->PostDrapeTask([bnc]() - { - frm()->ShowBookmark(bnc); - }); + frm()->ShowBookmark(bnc); } JNIEXPORT void JNICALL diff --git a/android/src/com/mapswithme/maps/MapFragment.java b/android/src/com/mapswithme/maps/MapFragment.java index 2e55d28230..3a7ae66df7 100644 --- a/android/src/com/mapswithme/maps/MapFragment.java +++ b/android/src/com/mapswithme/maps/MapFragment.java @@ -52,7 +52,7 @@ public class MapFragment extends BaseMwmFragment private int mHeight; private int mWidth; private boolean mRequireResize; - private boolean mEngineCreated; + private boolean mContextCreated; private boolean mFirstStart; private static boolean sWasCopyrightDisplayed; @@ -98,7 +98,7 @@ public class MapFragment extends BaseMwmFragment UiUtils.dimen(R.dimen.margin_compass_left) + offsetX, mHeight - UiUtils.dimen(R.dimen.margin_compass_bottom) + offsetY, ANCHOR_CENTER); - if (forceRedraw && mEngineCreated) + if (forceRedraw && mContextCreated) nativeApplyWidgets(); } @@ -108,7 +108,7 @@ public class MapFragment extends BaseMwmFragment mWidth - UiUtils.dimen(R.dimen.margin_ruler_right) + offsetX, mHeight - UiUtils.dimen(R.dimen.margin_ruler_bottom) + offsetY, ANCHOR_RIGHT_BOTTOM); - if (forceRedraw && mEngineCreated) + if (forceRedraw && mContextCreated) nativeApplyWidgets(); } @@ -141,6 +141,7 @@ public class MapFragment extends BaseMwmFragment if (nativeIsEngineCreated()) { nativeAttachSurface(surface); + mContextCreated = true; mRequireResize = true; return; } @@ -154,20 +155,20 @@ public class MapFragment extends BaseMwmFragment final float exactDensityDpi = metrics.densityDpi; mFirstStart = ((MwmActivity) getMwmActivity()).isFirstStart(); - mEngineCreated = nativeCreateEngine(surface, (int) exactDensityDpi, mFirstStart); - if (!mEngineCreated) + if (!nativeCreateEngine(surface, (int) exactDensityDpi, mFirstStart)) { reportUnsupported(); return; } + mContextCreated = true; onRenderingInitialized(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { - if (!mEngineCreated || + if (!mContextCreated || (!mRequireResize && surfaceHolder.isCreating())) return; @@ -181,22 +182,22 @@ public class MapFragment extends BaseMwmFragment @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { - if (!mEngineCreated) + if (!mContextCreated) return; if (getActivity() == null || !getActivity().isChangingConfigurations()) - destroyEngine(); + destroyContext(); else - nativeDetachSurface(); + nativeDetachSurface(false); } - void destroyEngine() + void destroyContext() { - if (!mEngineCreated) + if (!mContextCreated) return; - nativeDestroyEngine(); - mEngineCreated = false; + nativeDetachSurface(true); + mContextCreated = false; } @Override @@ -281,9 +282,8 @@ public class MapFragment extends BaseMwmFragment static native boolean nativeShowMapForUrl(String url); static native boolean nativeIsEngineCreated(); private static native boolean nativeCreateEngine(Surface surface, int density, boolean firstLaunch); - private static native void nativeDestroyEngine(); private static native void nativeAttachSurface(Surface surface); - private static native void nativeDetachSurface(); + private static native void nativeDetachSurface(boolean destroyContext); private static native void nativeSurfaceChanged(int w, int h); private static native void nativeOnTouch(int actionType, int id1, float x1, float y1, int id2, float x2, float y2, int maskedPointer); private static native void nativeSetupWidget(int widget, float x, float y, int anchor); diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java index 19cdd0c125..84489a0994 100644 --- a/android/src/com/mapswithme/maps/MwmActivity.java +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -751,8 +751,8 @@ public class MwmActivity extends BaseMwmFragmentActivity @Override public void recreate() { - // Explicitly destroy engine before activity recreation. - mMapFragment.destroyEngine(); + // Explicitly destroy context before activity recreation. + mMapFragment.destroyContext(); super.recreate(); } diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index d7a7af41f5..b959923619 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -319,16 +319,33 @@ void BackendRenderer::ReleaseResources() m_contextFactory->getResourcesUploadContext()->doneCurrent(); } +void BackendRenderer::OnContextCreate() +{ + LOG(LWARNING, ("On context create.")); + m_contextFactory->waitForInitialization(); + m_contextFactory->getResourcesUploadContext()->makeCurrent(); + + GLFunctions::Init(); + + InitGLDependentResource(); +} + +void BackendRenderer::OnContextDestroy() +{ + LOG(LWARNING, ("On context destroy.")); + m_readManager->InvalidateAll(); + m_batchersPool.reset(); + m_texMng->Release(); + + m_contextFactory->getResourcesUploadContext()->doneCurrent(); +} + BackendRenderer::Routine::Routine(BackendRenderer & renderer) : m_renderer(renderer) {} void BackendRenderer::Routine::Do() { - m_renderer.m_contextFactory->waitForInitialization(); - - m_renderer.m_contextFactory->getResourcesUploadContext()->makeCurrent(); - GLFunctions::Init(); - - m_renderer.InitGLDependentResource(); + LOG(LWARNING, ("Start routine.")); + m_renderer.OnContextCreate(); while (!IsCancelled()) { diff --git a/drape_frontend/backend_renderer.hpp b/drape_frontend/backend_renderer.hpp index 8222f674a7..ca34b14e4a 100644 --- a/drape_frontend/backend_renderer.hpp +++ b/drape_frontend/backend_renderer.hpp @@ -58,6 +58,9 @@ public: protected: unique_ptr CreateRoutine() override; + void OnContextCreate() override; + void OnContextDestroy() override; + private: void RecacheGui(gui::TWidgetsInitInfo const & initInfo, bool needResetOldGui); void RecacheChoosePositionMark(); diff --git a/drape_frontend/base_renderer.cpp b/drape_frontend/base_renderer.cpp index 8cc083b2ca..725c43b7a5 100644 --- a/drape_frontend/base_renderer.cpp +++ b/drape_frontend/base_renderer.cpp @@ -39,23 +39,18 @@ void BaseRenderer::StopThread() m_selfThread.Join(); } -void BaseRenderer::SetRenderingEnabled(bool const isEnabled) +void BaseRenderer::SetRenderingEnabled(ref_ptr contextFactory) { - // here we have to wait for completion of internal SetRenderingEnabled - mutex completionMutex; - condition_variable completionCondition; - bool notified = false; - auto completionHandler = [&]() - { - lock_guard lock(completionMutex); - notified = true; - completionCondition.notify_one(); - }; + if (m_wasContextReset) + m_contextFactory = contextFactory; + SetRenderingEnabled(true); +} - SetRenderingEnabled(isEnabled, completionHandler); - - unique_lock lock(completionMutex); - completionCondition.wait(lock, [¬ified] { return notified; }); +void BaseRenderer::SetRenderingDisabled(bool const destroyContext) +{ + if (destroyContext) + m_wasContextReset = true; + SetRenderingEnabled(false); } bool BaseRenderer::IsRenderingEnabled() const @@ -63,17 +58,22 @@ bool BaseRenderer::IsRenderingEnabled() const return m_isEnabled; } -void BaseRenderer::SetRenderingEnabled(bool const isEnabled, TCompletionHandler completionHandler) +void BaseRenderer::SetRenderingEnabled(bool const isEnabled) { if (isEnabled == m_isEnabled) - { - if (completionHandler != nullptr) - completionHandler(); - return; - } - m_renderingEnablingCompletionHandler = move(completionHandler); + // here we have to wait for completion of internal SetRenderingEnabled + mutex completionMutex; + condition_variable completionCondition; + bool notified = false; + m_renderingEnablingCompletionHandler = [&]() + { + lock_guard lock(completionMutex); + notified = true; + completionCondition.notify_one(); + }; + if (isEnabled) { // wake up rendering thread @@ -87,19 +87,30 @@ void BaseRenderer::SetRenderingEnabled(bool const isEnabled, TCompletionHandler // if renderer thread is waiting for message let it go CancelMessageWaiting(); } + + unique_lock lock(completionMutex); + completionCondition.wait(lock, [¬ified] { return notified; }); } void BaseRenderer::CheckRenderingEnabled() { if (!m_isEnabled) { - bool const isDrawContext = m_threadName == ThreadsCommutator::RenderThread; - dp::OGLContext * context = isDrawContext ? m_contextFactory->getDrawContext() : - m_contextFactory->getResourcesUploadContext(); + dp::OGLContext * context = nullptr; - context->setRenderingEnabled(false); + if (m_wasContextReset) + { + OnContextDestroy(); + } + else + { + bool const isDrawContext = m_threadName == ThreadsCommutator::RenderThread; + context = isDrawContext ? m_contextFactory->getDrawContext() : + m_contextFactory->getResourcesUploadContext(); + context->setRenderingEnabled(false); + } - // nofity initiator-thread about rendering disabling + // notify initiator-thread about rendering disabling Notify(); // wait for signal @@ -110,9 +121,17 @@ void BaseRenderer::CheckRenderingEnabled() m_wasNotified = false; m_isEnabled = true; - context->setRenderingEnabled(true); + if (m_wasContextReset) + { + m_wasContextReset = false; + OnContextCreate(); + } + else + { + context->setRenderingEnabled(true); + } - // nofity initiator-thread about rendering enabling + // notify initiator-thread about rendering enabling // m_renderingEnablingCompletionHandler will be setup before awakening of this thread Notify(); } diff --git a/drape_frontend/base_renderer.hpp b/drape_frontend/base_renderer.hpp index 14d4da18b4..d0e446d7c3 100644 --- a/drape_frontend/base_renderer.hpp +++ b/drape_frontend/base_renderer.hpp @@ -40,7 +40,9 @@ public: bool CanReceiveMessages(); - void SetRenderingEnabled(bool const isEnabled); + void SetRenderingEnabled(ref_ptr contextFactory); + void SetRenderingDisabled(bool const destroyContext); + bool IsRenderingEnabled() const; protected: @@ -55,6 +57,9 @@ protected: virtual unique_ptr CreateRoutine() = 0; + virtual void OnContextCreate() = 0; + virtual void OnContextDestroy() = 0; + private: using TCompletionHandler = function; @@ -67,7 +72,9 @@ private: TCompletionHandler m_renderingEnablingCompletionHandler; bool m_wasNotified; - void SetRenderingEnabled(bool const isEnabled, TCompletionHandler completionHandler); + atomic m_wasContextReset; + + void SetRenderingEnabled(bool const isEnabled); void Notify(); void WakeUp(); }; diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 9b2698c9b8..5b2d4be1dc 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -92,6 +92,24 @@ DrapeEngine::~DrapeEngine() m_textureManager->Release(); } +void DrapeEngine::Update(int w, int h) +{ + LOG(LWARNING, (w, h)); + + RecacheGui(false); + + UpdateMapStyleMessage::Blocker blocker; + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(blocker), + MessagePriority::High); + blocker.Wait(); + + m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, + make_unique_dp(m_widgetsLayout), + MessagePriority::Normal); + ResizeImpl(w, h); +} + void DrapeEngine::Resize(int w, int h) { if (m_viewport.GetHeight() != h || m_viewport.GetWidth() != w) @@ -151,12 +169,20 @@ void DrapeEngine::UpdateUserMarksLayer(TileKey const & tileKey, UserMarksProvide MessagePriority::Normal); } -void DrapeEngine::SetRenderingEnabled(bool const isEnabled) +void DrapeEngine::SetRenderingEnabled(ref_ptr contextFactory) { - m_frontend->SetRenderingEnabled(isEnabled); - m_backend->SetRenderingEnabled(isEnabled); + m_backend->SetRenderingEnabled(contextFactory); + m_frontend->SetRenderingEnabled(contextFactory); - LOG(LDEBUG, (isEnabled ? "Rendering enabled" : "Rendering disabled")); + LOG(LDEBUG, ("Rendering enabled")); +} + +void DrapeEngine::SetRenderingDisabled(bool const destroyContext) +{ + m_frontend->SetRenderingDisabled(destroyContext); + m_backend->SetRenderingDisabled(destroyContext); + + LOG(LDEBUG, ("Rendering disabled")); } void DrapeEngine::InvalidateRect(m2::RectD const & rect) diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 12c86481cc..2b64b79eaf 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -84,6 +84,8 @@ public: DrapeEngine(Params && params); ~DrapeEngine(); + void Update(int w, int h); + void Resize(int w, int h); void Invalidate(); @@ -102,7 +104,8 @@ public: void ChangeVisibilityUserMarksLayer(TileKey const & tileKey, bool isVisible); void UpdateUserMarksLayer(TileKey const & tileKey, UserMarksProvider * provider); - void SetRenderingEnabled(bool const isEnabled); + void SetRenderingEnabled(ref_ptr contextFactory); + void SetRenderingDisabled(bool const destroyContext); void InvalidateRect(m2::RectD const & rect); void UpdateMapStyle(); diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 38d71b5e2e..dbf559fbb0 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -129,6 +129,7 @@ FrontendRenderer::FrontendRenderer(Params const & params) , m_userPositionChangedFn(params.m_positionChangedFn) , m_requestedTiles(params.m_requestedTiles) , m_maxGeneration(0) + , m_needRestoreSize(false) { #ifdef DRAW_INFO m_tpf = 0.0; @@ -819,8 +820,13 @@ void FrontendRenderer::OnResize(ScreenBase const & screen) { m_myPositionController->OnNewViewportRect(); m_viewport.SetViewport(0, 0, viewportRect.SizeX(), viewportRect.SizeY()); + } + + if (viewportChanged || m_needRestoreSize) + { m_contextFactory->getDrawContext()->resize(viewportRect.SizeX(), viewportRect.SizeY()); m_framebuffer->SetSize(viewportRect.SizeX(), viewportRect.SizeY()); + m_needRestoreSize = false; } RefreshProjection(screen); @@ -1451,24 +1457,49 @@ TTilesCollection FrontendRenderer::ResolveTileKeys(ScreenBase const & screen) return tiles; } -FrontendRenderer::Routine::Routine(FrontendRenderer & renderer) : m_renderer(renderer) {} - -void FrontendRenderer::Routine::Do() +void FrontendRenderer::OnContextDestroy() { - m_renderer.m_contextFactory->waitForInitialization(); + LOG(LWARNING, ("On context destroy.")); - gui::DrapeGui::Instance().ConnectOnCompassTappedHandler(bind(&FrontendRenderer::OnCompassTapped, &m_renderer)); - m_renderer.m_myPositionController->SetListener(ref_ptr(&m_renderer)); - m_renderer.m_userEventStream.SetListener(ref_ptr(&m_renderer)); + // Clear all graphics. + for (RenderLayer & layer : m_layers) + { + layer.m_renderGroups.clear(); + layer.m_isDirty = false; + } - dp::OGLContext * context = m_renderer.m_contextFactory->getDrawContext(); + m_userMarkRenderGroups.clear(); + m_guiRenderer.reset(); + m_selectionShape.release(); + m_framebuffer.reset(); + m_transparentLayer.reset(); + + m_myPositionController->ResetRenderShape(); + m_routeRenderer->ClearGLDependentResources(); + m_gpsTrackRenderer->ClearRenderData(); + +#ifdef RENDER_DEBUG_RECTS + dp::DebugRectRenderer::Instance().Destroy(); +#endif + + m_gpuProgramManager.reset(); + m_contextFactory->getDrawContext()->doneCurrent(); + + m_needRestoreSize = true; +} + +void FrontendRenderer::OnContextCreate() +{ + LOG(LWARNING, ("On context create.")); + + m_contextFactory->waitForInitialization(); + + dp::OGLContext * context = m_contextFactory->getDrawContext(); context->makeCurrent(); - m_renderer.m_framebuffer->SetDefaultContext(context); + GLFunctions::Init(); GLFunctions::AttachCache(this_thread::get_id()); - dp::SupportManager::Instance().Init(); - GLFunctions::glPixelStore(gl_const::GLUnpackAlignment, 1); GLFunctions::glEnable(gl_const::GLDepthTest); @@ -1481,7 +1512,10 @@ void FrontendRenderer::Routine::Do() GLFunctions::glEnable(gl_const::GLCullFace); GLFunctions::glEnable(gl_const::GLScissorTest); - m_renderer.m_gpuProgramManager->Init(); + dp::SupportManager::Instance().Init(); + + m_gpuProgramManager = make_unique_dp(); + m_gpuProgramManager->Init(); dp::BlendingParams blendingParams; blendingParams.Apply(); @@ -1490,6 +1524,25 @@ void FrontendRenderer::Routine::Do() dp::DebugRectRenderer::Instance().Init(make_ref(m_renderer.m_gpuProgramManager)); #endif + // resources recovering + m_framebuffer.reset(new Framebuffer()); + m_framebuffer->SetDefaultContext(context); + + m_transparentLayer.reset(new TransparentLayer()); +} + +FrontendRenderer::Routine::Routine(FrontendRenderer & renderer) : m_renderer(renderer) {} + +void FrontendRenderer::Routine::Do() +{ + LOG(LWARNING, ("Start routine")); + + gui::DrapeGui::Instance().ConnectOnCompassTappedHandler(bind(&FrontendRenderer::OnCompassTapped, &m_renderer)); + m_renderer.m_myPositionController->SetListener(ref_ptr(&m_renderer)); + m_renderer.m_userEventStream.SetListener(ref_ptr(&m_renderer)); + + m_renderer.OnContextCreate(); + double const kMaxInactiveSeconds = 2.0; my::Timer timer; @@ -1499,6 +1552,8 @@ void FrontendRenderer::Routine::Do() bool modelViewChanged = true; bool viewportChanged = true; + dp::OGLContext * context = m_renderer.m_contextFactory->getDrawContext(); + while (!IsCancelled()) { ScreenBase modelView = m_renderer.ProcessEvents(modelViewChanged, viewportChanged); diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 2bb43a25be..54267771ce 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -151,6 +151,8 @@ public: protected: void AcceptMessage(ref_ptr message) override; unique_ptr CreateRoutine() override; + void OnContextCreate() override; + void OnContextDestroy() override; private: void OnResize(ScreenBase const & screen); @@ -325,6 +327,8 @@ private: drape_ptr m_selectObjectMessage; + bool m_needRestoreSize; + #ifdef DEBUG bool m_isTeardowned; #endif diff --git a/drape_frontend/gps_track_renderer.cpp b/drape_frontend/gps_track_renderer.cpp index d3c82e404e..b5137402be 100644 --- a/drape_frontend/gps_track_renderer.cpp +++ b/drape_frontend/gps_track_renderer.cpp @@ -90,6 +90,12 @@ void GpsTrackRenderer::AddRenderData(ref_ptr mng, m_waitForRenderData = false; } +void GpsTrackRenderer::ClearRenderData() +{ + m_renderData.clear(); + m_waitForRenderData = false; +} + void GpsTrackRenderer::UpdatePoints(vector const & toAdd, vector const & toRemove) { bool wasChanged = false; diff --git a/drape_frontend/gps_track_renderer.hpp b/drape_frontend/gps_track_renderer.hpp index 0ddd6063d3..cb40cb34e8 100644 --- a/drape_frontend/gps_track_renderer.hpp +++ b/drape_frontend/gps_track_renderer.hpp @@ -34,6 +34,7 @@ public: void Update(); void Clear(); + void ClearRenderData(); private: float CalculateRadius(ScreenBase const & screen) const; diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 3d868a8efd..e51f72c1ce 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -285,6 +285,11 @@ void MyPositionController::SetRenderShape(drape_ptr && shape) m_shape = move(shape); } +void MyPositionController::ResetRenderShape() +{ + m_shape.reset(); +} + void MyPositionController::NextMode(ScreenBase const & screen) { string const kAlohalyticsClickEvent = "$onClick"; diff --git a/drape_frontend/my_position_controller.hpp b/drape_frontend/my_position_controller.hpp index 00bd0be3bc..9d555fc880 100644 --- a/drape_frontend/my_position_controller.hpp +++ b/drape_frontend/my_position_controller.hpp @@ -69,6 +69,7 @@ public: void CorrectGlobalScalePoint(m2::PointD & pt) const; void SetRenderShape(drape_ptr && shape); + void ResetRenderShape(); void ActivateRouting(int zoomLevel, bool enableAutoZoom); void DeactivateRouting(); diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index 4a7b115980..3f041b3ce7 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -229,7 +229,7 @@ void RouteRenderer::UpdateRoute(ScreenBase const & screen, TCacheRouteArrowsCall void RouteRenderer::RenderRoute(ScreenBase const & screen, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { - if (!m_routeData) + if (!m_routeData || m_invalidGLResources) return; // Render route. @@ -284,6 +284,9 @@ void RouteRenderer::RenderRoute(ScreenBase const & screen, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { + if (m_invalidGLResources) + return; + if (m_startRouteSign) { ASSERT(m_startRouteSign->m_isValid, ()); @@ -301,6 +304,9 @@ void RouteRenderer::RenderRouteSign(drape_ptr const & sign, Scree ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { + if (m_invalidGLResources) + return; + dp::GLState const & state = sign->m_sign.m_state; dp::UniformValuesStorage uniforms = commonUniforms; @@ -322,6 +328,8 @@ void RouteRenderer::RenderRouteSign(drape_ptr const & sign, Scree void RouteRenderer::SetRouteData(drape_ptr && routeData, ref_ptr mng) { + m_invalidGLResources = false; + m_routeData = move(routeData); m_arrowBorders.clear(); @@ -331,6 +339,8 @@ void RouteRenderer::SetRouteData(drape_ptr && routeData, ref_ptr && routeSignData, ref_ptr mng) { + m_invalidGLResources = false; + if (routeSignData->m_isStart) { if (!routeSignData->m_isValid) @@ -373,6 +383,8 @@ drape_ptr const & RouteRenderer::GetRouteData() const void RouteRenderer::SetRouteArrows(drape_ptr && routeArrowsData, ref_ptr mng) { + m_invalidGLResources = false; + m_routeArrows = move(routeArrowsData); BuildBuckets(m_routeArrows->m_arrows, mng); } @@ -389,6 +401,19 @@ void RouteRenderer::Clear(bool keepDistanceFromBegin) m_distanceFromBegin = 0.0; } +void RouteRenderer::ClearGLDependentResources() +{ + m_invalidGLResources = true; + + if (m_routeData != nullptr) + m_routeData->m_route.m_buckets.clear(); + if (m_startRouteSign != nullptr) + m_startRouteSign->m_sign.m_buckets.clear(); + if (m_finishRouteSign != nullptr) + m_finishRouteSign->m_sign.m_buckets.clear(); + m_routeArrows.reset(); +} + void RouteRenderer::UpdateDistanceFromBegin(double distanceFromBegin) { m_distanceFromBegin = distanceFromBegin; diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp index a9f530704c..f98b9858f5 100644 --- a/drape_frontend/route_renderer.hpp +++ b/drape_frontend/route_renderer.hpp @@ -35,6 +35,7 @@ public: void SetRouteArrows(drape_ptr && routeArrowsData, ref_ptr mng); void Clear(bool keepDistanceFromBegin = false); + void ClearGLDependentResources(); void UpdateDistanceFromBegin(double distanceFromBegin); @@ -54,6 +55,8 @@ private: float m_currentHalfWidth = 0.0f; float m_currentAlpha = 0.0f; + + bool m_invalidGLResources = false; }; } // namespace df diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index c51a63338f..e97e74a7e5 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -160,7 +160,9 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool m2::RectD const prevPixelRect = GetCurrentScreen().PixelRect(); + viewportChanged = false; m_modelViewChanged = !events.empty() || m_state == STATE_SCALE || m_state == STATE_DRAG; + for (auto const & e : events) { bool breakAnim = false; @@ -178,6 +180,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool { ref_ptr resizeEvent = make_ref(e); m_navigator.OnSize(resizeEvent->GetWidth(), resizeEvent->GetHeight()); + viewportChanged = true; breakAnim = true; TouchCancel(m_touches); if (m_state == STATE_DOUBLE_TAP_HOLD) @@ -258,7 +261,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool modelViewChanged = m_modelViewChanged; double const kEps = 1e-5; - viewportChanged = !m2::IsEqualSize(prevPixelRect, GetCurrentScreen().PixelRect(), kEps, kEps); + viewportChanged |= !m2::IsEqualSize(prevPixelRect, GetCurrentScreen().PixelRect(), kEps, kEps); m_modelViewChanged = false; return m_navigator.Screen(); diff --git a/map/framework.cpp b/map/framework.cpp index aa9732b0ff..38de0dce7b 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -290,7 +290,7 @@ void Framework::Migrate(bool keepDownloaded) // If we do not suspend drape, it tries to access framework fields (i.e. m_infoGetter) which are null // while migration is performed. if (m_drapeEngine && m_isRenderingEnabled) - m_drapeEngine->SetRenderingEnabled(false); + m_drapeEngine->SetRenderingDisabled(false); m_selectedFeature = FeatureID(); m_searchEngine.reset(); m_infoGetter.reset(); @@ -303,7 +303,7 @@ void Framework::Migrate(bool keepDownloaded) InitSearchEngine(); RegisterAllMaps(); if (m_drapeEngine && m_isRenderingEnabled) - m_drapeEngine->SetRenderingEnabled(true); + m_drapeEngine->SetRenderingEnabled(nullptr); InvalidateRect(MercatorBounds::FullRect()); } @@ -1659,6 +1659,15 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, }); } +void Framework::UpdateDrapeEngine(int width, int height) +{ + if (m_drapeEngine) + { + m_drapeEngine->Update(width, height); + InvalidateUserMarks(); + } +} + ref_ptr Framework::GetDrapeEngine() { return make_ref(m_drapeEngine); @@ -1670,11 +1679,18 @@ void Framework::DestroyDrapeEngine() m_drapeEngine.reset(); } -void Framework::SetRenderingEnabled(bool enable) +void Framework::SetRenderingEnabled(ref_ptr contextFactory) { - m_isRenderingEnabled = enable; + m_isRenderingEnabled = true; if (m_drapeEngine) - m_drapeEngine->SetRenderingEnabled(enable); + m_drapeEngine->SetRenderingEnabled(contextFactory); +} + +void Framework::SetRenderingDisabled(bool destroyContext) +{ + m_isRenderingEnabled = false; + if (m_drapeEngine) + m_drapeEngine->SetRenderingDisabled(destroyContext); } void Framework::ConnectToGpsTracker() diff --git a/map/framework.hpp b/map/framework.hpp index ff78f9b079..60b3f47277 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -392,7 +392,11 @@ public: bool IsDrapeEngineCreated() const { return m_drapeEngine != nullptr; } void DestroyDrapeEngine(); /// Called when graphics engine should be temporarily paused and then resumed. - void SetRenderingEnabled(bool enable); + void SetRenderingEnabled(ref_ptr contextFactory); + void SetRenderingDisabled(bool destroyContext); + + void UpdateDrapeEngine(int width, int height); + private: /// Depends on initialized Drape engine. void SaveViewport();