diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index 5326ae11a7..48fbe9568a 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -435,8 +435,14 @@ void RouteRenderer::RenderSubroute(ref_ptr context, ref_ptr mng->GetParamsSetter()->Apply(context, prg, params); // Render buckets. - for (auto const & bucket : subrouteData->m_renderProperty.m_buckets) - bucket->Render(context, state.GetDrawAsLine()); + auto const & clipRect = screen.ClipRect(); + CHECK_EQUAL(subrouteData->m_renderProperty.m_buckets.size(), + subrouteData->m_renderProperty.m_boundingBoxes.size(), ()); + for (size_t i = 0; i < subrouteData->m_renderProperty.m_buckets.size(); ++i) + { + if (subrouteData->m_renderProperty.m_boundingBoxes[i].IsIntersect(clipRect)) + subrouteData->m_renderProperty.m_buckets[i]->Render(context, state.GetDrawAsLine()); + } } void RouteRenderer::RenderSubrouteArrows(ref_ptr context, ref_ptr mng, @@ -470,8 +476,15 @@ void RouteRenderer::RenderSubrouteArrows(ref_ptr context, r prg->Bind(); dp::ApplyState(context, prg, state); mng->GetParamsSetter()->Apply(context, prg, params); - for (auto const & bucket : subrouteInfo.m_arrowsData->m_renderProperty.m_buckets) - bucket->Render(context, state.GetDrawAsLine()); + + auto const & clipRect = screen.ClipRect(); + CHECK_EQUAL(subrouteInfo.m_arrowsData->m_renderProperty.m_buckets.size(), + subrouteInfo.m_arrowsData->m_renderProperty.m_boundingBoxes.size(), ()); + for (size_t i = 0; i < subrouteInfo.m_arrowsData->m_renderProperty.m_buckets.size(); ++i) + { + if (subrouteInfo.m_arrowsData->m_renderProperty.m_boundingBoxes[i].IsIntersect(clipRect)) + subrouteInfo.m_arrowsData->m_renderProperty.m_buckets[i]->Render(context, state.GetDrawAsLine()); + } } void RouteRenderer::RenderSubrouteMarkers(ref_ptr context, ref_ptr mng, diff --git a/drape_frontend/route_shape.cpp b/drape_frontend/route_shape.cpp index 7703d954f0..c356f165e5 100644 --- a/drape_frontend/route_shape.cpp +++ b/drape_frontend/route_shape.cpp @@ -13,7 +13,10 @@ #include "drape/glsl_types.hpp" #include "drape/texture_manager.hpp" +#include "geometry/mercator.hpp" + #include "base/logging.hpp" +#include "base/math.hpp" namespace df { @@ -116,7 +119,7 @@ float SideByNormal(glsl::vec2 const & normal, bool isLeft) void GenerateJoinsTriangles(glsl::vec3 const & pivot, std::vector const & normals, glsl::vec4 const & color, glsl::vec2 const & length, bool isLeft, - RouteShape::TGeometryBuffer & joinsGeometry) + RouteShape::GeometryBuffer & joinsGeometry) { size_t const trianglesCount = normals.size() / 3; for (size_t j = 0; j < trianglesCount; j++) @@ -125,9 +128,9 @@ void GenerateJoinsTriangles(glsl::vec3 const & pivot, std::vector co glsl::vec3 const len2 = glsl::vec3(length.x, length.y, SideByNormal(normals[3 * j + 1], isLeft)); glsl::vec3 const len3 = glsl::vec3(length.x, length.y, SideByNormal(normals[3 * j + 2], isLeft)); - joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j], len1, color)); - joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j + 1], len2, color)); - joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j + 2], len3, color)); + joinsGeometry.emplace_back(RouteShape::RV(pivot, normals[3 * j], len1, color)); + joinsGeometry.emplace_back(RouteShape::RV(pivot, normals[3 * j + 1], len2, color)); + joinsGeometry.emplace_back(RouteShape::RV(pivot, normals[3 * j + 2], len3, color)); } } @@ -144,17 +147,17 @@ glsl::vec2 GetUV(m2::RectF const & texRect, glsl::vec2 const & uv) void GenerateArrowsTriangles(glsl::vec4 const & pivot, std::vector const & normals, m2::RectF const & texRect, std::vector const & uv, - bool normalizedUV, RouteShape::TArrowGeometryBuffer & joinsGeometry) + bool normalizedUV, RouteShape::ArrowGeometryBuffer & joinsGeometry) { size_t const trianglesCount = normals.size() / 3; for (size_t j = 0; j < trianglesCount; j++) { - joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j], - normalizedUV ? GetUV(texRect, uv[3 * j]) : uv[3 * j])); - joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j + 1], - normalizedUV ? GetUV(texRect, uv[3 * j + 1]) : uv[3 * j + 1])); - joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j + 2], - normalizedUV ? GetUV(texRect, uv[3 * j + 2]) : uv[3 * j + 2])); + joinsGeometry.emplace_back(RouteShape::AV(pivot, normals[3 * j], + normalizedUV ? GetUV(texRect, uv[3 * j]) : uv[3 * j])); + joinsGeometry.emplace_back(RouteShape::AV(pivot, normals[3 * j + 1], + normalizedUV ? GetUV(texRect, uv[3 * j + 1]) : uv[3 * j + 1])); + joinsGeometry.emplace_back(RouteShape::AV(pivot, normals[3 * j + 2], + normalizedUV ? GetUV(texRect, uv[3 * j + 2]) : uv[3 * j + 2])); } } @@ -178,7 +181,7 @@ void Subroute::AddStyle(SubrouteStyle const & style) void RouteShape::PrepareGeometry(std::vector const & path, m2::PointD const & pivot, std::vector const & segmentsColors, float baseDepth, - TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry) + std::vector> & geometryBufferData) { ASSERT(path.size() > 1, ()); @@ -195,13 +198,24 @@ void RouteShape::PrepareGeometry(std::vector const & path, m2::Point for (auto const & segment : segments) length += glsl::length(segment.m_points[EndPoint] - segment.m_points[StartPoint]); + geometryBufferData.emplace_back(GeometryBufferData()); + + uint32_t constexpr kMinVertices = 5000; + double constexpr kMinExtent = MercatorBounds::kRangeX / (1 << 10); + float depth = baseDepth; float const depthStep = kRouteDepth / (1 + segments.size()); for (auto i = static_cast(segments.size() - 1); i >= 0; i--) { + auto & geomBufferData = geometryBufferData.back(); + auto & geometry = geomBufferData.m_geometry; + UpdateNormals(&segments[i], (i > 0) ? &segments[i - 1] : nullptr, (i < static_cast(segments.size()) - 1) ? &segments[i + 1] : nullptr); + geomBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[StartPoint])); + geomBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[EndPoint])); + // Generate main geometry. m2::PointD const startPt = MapShape::ConvertToLocal(glsl::FromVec2(segments[i].m_points[StartPoint]), pivot, kShapeCoordScalar); @@ -224,23 +238,25 @@ void RouteShape::PrepareGeometry(std::vector const & path, m2::Point float const projRightStart = -segments[i].m_rightWidthScalar[StartPoint].y; float const projRightEnd = segments[i].m_rightWidthScalar[EndPoint].y; - geometry.push_back(RV(startPivot, glsl::vec2(0, 0), - glsl::vec3(startLength, 0, kCenter), segments[i].m_color)); - geometry.push_back(RV(startPivot, leftNormalStart, - glsl::vec3(startLength, projLeftStart, kLeftSide), segments[i].m_color)); - geometry.push_back(RV(endPivot, glsl::vec2(0, 0), - glsl::vec3(length, 0, kCenter), segments[i].m_color)); - geometry.push_back(RV(endPivot, leftNormalEnd, - glsl::vec3(length, projLeftEnd, kLeftSide), segments[i].m_color)); + geometry.emplace_back(RV(startPivot, glsl::vec2(0, 0), + glsl::vec3(startLength, 0, kCenter), segments[i].m_color)); + geometry.emplace_back(RV(startPivot, leftNormalStart, + glsl::vec3(startLength, projLeftStart, kLeftSide), segments[i].m_color)); + geometry.emplace_back(RV(endPivot, glsl::vec2(0, 0), + glsl::vec3(length, 0, kCenter), segments[i].m_color)); + geometry.emplace_back(RV(endPivot, leftNormalEnd, + glsl::vec3(length, projLeftEnd, kLeftSide), segments[i].m_color)); - geometry.push_back(RV(startPivot, rightNormalStart, - glsl::vec3(startLength, projRightStart, kRightSide), segments[i].m_color)); - geometry.push_back(RV(startPivot, glsl::vec2(0, 0), - glsl::vec3(startLength, 0, kCenter), segments[i].m_color)); - geometry.push_back(RV(endPivot, rightNormalEnd, - glsl::vec3(length, projRightEnd, kRightSide), segments[i].m_color)); - geometry.push_back(RV(endPivot, glsl::vec2(0, 0), - glsl::vec3(length, 0, kCenter), segments[i].m_color)); + geometry.emplace_back(RV(startPivot, rightNormalStart, + glsl::vec3(startLength, projRightStart, kRightSide), segments[i].m_color)); + geometry.emplace_back(RV(startPivot, glsl::vec2(0, 0), + glsl::vec3(startLength, 0, kCenter), segments[i].m_color)); + geometry.emplace_back(RV(endPivot, rightNormalEnd, + glsl::vec3(length, projRightEnd, kRightSide), segments[i].m_color)); + geometry.emplace_back(RV(endPivot, glsl::vec2(0, 0), + glsl::vec3(length, 0, kCenter), segments[i].m_color)); + + auto & joinsGeometry = geomBufferData.m_joinsGeometry; // Generate joins. if (segments[i].m_generateJoin && i < static_cast(segments.size()) - 1) @@ -287,13 +303,18 @@ void RouteShape::PrepareGeometry(std::vector const & path, m2::Point true, joinsGeometry); } + auto const verticesCount = geomBufferData.m_geometry.size() + geomBufferData.m_joinsGeometry.size(); + auto const extent = std::max(geomBufferData.m_boundingBox.SizeX(), geomBufferData.m_boundingBox.SizeY()); + if (verticesCount > kMinVertices && extent > kMinExtent) + geometryBufferData.emplace_back(GeometryBufferData()); + length = startLength; } } void RouteShape::PrepareArrowGeometry(std::vector const & path, m2::PointD const & pivot, m2::RectF const & texRect, float depthStep, float depth, - TArrowGeometryBuffer & geometry, TArrowGeometryBuffer & joinsGeometry) + GeometryBufferData & geometryBufferData) { ASSERT(path.size() > 1, ()); @@ -310,9 +331,14 @@ void RouteShape::PrepareArrowGeometry(std::vector const & path, m2:: float const depthInc = depthStep / (segments.size() + 1); for (size_t i = 0; i < segments.size(); i++) { + auto & geometry = geometryBufferData.m_geometry; + UpdateNormals(&segments[i], (i > 0) ? &segments[i - 1] : nullptr, (i < segments.size() - 1) ? &segments[i + 1] : nullptr); + geometryBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[StartPoint])); + geometryBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[EndPoint])); + // Generate main geometry. m2::PointD const startPt = MapShape::ConvertToLocal(glsl::FromVec2(segments[i].m_points[StartPoint]), pivot, kShapeCoordScalar); @@ -332,15 +358,17 @@ void RouteShape::PrepareArrowGeometry(std::vector const & path, m2:: glsl::vec2 const uvLeft = GetUV(tr, 0.5f, 0.0f); glsl::vec2 const uvRight = GetUV(tr, 0.5f, 1.0f); - geometry.push_back(AV(startPivot, glsl::vec2(0, 0), uvCenter)); - geometry.push_back(AV(startPivot, leftNormalStart, uvLeft)); - geometry.push_back(AV(endPivot, glsl::vec2(0, 0), uvCenter)); - geometry.push_back(AV(endPivot, leftNormalEnd, uvLeft)); + geometry.emplace_back(AV(startPivot, glsl::vec2(0, 0), uvCenter)); + geometry.emplace_back(AV(startPivot, leftNormalStart, uvLeft)); + geometry.emplace_back(AV(endPivot, glsl::vec2(0, 0), uvCenter)); + geometry.emplace_back(AV(endPivot, leftNormalEnd, uvLeft)); - geometry.push_back(AV(startPivot, rightNormalStart, uvRight)); - geometry.push_back(AV(startPivot, glsl::vec2(0, 0), uvCenter)); - geometry.push_back(AV(endPivot, rightNormalEnd, uvRight)); - geometry.push_back(AV(endPivot, glsl::vec2(0, 0), uvCenter)); + geometry.emplace_back(AV(startPivot, rightNormalStart, uvRight)); + geometry.emplace_back(AV(startPivot, glsl::vec2(0, 0), uvCenter)); + geometry.emplace_back(AV(endPivot, rightNormalEnd, uvRight)); + geometry.emplace_back(AV(endPivot, glsl::vec2(0, 0), uvCenter)); + + auto & joinsGeometry = geometryBufferData.m_joinsGeometry; // Generate joins. if (segments[i].m_generateJoin && i < segments.size() - 1) @@ -411,7 +439,7 @@ void RouteShape::PrepareArrowGeometry(std::vector const & path, m2:: void RouteShape::PrepareMarkersGeometry(std::vector const & markers, m2::PointD const & pivot, float baseDepth, - TMarkersGeometryBuffer & geometry) + MarkersGeometryBuffer & geometry) { ASSERT(!markers.empty(), ()); @@ -488,8 +516,7 @@ void RouteShape::CacheRouteArrows(ref_ptr context, std::vector const & borders, double baseDepthIndex, SubrouteArrowsData & routeArrowsData) { - TArrowGeometryBuffer geometry; - TArrowGeometryBuffer joinsGeometry; + GeometryBufferData geometryData; dp::TextureManager::SymbolRegion region; GetArrowTextureRegion(mng, region); auto state = CreateRenderState(gpu::Program::RouteArrow, DepthLayer::GeometryLayer); @@ -504,18 +531,23 @@ void RouteShape::CacheRouteArrows(ref_ptr context, std::vector points = CalculatePoints(polyline, b.m_startDistance, b.m_endDistance); ASSERT_LESS_OR_EQUAL(points.size(), polyline.GetSize(), ()); PrepareArrowGeometry(points, routeArrowsData.m_pivot, region.GetTexRect(), depthStep, - depth, geometry, joinsGeometry); + depth, geometryData); } - BatchGeometry(context, state, make_ref(geometry.data()), static_cast(geometry.size()), - make_ref(joinsGeometry.data()), static_cast(joinsGeometry.size()), - AV::GetBindingInfo(), routeArrowsData.m_renderProperty); + double constexpr kBoundingBoxScale = 1.2; + geometryData.m_boundingBox.Scale(kBoundingBoxScale); + + BatchGeometry(context, state, make_ref(geometryData.m_geometry.data()), + static_cast(geometryData.m_geometry.size()), + make_ref(geometryData.m_joinsGeometry.data()), + static_cast(geometryData.m_joinsGeometry.size()), + geometryData.m_boundingBox, AV::GetBindingInfo(), + routeArrowsData.m_renderProperty); } drape_ptr RouteShape::CacheRoute(ref_ptr context, - dp::DrapeID subrouteId, - SubrouteConstPtr subroute, size_t styleIndex, - int recacheId, + dp::DrapeID subrouteId, SubrouteConstPtr subroute, + size_t styleIndex, int recacheId, ref_ptr textures) { size_t startIndex; @@ -565,28 +597,34 @@ drape_ptr RouteShape::CacheRoute(ref_ptr subrouteData->m_recacheId = recacheId; subrouteData->m_distanceOffset = subroute->m_polyline.GetLength(startIndex); - TGeometryBuffer geometry; - TGeometryBuffer joinsGeometry; + std::vector> geometryBufferData; PrepareGeometry(points, subrouteData->m_pivot, segmentsColors, static_cast(subroute->m_baseDepthIndex * kDepthPerSubroute), - geometry, joinsGeometry); + geometryBufferData); auto state = CreateRenderState(subroute->m_style[styleIndex].m_pattern.m_isDashed ? gpu::Program::RouteDash : gpu::Program::Route, DepthLayer::GeometryLayer); state.SetColorTexture(textures->GetSymbolsTexture()); - BatchGeometry(context, state, make_ref(geometry.data()), static_cast(geometry.size()), - make_ref(joinsGeometry.data()), static_cast(joinsGeometry.size()), - RV::GetBindingInfo(), subrouteData->m_renderProperty); + double constexpr kBoundingBoxScale = 1.2; + for (auto & data : geometryBufferData) + { + data.m_boundingBox.Scale(kBoundingBoxScale); + BatchGeometry(context, state, make_ref(data.m_geometry.data()), + static_cast(data.m_geometry.size()), + make_ref(data.m_joinsGeometry.data()), + static_cast(data.m_joinsGeometry.size()), + data.m_boundingBox, RV::GetBindingInfo(), + subrouteData->m_renderProperty); + } + return subrouteData; } drape_ptr RouteShape::CacheMarkers(ref_ptr context, - dp::DrapeID subrouteId, - SubrouteConstPtr subroute, - int recacheId, - ref_ptr textures) + dp::DrapeID subrouteId, SubrouteConstPtr subroute, + int recacheId, ref_ptr textures) { if (subroute->m_markers.empty()) return nullptr; @@ -596,7 +634,7 @@ drape_ptr RouteShape::CacheMarkers(ref_ptrm_pivot = subroute->m_polyline.GetLimitRect().Center(); markersData->m_recacheId = recacheId; - TMarkersGeometryBuffer geometry; + MarkersGeometryBuffer geometry; auto const depth = static_cast(subroute->m_baseDepthIndex * kDepthPerSubroute + kMarkersDepth); PrepareMarkersGeometry(subroute->m_markers, markersData->m_pivot, depth, geometry); if (geometry.empty()) @@ -628,19 +666,27 @@ drape_ptr RouteShape::CacheMarkers(ref_ptr context, dp::RenderState const & state, ref_ptr geometry, uint32_t geomSize, ref_ptr joinsGeometry, uint32_t joinsGeomSize, - dp::BindingInfo const & bindingInfo, RouteRenderProperty & property) + m2::RectD const & boundingBox, dp::BindingInfo const & bindingInfo, + RouteRenderProperty & property) { - size_t const verticesCount = geomSize + joinsGeomSize; + auto verticesCount = geomSize + joinsGeomSize; if (verticesCount == 0) return; - uint32_t const kBatchSize = 5000; - dp::Batcher batcher(kBatchSize, kBatchSize); + uint32_t constexpr kMinBatchSize = 100; + uint32_t constexpr kMaxBatchSize = 65000; + uint32_t constexpr kIndicesScalar = 2; + + verticesCount = base::clamp(verticesCount, kMinBatchSize, kMaxBatchSize); + auto const indicesCount = base::clamp(verticesCount * kIndicesScalar, kMinBatchSize, kMaxBatchSize); + + dp::Batcher batcher(indicesCount, verticesCount); batcher.SetBatcherHash(static_cast(BatcherBucket::Routing)); - dp::SessionGuard guard(context, batcher, [&property](dp::RenderState const & state, - drape_ptr && b) + dp::SessionGuard guard(context, batcher, [&property, &boundingBox](dp::RenderState const & state, + drape_ptr && b) { property.m_buckets.push_back(std::move(b)); + property.m_boundingBoxes.push_back(boundingBox); property.m_state = state; }); diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp index 32e9d221b2..29913ff57f 100644 --- a/drape_frontend/route_shape.hpp +++ b/drape_frontend/route_shape.hpp @@ -50,10 +50,6 @@ enum class RouteType : uint8_t struct RoutePattern { - bool m_isDashed = false; - double m_dashLength = 0.0; - double m_gapLength = 0.0; - RoutePattern() = default; RoutePattern(double dashLength, double gapLength) @@ -69,6 +65,10 @@ struct RoutePattern std::fabs(m_dashLength - pattern.m_dashLength) < kEps && std::fabs(m_gapLength - pattern.m_gapLength) < kEps; } + + bool m_isDashed = false; + double m_dashLength = 0.0; + double m_gapLength = 0.0; }; enum class SubrouteStyleType @@ -79,14 +79,8 @@ enum class SubrouteStyleType struct SubrouteStyle { - df::ColorConstant m_color; - df::ColorConstant m_outlineColor; - df::RoutePattern m_pattern; - size_t m_startIndex = 0; - size_t m_endIndex = 0; - SubrouteStyle() = default; - SubrouteStyle(df::ColorConstant const & color) + explicit SubrouteStyle(df::ColorConstant const & color) : m_color(color) , m_outlineColor(color) {} @@ -106,16 +100,19 @@ struct SubrouteStyle , m_pattern(pattern) {} - bool operator == (SubrouteStyle const & style) const + bool operator==(SubrouteStyle const & style) const { return m_color == style.m_color && m_outlineColor == style.m_outlineColor && m_pattern == style.m_pattern; } - bool operator != (SubrouteStyle const & style) const - { - return !operator == (style); - } + bool operator!=(SubrouteStyle const & style) const { return !operator==(style); } + + df::ColorConstant m_color; + df::ColorConstant m_outlineColor; + df::RoutePattern m_pattern; + size_t m_startIndex = 0; + size_t m_endIndex = 0; }; // Colored circle on the subroute. @@ -157,11 +154,13 @@ using SubrouteConstPtr = std::shared_ptr; struct RouteRenderProperty { - dp::RenderState m_state; - std::vector> m_buckets; RouteRenderProperty() : m_state(CreateRenderState(gpu::Program::Route, DepthLayer::GeometryLayer)) {} + + dp::RenderState m_state; + std::vector> m_buckets; + std::vector m_boundingBoxes; }; struct BaseSubrouteData @@ -196,11 +195,11 @@ class RouteShape { public: using RV = gpu::RouteVertex; - using TGeometryBuffer = buffer_vector; + using GeometryBuffer = buffer_vector; using AV = gpu::SolidTexturingVertex; - using TArrowGeometryBuffer = buffer_vector; + using ArrowGeometryBuffer = buffer_vector; using MV = gpu::RouteMarkerVertex; - using TMarkersGeometryBuffer = buffer_vector; + using MarkersGeometryBuffer = buffer_vector; static drape_ptr CacheRoute(ref_ptr context, dp::DrapeID subrouteId, SubrouteConstPtr subroute, @@ -218,20 +217,30 @@ public: SubrouteArrowsData & routeArrowsData); private: + template + struct GeometryBufferData + { + GeometryBufferData() + : m_boundingBox(m2::RectD::GetEmptyRect()) + {} + + GeometryBufferType m_geometry; + GeometryBufferType m_joinsGeometry; + m2::RectD m_boundingBox; + }; static void PrepareGeometry(std::vector const & path, m2::PointD const & pivot, std::vector const & segmentsColors, float baseDepth, - TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry); + std::vector> & geometryBufferData); static void PrepareArrowGeometry(std::vector const & path, m2::PointD const & pivot, m2::RectF const & texRect, float depthStep, float depth, - TArrowGeometryBuffer & geometry, - TArrowGeometryBuffer & joinsGeometry); + GeometryBufferData & geometryBufferData); static void PrepareMarkersGeometry(std::vector const & markers, m2::PointD const & pivot, float baseDepth, - TMarkersGeometryBuffer & geometry); + MarkersGeometryBuffer & geometry); static void BatchGeometry(ref_ptr context, dp::RenderState const & state, ref_ptr geometry, uint32_t geomSize, ref_ptr joinsGeometry, - uint32_t joinsGeomSize, dp::BindingInfo const & bindingInfo, - RouteRenderProperty & property); + uint32_t joinsGeomSize, m2::RectD const & boundingBox, + dp::BindingInfo const & bindingInfo, RouteRenderProperty & property); }; } // namespace df