void ReadManager::Invalidate(TTilesCollection const & keyStorage) { TTileSet tilesToErase; for (auto const & info : m_tileInfos) { if (keyStorage.find(info->GetTileKey()) != keyStorage.end()) tilesToErase.insert(info); } for (auto const & info : tilesToErase) { CancelTileInfo(info); m_tileInfos.erase(info); } m_forceUpdate = true; }
void FrontendRenderer::AcceptMessage(ref_ptr<Message> message) { switch (message->GetType()) { case Message::FlushTile: { ref_ptr<FlushRenderBucketMessage> msg = message; dp::GLState const & state = msg->GetState(); TileKey const & key = msg->GetKey(); drape_ptr<dp::RenderBucket> bucket = msg->AcceptBuffer(); ref_ptr<dp::GpuProgram> program = m_gpuProgramManager->GetProgram(state.GetProgramIndex()); ref_ptr<dp::GpuProgram> program3d = m_gpuProgramManager->GetProgram(state.GetProgram3dIndex()); bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); if (isPerspective) program3d->Bind(); else program->Bind(); bucket->GetBuffer()->Build(isPerspective ? program3d : program); if (!IsUserMarkLayer(key)) { if (CheckTileGenerations(key)) m_tileTree->ProcessTile(key, GetCurrentZoomLevelForData(), state, move(bucket)); } else { m_userMarkRenderGroups.emplace_back(make_unique_dp<UserMarkRenderGroup>(state, key, move(bucket))); m_userMarkRenderGroups.back()->SetRenderParams(program, program3d, make_ref(&m_generalUniforms)); } break; } case Message::FinishReading: { ref_ptr<FinishReadingMessage> msg = message; for (auto const & tileKey : msg->GetTiles()) CheckTileGenerations(tileKey); m_tileTree->FinishTiles(msg->GetTiles(), GetCurrentZoomLevelForData()); break; } case Message::InvalidateRect: { ref_ptr<InvalidateRectMessage> m = message; TTilesCollection tiles; ScreenBase screen = m_userEventStream.GetCurrentScreen(); m2::RectD rect = m->GetRect(); if (rect.Intersect(screen.ClipRect())) { m_tileTree->Invalidate(); ResolveTileKeys(rect, tiles); auto eraseFunction = [&tiles](vector<drape_ptr<RenderGroup>> & groups) { vector<drape_ptr<RenderGroup> > newGroups; for (drape_ptr<RenderGroup> & group : groups) { if (tiles.find(group->GetTileKey()) == tiles.end()) newGroups.push_back(move(group)); } swap(groups, newGroups); }; eraseFunction(m_renderGroups); eraseFunction(m_deferredRenderGroups); BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateReadManagerRectMessage>(blocker, tiles), MessagePriority::High); blocker.Wait(); m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), move(tiles)); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<UpdateReadManagerMessage>(), MessagePriority::UberHighSingleton); } break; } case Message::ClearUserMarkLayer: { TileKey const & tileKey = ref_ptr<ClearUserMarkLayerMessage>(message)->GetKey(); auto const functor = [&tileKey](drape_ptr<UserMarkRenderGroup> const & g) { return g->GetTileKey() == tileKey; }; auto const iter = remove_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), functor); m_userMarkRenderGroups.erase(iter, m_userMarkRenderGroups.end()); break; } case Message::ChangeUserMarkLayerVisibility: { ref_ptr<ChangeUserMarkLayerVisibilityMessage> m = message; TileKey const & key = m->GetKey(); if (m->IsVisible()) m_userMarkVisibility.insert(key); else m_userMarkVisibility.erase(key); break; } case Message::GuiLayerRecached: { ref_ptr<GuiLayerRecachedMessage> msg = message; drape_ptr<gui::LayerRenderer> renderer = move(msg->AcceptRenderer()); renderer->Build(make_ref(m_gpuProgramManager)); if (m_guiRenderer == nullptr) m_guiRenderer = move(renderer); else m_guiRenderer->Merge(make_ref(renderer)); break; } case Message::GuiLayerLayout: { ASSERT(m_guiRenderer != nullptr, ()); m_guiRenderer->SetLayout(ref_ptr<GuiLayerLayoutMessage>(message)->GetLayoutInfo()); break; } case Message::StopRendering: { ProcessStopRenderingMessage(); break; } case Message::MyPositionShape: { ref_ptr<MyPositionShapeMessage> msg = message; m_myPositionController->SetRenderShape(msg->AcceptShape()); m_selectionShape = msg->AcceptSelection(); } break; case Message::ChangeMyPostitionMode: { ref_ptr<ChangeMyPositionModeMessage> msg = message; switch (msg->GetChangeType()) { case ChangeMyPositionModeMessage::TYPE_NEXT: m_myPositionController->NextMode(msg->GetPreferredZoomLevel()); break; case ChangeMyPositionModeMessage::TYPE_STOP_FOLLOW: m_myPositionController->StopLocationFollow(); break; case ChangeMyPositionModeMessage::TYPE_INVALIDATE: m_myPositionController->Invalidate(); break; case ChangeMyPositionModeMessage::TYPE_CANCEL: m_myPositionController->TurnOff(); break; default: ASSERT(false, ("Unknown change type:", static_cast<int>(msg->GetChangeType()))); break; } break; } case Message::CompassInfo: { ref_ptr<CompassInfoMessage> msg = message; m_myPositionController->OnCompassUpdate(msg->GetInfo(), m_userEventStream.GetCurrentScreen()); break; } case Message::GpsInfo: { ref_ptr<GpsInfoMessage> msg = message; m_myPositionController->OnLocationUpdate(msg->GetInfo(), msg->IsNavigable(), m_userEventStream.GetCurrentScreen()); location::RouteMatchingInfo const & info = msg->GetRouteInfo(); if (info.HasDistanceFromBegin()) m_routeRenderer->UpdateDistanceFromBegin(info.GetDistanceFromBegin()); break; } case Message::FindVisiblePOI: { ref_ptr<FindVisiblePOIMessage> msg = message; ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); msg->SetFeatureID(GetVisiblePOI(screen.isPerspective() ? screen.PtoP3d(screen.GtoP(msg->GetPoint())) : screen.GtoP(msg->GetPoint()))); break; } case Message::SelectObject: { ref_ptr<SelectObjectMessage> msg = message; if (m_selectionShape == nullptr) break; if (msg->IsDismiss()) { m_selectionShape->Hide(); } else { double offsetZ = 0.0; if (m_userEventStream.GetCurrentScreen().isPerspective()) { dp::OverlayTree::TSelectResult selectResult; m_overlayTree->Select(msg->GetPosition(), selectResult); for (ref_ptr<dp::OverlayHandle> handle : selectResult) offsetZ = max(offsetZ, handle->GetPivotZ()); } m_selectionShape->Show(msg->GetSelectedObject(), msg->GetPosition(), offsetZ, msg->IsAnim()); } break; } case Message::GetSelectedObject: { ref_ptr<GetSelectedObjectMessage> msg = message; if (m_selectionShape != nullptr) msg->SetSelectedObject(m_selectionShape->GetSelectedObject()); else msg->SetSelectedObject(SelectionShape::OBJECT_EMPTY); break; } case Message::GetMyPosition: { ref_ptr<GetMyPositionMessage> msg = message; msg->SetMyPosition(m_myPositionController->IsModeHasPosition(), m_myPositionController->Position()); break; } case Message::FlushRoute: { ref_ptr<FlushRouteMessage> msg = message; drape_ptr<RouteData> routeData = msg->AcceptRouteData(); m2::PointD const startPoint = routeData->m_sourcePolyline.Front(); m2::PointD const finishPoint = routeData->m_sourcePolyline.Back(); m_routeRenderer->SetRouteData(move(routeData), make_ref(m_gpuProgramManager)); if (!m_routeRenderer->GetStartPoint()) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(startPoint, true /* isStart */, true /* isValid */), MessagePriority::High); } if (!m_routeRenderer->GetFinishPoint()) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(finishPoint, false /* isStart */, true /* isValid */), MessagePriority::High); } m_myPositionController->ActivateRouting(); break; } case Message::FlushRouteSign: { ref_ptr<FlushRouteSignMessage> msg = message; drape_ptr<RouteSignData> routeSignData = msg->AcceptRouteSignData(); m_routeRenderer->SetRouteSign(move(routeSignData), make_ref(m_gpuProgramManager)); break; } case Message::RemoveRoute: { ref_ptr<RemoveRouteMessage> msg = message; m_routeRenderer->Clear(); if (msg->NeedDeactivateFollowing()) { m_myPositionController->DeactivateRouting(); m_overlayTree->SetFollowingMode(false); if (m_enablePerspectiveInNavigation) DisablePerspective(); } break; } case Message::FollowRoute: { ref_ptr<FollowRouteMessage> const msg = message; m_myPositionController->NextMode(!m_enablePerspectiveInNavigation ? msg->GetPreferredZoomLevel() : msg->GetPreferredZoomLevelIn3d()); m_overlayTree->SetFollowingMode(true); if (m_enablePerspectiveInNavigation) { bool immediatelyStart = !m_myPositionController->IsRotationActive(); AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), true /* animated */, immediatelyStart)); } break; } case Message::DeactivateRouteFollowing: { m_myPositionController->DeactivateRouting(); m_overlayTree->SetFollowingMode(false); if (m_enablePerspectiveInNavigation) DisablePerspective(); break; } case Message::UpdateMapStyle: { // Clear tile tree. m_tileTree->Invalidate(); // Get new tiles. TTilesCollection tiles; ScreenBase screen = m_userEventStream.GetCurrentScreen(); ResolveTileKeys(screen.ClipRect(), tiles); // Clear all graphics. m_renderGroups.clear(); m_deferredRenderGroups.clear(); // Invalidate read manager. { BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateReadManagerRectMessage>(blocker, tiles), MessagePriority::High); blocker.Wait(); } // Invalidate textures and wait for completion. { BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateTexturesMessage>(blocker), MessagePriority::High); blocker.Wait(); } // Invalidate route. if (m_routeRenderer->GetStartPoint()) { m2::PointD const & position = m_routeRenderer->GetStartPoint()->m_position; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(position, true /* isStart */, true /* isValid */), MessagePriority::High); } if (m_routeRenderer->GetFinishPoint()) { m2::PointD const & position = m_routeRenderer->GetFinishPoint()->m_position; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(position, false /* isStart */, true /* isValid */), MessagePriority::High); } auto const & routeData = m_routeRenderer->GetRouteData(); if (routeData != nullptr) { auto recacheRouteMsg = make_unique_dp<AddRouteMessage>(routeData->m_sourcePolyline, routeData->m_sourceTurns, routeData->m_color); m_routeRenderer->Clear(true /* keepDistanceFromBegin */); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, move(recacheRouteMsg), MessagePriority::Normal); } // Request new tiles. m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), move(tiles)); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<UpdateReadManagerMessage>(), MessagePriority::UberHighSingleton); break; } case Message::EnablePerspective: { ref_ptr<EnablePerspectiveMessage> const msg = message; AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), false /* animated */, true /* immediately start */)); break; } case Message::Allow3dMode: { ref_ptr<Allow3dModeMessage> const msg = message; bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); #ifdef OMIM_OS_DESKTOP if (m_enablePerspectiveInNavigation == msg->AllowPerspective() && m_enablePerspectiveInNavigation != isPerspective) { if (m_enablePerspectiveInNavigation) AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), false /* animated */, true /* immediately start */)); else AddUserEvent(DisablePerspectiveEvent()); } #endif m_enablePerspectiveInNavigation = msg->AllowPerspective(); m_enable3dBuildings = msg->Allow3dBuildings(); if (m_myPositionController->IsInRouting()) { if (m_enablePerspectiveInNavigation && !isPerspective && !m_perspectiveDiscarded) { AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), true /* animated */, true /* immediately start */)); } else if (!m_enablePerspectiveInNavigation && (isPerspective || m_perspectiveDiscarded)) { DisablePerspective(); } } break; } case Message::Invalidate: { // Do nothing here, new frame will be rendered because of this message processing. break; } default: ASSERT(false, ()); } }