From 2c082911415386e11a88f2c9d3c956f12c4eb139 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Mon, 21 Nov 2016 14:00:51 +0300 Subject: [PATCH] Improved rendering --- drape/batcher.cpp | 4 +- drape/batcher.hpp | 9 +++ drape_frontend/backend_renderer.cpp | 7 +- drape_frontend/batchers_pool.hpp | 5 +- drape_frontend/traffic_generator.cpp | 72 +++++++++++++-------- drape_frontend/traffic_generator.hpp | 43 ++++++++++-- drape_frontend/traffic_renderer.cpp | 97 ++++++++++++++++++++++++---- map/traffic_manager.cpp | 18 ++++-- 8 files changed, 196 insertions(+), 59 deletions(-) diff --git a/drape/batcher.cpp b/drape/batcher.cpp index c8bc1b548a..1f4cdc1ea9 100644 --- a/drape/batcher.cpp +++ b/drape/batcher.cpp @@ -283,9 +283,7 @@ IndicesRange Batcher::InsertPrimitives(GLState const & state, ref_ptr message) case Message::CacheTrafficSegments: { ref_ptr msg = message; - for (auto const & segment : msg->GetSegments()) - m_trafficGenerator->AddSegment(segment.first, segment.second); + m_trafficGenerator->AddSegmentsGeometry(msg->GetSegments()); break; } @@ -456,8 +455,10 @@ void BackendRenderer::Routine::Do() void BackendRenderer::InitGLDependentResource() { + int constexpr kBatchSize = 5000; m_batchersPool = make_unique_dp>(ReadManager::ReadCount(), - bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3)); + bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3), + kBatchSize, kBatchSize); m_trafficGenerator->Init(); dp::TextureManager::Params params; diff --git a/drape_frontend/batchers_pool.hpp b/drape_frontend/batchers_pool.hpp index d9586b46bf..8b14fb09fe 100644 --- a/drape_frontend/batchers_pool.hpp +++ b/drape_frontend/batchers_pool.hpp @@ -19,9 +19,10 @@ class BatchersPool public: using TFlushFn = function && buffer)>; - BatchersPool(int initBatchersCount, TFlushFn const & flushFn) + BatchersPool(int initBatchersCount, TFlushFn const & flushFn, + uint32_t indexBufferSize, uint32_t vertexBufferSize) : m_flushFn(flushFn) - , m_pool(initBatchersCount, dp::BatcherFactory()) + , m_pool(initBatchersCount, dp::BatcherFactory(indexBufferSize, vertexBufferSize)) {} ~BatchersPool() diff --git a/drape_frontend/traffic_generator.cpp b/drape_frontend/traffic_generator.cpp index f23bcf007b..f0780dc53b 100644 --- a/drape_frontend/traffic_generator.cpp +++ b/drape_frontend/traffic_generator.cpp @@ -85,10 +85,13 @@ void GenerateCapTriangles(glsl::vec3 const & pivot, vector const & n } // namespace -TrafficHandle::TrafficHandle(TrafficSegmentID const & segmentId, glsl::vec2 const & texCoord, +TrafficHandle::TrafficHandle(TrafficSegmentID const & segmentId, RoadClass const & roadClass, + m2::RectD const & boundingBox, glsl::vec2 const & texCoord, size_t verticesCount) : OverlayHandle(FeatureID(), dp::Anchor::Center, 0, false) , m_segmentId(segmentId) + , m_roadClass(roadClass) + , m_boundingBox(boundingBox) , m_needUpdate(false) { m_buffer.resize(verticesCount); @@ -153,11 +156,23 @@ TrafficSegmentID TrafficHandle::GetSegmentId() const return m_segmentId; } +RoadClass const & TrafficHandle::GetRoadClass() const +{ + return m_roadClass; +} + +m2::RectD const & TrafficHandle::GetBoundingBox() const +{ + return m_boundingBox; +} + void TrafficGenerator::Init() { - int const kBatchersCount = 3; + int constexpr kBatchersCount = 3; + int constexpr kBatchSize = 65000; m_batchersPool = make_unique_dp>( - kBatchersCount, bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3)); + kBatchersCount, bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3), + kBatchSize, kBatchSize); } void TrafficGenerator::ClearGLDependentResources() @@ -166,9 +181,9 @@ void TrafficGenerator::ClearGLDependentResources() m_batchersPool.reset(); } -void TrafficGenerator::AddSegment(TrafficSegmentID const & segmentId, m2::PolylineD const & polyline) +void TrafficGenerator::AddSegmentsGeometry(TrafficSegmentsGeometry const & geom) { - m_segments.insert(make_pair(segmentId, polyline)); + m_segments.insert(geom.begin(), geom.end()); } void TrafficGenerator::ClearCache() @@ -221,7 +236,7 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, int const kZoomLevel = 10; - using TSegIter = TSegmentCollection::iterator; + using TSegIter = TrafficSegmentsGeometry::iterator; map>> segmentsByTiles; for (auto const & segment : trafficColoring) { @@ -235,7 +250,7 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, continue; m_segmentsCache.insert(segment.m_id); - TileKey const tileKey = GetTileKeyByPoint(it->second.GetLimitRect().Center(), kZoomLevel); + TileKey const tileKey = GetTileKeyByPoint(it->second.m_polyline.GetLimitRect().Center(), kZoomLevel); segmentsByTiles[tileKey].emplace_back(make_pair(it, segment.m_speedGroup)); } @@ -247,14 +262,14 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, { TSegIter it = segmentPair.first; - TrafficBatcherKey bk(it->first.m_mwmId, tileKey); + TrafficBatcherKey bk(it->first.m_mwmId, tileKey, it->second.m_roadClass); m_batchersPool->ReserveBatcher(bk); ref_ptr batcher = m_batchersPool->GetBatcher(bk); ASSERT(m_colorsCacheValid, ()); dp::TextureManager::ColorRegion const & colorRegion = m_colorsCache[static_cast(segmentPair.second)]; - m2::PolylineD const & polyline = it->second; + m2::PolylineD const & polyline = it->second.m_polyline; vector staticGeometry; vector dynamicGeometry; @@ -265,7 +280,9 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, continue; glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center()); - drape_ptr handle = make_unique_dp(it->first, uv, staticGeometry.size()); + drape_ptr handle = make_unique_dp(it->first, it->second.m_roadClass, + polyline.GetLimitRect(), uv, + staticGeometry.size()); dp::AttributeProvider provider(2 /* stream count */, staticGeometry.size()); provider.InitStream(0 /* stream index */, GetTrafficStaticBindingInfo(), make_ref(staticGeometry.data())); @@ -274,7 +291,10 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, } for (auto const & segmentPair : s.second) - m_batchersPool->ReleaseBatcher(TrafficBatcherKey(segmentPair.first->first.m_mwmId, tileKey)); + { + m_batchersPool->ReleaseBatcher(TrafficBatcherKey(segmentPair.first->first.m_mwmId, tileKey, + segmentPair.first->second.m_roadClass)); + } } GLFunctions::glFlush(); @@ -339,22 +359,22 @@ void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & c } // Generate caps. - if (firstFilled) - { - int const kSegmentsCount = 4; - vector normals; - normals.reserve(kAverageCapSize); - GenerateCapNormals(dp::RoundCap, firstLeftNormal, firstRightNormal, -firstTangent, - 1.0f, true /* isStart */, normals, kSegmentsCount); - GenerateCapTriangles(glsl::vec3(firstPoint, kDepth), normals, colorRegion, - staticGeometry, dynamicGeometry); +// if (firstFilled) +// { +// int const kSegmentsCount = 4; +// vector normals; +// normals.reserve(kAverageCapSize); +// GenerateCapNormals(dp::RoundCap, firstLeftNormal, firstRightNormal, -firstTangent, +// 1.0f, true /* isStart */, normals, kSegmentsCount); +// GenerateCapTriangles(glsl::vec3(firstPoint, kDepth), normals, colorRegion, +// staticGeometry, dynamicGeometry); - normals.clear(); - GenerateCapNormals(dp::RoundCap, lastLeftNormal, lastRightNormal, lastTangent, - 1.0f, false /* isStart */, normals, kSegmentsCount); - GenerateCapTriangles(glsl::vec3(lastPoint, kDepth), normals, colorRegion, - staticGeometry, dynamicGeometry); - } +// normals.clear(); +// GenerateCapNormals(dp::RoundCap, lastLeftNormal, lastRightNormal, lastTangent, +// 1.0f, false /* isStart */, normals, kSegmentsCount); +// GenerateCapTriangles(glsl::vec3(lastPoint, kDepth), normals, colorRegion, +// staticGeometry, dynamicGeometry); +// } } void TrafficGenerator::FillColorsCache(ref_ptr textures) diff --git a/drape_frontend/traffic_generator.hpp b/drape_frontend/traffic_generator.hpp index 9b4bb35d4b..f6031dab2e 100644 --- a/drape_frontend/traffic_generator.hpp +++ b/drape_frontend/traffic_generator.hpp @@ -26,6 +26,13 @@ namespace df { +enum class RoadClass : uint8_t +{ + Class0, + Class1, + Class2 +}; + struct TrafficSegmentID { MwmSet::MwmId m_mwmId; @@ -52,7 +59,18 @@ struct TrafficSegmentID inline bool operator!=(TrafficSegmentID const & r) const { return !(*this == r); } }; -using TrafficSegmentsGeometry = vector>; +struct TrafficSegmentGeometry +{ + m2::PolylineD m_polyline; + RoadClass m_roadClass; + + TrafficSegmentGeometry(m2::PolylineD && polyline, RoadClass const & roadClass) + : m_polyline(move(polyline)) + , m_roadClass(roadClass) + {} +}; + +using TrafficSegmentsGeometry = map; struct TrafficSegmentColoring { @@ -73,6 +91,7 @@ struct TrafficRenderData drape_ptr m_bucket; TileKey m_tileKey; MwmSet::MwmId m_mwmId; + m2::RectD m_boundingBox; TrafficRenderData(dp::GLState const & state) : m_state(state) {} }; @@ -108,7 +127,9 @@ class TrafficHandle : public dp::OverlayHandle using TBase = dp::OverlayHandle; public: - TrafficHandle(TrafficSegmentID const & segmentId, glsl::vec2 const & texCoord, size_t verticesCount); + TrafficHandle(TrafficSegmentID const & segmentId, RoadClass const & roadClass, + m2::RectD const & boundingBox, glsl::vec2 const & texCoord, + size_t verticesCount); void GetAttributeMutation(ref_ptr mutator) const override; bool Update(ScreenBase const & screen) override; @@ -118,10 +139,14 @@ public: void SetTexCoord(glsl::vec2 const & texCoord); TrafficSegmentID GetSegmentId() const; + RoadClass const & GetRoadClass() const; + m2::RectD const & GetBoundingBox() const; private: TrafficSegmentID m_segmentId; + RoadClass m_roadClass; vector m_buffer; + m2::RectD m_boundingBox; mutable bool m_needUpdate; }; @@ -139,7 +164,7 @@ public: void Init(); void ClearGLDependentResources(); - void AddSegment(TrafficSegmentID const & segmentId, m2::PolylineD const & polyline); + void AddSegmentsGeometry(TrafficSegmentsGeometry const & geom); TrafficSegmentsColoring GetSegmentsToUpdate(TrafficSegmentsColoring const & trafficColoring) const; @@ -156,13 +181,15 @@ private: struct TrafficBatcherKey { TrafficBatcherKey() = default; - TrafficBatcherKey(MwmSet::MwmId const & mwmId, TileKey const & tileKey) + TrafficBatcherKey(MwmSet::MwmId const & mwmId, TileKey const & tileKey, RoadClass const & roadClass) : m_mwmId(mwmId) , m_tileKey(tileKey) + , m_roadClass(roadClass) {} MwmSet::MwmId m_mwmId; TileKey m_tileKey; + RoadClass m_roadClass; }; struct TrafficBatcherKeyComparator @@ -170,13 +197,15 @@ private: bool operator() (TrafficBatcherKey const & lhs, TrafficBatcherKey const & rhs) const { if (lhs.m_mwmId == rhs.m_mwmId) + { + if (lhs.m_tileKey == rhs.m_tileKey) + return lhs.m_roadClass < rhs.m_roadClass; return lhs.m_tileKey < rhs.m_tileKey; + } return lhs.m_mwmId < rhs.m_mwmId; } }; - using TSegmentCollection = map; - void GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion, m2::PolylineD const & polyline, m2::PointD const & tileCenter, vector & staticGeometry, @@ -185,7 +214,7 @@ private: void FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, drape_ptr && buffer); - TSegmentCollection m_segments; + TrafficSegmentsGeometry m_segments; set m_segmentsCache; array(traffic::SpeedGroup::Count)> m_colorsCache; diff --git a/drape_frontend/traffic_renderer.cpp b/drape_frontend/traffic_renderer.cpp index 70864ea21d..31d13d56d0 100644 --- a/drape_frontend/traffic_renderer.cpp +++ b/drape_frontend/traffic_renderer.cpp @@ -20,7 +20,12 @@ namespace { int const kMinVisibleZoomLevel = 10; + int const kMinVisibleArrowZoomLevel = 16; +int const kRoadClass2MinVisibleArrowZoomLevel = 18; + +int const kRoadClass1ZoomLevel = 12; +int const kRoadClass2ZoomLevel = 14; float const kTrafficArrowAspect = 24.0f / 8.0f; @@ -35,43 +40,74 @@ float const kLeftWidthInPixel[] = float const kRightWidthInPixel[] = { // 1 2 3 4 5 6 7 8 9 10 - 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 3.0f, 3.0f, //11 12 13 14 15 16 17 18 19 20 - 4.0f, 4.0f, 4.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f + 3.0f, 3.0f, 3.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f }; -float CalculateHalfWidth(ScreenBase const & screen, bool left) +float const kRoadClass1WidthScalar[] = +{ + // 1 2 3 4 5 6 7 8 9 10 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + //11 12 13 14 15 16 17 18 19 20 + 0.0f, 0.4f, 0.5f, 0.6f, 0.8f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f +}; + +float const kRoadClass2WidthScalar[] = +{ + // 1 2 3 4 5 6 7 8 9 10 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + //11 12 13 14 15 16 17 18 19 20 + 0.0f, 0.0f, 0.0f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.8f, 1.0f +}; + +float CalculateHalfWidth(ScreenBase const & screen, RoadClass const & roadClass, bool left) { double const zoomLevel = GetZoomLevel(screen.GetScale()); double zoom = trunc(zoomLevel); int const index = zoom - 1.0; float const lerpCoef = zoomLevel - zoom; + float const * widthScalar = nullptr; + if (roadClass == RoadClass::Class1) + widthScalar = kRoadClass1WidthScalar; + else if (roadClass == RoadClass::Class2) + widthScalar = kRoadClass2WidthScalar; + float const * halfWidth = left ? kLeftWidthInPixel : kRightWidthInPixel; float radius = 0.0f; if (index < scales::UPPER_STYLE_SCALE) + { radius = halfWidth[index] + lerpCoef * (halfWidth[index + 1] - halfWidth[index]); + if (widthScalar != nullptr) + radius *= (widthScalar[index] + lerpCoef * (widthScalar[index + 1] - widthScalar[index])); + } else + { radius = halfWidth[scales::UPPER_STYLE_SCALE]; + if (widthScalar != nullptr) + radius *= widthScalar[scales::UPPER_STYLE_SCALE]; + } return radius * VisualParams::Instance().GetVisualScale(); } } // namespace -void TrafficRenderer::AddRenderData(ref_ptr mng, - TrafficRenderData && renderData) +void TrafficRenderer::AddRenderData(ref_ptr mng, TrafficRenderData && renderData) { m_renderData.emplace_back(move(renderData)); + TrafficRenderData & rd = m_renderData.back(); - ref_ptr program = mng->GetProgram(m_renderData.back().m_state.GetProgramIndex()); + ref_ptr program = mng->GetProgram(rd.m_state.GetProgramIndex()); program->Bind(); - m_renderData.back().m_bucket->GetBuffer()->Build(program); + rd.m_bucket->GetBuffer()->Build(program); - for (size_t j = 0; j < m_renderData.back().m_bucket->GetOverlayHandlesCount(); j++) + for (size_t j = 0; j < rd.m_bucket->GetOverlayHandlesCount(); j++) { - TrafficHandle * handle = static_cast(m_renderData.back().m_bucket->GetOverlayHandle(j).get()); + TrafficHandle * handle = static_cast(rd.m_bucket->GetOverlayHandle(j).get()); m_handles.insert(make_pair(handle->GetSegmentId(), handle)); + rd.m_boundingBox.Add(handle->GetBoundingBox()); } } @@ -96,12 +132,47 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, if (m_renderData.empty() || zoomLevel < kMinVisibleZoomLevel) return; - float const pixelHalfWidth = CalculateHalfWidth(screen, true /* left */); - float const invPixelLength = 1.0f / (2.0f * pixelHalfWidth * kTrafficArrowAspect); + m2::RectD const clipRect = screen.ClipRect(); GLFunctions::glClearDepth(); for (TrafficRenderData & renderData : m_renderData) { + if (!clipRect.IsIntersect(renderData.m_boundingBox)) + continue; + + // Filter by road class. + float leftPixelHalfWidth = 0.0f; + float invLeftPixelLength = 0.0f; + float rightPixelHalfWidth = 0.0f; + int minVisibleArrowZoomLevel = kMinVisibleArrowZoomLevel; + + if (renderData.m_bucket->GetOverlayHandlesCount() > 0) + { + TrafficHandle * handle = static_cast(renderData.m_bucket->GetOverlayHandle(0).get()); + ASSERT(handle != nullptr, ()); + + int visibleZoomLevel = kMinVisibleZoomLevel; + if (handle->GetRoadClass() == RoadClass::Class1) + { + visibleZoomLevel = kRoadClass1ZoomLevel; + } + else if (handle->GetRoadClass() == RoadClass::Class2) + { + visibleZoomLevel = kRoadClass2ZoomLevel; + minVisibleArrowZoomLevel = kRoadClass2MinVisibleArrowZoomLevel; + } + + if (zoomLevel < visibleZoomLevel) + continue; + + leftPixelHalfWidth = CalculateHalfWidth(screen, handle->GetRoadClass(), true /* left */); + invLeftPixelLength = 1.0f / (2.0f * leftPixelHalfWidth * kTrafficArrowAspect); + rightPixelHalfWidth = CalculateHalfWidth(screen, handle->GetRoadClass(), false /* left */); + float const kEps = 1e-5; + if (fabs(leftPixelHalfWidth) < kEps && fabs(rightPixelHalfWidth) < kEps) + continue; + } + ref_ptr program = mng->GetProgram(renderData.m_state.GetProgramIndex()); program->Bind(); dp::ApplyState(renderData.m_state, program); @@ -110,8 +181,8 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, math::Matrix const mv = renderData.m_tileKey.GetTileBasedModelView(screen); uniforms.SetMatrix4x4Value("modelView", mv.m_data); uniforms.SetFloatValue("u_opacity", 1.0f); - uniforms.SetFloatValue("u_trafficParams", pixelHalfWidth, CalculateHalfWidth(screen, false /* left */), - invPixelLength, zoomLevel >= kMinVisibleArrowZoomLevel ? 1.0f : 0.0f); + uniforms.SetFloatValue("u_trafficParams", leftPixelHalfWidth, rightPixelHalfWidth, + invLeftPixelLength, zoomLevel >= minVisibleArrowZoomLevel ? 1.0f : 0.0f); dp::ApplyUniforms(uniforms, program); renderData.m_bucket->Render(renderData.m_state.GetDrawAsLine()); diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index a614608094..9cd76190d7 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -5,6 +5,7 @@ #include "drape_frontend/drape_engine.hpp" #include "drape_frontend/visual_params.hpp" +#include "indexer/ftypes_matcher.hpp" #include "indexer/scales.hpp" namespace @@ -101,7 +102,6 @@ void TrafficManager::CalculateSegmentsGeometry(traffic::TrafficInfo const & traf df::TrafficSegmentsGeometry & output) const { size_t const coloringSize = trafficInfo.GetColoring().size(); - output.reserve(coloringSize); vector features; features.reserve(coloringSize); @@ -109,7 +109,7 @@ void TrafficManager::CalculateSegmentsGeometry(traffic::TrafficInfo const & traf features.emplace_back(trafficInfo.GetMwmId(), c.first.m_fid); int constexpr kScale = scales::GetUpperScale(); - unordered_map polylines; + unordered_map> polylines; auto featureReader = [&polylines](FeatureType & ft) { uint32_t const fid = ft.GetID().m_index; @@ -118,10 +118,17 @@ void TrafficManager::CalculateSegmentsGeometry(traffic::TrafficInfo const & traf if (routing::IsRoad(feature::TypesHolder(ft))) { + auto const highwayClass = ftypes::GetHighwayClass(ft); + df::RoadClass roadClass = df::RoadClass::Class2; + if (highwayClass == ftypes::HighwayClass::Trunk || highwayClass == ftypes::HighwayClass::Primary) + roadClass = df::RoadClass::Class0; + else if (highwayClass == ftypes::HighwayClass::Secondary || highwayClass == ftypes::HighwayClass::Tertiary) + roadClass = df::RoadClass::Class1; + m2::PolylineD polyline; ft.ForEachPoint([&polyline](m2::PointD const & pt) { polyline.Add(pt); }, kScale); if (polyline.GetSize() > 1) - polylines[fid] = polyline; + polylines[fid] = make_pair(polyline, roadClass); } }; m_index.ReadFeatures(featureReader, features); @@ -132,9 +139,10 @@ void TrafficManager::CalculateSegmentsGeometry(traffic::TrafficInfo const & traf if (it == polylines.end()) continue; bool const isReversed = (c.first.m_dir == traffic::TrafficInfo::RoadSegmentId::kReverseDirection); - m2::PolylineD polyline = it->second.ExtractSegment(c.first.m_idx, isReversed); + m2::PolylineD polyline = it->second.first.ExtractSegment(c.first.m_idx, isReversed); if (polyline.GetSize() > 1) - output.emplace_back(df::TrafficSegmentID(trafficInfo.GetMwmId(), c.first), move(polyline)); + output.insert(make_pair(df::TrafficSegmentID(trafficInfo.GetMwmId(), c.first), + df::TrafficSegmentGeometry(move(polyline), it->second.second))); } }