diff --git a/drape/glstate.hpp b/drape/glstate.hpp index e06f0013fc..3fa7788128 100644 --- a/drape/glstate.hpp +++ b/drape/glstate.hpp @@ -38,7 +38,6 @@ public: { /// Do not change order GeometryLayer, - DynamicGeometry, OverlayLayer, UserMarkLayer, Gui diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index ac19ec4348..8e904febc2 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -58,6 +58,97 @@ struct MergedGroupKey } }; +template +bool RemoveGroups(ToDo & filter, vector> & groups) +{ + size_t startCount = groups.size(); + size_t count = startCount; + size_t current = 0; + while (current < count) + { + drape_ptr & group = groups[current]; + if (filter(move(group))) + { + swap(group, groups.back()); + groups.pop_back(); + --count; + } + else + ++current; + } + + return startCount != count; +} + +struct ActivateTilePredicate +{ + TileKey const & m_tileKey; + + ActivateTilePredicate(TileKey const & tileKey) + : m_tileKey(tileKey) + { + } + + bool operator()(drape_ptr & group) const + { + if (group->GetTileKey() == m_tileKey) + { + group->Appear(); + return true; + } + + return false; + } +}; + +struct RemoveTilePredicate +{ + mutable bool m_deletionMark = false; + function const &)> const & m_predicate; + + RemoveTilePredicate(function const &)> const & predicate) + : m_predicate(predicate) + { + } + + bool operator()(drape_ptr && group) const + { + if (m_predicate(group)) + { + group->Disappear(); + group->DeleteLater(); + m_deletionMark = true; + return group->CanBeDeleted(); + } + + return false; + } +}; + +template +struct MoveTileFunctor +{ + TPredicate m_predicate; + vector> & m_targetGroups; + + MoveTileFunctor(TPredicate predicate, vector> & groups) + : m_predicate(predicate) + , m_targetGroups(groups) + { + } + + bool operator()(drape_ptr && group) + { + if (m_predicate(group)) + { + m_targetGroups.push_back(move(group)); + return true; + } + + return false; + } +}; + } // namespace FrontendRenderer::FrontendRenderer(Params const & params) @@ -435,8 +526,12 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) m_tileTree->Invalidate(); // Clear all graphics. - m_renderGroups.clear(); - m_deferredRenderGroups.clear(); + for (RenderLayer & layer : m_layers) + { + layer.m_renderGroups.clear(); + layer.m_deferredRenderGroups.clear(); + layer.m_isDirty = false; + } // Invalidate read manager. { @@ -613,20 +708,17 @@ void FrontendRenderer::InvalidateRect(m2::RectD const & gRect) m_tileTree->Invalidate(); ResolveTileKeys(rect, tiles); - auto eraseFunction = [&tiles](vector> & groups) + auto eraseFunction = [&tiles](drape_ptr && group) { - vector > newGroups; - for (drape_ptr & group : groups) - { - if (tiles.find(group->GetTileKey()) == tiles.end()) - newGroups.push_back(move(group)); - } - - swap(groups, newGroups); + return tiles.count(group->GetTileKey()) == 0; }; - eraseFunction(m_renderGroups); - eraseFunction(m_deferredRenderGroups); + for (RenderLayer & layer : m_layers) + { + RemoveGroups(eraseFunction, layer.m_renderGroups); + RemoveGroups(eraseFunction, layer.m_deferredRenderGroups); + layer.m_isDirty = true; + } BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, @@ -673,30 +765,26 @@ void FrontendRenderer::AddToRenderGroup(vector> & groups, void FrontendRenderer::OnAddRenderGroup(TileKey const & tileKey, dp::GLState const & state, drape_ptr && renderBucket) { - AddToRenderGroup(m_renderGroups, state, move(renderBucket), tileKey); - m_renderGroups.back()->Appear(); + RenderLayer::RenderLayerID id = RenderLayer::GetLayerID(state); + RenderLayer & layer = m_layers[id]; + AddToRenderGroup(layer.m_renderGroups, state, move(renderBucket), tileKey); + layer.m_renderGroups.back()->Appear(); + layer.m_isDirty = true; } void FrontendRenderer::OnDeferRenderGroup(TileKey const & tileKey, dp::GLState const & state, drape_ptr && renderBucket) { - AddToRenderGroup(m_deferredRenderGroups, state, move(renderBucket), tileKey); + RenderLayer::RenderLayerID id = RenderLayer::GetLayerID(state); + AddToRenderGroup(m_layers[id].m_deferredRenderGroups, state, move(renderBucket), tileKey); } void FrontendRenderer::OnActivateTile(TileKey const & tileKey) { - for(auto it = m_deferredRenderGroups.begin(); it != m_deferredRenderGroups.end();) + for (RenderLayer & layer : m_layers) { - if ((*it)->GetTileKey() == tileKey) - { - m_renderGroups.push_back(move(*it)); - it = m_deferredRenderGroups.erase(it); - m_renderGroups.back()->Appear(); - } - else - { - ++it; - } + MoveTileFunctor f(ActivateTilePredicate(tileKey), layer.m_renderGroups); + layer.m_isDirty |= RemoveGroups(f, layer.m_deferredRenderGroups); } } @@ -714,19 +802,13 @@ void FrontendRenderer::RemoveRenderGroups(TRenderGroupRemovePredicate const & pr ASSERT(predicate != nullptr, ()); m_overlayTree->ForceUpdate(); - for(auto const & group : m_renderGroups) + for (RenderLayer & layer : m_layers) { - if (predicate(group)) - { - group->DeleteLater(); - group->Disappear(); - } + RemoveTilePredicate f(predicate); + RemoveGroups(f, layer.m_renderGroups); + RemoveGroups(predicate, layer.m_deferredRenderGroups); + layer.m_isDirty |= f.m_deletionMark; } - - m_deferredRenderGroups.erase(remove_if(m_deferredRenderGroups.begin(), - m_deferredRenderGroups.end(), - predicate), - m_deferredRenderGroups.end()); } bool FrontendRenderer::CheckTileGenerations(TileKey const & tileKey) @@ -817,78 +899,17 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) bool const isPerspective = modelView.isPerspective(); - RenderGroupComparator comparator; - sort(m_renderGroups.begin(), m_renderGroups.end(), bind(&RenderGroupComparator::operator (), &comparator, _1, _2)); - - BeginUpdateOverlayTree(modelView); - size_t eraseCount = 0; GLFunctions::glEnable(gl_const::GLDepthTest); - for (size_t i = 0; i < m_renderGroups.size(); ++i) - { - drape_ptr & group = m_renderGroups[i]; - if (group->IsEmpty()) - continue; - - if (group->CanBeDeleted()) - { - group.reset(); - ++eraseCount; - continue; - } - - switch (group->GetState().GetDepthLayer()) - { - case dp::GLState::OverlayLayer: - UpdateOverlayTree(modelView, group); - break; - case dp::GLState::DynamicGeometry: - group->Update(modelView); - break; - default: - break; - } - } - EndUpdateOverlayTree(); - m_renderGroups.resize(m_renderGroups.size() - eraseCount); - m_viewport.Apply(); RefreshBgColor(); GLFunctions::glClear(); - dp::GLState::DepthLayer prevLayer = dp::GLState::GeometryLayer; - size_t currentRenderGroup = 0; - bool has3dAreas = false; - size_t area3dRenderGroupStart = 0; - size_t area3dRenderGroupEnd = 0; - for (; currentRenderGroup < m_renderGroups.size(); ++currentRenderGroup) - { - drape_ptr const & group = m_renderGroups[currentRenderGroup]; + Render2dLayer(modelView); - dp::GLState const & state = group->GetState(); - - if ((isPerspective || m_isIsometry) && state.GetProgram3dIndex() == gpu::AREA_3D_PROGRAM) - { - if (!has3dAreas) - { - area3dRenderGroupStart = currentRenderGroup; - has3dAreas = true; - } - area3dRenderGroupEnd = currentRenderGroup; - continue; - } - - dp::GLState::DepthLayer layer = state.GetDepthLayer(); - if (prevLayer != layer && layer == dp::GLState::OverlayLayer) - break; - - prevLayer = layer; - RenderSingleGroup(modelView, make_ref(group)); - } - - GLFunctions::glDisable(gl_const::GLDepthTest); bool hasSelectedPOI = false; if (m_selectionShape != nullptr) { + GLFunctions::glDisable(gl_const::GLDepthTest); SelectionShape::ESelectedObject selectedObject = m_selectionShape->GetSelectedObject(); if (selectedObject == SelectionShape::OBJECT_MY_POSITION) { @@ -898,7 +919,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) } else if (selectedObject == SelectionShape::OBJECT_POI) { - if (!isPerspective && !has3dAreas) + if (!isPerspective && m_layers[RenderLayer::Geometry3dID].m_renderGroups.empty()) m_selectionShape->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); else hasSelectedPOI = true; @@ -908,34 +929,20 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) m_myPositionController->Render(MyPositionController::RenderAccuracy, modelView, make_ref(m_gpuProgramManager), m_generalUniforms); - if (has3dAreas) + if (m_framebuffer->IsSupported()) { - if (m_framebuffer->IsSupported()) - { - m_framebuffer->Enable(); - GLFunctions::glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - GLFunctions::glClear(); - GLFunctions::glClearDepth(); - } - else - { - GLFunctions::glClearDepth(); - } - - GLFunctions::glEnable(gl_const::GLDepthTest); - for (size_t index = area3dRenderGroupStart; index <= area3dRenderGroupEnd; ++index) - { - drape_ptr const & group = m_renderGroups[index]; - if (group->GetState().GetProgram3dIndex() == gpu::AREA_3D_PROGRAM) - RenderSingleGroup(modelView, make_ref(group)); - } - - if (m_framebuffer->IsSupported()) - { - m_framebuffer->Disable(); - GLFunctions::glDisable(gl_const::GLDepthTest); - m_transparentLayer->Render(m_framebuffer->GetTextureId(), make_ref(m_gpuProgramManager)); - } + m_framebuffer->Enable(); + GLFunctions::glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GLFunctions::glClear(); + Render3dLayer(modelView); + m_framebuffer->Disable(); + GLFunctions::glDisable(gl_const::GLDepthTest); + m_transparentLayer->Render(m_framebuffer->GetTextureId(), make_ref(m_gpuProgramManager)); + } + else + { + GLFunctions::glClearDepth(); + Render3dLayer(modelView); } if (hasSelectedPOI) @@ -946,11 +953,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) GLFunctions::glEnable(gl_const::GLDepthTest); GLFunctions::glClearDepth(); - for (; currentRenderGroup < m_renderGroups.size(); ++currentRenderGroup) - { - drape_ptr const & group = m_renderGroups[currentRenderGroup]; - RenderSingleGroup(modelView, make_ref(group)); - } + RenderOverlayLayer(modelView); m_gpsTrackRenderer->RenderTrack(modelView, GetCurrentZoomLevel(), make_ref(m_gpuProgramManager), m_generalUniforms); @@ -1001,6 +1004,36 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) MergeBuckets(); } +void FrontendRenderer::Render2dLayer(ScreenBase const & modelView) +{ + RenderLayer & layer2d = m_layers[RenderLayer::Geometry2dID]; + layer2d.Sort(); + + for (drape_ptr const & group : layer2d.m_renderGroups) + RenderSingleGroup(modelView, make_ref(group)); +} + +void FrontendRenderer::Render3dLayer(ScreenBase const & modelView) +{ + GLFunctions::glEnable(gl_const::GLDepthTest); + RenderLayer & layer = m_layers[RenderLayer::Geometry3dID]; + layer.Sort(); + for (drape_ptr const & group : layer.m_renderGroups) + RenderSingleGroup(modelView, make_ref(group)); +} + +void FrontendRenderer::RenderOverlayLayer(ScreenBase const & modelView) +{ + RenderLayer & overlay = m_layers[RenderLayer::OverlayID]; + overlay.Sort(); + BeginUpdateOverlayTree(modelView); + for (drape_ptr & group : overlay.m_renderGroups) + UpdateOverlayTree(modelView, group); + EndUpdateOverlayTree(); + for (drape_ptr & group : overlay.m_renderGroups) + RenderSingleGroup(modelView, make_ref(group)); +} + void FrontendRenderer::MergeBuckets() { if (BatchMergeHelper::IsMergeSupported() == false) @@ -1010,37 +1043,37 @@ void FrontendRenderer::MergeBuckets() if (m_mergeBucketsCounter < 60) return; - if (m_renderGroups.empty()) - return; - - using TGroupMap = map>>; - TGroupMap forMerge; - - vector> newGroups; - newGroups.reserve(m_renderGroups.size()); - m_mergeBucketsCounter = 0; - size_t groupsCount = m_renderGroups.size(); - for (size_t i = 0; i < groupsCount; ++i) + + auto mergeFn = [](RenderLayer & layer, bool isPerspective) { - ref_ptr group = make_ref(m_renderGroups[i]); - dp::GLState state = group->GetState(); - if (state.GetDepthLayer() == dp::GLState::GeometryLayer && !group->IsPendingOnDelete()) + if (layer.m_renderGroups.empty()) + return; + + using TGroupMap = map>>; + TGroupMap forMerge; + + vector> newGroups; + newGroups.reserve(layer.m_renderGroups.size()); + + size_t groupsCount = layer.m_renderGroups.size(); + for (size_t i = 0; i < groupsCount; ++i) { - MergedGroupKey const key(state, group->GetTileKey()); - forMerge[key].push_back(move(m_renderGroups[i])); + ref_ptr group = make_ref(layer.m_renderGroups[i]); + dp::GLState state = group->GetState(); + ASSERT_EQUAL(state.GetDepthLayer(), dp::GLState::GeometryLayer, ()); + forMerge[MergedGroupKey(state, group->GetTileKey())].push_back(move(layer.m_renderGroups[i])); } - else - { - newGroups.push_back(move(m_renderGroups[i])); - } - } + + for (TGroupMap::value_type & node : forMerge) + BatchMergeHelper::MergeBatches(node.second, newGroups, isPerspective); + + layer.m_renderGroups = move(newGroups); + }; bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); - for (TGroupMap::value_type & node : forMerge) - BatchMergeHelper::MergeBatches(node.second, newGroups, isPerspective); - - m_renderGroups = move(newGroups); + mergeFn(m_layers[RenderLayer::Geometry2dID], isPerspective); + mergeFn(m_layers[RenderLayer::Geometry3dID], isPerspective); } bool FrontendRenderer::IsPerspective() const @@ -1426,8 +1459,11 @@ void FrontendRenderer::Routine::Do() void FrontendRenderer::ReleaseResources() { m_tileTree.reset(); - m_renderGroups.clear(); - m_deferredRenderGroups.clear(); + for (RenderLayer & layer : m_layers) + { + layer.m_renderGroups.clear(); + layer.m_deferredRenderGroups.clear(); + } m_userMarkRenderGroups.clear(); m_guiRenderer.reset(); m_myPositionController.reset(); @@ -1514,4 +1550,28 @@ void FrontendRenderer::EmitModelViewChanged(ScreenBase const & modelView) const m_modelViewChangedFn(modelView); } +FrontendRenderer::RenderLayer::RenderLayerID FrontendRenderer::RenderLayer::GetLayerID(dp::GLState const & state) +{ + if (state.GetDepthLayer() == dp::GLState::OverlayLayer) + return OverlayID; + + if (state.GetProgram3dIndex() == gpu::AREA_3D_PROGRAM) + return Geometry3dID; + + return Geometry2dID; +} + +void FrontendRenderer::RenderLayer::Sort() +{ + if (!m_isDirty) + return; + + RenderGroupComparator comparator; + sort(m_renderGroups.begin(), m_renderGroups.end(), comparator); + m_isDirty = comparator.m_pendingOnDeleteFound; + + while (!m_renderGroups.empty() && m_renderGroups.back()->CanBeDeleted()) + m_renderGroups.pop_back(); +} + } // namespace df diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 8967f5cd06..9761c77aaa 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -36,6 +36,7 @@ #include "std/function.hpp" #include "std/map.hpp" +#include "std/array.hpp" namespace dp { @@ -148,6 +149,12 @@ private: void RefreshPivotTransform(ScreenBase const & screen); void RefreshBgColor(); + ////// + /// Render part of scene + void Render2dLayer(ScreenBase const & modelView); + void Render3dLayer(ScreenBase const & modelView); + void RenderOverlayLayer(ScreenBase const & modelView); + ////// ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged); void PrepareScene(ScreenBase const & modelView); void UpdateScene(ScreenBase const & modelView); @@ -230,8 +237,26 @@ private: private: drape_ptr m_gpuProgramManager; - vector> m_renderGroups; - vector> m_deferredRenderGroups; + struct RenderLayer + { + enum RenderLayerID + { + Geometry2dID, + OverlayID, + Geometry3dID, + LayerCountID + }; + + static RenderLayerID GetLayerID(dp::GLState const & renderGroup); + + vector> m_renderGroups; + vector> m_deferredRenderGroups; + bool m_isDirty = false; + + inline void Sort(); + }; + + array m_layers; vector> m_userMarkRenderGroups; set m_userMarkVisibility; diff --git a/drape_frontend/render_group.cpp b/drape_frontend/render_group.cpp index 29dfaab54e..1a2aa10369 100755 --- a/drape_frontend/render_group.cpp +++ b/drape_frontend/render_group.cpp @@ -190,20 +190,14 @@ void RenderGroup::Disappear() bool RenderGroupComparator::operator()(drape_ptr const & l, drape_ptr const & r) { - dp::GLState const & lState = l->GetState(); - dp::GLState const & rState = r->GetState(); - - if (!l->CanBeDeleted() && l->IsEmpty()) - l->DeleteLater(); - - if (!r->CanBeDeleted() && r->IsEmpty()) - r->DeleteLater(); - + m_pendingOnDeleteFound |= (l->IsPendingOnDelete() || r->IsPendingOnDelete()); bool const lCanBeDeleted = l->CanBeDeleted(); bool const rCanBeDeleted = r->CanBeDeleted(); if (rCanBeDeleted == lCanBeDeleted) { + dp::GLState const & lState = l->GetState(); + dp::GLState const & rState = r->GetState(); dp::GLState::DepthLayer lDepth = lState.GetDepthLayer(); dp::GLState::DepthLayer rDepth = rState.GetDepthLayer(); if (lDepth != rDepth) diff --git a/drape_frontend/render_group.hpp b/drape_frontend/render_group.hpp index 6f15277dee..49f61a5063 100755 --- a/drape_frontend/render_group.hpp +++ b/drape_frontend/render_group.hpp @@ -90,6 +90,7 @@ class RenderGroupComparator { public: bool operator()(drape_ptr const & l, drape_ptr const & r); + bool m_pendingOnDeleteFound = false; }; class UserMarkRenderGroup : public BaseRenderGroup