From 24a00231f3f6cf119e3e7e349d1b43ff36750ca9 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 26 Jun 2017 08:50:49 -0700 Subject: =?UTF-8?q?[core]=20fix=20render=20doesn=E2=80=99t=20flag=20style?= =?UTF-8?q?=20mutation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mbgl/map/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 37442770fa..d52315d19c 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -238,8 +238,8 @@ void Map::Impl::render(View& view) { transform.getState(), style->impl->getGlyphURL(), style->impl->spriteLoaded, - style->getTransitionOptions(), - style->getLight()->impl, + style->impl->getTransitionOptions(), + style->impl->getLight()->impl, style->impl->getImageImpls(), style->impl->getSourceImpls(), style->impl->getLayerImpls(), -- cgit v1.2.1 From 20189db67fa6b5b769fc802d67df77e0988799b2 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 26 Jun 2017 10:06:47 -0700 Subject: [core] remove tile cache size setter --- src/mbgl/annotation/render_annotation_source.cpp | 4 ---- src/mbgl/annotation/render_annotation_source.hpp | 1 - src/mbgl/map/map.cpp | 11 ----------- src/mbgl/renderer/render_source.hpp | 1 - src/mbgl/renderer/render_style.cpp | 6 ------ src/mbgl/renderer/render_style.hpp | 1 - src/mbgl/renderer/sources/render_geojson_source.cpp | 4 ---- src/mbgl/renderer/sources/render_geojson_source.hpp | 1 - src/mbgl/renderer/sources/render_image_source.hpp | 2 -- src/mbgl/renderer/sources/render_raster_source.cpp | 4 ---- src/mbgl/renderer/sources/render_raster_source.hpp | 1 - src/mbgl/renderer/sources/render_vector_source.cpp | 4 ---- src/mbgl/renderer/sources/render_vector_source.hpp | 1 - 13 files changed, 41 deletions(-) (limited to 'src') diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index b8601d4ed2..8fb11785fd 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -69,10 +69,6 @@ std::vector RenderAnnotationSource::querySourceFeatures(const SourceQue return {}; } -void RenderAnnotationSource::setCacheSize(size_t size) { - tilePyramid.setCacheSize(size); -} - void RenderAnnotationSource::onLowMemory() { tilePyramid.onLowMemory(); } diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp index fe384c64ca..7231452d4f 100644 --- a/src/mbgl/annotation/render_annotation_source.hpp +++ b/src/mbgl/annotation/render_annotation_source.hpp @@ -32,7 +32,6 @@ public: std::vector querySourceFeatures(const SourceQueryOptions&) const final; - void setCacheSize(size_t) final; void onLowMemory() final; void dumpDebugLogs() const final; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index d52315d19c..4d073802c2 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -92,8 +92,6 @@ public: std::unique_ptr renderStyle; bool cameraMutated = false; - - size_t sourceCacheSize; bool loading = false; util::AsyncTask asyncInvalidate; @@ -823,15 +821,6 @@ bool Map::isFullyLoaded() const { return impl->style->impl->isLoaded() && impl->renderStyle && impl->renderStyle->isLoaded(); } -void Map::setSourceTileCacheSize(size_t size) { - if (size != impl->sourceCacheSize) { - impl->sourceCacheSize = size; - if (!impl->renderStyle) return; - impl->renderStyle->setSourceTileCacheSize(size); - impl->backend.invalidate(); - } -} - void Map::onLowMemory() { if (impl->painter) { BackendScope guard(impl->backend); diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index a00a6c797d..b82547b375 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -68,7 +68,6 @@ public: virtual std::vector querySourceFeatures(const SourceQueryOptions&) const = 0; - virtual void setCacheSize(size_t) = 0; virtual void onLowMemory() = 0; virtual void dumpDebugLogs() const = 0; diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index f9c3f0ca9f..79b20a9d71 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -417,12 +417,6 @@ std::vector RenderStyle::queryRenderedFeatures(const ScreenLineString& return result; } -void RenderStyle::setSourceTileCacheSize(size_t size) { - for (const auto& entry : renderSources) { - entry.second->setCacheSize(size); - } -} - void RenderStyle::onLowMemory() { for (const auto& entry : renderSources) { entry.second->onLowMemory(); diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp index dc33e7b2f4..23a640c482 100644 --- a/src/mbgl/renderer/render_style.hpp +++ b/src/mbgl/renderer/render_style.hpp @@ -59,7 +59,6 @@ public: const TransformState& transformState, const RenderedQueryOptions& options) const; - void setSourceTileCacheSize(size_t); void onLowMemory(); void dumpDebugLogs() const; diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 337b7b8b7a..2c6935b273 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -84,10 +84,6 @@ std::vector RenderGeoJSONSource::querySourceFeatures(const SourceQueryO return tilePyramid.querySourceFeatures(options); } -void RenderGeoJSONSource::setCacheSize(size_t size) { - tilePyramid.setCacheSize(size); -} - void RenderGeoJSONSource::onLowMemory() { tilePyramid.onLowMemory(); } diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index 9b5477e1d0..b7c5a3fa7f 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -36,7 +36,6 @@ public: std::vector querySourceFeatures(const SourceQueryOptions&) const final; - void setCacheSize(size_t) final; void onLowMemory() final; void dumpDebugLogs() const final; diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 5175cbf4a4..88f1c56567 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -42,8 +42,6 @@ public: std::vector querySourceFeatures(const SourceQueryOptions&) const final; - void setCacheSize(size_t) final { - } void onLowMemory() final { } void dumpDebugLogs() const final; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index 385437af1d..20c148870e 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -80,10 +80,6 @@ std::vector RenderRasterSource::querySourceFeatures(const SourceQueryOp return {}; } -void RenderRasterSource::setCacheSize(size_t size) { - tilePyramid.setCacheSize(size); -} - void RenderRasterSource::onLowMemory() { tilePyramid.onLowMemory(); } diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index d1e37a3099..7d0c245e45 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -32,7 +32,6 @@ public: std::vector querySourceFeatures(const SourceQueryOptions&) const final; - void setCacheSize(size_t) final; void onLowMemory() final; void dumpDebugLogs() const final; diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index 5b266b10a5..4302fb21ee 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -85,10 +85,6 @@ std::vector RenderVectorSource::querySourceFeatures(const SourceQueryOp return tilePyramid.querySourceFeatures(options); } -void RenderVectorSource::setCacheSize(size_t size) { - tilePyramid.setCacheSize(size); -} - void RenderVectorSource::onLowMemory() { tilePyramid.onLowMemory(); } diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index d5d9598a75..5e15fee533 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -32,7 +32,6 @@ public: std::vector querySourceFeatures(const SourceQueryOptions&) const final; - void setCacheSize(size_t) final; void onLowMemory() final; void dumpDebugLogs() const final; -- cgit v1.2.1 From 433e54e636293eb3b6644c143866aa0d39198441 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Wed, 28 Jun 2017 14:23:39 +0300 Subject: [core] Clamp to scale boundaries in TransformState::setLatLngZoom --- src/mbgl/map/transform_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index bbf7e22b31..f052e30a6b 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -358,7 +358,7 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) { constrained = bounds->constrain(latLng); } - double newScale = zoomScale(zoom); + double newScale = util::clamp(zoomScale(zoom), min_scale, max_scale); const double newWorldSize = newScale * util::tileSize; Bc = newWorldSize / util::DEGREES_MAX; Cc = newWorldSize / util::M2PI; -- cgit v1.2.1 From 1df45a5e42b8f299d01cea09c9717c5df287f0b7 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Wed, 28 Jun 2017 14:36:28 +0300 Subject: [core] Check if frameZoom is NaN in Transform::flyTo callback --- src/mbgl/map/transform.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 8d05bc0e91..50f979437d 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -293,6 +293,11 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima Point framePoint = util::interpolate(startPoint, endPoint, us); double frameZoom = startZoom + state.scaleZoom(1 / w(s)); + // Zoom can be NaN if size is empty. + if (std::isnan(frameZoom)) { + frameZoom = zoom; + } + // Convert to geographic coordinates and set the new viewpoint. LatLng frameLatLng = Projection::unproject(framePoint, startScale); state.setLatLngZoom(frameLatLng, frameZoom); -- cgit v1.2.1 From b5fed1172d77bac0ba122c73a9d30739a51e5028 Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Thu, 29 Jun 2017 11:29:48 -0700 Subject: [core] Bind only active attributes in order to avoid exceeding attribute limits (#9373) Introducing two new attributes to enable property functions for line-width (#9250) pushed the attribute count over GL_MAX_VERTEX_ATTRIBS on some devices. Now we selectively bind only attributes that are used, making it unlikely to surpass GL_MAX_VERTEX_ATTRIBS. --- src/mbgl/gl/attribute.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/mbgl/gl/attribute.hpp | 12 +++++++++++- src/mbgl/gl/program.hpp | 12 +++++++----- 3 files changed, 64 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index e05ca75866..4e6f78e689 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -2,14 +2,55 @@ #include #include +#include + namespace mbgl { namespace gl { AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { + assert(location < 8); MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); return location; } +int32_t getActiveAttributeCount(ProgramID id) { + GLint numAttributes; + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &numAttributes)); + return numAttributes; +} + +int32_t getMaxAttributeNameLength(ProgramID id) { + GLint nameLength; + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameLength)); + return nameLength; +} + +std::string getAttributeName(ProgramID id, int32_t maxLength, AttributeLocation location) { + std::string attributeName; + attributeName.resize(maxLength); + GLsizei actualLength; + GLint size; + GLenum type; + MBGL_CHECK_ERROR(glGetActiveAttrib(id, static_cast(location), + static_cast(maxLength), &actualLength, &size, &type, + const_cast(attributeName.data()))); + attributeName.resize(actualLength); + return attributeName; +} + +std::set getActiveAttributes(ProgramID id) { + std::set activeAttributes; + + GLint attributeCount = getActiveAttributeCount(id); + GLint maxAttributeLength = getMaxAttributeNameLength(id); + + for (int32_t i = 0; i < attributeCount; i++) { + activeAttributes.emplace(getAttributeName(id, maxAttributeLength, i)); + } + + return activeAttributes; +} + void DisabledAttribute::bind(Context&, AttributeLocation location, std::size_t) const { MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); } @@ -25,6 +66,11 @@ template <> DataType DataTypeOf = DataType::Float; template void AttributeBinding::bind(Context& context, AttributeLocation location, std::size_t vertexOffset) const { + // FillProgram will attempt to bind at location -1 because it includes + // a fill-outline-color paint property but does not use it or have an + // a_outline_color shader attribute - in this case, we have nothing to bind. + if (location == -1) return; + context.vertexBuffer = vertexBuffer; MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); MBGL_CHECK_ERROR(glVertexAttribPointer( diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 48222146fa..f018a1d261 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace mbgl { @@ -223,6 +224,7 @@ const std::size_t Vertex::attributeOffsets[5] = { } // namespace detail AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); +std::set getActiveAttributes(ProgramID); template class Attributes { @@ -242,7 +244,15 @@ public: static constexpr std::size_t Index = TypeIndex::value; static Locations bindLocations(const ProgramID& id) { - return Locations { bindAttributeLocation(id, Index, As::name())... }; + std::set activeAttributes = getActiveAttributes(id); + + AttributeLocation location = -1; + auto bindAndIncrement = [&](const char* name) { + location++; + return bindAttributeLocation(id, location, name); + }; + return Locations{ (activeAttributes.count(As::name()) ? bindAndIncrement(As::name()) + : -1)... }; } template diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 47ad39de7c..583d53e4ec 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -33,15 +33,17 @@ public: : program( context.createProgram(context.createShader(ShaderType::Vertex, vertexSource), context.createShader(ShaderType::Fragment, fragmentSource))), - attributeLocations(Attributes::bindLocations(program)), - uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))) { + uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))), + attributeLocations(Attributes::bindLocations(program)) { + // Re-link program after manually binding only active attributes in Attributes::bindLocations + context.linkProgram(program); } template Program(Context& context, const BinaryProgram& binaryProgram) : program(context.createProgram(binaryProgram.format(), binaryProgram.code())), - attributeLocations(Attributes::loadNamedLocations(binaryProgram)), - uniformsState(Uniforms::loadNamedLocations(binaryProgram)) { + uniformsState(Uniforms::loadNamedLocations(binaryProgram)), + attributeLocations(Attributes::loadNamedLocations(binaryProgram)) { } static Program createProgram(gl::Context& context, @@ -144,8 +146,8 @@ public: private: UniqueProgram program; - typename Attributes::Locations attributeLocations; typename Uniforms::State uniformsState; + typename Attributes::Locations attributeLocations; }; } // namespace gl -- cgit v1.2.1 From 60eae41549cec18dfeed5175fe1d6c327060a8de Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Thu, 29 Jun 2017 22:40:50 +0300 Subject: [core] Factor timePoint initialization: take 2 --- src/mbgl/map/map.cpp | 4 +++- src/mbgl/map/zoom_history.hpp | 7 ++++--- src/mbgl/renderer/render_style.cpp | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 4d073802c2..034e43f260 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -207,7 +207,9 @@ void Map::render(View& view) { } void Map::Impl::render(View& view) { - TimePoint timePoint = Clock::now(); + TimePoint timePoint = mode == MapMode::Continuous + ? Clock::now() + : Clock::time_point::max(); transform.updateTransitions(timePoint); diff --git a/src/mbgl/map/zoom_history.hpp b/src/mbgl/map/zoom_history.hpp index 308846b1e3..697e28573c 100644 --- a/src/mbgl/map/zoom_history.hpp +++ b/src/mbgl/map/zoom_history.hpp @@ -13,19 +13,20 @@ struct ZoomHistory { bool first = true; bool update(float z, const TimePoint& now) { + constexpr TimePoint zero = TimePoint(Duration::zero()); if (first) { first = false; lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = TimePoint(Duration::zero()); + lastIntegerZoomTime = zero; lastZoom = z; return true; } else { if (std::floor(lastZoom) < std::floor(z)) { lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = now; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; } else if (std::floor(lastZoom) > std::floor(z)) { lastIntegerZoom = std::floor(z + 1); - lastIntegerZoomTime = now; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; } if (z != lastZoom) { diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index 79b20a9d71..91efb6c737 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -86,13 +86,13 @@ void RenderStyle::update(const UpdateParameters& parameters) { const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); const TransitionParameters transitionParameters { - parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), + parameters.timePoint, parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions() }; const PropertyEvaluationParameters evaluationParameters { zoomHistory, - parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), + parameters.timePoint, parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero() }; -- cgit v1.2.1 From 87081b8391edb3a5e3bd0dede45534f191d1f84a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 28 Jun 2017 17:29:20 -0700 Subject: [core] Fix iterator invalidation in erase_if vector::erase invalidates iterators. It's not safe for erase_if to cache the end iterator nor increment, then erase. --- src/mbgl/util/std.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/std.hpp b/src/mbgl/util/std.hpp index 974e21329c..1db20e09e5 100644 --- a/src/mbgl/util/std.hpp +++ b/src/mbgl/util/std.hpp @@ -8,10 +8,10 @@ namespace mbgl { namespace util { template -void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) { - while (it != end) { +void erase_if(Container &container, ForwardIterator it, Predicate pred) { + while (it != container.end()) { if (pred(*it)) { - container.erase(it++); + it = container.erase(it); } else { ++it; } @@ -20,7 +20,7 @@ void erase_if(Container &container, ForwardIterator it, const ForwardIterator en template void erase_if(Container &container, Predicate pred) { - erase_if(container, container.begin(), container.end(), pred); + erase_if(container, container.begin(), pred); } } // namespace util -- cgit v1.2.1 From 6d526c7b1dad81c8da1cf0d221d0b83ed2be9862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 4 Jul 2017 18:18:05 +0200 Subject: [core] refactor ClipID generation --- src/mbgl/algorithm/generate_clip_ids.hpp | 4 ++-- src/mbgl/algorithm/generate_clip_ids_impl.hpp | 26 +++++++++++---------- src/mbgl/annotation/render_annotation_source.cpp | 2 +- src/mbgl/annotation/render_annotation_source.hpp | 2 +- src/mbgl/renderer/render_source.hpp | 3 ++- src/mbgl/renderer/render_style.cpp | 10 +++----- src/mbgl/renderer/render_tile.hpp | 2 +- .../renderer/sources/render_geojson_source.cpp | 2 +- .../renderer/sources/render_geojson_source.hpp | 2 +- src/mbgl/renderer/sources/render_image_source.hpp | 5 ++-- src/mbgl/renderer/sources/render_raster_source.cpp | 2 +- src/mbgl/renderer/sources/render_raster_source.hpp | 2 +- src/mbgl/renderer/sources/render_vector_source.cpp | 2 +- src/mbgl/renderer/sources/render_vector_source.hpp | 2 +- src/mbgl/renderer/tile_pyramid.cpp | 27 +++++++++------------- src/mbgl/renderer/tile_pyramid.hpp | 4 ++-- 16 files changed, 45 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/mbgl/algorithm/generate_clip_ids.hpp b/src/mbgl/algorithm/generate_clip_ids.hpp index d917b398af..c4d332343b 100644 --- a/src/mbgl/algorithm/generate_clip_ids.hpp +++ b/src/mbgl/algorithm/generate_clip_ids.hpp @@ -25,8 +25,8 @@ private: std::unordered_multimap pool; public: - template - void update(Renderables& renderables); + template + void update(std::vector> renderables); std::map getStencils() const; }; diff --git a/src/mbgl/algorithm/generate_clip_ids_impl.hpp b/src/mbgl/algorithm/generate_clip_ids_impl.hpp index d63ba27b6b..db62214220 100644 --- a/src/mbgl/algorithm/generate_clip_ids_impl.hpp +++ b/src/mbgl/algorithm/generate_clip_ids_impl.hpp @@ -7,14 +7,16 @@ namespace mbgl { namespace algorithm { -template -void ClipIDGenerator::update(Renderables& renderables) { +template +void ClipIDGenerator::update(std::vector> renderables) { std::size_t size = 0; + std::sort(renderables.begin(), renderables.end(), + [](const auto& a, const auto& b) { return a.get().id < b.get().id; }); + const auto end = renderables.end(); for (auto it = renderables.begin(); it != end; it++) { - auto& tileID = it->first; - auto& renderable = it->second; + auto& renderable = it->get(); if (!renderable.used) { continue; } @@ -28,17 +30,17 @@ void ClipIDGenerator::update(Renderables& renderables) { // can never be children of the current wrap. auto child_it = std::next(it); const auto children_end = std::lower_bound( - child_it, end, UnwrappedTileID{ static_cast(tileID.wrap + 1), { 0, 0, 0 } }, - [](auto& a, auto& b) { return a.first < b; }); + child_it, end, UnwrappedTileID{ static_cast(renderable.id.wrap + 1), { 0, 0, 0 } }, + [](auto& a, auto& b) { return a.get().id < b; }); for (; child_it != children_end; ++child_it) { - auto& childTileID = child_it->first; - if (childTileID.isChildOf(tileID)) { + auto& childTileID = child_it->get().id; + if (childTileID.isChildOf(it->get().id)) { leaf.add(childTileID.canonical); } } // Find a leaf with matching children. - for (auto its = pool.equal_range(tileID); its.first != its.second; ++its.first) { + for (auto its = pool.equal_range(renderable.id); its.first != its.second; ++its.first) { auto& existing = its.first->second; if (existing == leaf) { leaf.clip = existing.clip; @@ -50,7 +52,7 @@ void ClipIDGenerator::update(Renderables& renderables) { size++; } - pool.emplace(tileID, std::move(leaf)); + pool.emplace(renderable.id, std::move(leaf)); } if (size > 0) { @@ -60,8 +62,8 @@ void ClipIDGenerator::update(Renderables& renderables) { // We are starting our count with 1 since we need at least 1 bit set to distinguish between // areas without any tiles whatsoever and the current area. uint8_t count = 1; - for (auto& pair : renderables) { - auto& renderable = pair.second; + for (auto& it : renderables) { + auto& renderable = it.get(); if (!renderable.used) { continue; } diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index 8fb11785fd..0d0427b7a7 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -53,7 +53,7 @@ void RenderAnnotationSource::finishRender(Painter& painter) { tilePyramid.finishRender(painter); } -std::map& RenderAnnotationSource::getRenderTiles() { +std::vector> RenderAnnotationSource::getRenderTiles() { return tilePyramid.getRenderTiles(); } diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp index 7231452d4f..621298a112 100644 --- a/src/mbgl/annotation/render_annotation_source.hpp +++ b/src/mbgl/annotation/render_annotation_source.hpp @@ -21,7 +21,7 @@ public: void startRender(Painter&) final; void finishRender(Painter&) final; - std::map& getRenderTiles() final; + std::vector> getRenderTiles() final; std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index b82547b375..9d2e74b50b 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -57,7 +57,8 @@ public: virtual void startRender(Painter&) = 0; virtual void finishRender(Painter&) = 0; - virtual std::map& getRenderTiles() = 0; + // Returns an unsorted list of RenderTiles. + virtual std::vector> getRenderTiles() = 0; virtual std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index 91efb6c737..bae879dca7 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -309,16 +309,12 @@ RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) continue; } - auto& renderTiles = source->getRenderTiles(); const bool symbolLayer = layer->is(); - // Sort symbol tiles in opposite y position, so tiles with overlapping - // symbols are drawn on top of each other, with lower symbols being - // drawn on top of higher symbols. - std::vector> sortedTiles; - std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), - [](auto& pair) { return std::ref(pair.second); }); + auto sortedTiles = source->getRenderTiles(); if (symbolLayer) { + // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn + // on top of each other, with lower symbols being drawn on top of higher symbols. std::sort(sortedTiles.begin(), sortedTiles.end(), [angle](const RenderTile& a, const RenderTile& b) { Point pa(a.id.canonical.x, a.id.canonical.y); diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 6677278873..07e2d699f7 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -13,7 +13,7 @@ class Tile; class TransformState; class Painter; -class RenderTile { +class RenderTile final { public: RenderTile(UnwrappedTileID id_, Tile& tile_) : id(std::move(id_)), tile(tile_) {} RenderTile(const RenderTile&) = delete; diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 2c6935b273..c45a62498d 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -68,7 +68,7 @@ void RenderGeoJSONSource::finishRender(Painter& painter) { tilePyramid.finishRender(painter); } -std::map& RenderGeoJSONSource::getRenderTiles() { +std::vector> RenderGeoJSONSource::getRenderTiles() { return tilePyramid.getRenderTiles(); } diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index b7c5a3fa7f..8d4154112f 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -25,7 +25,7 @@ public: void startRender(Painter&) final; void finishRender(Painter&) final; - std::map& getRenderTiles() final; + std::vector> getRenderTiles() final; std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 88f1c56567..41c4bd5483 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -30,8 +30,8 @@ public: bool needsRelayout, const TileParameters&) final; - std::map& getRenderTiles() final { - return tiles; + std::vector> getRenderTiles() final { + return {}; } std::unordered_map> @@ -48,7 +48,6 @@ public: private: const style::ImageSource::Impl& impl() const; - std::map tiles; std::vector tileIds; std::unique_ptr bucket; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index 20c148870e..2006e31628 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -64,7 +64,7 @@ void RenderRasterSource::finishRender(Painter& painter) { tilePyramid.finishRender(painter); } -std::map& RenderRasterSource::getRenderTiles() { +std::vector> RenderRasterSource::getRenderTiles() { return tilePyramid.getRenderTiles(); } diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index 7d0c245e45..73a2ac3b22 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -21,7 +21,7 @@ public: void startRender(Painter&) final; void finishRender(Painter&) final; - std::map& getRenderTiles() final; + std::vector> getRenderTiles() final; std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index 4302fb21ee..0f44a64b63 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -69,7 +69,7 @@ void RenderVectorSource::finishRender(Painter& painter) { tilePyramid.finishRender(painter); } -std::map& RenderVectorSource::getRenderTiles() { +std::vector> RenderVectorSource::getRenderTiles() { return tilePyramid.getRenderTiles(); } diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index 5e15fee533..231a9071ab 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -21,7 +21,7 @@ public: void startRender(Painter&) final; void finishRender(Painter&) final; - std::map& getRenderTiles() final; + std::vector> getRenderTiles() final; std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index c2806299e3..caf55d64e8 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -40,22 +40,21 @@ bool TilePyramid::isLoaded() const { } void TilePyramid::startRender(Painter& painter) { - for (auto& pair : renderTiles) { - pair.second.startRender(painter); + for (auto& tile : renderTiles) { + tile.startRender(painter); } } void TilePyramid::finishRender(Painter& painter) { - for (auto& pair : renderTiles) { - auto& tile = pair.second; + for (auto& tile : renderTiles) { if (tile.used) { painter.renderTileDebug(tile); } } } -std::map& TilePyramid::getRenderTiles() { - return renderTiles; +std::vector> TilePyramid::getRenderTiles() { + return { renderTiles.begin(), renderTiles.end() }; } void TilePyramid::update(const std::vector>& layers, @@ -134,7 +133,7 @@ void TilePyramid::update(const std::vector>& layer return tiles.emplace(tileID, std::move(tile)).first->second.get(); }; auto renderTileFn = [&](const UnwrappedTileID& tileID, Tile& tile) { - renderTiles.emplace(tileID, RenderTile{ tileID, tile }); + renderTiles.emplace_back(tileID, tile); }; renderTiles.clear(); @@ -199,18 +198,14 @@ std::unordered_map> TilePyramid::queryRendered mapbox::geometry::box box = mapbox::geometry::envelope(queryGeometry); - - auto sortRenderTiles = [](const RenderTile& a, const RenderTile& b) { + std::vector> sortedTiles{ renderTiles.begin(), + renderTiles.end() }; + std::sort(sortedTiles.begin(), sortedTiles.end(), [](const RenderTile& a, const RenderTile& b) { return std::tie(a.id.canonical.z, a.id.canonical.y, a.id.wrap, a.id.canonical.x) < std::tie(b.id.canonical.z, b.id.canonical.y, b.id.wrap, b.id.canonical.x); - }; - std::vector> sortedTiles; - std::transform(renderTiles.cbegin(), renderTiles.cend(), std::back_inserter(sortedTiles), - [](const auto& pair) { return std::ref(pair.second); }); - std::sort(sortedTiles.begin(), sortedTiles.end(), sortRenderTiles); + }); - for (const auto& renderTileRef : sortedTiles) { - const RenderTile& renderTile = renderTileRef.get(); + for (const RenderTile& renderTile : sortedTiles) { GeometryCoordinate tileSpaceBoundsMin = TileCoordinate::toGeometryCoordinate(renderTile.id, box.min); if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT) { continue; diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index 5846560808..a3db65b460 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -45,7 +45,7 @@ public: void startRender(Painter&); void finishRender(Painter&); - std::map& getRenderTiles(); + std::vector> getRenderTiles(); std::unordered_map> queryRenderedFeatures(const ScreenLineString& geometry, @@ -68,7 +68,7 @@ public: std::map> tiles; TileCache cache; - std::map renderTiles; + std::vector renderTiles; TileObserver* observer = nullptr; }; -- cgit v1.2.1 From 107622a72ba6929bdd70e42d96c16b62c9f65dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 4 Jul 2017 18:26:50 +0200 Subject: [core] don't use unordered_* collections for things we need to sort anyway --- src/mbgl/algorithm/generate_clip_ids.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/algorithm/generate_clip_ids.hpp b/src/mbgl/algorithm/generate_clip_ids.hpp index c4d332343b..8338c7c145 100644 --- a/src/mbgl/algorithm/generate_clip_ids.hpp +++ b/src/mbgl/algorithm/generate_clip_ids.hpp @@ -3,9 +3,9 @@ #include #include -#include +#include #include -#include +#include namespace mbgl { namespace algorithm { @@ -17,12 +17,12 @@ private: void add(const CanonicalTileID &p); bool operator==(const Leaf &other) const; - std::unordered_set children; + std::set children; ClipID& clip; }; uint8_t bit_offset = 0; - std::unordered_multimap pool; + std::multimap pool; public: template -- cgit v1.2.1 From 64a827c3250dda0dd97189abf342e7d3c76fd006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 4 Jul 2017 18:31:37 +0200 Subject: [core] rename getStencils() to getClipIDs() to better reflect what it actually does --- src/mbgl/algorithm/generate_clip_ids.cpp | 16 ++++++++-------- src/mbgl/algorithm/generate_clip_ids.hpp | 2 +- src/mbgl/renderer/painter.cpp | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/mbgl/algorithm/generate_clip_ids.cpp b/src/mbgl/algorithm/generate_clip_ids.cpp index 74e0ee242f..287d2a408e 100644 --- a/src/mbgl/algorithm/generate_clip_ids.cpp +++ b/src/mbgl/algorithm/generate_clip_ids.cpp @@ -31,14 +31,14 @@ bool ClipIDGenerator::Leaf::operator==(const Leaf& other) const { return children == other.children; } -std::map ClipIDGenerator::getStencils() const { - std::map stencils; +std::map ClipIDGenerator::getClipIDs() const { + std::map clipIDs; // Merge everything. for (auto& pair : pool) { auto& id = pair.first; auto& leaf = pair.second; - auto res = stencils.emplace(id, leaf.clip); + auto res = clipIDs.emplace(id, leaf.clip); if (!res.second) { // Merge with the existing ClipID when there was already an element with the // same tile ID. @@ -46,14 +46,14 @@ std::map ClipIDGenerator::getStencils() const { } } - for (auto it = stencils.begin(); it != stencils.end(); ++it) { + for (auto it = clipIDs.begin(); it != clipIDs.end(); ++it) { auto& childId = it->first; auto& childClip = it->second; // Loop through all preceding stencils, and find all parents. for (auto parentIt = std::reverse_iterator(it); - parentIt != stencils.rend(); ++parentIt) { + parentIt != clipIDs.rend(); ++parentIt) { auto& parentId = parentIt->first; if (childId.isChildOf(parentId)) { // Once we have a parent, we add the bits that this ID hasn't set yet. @@ -66,11 +66,11 @@ std::map ClipIDGenerator::getStencils() const { } // Remove tiles that are entirely covered by children. - util::erase_if(stencils, [&](const auto& stencil) { - return algorithm::coveredByChildren(stencil.first, stencils); + util::erase_if(clipIDs, [&](const auto& stencil) { + return algorithm::coveredByChildren(stencil.first, clipIDs); }); - return stencils; + return clipIDs; } } // namespace algorithm diff --git a/src/mbgl/algorithm/generate_clip_ids.hpp b/src/mbgl/algorithm/generate_clip_ids.hpp index 8338c7c145..adcf87a72a 100644 --- a/src/mbgl/algorithm/generate_clip_ids.hpp +++ b/src/mbgl/algorithm/generate_clip_ids.hpp @@ -28,7 +28,7 @@ public: template void update(std::vector> renderables); - std::map getStencils() const; + std::map getClipIDs() const; }; } // namespace algorithm diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 47db8254e2..a3decdb603 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -198,9 +198,9 @@ void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { MBGL_DEBUG_GROUP(context, "clipping masks"); - for (const auto& stencil : clipIDGenerator.getStencils()) { - MBGL_DEBUG_GROUP(context, std::string{ "mask: " } + util::toString(stencil.first)); - renderClippingMask(stencil.first, stencil.second); + for (const auto& clipID : clipIDGenerator.getClipIDs()) { + MBGL_DEBUG_GROUP(context, std::string{ "mask: " } + util::toString(clipID.first)); + renderClippingMask(clipID.first, clipID.second); } } -- cgit v1.2.1 From 754d2f377aa1b8993ca5365109dfec98475e6de4 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 23 Jun 2017 11:36:54 -0700 Subject: [core] make{Glyph,Image}Atlas only once for any number of symbol layers --- src/mbgl/layout/symbol_layout.hpp | 7 ----- src/mbgl/tile/geometry_tile_worker.cpp | 49 ++++++++++++++++------------------ src/mbgl/tile/geometry_tile_worker.hpp | 2 +- 3 files changed, 24 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 8cdaadff00..4ee52e843f 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -40,13 +40,6 @@ public: bool hasSymbolInstances() const; - enum State { - Pending, // Waiting for the necessary glyphs or icons to be available. - Placed // The final positions have been determined, taking into account prior layers. - }; - - State state = Pending; - std::map> layerPaintProperties; diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 12bb84d7e3..c622d82e31 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -144,14 +144,14 @@ void GeometryTileWorker::symbolDependenciesChanged() { try { switch (state) { case Idle: - if (hasPendingSymbolLayouts()) { + if (symbolLayoutsNeedPreparation) { attemptPlacement(); coalesce(); } break; case Coalescing: - if (hasPendingSymbolLayouts()) { + if (symbolLayoutsNeedPreparation) { state = NeedPlacement; } break; @@ -312,6 +312,7 @@ void GeometryTileWorker::redoLayout() { auto layout = leader.as()->createLayout( parameters, group, std::move(geometryLayer), glyphDependencies, imageDependencies); symbolLayoutMap.emplace(leader.getID(), std::move(layout)); + symbolLayoutsNeedPreparation = true; } else { const Filter& filter = leader.baseImpl->filter; const std::string& sourceLayerID = leader.baseImpl->sourceLayer; @@ -359,16 +360,6 @@ void GeometryTileWorker::redoLayout() { attemptPlacement(); } -bool GeometryTileWorker::hasPendingSymbolLayouts() const { - for (const auto& symbolLayout : symbolLayouts) { - if (symbolLayout->state == SymbolLayout::Pending) { - return true; - } - } - - return false; -} - bool GeometryTileWorker::hasPendingSymbolDependencies() const { for (auto& glyphDependency : pendingGlyphDependencies) { if (!glyphDependency.second.empty()) { @@ -378,33 +369,39 @@ bool GeometryTileWorker::hasPendingSymbolDependencies() const { return !pendingImageDependencies.empty(); } - void GeometryTileWorker::attemptPlacement() { if (!data || !layers || !placementConfig || hasPendingSymbolDependencies()) { return; } - auto collisionTile = std::make_unique(*placementConfig); - std::unordered_map> buckets; - optional glyphAtlasImage; optional iconAtlasImage; - for (auto& symbolLayout : symbolLayouts) { - if (obsolete) { - return; - } + if (symbolLayoutsNeedPreparation) { + GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); + ImageAtlas imageAtlas = makeImageAtlas(imageMap); + + glyphAtlasImage = std::move(glyphAtlas.image); + iconAtlasImage = std::move(imageAtlas.image); - if (symbolLayout->state == SymbolLayout::Pending) { - GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); - ImageAtlas imageAtlas = makeImageAtlas(imageMap); + for (auto& symbolLayout : symbolLayouts) { + if (obsolete) { + return; + } symbolLayout->prepare(glyphMap, glyphAtlas.positions, imageMap, imageAtlas.positions); - symbolLayout->state = SymbolLayout::Placed; + } + + symbolLayoutsNeedPreparation = false; + } - glyphAtlasImage = std::move(glyphAtlas.image); - iconAtlasImage = std::move(imageAtlas.image); + auto collisionTile = std::make_unique(*placementConfig); + std::unordered_map> buckets; + + for (auto& symbolLayout : symbolLayouts) { + if (obsolete) { + return; } if (!symbolLayout->hasSymbolInstances()) { diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 194477e7b8..7f80c3b4f7 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -52,7 +52,6 @@ private: void symbolDependenciesChanged(); bool hasPendingSymbolDependencies() const; - bool hasPendingSymbolLayouts() const; ActorRef self; ActorRef parent; @@ -77,6 +76,7 @@ private: optional> data; optional placementConfig; + bool symbolLayoutsNeedPreparation = false; std::vector> symbolLayouts; GlyphDependencies pendingGlyphDependencies; ImageDependencies pendingImageDependencies; -- cgit v1.2.1 From a1ed9f879408a12e462196d961075c2ae3d7486e Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Wed, 5 Jul 2017 14:37:49 +0300 Subject: [core] Don't upload empty buckets --- src/mbgl/renderer/bucket.hpp | 5 ++++- src/mbgl/renderer/buckets/symbol_bucket.cpp | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 6c391cf014..a411daf3d4 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -28,6 +28,9 @@ public: Bucket() = default; virtual ~Bucket() = default; + // Feature geometries are also used to populate the feature index. + // Obtaining these is a costly operation, so we do it only once, and + // pass-by-const-ref the geometries as a second parameter. virtual void addFeature(const GeometryTileFeature&, const GeometryCollection&) {}; @@ -46,7 +49,7 @@ public: }; bool needsUpload() const { - return !uploaded; + return hasData() && !uploaded; } protected: diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index cbddade899..28e6a47250 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -69,8 +69,7 @@ void SymbolBucket::render(Painter& painter, } bool SymbolBucket::hasData() const { - assert(false); // Should be calling SymbolLayout::has{Text,Icon,CollisonBox}Data() instead. - return false; + return hasTextData() || hasIconData() || hasCollisionBoxData(); } bool SymbolBucket::hasTextData() const { -- cgit v1.2.1 From d5fbcb242acff2ab270b4018b01c2c6be9c4955f Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 5 Jul 2017 13:59:45 -0700 Subject: [core] Implement circle-pitch-alignment property Closes issue #9349. --- src/mbgl/programs/circle_program.hpp | 4 +++- src/mbgl/programs/symbol_program.hpp | 1 - src/mbgl/programs/uniforms.hpp | 2 ++ src/mbgl/renderer/painters/painter_circle.cpp | 12 ++++++---- src/mbgl/shaders/circle.cpp | 28 +++++++++++++++++++---- src/mbgl/style/layers/circle_layer.cpp | 27 ++++++++++++++++++++++ src/mbgl/style/layers/circle_layer_properties.hpp | 5 ++++ 7 files changed, 67 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp index 8f056048b1..3590acbeef 100644 --- a/src/mbgl/programs/circle_program.hpp +++ b/src/mbgl/programs/circle_program.hpp @@ -21,7 +21,9 @@ class CircleProgram : public Program< gl::Uniforms< uniforms::u_matrix, uniforms::u_scale_with_map, - uniforms::u_extrude_scale>, + uniforms::u_extrude_scale, + uniforms::u_camera_to_center_distance, + uniforms::u_pitch_with_map>, style::CirclePaintProperties> { public: diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index e7c428034b..c11e0b5ca1 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -30,7 +30,6 @@ class TransformState; namespace uniforms { MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index f1b2c2fb54..c8f8684ba1 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -33,6 +33,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth); MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset); MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); diff --git a/src/mbgl/renderer/painters/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp index 58e384979d..a077f557fc 100644 --- a/src/mbgl/renderer/painters/painter_circle.cpp +++ b/src/mbgl/renderer/painters/painter_circle.cpp @@ -22,6 +22,7 @@ void Painter::renderCircle(PaintParameters& parameters, const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated; const bool scaleWithMap = properties.get() == CirclePitchScaleType::Map; + const bool pitchWithMap = properties.get() == AlignmentType::Map; parameters.programs.circle.get(properties).draw( context, @@ -38,12 +39,13 @@ void Painter::renderCircle(PaintParameters& parameters, state) }, uniforms::u_scale_with_map::Value{ scaleWithMap }, - uniforms::u_extrude_scale::Value{ scaleWithMap + uniforms::u_extrude_scale::Value{ pitchWithMap ? std::array {{ - pixelsToGLUnits[0] * state.getCameraToCenterDistance(), - pixelsToGLUnits[1] * state.getCameraToCenterDistance() - }} - : pixelsToGLUnits } + tile.id.pixelsToTileUnits(1, state.getZoom()), + tile.id.pixelsToTileUnits(1, state.getZoom()) }} + : pixelsToGLUnits }, + uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, + uniforms::u_pitch_with_map::Value{ pitchWithMap } }, *bucket.vertexBuffer, *bucket.indexBuffer, diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp index 2e0c76122c..953e750776 100644 --- a/src/mbgl/shaders/circle.cpp +++ b/src/mbgl/shaders/circle.cpp @@ -9,7 +9,9 @@ const char* circle::name = "circle"; const char* circle::vertexSource = R"MBGL_SHADER( uniform mat4 u_matrix; uniform bool u_scale_with_map; +uniform bool u_pitch_with_map; uniform vec2 u_extrude_scale; +uniform highp float u_camera_to_center_distance; attribute vec2 a_pos; @@ -121,12 +123,28 @@ void main(void) { // multiply a_pos by 0.5, since we had it * 2 in order to sneak // in extrusion data - gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1); - - if (u_scale_with_map) { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale; + vec2 circle_center = floor(a_pos * 0.5); + if (u_pitch_with_map) { + vec2 corner_position = circle_center; + if (u_scale_with_map) { + corner_position += extrude * (radius + stroke_width) * u_extrude_scale; + } else { + // Pitching the circle with the map effectively scales it with the map + // To counteract the effect for pitch-scale: viewport, we rescale the + // whole circle based on the pitch scaling effect at its central point + vec4 projected_center = u_matrix * vec4(circle_center, 0, 1); + corner_position += extrude * (radius + stroke_width) * u_extrude_scale * (projected_center.w / u_camera_to_center_distance); + } + + gl_Position = u_matrix * vec4(corner_position, 0, 1); } else { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; + gl_Position = u_matrix * vec4(circle_center, 0, 1); + + if (u_scale_with_map) { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * u_camera_to_center_distance; + } else { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; + } } // This is a minimum blur distance that serves as a faux-antialiasing for diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 3bba135c84..9854932699 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -283,6 +283,33 @@ TransitionOptions CircleLayer::getCirclePitchScaleTransition() const { return impl().paint.template get().options; } +PropertyValue CircleLayer::getDefaultCirclePitchAlignment() { + return { AlignmentType::Viewport }; +} + +PropertyValue CircleLayer::getCirclePitchAlignment() const { + return impl().paint.template get().value; +} + +void CircleLayer::setCirclePitchAlignment(PropertyValue value) { + if (value == getCirclePitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void CircleLayer::setCirclePitchAlignmentTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions CircleLayer::getCirclePitchAlignmentTransition() const { + return impl().paint.template get().options; +} + DataDrivenPropertyValue CircleLayer::getDefaultCircleStrokeWidth() { return { 0 }; } diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index 73b7028465..bc0c961e75 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -40,6 +40,10 @@ struct CirclePitchScale : PaintProperty { static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; } }; +struct CirclePitchAlignment : PaintProperty { + static AlignmentType defaultValue() { return AlignmentType::Viewport; } +}; + struct CircleStrokeWidth : DataDrivenPaintProperty { static float defaultValue() { return 0; } }; @@ -60,6 +64,7 @@ class CirclePaintProperties : public Properties< CircleTranslate, CircleTranslateAnchor, CirclePitchScale, + CirclePitchAlignment, CircleStrokeWidth, CircleStrokeColor, CircleStrokeOpacity -- cgit v1.2.1 From 2fe3dd64c016c676d7aa35c510cf7d96df8b91dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Fri, 30 Jun 2017 00:36:40 -0700 Subject: [core] Updated script detection for Unicode 10 Updated script detection code to reflect changes in Unicode 10 and UTR 50 revision 17. --- src/mbgl/util/i18n.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp index ada6f6526c..16f1d669f3 100644 --- a/src/mbgl/util/i18n.cpp +++ b/src/mbgl/util/i18n.cpp @@ -15,7 +15,7 @@ namespace { return codepoint >= first && codepoint <= last; \ } -// The following table comes from . +// The following table comes from . // Keep it synchronized with . // DEFINE_IS_IN_UNICODE_BLOCK(BasicLatin, 0x0000, 0x007F) @@ -37,6 +37,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(ArabicSupplement, 0x0750, 0x077F) // DEFINE_IS_IN_UNICODE_BLOCK(NKo, 0x07C0, 0x07FF) // DEFINE_IS_IN_UNICODE_BLOCK(Samaritan, 0x0800, 0x083F) // DEFINE_IS_IN_UNICODE_BLOCK(Mandaic, 0x0840, 0x085F) +// DEFINE_IS_IN_UNICODE_BLOCK(Syriac Supplement, 0x0860, 0x086F) DEFINE_IS_IN_UNICODE_BLOCK(ArabicExtendedA, 0x08A0, 0x08FF) // DEFINE_IS_IN_UNICODE_BLOCK(Devanagari, 0x0900, 0x097F) // DEFINE_IS_IN_UNICODE_BLOCK(Bengali, 0x0980, 0x09FF) @@ -239,9 +240,12 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF) // DEFINE_IS_IN_UNICODE_BLOCK(Takri, 0x11680, 0x116CF) // DEFINE_IS_IN_UNICODE_BLOCK(Ahom, 0x11700, 0x1173F) // DEFINE_IS_IN_UNICODE_BLOCK(WarangCiti, 0x118A0, 0x118FF) +// DEFINE_IS_IN_UNICODE_BLOCK(ZanabazarSquare, 0x11A00, 0x11A4F) +// DEFINE_IS_IN_UNICODE_BLOCK(Soyombo, 0x11A50, 0x11AAF) // DEFINE_IS_IN_UNICODE_BLOCK(PauCinHau, 0x11AC0, 0x11AFF) // DEFINE_IS_IN_UNICODE_BLOCK(Bhaiksuki, 0x11C00, 0x11C6F) // DEFINE_IS_IN_UNICODE_BLOCK(Marchen, 0x11C70, 0x11CBF) +// DEFINE_IS_IN_UNICODE_BLOCK(MasaramGondi, 0x11D00, 0x11D5F) // DEFINE_IS_IN_UNICODE_BLOCK(Cuneiform, 0x12000, 0x123FF) // DEFINE_IS_IN_UNICODE_BLOCK(CuneiformNumbersandPunctuation, 0x12400, 0x1247F) // DEFINE_IS_IN_UNICODE_BLOCK(EarlyDynasticCuneiform, 0x12480, 0x1254F) @@ -256,6 +260,8 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF) // DEFINE_IS_IN_UNICODE_BLOCK(Tangut, 0x17000, 0x187FF) // DEFINE_IS_IN_UNICODE_BLOCK(TangutComponents, 0x18800, 0x18AFF) // DEFINE_IS_IN_UNICODE_BLOCK(KanaSupplement, 0x1B000, 0x1B0FF) +// DEFINE_IS_IN_UNICODE_BLOCK(KanaExtendedA, 0x1B100, 0x1B12F) +// DEFINE_IS_IN_UNICODE_BLOCK(Nushu, 0x1B170, 0x1B2FF) // DEFINE_IS_IN_UNICODE_BLOCK(Duployan, 0x1BC00, 0x1BC9F) // DEFINE_IS_IN_UNICODE_BLOCK(ShorthandFormatControls, 0x1BCA0, 0x1BCAF) // DEFINE_IS_IN_UNICODE_BLOCK(ByzantineMusicalSymbols, 0x1D000, 0x1D0FF) @@ -286,6 +292,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF) // DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionC, 0x2A700, 0x2B73F) // DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionD, 0x2B740, 0x2B81F) // DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionE, 0x2B820, 0x2CEAF) +// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionF, 0x2CEB0, 0x2EBEF) // DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographsSupplement, 0x2F800, 0x2FA1F) // DEFINE_IS_IN_UNICODE_BLOCK(Tags, 0xE0000, 0xE007F) // DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF) @@ -375,11 +382,13 @@ bool allowsIdeographicBreaking(char16_t chr) { // return (isInTangut(chr) // || isInTangutComponents(chr) // || isInIdeographicSymbolsandPunctuation(chr) + // || isInNushu(chr) // || isInEnclosedIdeographicSupplement(chr) // || isInCJKUnifiedIdeographsExtensionB(chr) // || isInCJKUnifiedIdeographsExtensionC(chr) // || isInCJKUnifiedIdeographsExtensionD(chr) // || isInCJKUnifiedIdeographsExtensionE(chr) + // || isInCJKUnifiedIdeographsExtensionF(chr) // || isInCJKCompatibilityIdeographsSupplement(chr)); } @@ -393,7 +402,7 @@ bool allowsVerticalWritingMode(const std::u16string& string) { } // The following logic comes from -// . +// . // The data file denotes with “U” or “Tu” any codepoint that may be drawn // upright in vertical text but does not distinguish between upright and // “neutral” characters. @@ -457,6 +466,8 @@ bool hasUprightVerticalOrientation(char16_t chr) { // if (isInTangut(chr)) return true; // if (isInTangutComponents(chr)) return true; // if (isInKanaSupplement(chr)) return true; + // if (isInKanaExtendedA(chr)) return true; + // if (isInNushu(chr)) return true; // if (isInByzantineMusicalSymbols(chr)) return true; // if (isInMusicalSymbols(chr)) return true; // if (isInTaiXuanJingSymbols(chr)) return true; @@ -478,6 +489,7 @@ bool hasUprightVerticalOrientation(char16_t chr) { // if (isInCJKUnifiedIdeographsExtensionC(chr)) return true; // if (isInCJKUnifiedIdeographsExtensionD(chr)) return true; // if (isInCJKUnifiedIdeographsExtensionE(chr)) return true; + // if (isInCJKUnifiedIdeographsExtensionF(chr)) return true; // if (isInCJKCompatibilityIdeographsSupplement(chr)) return true; return false; -- cgit v1.2.1 From 407fbc70b1dc6dab6b7aa5a4b9c57b4e08906c79 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sun, 15 Jan 2017 11:27:52 -0500 Subject: [core] Prefetch low resolution tiles --- src/mbgl/map/map.cpp | 15 ++++++++++++++- src/mbgl/renderer/render_style.cpp | 3 ++- src/mbgl/renderer/tile_parameters.hpp | 1 + src/mbgl/renderer/tile_pyramid.cpp | 28 ++++++++++++++++++++++++++-- src/mbgl/renderer/update_parameters.hpp | 2 ++ 5 files changed, 45 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 034e43f260..565d39c515 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,9 @@ public: std::unique_ptr renderStyle; bool cameraMutated = false; + + uint8_t prefetchZoomDelta = util::DEFAULT_PREFETCH_ZOOM_DELTA; + bool loading = false; util::AsyncTask asyncInvalidate; @@ -245,7 +249,8 @@ void Map::Impl::render(View& view) { style->impl->getLayerImpls(), scheduler, fileSource, - annotationManager + annotationManager, + prefetchZoomDelta }); bool loaded = style->impl->isLoaded() && renderStyle->isLoaded(); @@ -823,6 +828,14 @@ bool Map::isFullyLoaded() const { return impl->style->impl->isLoaded() && impl->renderStyle && impl->renderStyle->isLoaded(); } +void Map::setPrefetchZoomDelta(uint8_t delta) { + impl->prefetchZoomDelta = delta; +} + +uint8_t Map::getPrefetchZoomDelta() const { + return impl->prefetchZoomDelta; +} + void Map::onLowMemory() { if (impl->painter) { BackendScope guard(impl->backend); diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index bae879dca7..aacabe563d 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -105,7 +105,8 @@ void RenderStyle::update(const UpdateParameters& parameters) { parameters.mode, parameters.annotationManager, *imageManager, - *glyphManager + *glyphManager, + parameters.prefetchZoomDelta }; glyphManager->setURL(parameters.glyphURL); diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp index cf7a5b100a..9769ae6897 100644 --- a/src/mbgl/renderer/tile_parameters.hpp +++ b/src/mbgl/renderer/tile_parameters.hpp @@ -22,6 +22,7 @@ public: AnnotationManager& annotationManager; ImageManager& imageManager; GlyphManager& glyphManager; + const uint8_t prefetchZoomDelta = 0; }; } // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index caf55d64e8..a8e6c128ba 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -88,14 +88,30 @@ void TilePyramid::update(const std::vector>& layer // Determine the overzooming/underzooming amounts and required tiles. int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize); int32_t tileZoom = overscaledZoom; + int32_t panZoom = zoomRange.max; std::vector idealTiles; + std::vector panTiles; + if (overscaledZoom >= zoomRange.min) { int32_t idealZoom = std::min(zoomRange.max, overscaledZoom); // Make sure we're not reparsing overzoomed raster tiles. if (type == SourceType::Raster) { tileZoom = idealZoom; + + // FIXME: Prefetching is only enabled for raster + // tiles until we fix #7026. + + // Request lower zoom level tiles (if configure to do so) in an attempt + // to show something on the screen faster at the cost of a little of bandwidth. + if (parameters.prefetchZoomDelta) { + panZoom = std::max(tileZoom - parameters.prefetchZoomDelta, zoomRange.min); + } + + if (panZoom < tileZoom) { + panTiles = util::tileCover(parameters.transformState, panZoom); + } } idealTiles = util::tileCover(parameters.transformState, idealZoom); @@ -108,8 +124,10 @@ void TilePyramid::update(const std::vector>& layer std::set retain; auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void { - retain.emplace(tile.id); - tile.setNecessity(necessity); + if (retain.emplace(tile.id).second) { + tile.setNecessity(necessity); + } + if (needsRelayout) { tile.setLayers(layers); } @@ -137,6 +155,12 @@ void TilePyramid::update(const std::vector>& layer }; renderTiles.clear(); + + if (!panTiles.empty()) { + algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, + [](const UnwrappedTileID&, Tile&) {}, panTiles, zoomRange, panZoom); + } + algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn, idealTiles, zoomRange, tileZoom); diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp index ce79a4f31b..8ebcd11e21 100644 --- a/src/mbgl/renderer/update_parameters.hpp +++ b/src/mbgl/renderer/update_parameters.hpp @@ -33,6 +33,8 @@ public: Scheduler& scheduler; FileSource& fileSource; AnnotationManager& annotationManager; + + const uint8_t prefetchZoomDelta = 0; }; } // namespace mbgl -- cgit v1.2.1 From e962b79b0f434ab80556cede425bdc1daf7730b2 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Thu, 6 Jul 2017 15:49:22 +0200 Subject: [core] Fix sorting order for render tiles Sort by z order, so lower res tiles don't get rendered over high res tiles. --- src/mbgl/renderer/render_style.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index aacabe563d..25dbba76f6 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -326,6 +326,9 @@ RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x); }); + } else { + std::sort(sortedTiles.begin(), sortedTiles.end(), + [](const auto& a, const auto& b) { return a.get().id < b.get().id; }); } std::vector> sortedTilesForInsertion; -- cgit v1.2.1 From f734126416ee9748d66d439918471b2c1a0019a5 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 7 Jul 2017 16:36:13 +0300 Subject: [core] Fix conditional unitialized jump on RenderGeoJSONSource ``` ==24942== Conditional jump or move depends on uninitialised value(s) ==24942== at 0x7D943D: mbgl::RenderGeoJSONSource::update(mbgl::Immutable, std::vector, std::allocator > > const&, bool, bool, mbgl::TileParameters const&) (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x796445: mbgl::RenderStyle::update(mbgl::UpdateParameters const&) (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x77E29D: mbgl::Map::Impl::render(mbgl::View&) (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x77E559: mbgl::Map::Impl::renderStill() (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0xA39772: uv__async_event (async.c:98) ==24942== by 0xA398F8: uv__async_io (async.c:138) ==24942== by 0xA4375F: uv__io_poll (linux-core.c:380) ==24942== by 0xA3A1F2: uv_run (core.c:354) ==24942== by 0x61BADC: API_ZoomHistory_Test::TestBody() (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x89FDE9: void testing::internal::HandleExceptionsInMethodIfSupported(testing::Test*, void (testing::Test::*)(), char const*) (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x885450: testing::Test::Run() (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== by 0x88642F: testing::TestInfo::Run() (in /home/tmpsantos/Projects/mapbox-gl-native/build/linux-x86_64/Release/mbgl-test) ==24942== ``` --- src/mbgl/renderer/sources/render_geojson_source.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index 8d4154112f..bb390a71e3 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -43,7 +43,7 @@ private: const style::GeoJSONSource::Impl& impl() const; TilePyramid tilePyramid; - style::GeoJSONData* data; + style::GeoJSONData* data = nullptr; }; template <> -- cgit v1.2.1 From 7c117281bc8d53d9d6a1e3a9ff9760a5a5b44cf8 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 3 Aug 2016 19:24:04 +0300 Subject: [core] Isolate pthread-based tls implementation --- src/mbgl/util/thread_local.hpp | 44 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/thread_local.hpp b/src/mbgl/util/thread_local.hpp index 15d4d56524..b0e26356b4 100644 --- a/src/mbgl/util/thread_local.hpp +++ b/src/mbgl/util/thread_local.hpp @@ -1,12 +1,8 @@ #pragma once -#include #include -#include -#include - -#include +#include namespace mbgl { namespace util { @@ -14,40 +10,20 @@ namespace util { template class ThreadLocal : public noncopyable { public: - ThreadLocal() { - int ret = pthread_key_create(&key, [](void *ptr) { - delete reinterpret_cast(ptr); - }); - - if (ret) { - throw std::runtime_error("Failed to init local storage key."); - } - } - - ~ThreadLocal() { - if (pthread_key_delete(key)) { - Log::Error(Event::General, "Failed to delete local storage key."); - assert(false); - } + ThreadLocal(T* val) { + ThreadLocal(); + set(val); } - T* get() { - auto* ret = reinterpret_cast(pthread_getspecific(key)); - if (!ret) { - return nullptr; - } + ThreadLocal(); + ~ThreadLocal(); - return ret; - } - - void set(T* ptr) { - if (pthread_setspecific(key, ptr)) { - throw std::runtime_error("Failed to set local storage."); - } - } + T* get(); + void set(T* ptr); private: - pthread_key_t key; + class Impl; + std::unique_ptr impl; }; } // namespace util -- cgit v1.2.1 From d03fd0dce2efc101021b4cf351945680afaa4349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 10 Jul 2017 13:48:43 +0200 Subject: [build] Don't use maybe-uninitialized and misleading-indentation in Clang, since they're not implemented there --- src/mbgl/annotation/symbol_annotation_impl.hpp | 2 ++ src/mbgl/text/collision_tile.hpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/mbgl/annotation/symbol_annotation_impl.hpp b/src/mbgl/annotation/symbol_annotation_impl.hpp index 9270acb857..e41ff85f33 100644 --- a/src/mbgl/annotation/symbol_annotation_impl.hpp +++ b/src/mbgl/annotation/symbol_annotation_impl.hpp @@ -17,8 +17,10 @@ #pragma GCC diagnostic ignored "-Wdeprecated-register" #pragma GCC diagnostic ignored "-Wshorten-64-to-32" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#ifndef __clang__ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif #include #include #include diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp index bdacbb7437..59fd1a3927 100644 --- a/src/mbgl/text/collision_tile.hpp +++ b/src/mbgl/text/collision_tile.hpp @@ -16,8 +16,10 @@ #pragma GCC diagnostic ignored "-Wdeprecated-register" #pragma GCC diagnostic ignored "-Wshorten-64-to-32" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#ifndef __clang__ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif #include #include #include -- cgit v1.2.1 From 59df3a90f41461562a80688337ec53687e341124 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 15 May 2017 14:17:06 -0700 Subject: [core] Improved label pitch-scaling: approximate collision box shapes based on tile distance from camera. --- src/mbgl/map/transform_state.cpp | 12 +++++++++ src/mbgl/map/transform_state.hpp | 2 ++ src/mbgl/programs/symbol_program.cpp | 2 ++ src/mbgl/programs/symbol_program.hpp | 6 ++++- src/mbgl/renderer/tile_pyramid.cpp | 13 +++++++--- src/mbgl/text/collision_tile.cpp | 50 +++++++++++++++++++++++++----------- src/mbgl/text/collision_tile.hpp | 6 +++-- src/mbgl/text/placement_config.hpp | 8 +++--- src/mbgl/tile/geometry_tile.cpp | 4 +++ src/mbgl/tile/geometry_tile.hpp | 2 ++ src/mbgl/tile/tile.hpp | 2 ++ 11 files changed, 82 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index f052e30a6b..4606e3eece 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -385,4 +385,16 @@ void TransformState::setScalePoint(const double newScale, const ScreenCoordinate Cc = Projection::worldSize(scale) / util::M2PI; } +float TransformState::getCameraToTileDistance(const UnwrappedTileID& tileID) const { + mat4 projectionMatrix; + getProjMatrix(projectionMatrix); + mat4 tileProjectionMatrix; + matrixFor(tileProjectionMatrix, tileID); + matrix::multiply(tileProjectionMatrix, projectionMatrix, tileProjectionMatrix); + vec4 tileCenter = {{util::tileSize / 2, util::tileSize / 2, 0, 1}}; + vec4 projectedCenter; + matrix::transformMat4(projectedCenter, tileCenter, tileProjectionMatrix); + return projectedCenter[3]; +} + } // namespace mbgl diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index e6464aeacc..f35f570549 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -86,6 +86,8 @@ public: return !size.isEmpty() && (scale >= min_scale && scale <= max_scale); } + float getCameraToTileDistance(const UnwrappedTileID&) const; + private: bool rotatedNorth() const; void constrain(double& scale, double& x, double& y) const; diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index cdbd6b9713..789eed0dd8 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ Values makeValues(const bool isText, uniforms::u_texture::Value{ 0 }, uniforms::u_fadetexture::Value{ 1 }, uniforms::u_is_text::Value{ isText }, + uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, std::forward(args)... }; } diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index c11e0b5ca1..d1a6b4b994 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -42,6 +42,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); MBGL_DEFINE_UNIFORM_SCALAR(float, u_layout_size); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_collision_y_stretch); } // namespace uniforms struct SymbolLayoutAttributes : gl::Attributes< @@ -389,7 +390,8 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, - uniforms::u_is_text>, + uniforms::u_is_text, + uniforms::u_collision_y_stretch>, style::IconPaintProperties> { public: @@ -422,6 +424,7 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, + uniforms::u_collision_y_stretch, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -443,6 +446,7 @@ public: uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, + uniforms::u_collision_y_stretch, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index a8e6c128ba..57e7f6d375 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -175,11 +175,16 @@ void TilePyramid::update(const std::vector>& layer removeStaleTiles(retain); - const PlacementConfig config { parameters.transformState.getAngle(), - parameters.transformState.getPitch(), - parameters.debugOptions & MapDebugOptions::Collision }; - for (auto& pair : tiles) { + // TODO: Calculating yStretch based on tile distance means we can no longer use the same collision tile for two wrapped + // copies of the same data tile. For now the assumption that we're always at "wrap = 0" means collision detection is broken + // for wrapped tiles. + const PlacementConfig config { parameters.transformState.getAngle(), + parameters.transformState.getPitch(), + parameters.transformState.getCameraToCenterDistance(), + parameters.transformState.getCameraToTileDistance(pair.first.unwrapTo(0)), + parameters.debugOptions & MapDebugOptions::Collision }; + pair.second->setPlacementConfig(config); } } diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp index 368750c89f..520f66ead8 100644 --- a/src/mbgl/text/collision_tile.cpp +++ b/src/mbgl/text/collision_tile.cpp @@ -20,12 +20,17 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ rotationMatrix = { { angle_cos, -angle_sin, angle_sin, angle_cos } }; reverseRotationMatrix = { { angle_cos, angle_sin, -angle_sin, angle_cos } }; - // Stretch boxes in y direction to account for the map tilt. - const float _yStretch = 1.0f / std::cos(config.pitch); - - // The amount the map is squished depends on the y position. - // Sort of account for this by making all boxes a bit bigger. - yStretch = std::pow(_yStretch, 1.3f); + perspectiveRatio = 1.0f + 0.5f * ((config.cameraToTileDistance / config.cameraToCenterDistance) - 1.0f); + minScale /= perspectiveRatio; + maxScale /= perspectiveRatio; + + // We can only approximate here based on the y position of the tile + // The shaders calculate a more accurate "incidence_stretch" + // at render time to calculate an effective scale for collision + // purposes, but we still want to use the yStretch approximation + // here because we can't adjust the aspect ratio of the collision + // boxes at render time. + yStretch = util::max(1.0f, config.cameraToTileDistance / (config.cameraToCenterDistance * std::cos(config.pitch))); } @@ -157,13 +162,21 @@ void CollisionTile::insertFeature(CollisionFeature& feature, float minPlacementS Box CollisionTile::getTreeBox(const Point& anchor, const CollisionBox& box, const float scale) { assert(box.x1 <= box.x2 && box.y1 <= box.y2); return Box{ + // When the 'perspectiveRatio' is high, we're effectively underzooming + // the tile because it's in the distance. + // In order to detect collisions that only happen while underzoomed, + // we have to query a larger portion of the grid. + // This extra work is offset by having a lower 'maxScale' bound + // Note that this adjustment ONLY affects the bounding boxes + // in the grid. It doesn't affect the boxes used for the + // minPlacementScale calculations. CollisionPoint{ - anchor.x + box.x1 / scale, - anchor.y + box.y1 / scale * yStretch + anchor.x + box.x1 / scale * perspectiveRatio, + anchor.y + box.y1 / scale * yStretch * perspectiveRatio, }, CollisionPoint{ - anchor.x + box.x2 / scale, - anchor.y + box.y2 / scale * yStretch + anchor.x + box.x2 / scale * perspectiveRatio, + anchor.y + box.y2 / scale * yStretch * perspectiveRatio } }; } @@ -190,8 +203,14 @@ std::vector CollisionTile::queryRenderedSymbols(const Geometr return seenFeatures.find(feature.index) == seenFeatures.end(); }; + // "perspectiveRatio" is a tile-based approximation of how much larger symbols will + // be in the distance. It won't line up exactly with the actually rendered symbols + // Being exact would require running the collision detection logic in symbol_sdf.vertex + // in the CPU + const float perspectiveScale = scale / perspectiveRatio; + // Account for the rounding done when updating symbol shader variables. - const float roundedScale = std::pow(2.0f, std::ceil(util::log2(scale) * 10.0f) / 10.0f); + const float roundedScale = std::pow(2.0f, std::ceil(util::log2(perspectiveScale) * 10.0f) / 10.0f); // Check if feature is rendered (collision free) at current scale. auto visibleAtScale = [&] (const CollisionTreeBox& treeBox) -> bool { @@ -203,10 +222,11 @@ std::vector CollisionTile::queryRenderedSymbols(const Geometr auto intersectsAtScale = [&] (const CollisionTreeBox& treeBox) -> bool { const CollisionBox& collisionBox = std::get<1>(treeBox); const auto anchor = util::matrixMultiply(rotationMatrix, collisionBox.anchor); - const int16_t x1 = anchor.x + collisionBox.x1 / scale; - const int16_t y1 = anchor.y + collisionBox.y1 / scale * yStretch; - const int16_t x2 = anchor.x + collisionBox.x2 / scale; - const int16_t y2 = anchor.y + collisionBox.y2 / scale * yStretch; + + const int16_t x1 = anchor.x + (collisionBox.x1 / perspectiveScale); + const int16_t y1 = anchor.y + (collisionBox.y1 / perspectiveScale) * yStretch; + const int16_t x2 = anchor.x + (collisionBox.x2 / perspectiveScale); + const int16_t y2 = anchor.y + (collisionBox.y2 / perspectiveScale) * yStretch; auto bbox = GeometryCoordinates { { x1, y1 }, { x2, y1 }, { x2, y2 }, { x1, y2 } }; diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp index 59fd1a3927..dbff6a007b 100644 --- a/src/mbgl/text/collision_tile.hpp +++ b/src/mbgl/text/collision_tile.hpp @@ -49,8 +49,8 @@ public: const PlacementConfig config; - const float minScale = 0.5f; - const float maxScale = 2.0f; + float minScale = 0.5f; + float maxScale = 2.0f; float yStretch; std::array rotationMatrix; @@ -64,6 +64,8 @@ private: Tree tree; Tree ignoredTree; + + float perspectiveRatio; }; } // namespace mbgl diff --git a/src/mbgl/text/placement_config.hpp b/src/mbgl/text/placement_config.hpp index 7e61cabc24..c5c013055a 100644 --- a/src/mbgl/text/placement_config.hpp +++ b/src/mbgl/text/placement_config.hpp @@ -4,12 +4,12 @@ namespace mbgl { class PlacementConfig { public: - PlacementConfig(float angle_ = 0, float pitch_ = 0, bool debug_ = false) - : angle(angle_), pitch(pitch_), debug(debug_) { + PlacementConfig(float angle_ = 0, float pitch_ = 0, float cameraToCenterDistance_ = 0, float cameraToTileDistance_ = 0, bool debug_ = false) + : angle(angle_), pitch(pitch_), cameraToCenterDistance(cameraToCenterDistance_), cameraToTileDistance(cameraToTileDistance_), debug(debug_) { } bool operator==(const PlacementConfig& rhs) const { - return angle == rhs.angle && pitch == rhs.pitch && debug == rhs.debug; + return angle == rhs.angle && pitch == rhs.pitch && cameraToCenterDistance == rhs.cameraToCenterDistance && cameraToTileDistance == rhs.cameraToTileDistance && debug == rhs.debug; } bool operator!=(const PlacementConfig& rhs) const { @@ -19,6 +19,8 @@ public: public: float angle; float pitch; + float cameraToCenterDistance; + float cameraToTileDistance; bool debug; }; diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 4ab11d79fe..ad5c2edd4c 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -264,4 +264,8 @@ void GeometryTile::querySourceFeatures( } } +float GeometryTile::yStretch() const { + return collisionTile->yStretch; +} + } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 77202d20b6..3e2efe1093 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -86,6 +86,8 @@ public: void onError(std::exception_ptr); + float yStretch() const override; + protected: const GeometryTileData* getData() { return data.get(); diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index a925d88af3..1898f76849 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -105,6 +105,8 @@ public: // Contains the tile ID string for painting debug information. std::unique_ptr debugBucket; + + virtual float yStretch() const { return 1.0f; } protected: bool triedOptional = false; -- cgit v1.2.1 From 8f5e0b66ab13cff7d35ed46afaddbdca9ab1993f Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 17 May 2017 21:40:57 -0700 Subject: [core] Pass pitch-scaling vertex attributes and uniforms to shaders. --- src/mbgl/layout/symbol_layout.cpp | 23 ++++++++++++----------- src/mbgl/layout/symbol_layout.hpp | 3 ++- src/mbgl/programs/attributes.hpp | 2 ++ src/mbgl/programs/collision_box_program.cpp | 2 +- src/mbgl/programs/collision_box_program.hpp | 12 ++++++++++-- src/mbgl/programs/symbol_program.cpp | 6 ++++-- src/mbgl/programs/symbol_program.hpp | 21 +++++++++++++++++---- src/mbgl/programs/uniforms.hpp | 2 ++ src/mbgl/renderer/painters/painter_symbol.cpp | 3 +++ 9 files changed, 53 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index adc7eaaed8..a664957489 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -504,7 +504,7 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) for (const auto& symbol : symbolInstance.glyphQuads) { addSymbol( bucket->text, *bucket->textSizeBinder, symbol, feature, placementZoom, - keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes); + keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); } } } @@ -515,7 +515,7 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) { addSymbol( bucket->icon, *bucket->iconSizeBinder, *symbolInstance.iconQuad, feature, placementZoom, - keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes); + keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); } } @@ -541,7 +541,8 @@ void SymbolLayout::addSymbol(Buffer& buffer, const bool keepUpright, const style::SymbolPlacementType placement, const float placementAngle, - const WritingModeType writingModes) { + const WritingModeType writingModes, + const Point labelAnchor) { constexpr const uint16_t vertexLength = 4; const auto &tl = symbol.tl; @@ -590,13 +591,13 @@ void SymbolLayout::addSymbol(Buffer& buffer, uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256); // coordinates (2 triangles) - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tl, tex.x, tex.y, + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tl, labelAnchor, tex.x, tex.y, minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y, + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, labelAnchor, tex.x + tex.w, tex.y, minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h, + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, labelAnchor, tex.x, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h, + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, labelAnchor, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle)); sizeBinder.populateVertexVector(feature); @@ -646,10 +647,10 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& auto& segment = collisionBox.segments.back(); uint16_t index = segment.vertexLength; - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tl, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, tr, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, br, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, bl, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, tl, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, tr, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, br, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, bl, maxZoom, placementZoom)); collisionBox.lines.emplace_back(index + 0, index + 1); collisionBox.lines.emplace_back(index + 1, index + 2); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 4ee52e843f..5dc0f3eb76 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -65,7 +65,8 @@ private: const bool keepUpright, const style::SymbolPlacementType, const float placementAngle, - WritingModeType writingModes); + WritingModeType writingModes, + const Point labelAnchor); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 8f2751080f..f39af2deec 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -23,6 +23,8 @@ inline uint16_t packUint8Pair(T a, T b) { MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_label_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 3, a_normal); MBGL_DEFINE_ATTRIBUTE(uint16_t, 1, a_edgedistance); diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp index a3dc01ebe4..57107db75d 100644 --- a/src/mbgl/programs/collision_box_program.cpp +++ b/src/mbgl/programs/collision_box_program.cpp @@ -2,6 +2,6 @@ namespace mbgl { -static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 10, "expected CollisionBoxVertex size"); +static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 14, "expected CollisionBoxVertex size"); } // namespace mbgl diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 160fd42814..3b4260bb78 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -18,6 +18,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom); using CollisionBoxAttributes = gl::Attributes< attributes::a_pos, + attributes::a_anchor_pos, attributes::a_extrude, attributes::a_data>; @@ -29,18 +30,25 @@ class CollisionBoxProgram : public Program< uniforms::u_matrix, uniforms::u_scale, uniforms::u_zoom, - uniforms::u_maxzoom>, + uniforms::u_maxzoom, + uniforms::u_collision_y_stretch, + uniforms::u_camera_to_center_distance, + uniforms::u_pitch>, style::Properties<>> { public: using Program::Program; - static LayoutVertex vertex(Point a, Point o, float maxzoom, float placementZoom) { + static LayoutVertex vertex(Point a, Point anchor, Point o, float maxzoom, float placementZoom) { return LayoutVertex { {{ static_cast(a.x), static_cast(a.y) }}, + {{ + static_cast(anchor.x), + static_cast(anchor.y) + }}, {{ static_cast(::round(o.x)), static_cast(::round(o.y)) diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 789eed0dd8..1b5a7d9bff 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -10,7 +10,7 @@ namespace mbgl { using namespace style; -static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size"); +static_assert(sizeof(SymbolLayoutVertex) == 20, "expected SymbolLayoutVertex size"); std::unique_ptr SymbolSizeBinder::create(const float tileZoom, const style::DataDrivenPropertyValue& sizeProperty, @@ -59,6 +59,9 @@ Values makeValues(const bool isText, uniforms::u_fadetexture::Value{ 1 }, uniforms::u_is_text::Value{ isText }, uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, + uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, + uniforms::u_pitch::Value{ state.getPitch() }, + uniforms::u_max_camera_distance::Value{ 10.0f }, std::forward(args)... }; } @@ -103,7 +106,6 @@ typename SymbolSDFProgram::UniformValues SymbolSDFProgram> { static Vertex vertex(Point a, Point o, + Point labelAnchor, uint16_t tx, uint16_t ty, float minzoom, @@ -65,6 +67,10 @@ struct SymbolLayoutAttributes : gl::Attributes< static_cast(::round(o.x * 64)), // use 1/64 pixels for placement static_cast(::round(o.y * 64)) }}, + {{ + static_cast(labelAnchor.x), + static_cast(labelAnchor.y) + }}, {{ tx, ty, @@ -391,7 +397,10 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, - uniforms::u_collision_y_stretch>, + uniforms::u_collision_y_stretch, + uniforms::u_camera_to_center_distance, + uniforms::u_pitch, + uniforms::u_max_camera_distance>, style::IconPaintProperties> { public: @@ -425,8 +434,10 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_fadetexture, uniforms::u_is_text, uniforms::u_collision_y_stretch, - uniforms::u_gamma_scale, + uniforms::u_camera_to_center_distance, uniforms::u_pitch, + uniforms::u_max_camera_distance, + uniforms::u_gamma_scale, uniforms::u_bearing, uniforms::u_aspect_ratio, uniforms::u_pitch_with_map, @@ -447,8 +458,10 @@ public: uniforms::u_fadetexture, uniforms::u_is_text, uniforms::u_collision_y_stretch, - uniforms::u_gamma_scale, + uniforms::u_camera_to_center_distance, uniforms::u_pitch, + uniforms::u_max_camera_distance, + uniforms::u_gamma_scale, uniforms::u_bearing, uniforms::u_aspect_ratio, uniforms::u_pitch_with_map, diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index c8f8684ba1..8d606dcf08 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -14,6 +14,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(Color, u_color); MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur); MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_collision_y_stretch); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch); MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing); MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius); diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index d3a505aa3f..2d91ff41ad 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -152,6 +152,9 @@ void Painter::renderSymbol(PaintParameters& parameters, uniforms::u_scale::Value{ std::pow(2.0f, float(state.getZoom() - tile.tile.id.overscaledZ)) }, uniforms::u_zoom::Value{ float(state.getZoom() * 10) }, uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) }, + uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, + uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, + uniforms::u_pitch::Value{ state.getPitch() } }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.indexBuffer, -- cgit v1.2.1 From 7b29b90e7fb379ca4f592e98fd3144d424937632 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 18 May 2017 12:54:11 -0700 Subject: [core] Extend collision feature boxes to accommodate potential pitch-scaling. --- src/mbgl/text/collision_feature.cpp | 57 +++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp index 71d7cc74e0..58a7949a8e 100644 --- a/src/mbgl/text/collision_feature.cpp +++ b/src/mbgl/text/collision_feature.cpp @@ -49,7 +49,11 @@ CollisionFeature::CollisionFeature(const GeometryCoordinates& line, void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoordinate& anchorPoint, const int segment, const float labelLength, const float boxSize) { const float step = boxSize / 2; - const unsigned int nBoxes = std::floor(labelLength / step); + const int nBoxes = std::floor(labelLength / step); + // We calculate line collision boxes out to 150% of what would normally be our + // max size, to allow collision detection to work on labels that expand as + // they move into the distance + const int nPitchPaddingBoxes = std::floor(nBoxes / 4); // offset the center of the first box by half a box so that the edge of the // box is at the edge of the label. @@ -58,24 +62,40 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo GeometryCoordinate &p = anchorPoint; int index = segment + 1; float anchorDistance = firstBoxOffset; + const float labelStartDistance = -labelLength / 2; + const float paddingStartDistance = labelStartDistance - labelLength / 8; // move backwards along the line to the first segment the label appears on do { index--; - // there isn't enough room for the label after the beginning of the line - // checkMaxAngle should have already caught this - if (index < 0) return; + if (index < 0) { + if (anchorDistance > labelStartDistance) { + // there isn't enough room for the label after the beginning of the line + // checkMaxAngle should have already caught this + return; + } else { + // The line doesn't extend far enough back for all of our padding, + // but we got far enough to show the label under most conditions. + index = 0; + break; + } + } anchorDistance -= util::dist(line[index], p); p = line[index]; - } while (anchorDistance > -labelLength / 2); + } while (anchorDistance > paddingStartDistance); auto segmentLength = util::dist(line[index], line[index + 1]); - for (unsigned int i = 0; i < nBoxes; i++) { + for (int i = -nPitchPaddingBoxes; i < nBoxes + nPitchPaddingBoxes; i++) { // the distance the box will be from the anchor - const float boxDistanceToAnchor = -labelLength / 2 + i * step; + const float boxDistanceToAnchor = labelStartDistance + i * step; + if (boxDistanceToAnchor < anchorDistance) { + // The line doesn't extend far enough back for this box, skip it + // (This could allow for line collisions on distant tiles) + continue; + } // the box is not on the current segment. Move to the next segment. while (anchorDistance + segmentLength < boxDistanceToAnchor) { @@ -99,8 +119,29 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo p0.y + segmentBoxDistance / segmentLength * (p1.y - p0.y) }; + // Distance from label anchor point to inner (towards center) edge of this box + // The tricky thing here is that box positioning doesn't change with scale, + // but box size does change with scale. + // Technically, distanceToInnerEdge should be: + // Math.max(Math.abs(boxDistanceToAnchor - firstBoxOffset) - (step / scale), 0); + // But using that formula would make solving for maxScale more difficult, so we + // approximate with scale=2. + // This makes our calculation spot-on at scale=2, and on the conservative side for + // lower scales const float distanceToInnerEdge = std::max(std::fabs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0.0f); - const float maxScale = labelLength / 2 / distanceToInnerEdge; + float maxScale = labelLength / 2 / distanceToInnerEdge; + + // The box maxScale calculations are designed to be conservative on collisions in the scale range + // [1,2]. At scale=1, each box has 50% overlap, and at scale=2, the boxes are lined up edge + // to edge (beyond scale 2, gaps start to appear, which could potentially allow missed collisions). + // We add "pitch padding" boxes to the left and right to handle effective underzooming + // (scale < 1) when labels are in the distance. The overlap approximation could cause us to use + // these boxes when the scale is greater than 1, but we prevent that because we know + // they're only necessary for scales less than one. + // This preserves the pre-pitch-padding behavior for unpitched maps. + if (i < 0 || i >= nBoxes) { + maxScale = std::min(maxScale, 0.99f); + } boxes.emplace_back(boxAnchor, -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale); } -- cgit v1.2.1 From 2ee59796fb47c3152b2bdcfa5cde4be5a92316b4 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 18 May 2017 14:08:10 -0700 Subject: [core] Enable tile clipping for collision boxes. Necessary because collision boxes now change shape based on while tile they're part of. --- src/mbgl/renderer/painters/painter_symbol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 2d91ff41ad..c358d78b80 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -145,7 +145,7 @@ void Painter::renderSymbol(PaintParameters& parameters, context, gl::Lines { 1.0f }, gl::DepthMode::disabled(), - gl::StencilMode::disabled(), + stencilModeForClipping(tile.clip), colorModeForRenderPass(), CollisionBoxProgram::UniformValues { uniforms::u_matrix::Value{ tile.matrix }, -- cgit v1.2.1 From f8402e20425cee6cbad2a28809bce17ac46c1379 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Fri, 19 May 2017 13:30:17 -0700 Subject: [core] Set "max_camera_distance" to 1.5 for viewport-aligned road labels. Viewport-aligned curved labels start to look very strange in the distance. Until we have a better system for projecting them, just prevent them from showing. --- src/mbgl/programs/symbol_program.cpp | 2 +- src/mbgl/renderer/layers/render_symbol_layer.cpp | 18 ++++++++++++++++-- src/mbgl/renderer/layers/render_symbol_layer.hpp | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 1b5a7d9bff..bd43237b8f 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -61,7 +61,7 @@ Values makeValues(const bool isText, uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, uniforms::u_pitch::Value{ state.getPitch() }, - uniforms::u_max_camera_distance::Value{ 10.0f }, + uniforms::u_max_camera_distance::Value{ values.maxCameraDistance }, std::forward(args)... }; } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 6540fc9612..573e9db72e 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -88,11 +88,24 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && evaluated.get().constantOr(1), - evaluated.get().constantOr(Color::black()).a > 0 + evaluated.get().constantOr(Color::black()).a > 0, + 10.0f }; } style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { + // We hide line labels with viewport alignment as they move into the distance + // because the approximations we use for drawing their glyphs get progressively worse + // The "1.5" here means we start hiding them when the distance from the label + // to the camera is 50% greater than the distance from the center of the map + // to the camera. Depending on viewport properties, you might expect this to filter + // the top third of the screen at pitch 60, and do almost nothing at pitch 45 + // "10" is effectively infinite at any pitch we support + const bool limitMaxDistance = + layout_.get() == style::SymbolPlacementType::Line + && layout_.get() == style::AlignmentType::Map + && layout_.get() == style::AlignmentType::Viewport; + return style::SymbolPropertyValues { layout_.get(), layout_.get(), @@ -100,7 +113,8 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && evaluated.get().constantOr(1), - evaluated.get().constantOr(Color::black()).a > 0 + evaluated.get().constantOr(Color::black()).a > 0, + limitMaxDistance ? 1.5f : 10.0f }; } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 2199103de2..e788336cbd 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -47,6 +47,8 @@ public: bool hasHalo; bool hasFill; + + float maxCameraDistance; // 1.5 for road labels, or 10 (essentially infinite) for everything else }; } // namespace style -- cgit v1.2.1 From 8c23f14a9f47bc3e2d687ed25561b586643348f5 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 25 May 2017 09:15:27 -0700 Subject: [core] Use fade texture in collision debug boxes so that they agree more closely with symbol shaders. --- src/mbgl/programs/collision_box_program.hpp | 3 ++- src/mbgl/programs/symbol_program.hpp | 1 - src/mbgl/programs/uniforms.hpp | 1 + src/mbgl/renderer/painters/painter_symbol.cpp | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 3b4260bb78..ba99e0c087 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -33,7 +33,8 @@ class CollisionBoxProgram : public Program< uniforms::u_maxzoom, uniforms::u_collision_y_stretch, uniforms::u_camera_to_center_distance, - uniforms::u_pitch>, + uniforms::u_pitch, + uniforms::u_fadetexture>, style::Properties<>> { public: diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index c38ed04a1e..130e556b46 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -31,7 +31,6 @@ class TransformState; namespace uniforms { MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); -MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo); MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index 8d606dcf08..861f3271c9 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -51,6 +51,7 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower); MBGL_DEFINE_UNIFORM_SCALAR(float, u_mix); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image); +MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a); MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b); MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels); diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index c358d78b80..dc80f096f4 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -154,7 +154,8 @@ void Painter::renderSymbol(PaintParameters& parameters, uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) }, uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, - uniforms::u_pitch::Value{ state.getPitch() } + uniforms::u_pitch::Value{ state.getPitch() }, + uniforms::u_fadetexture::Value{ 1 } }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.indexBuffer, -- cgit v1.2.1 From 7c7564d72ed060bfd9ff1d5ebc6086a52f837c4b Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 16 May 2017 11:50:24 -0700 Subject: [core] Re-generate shaders. --- src/mbgl/shaders/collision_box.cpp | 36 ++++++- src/mbgl/shaders/symbol_icon.cpp | 44 ++++++--- src/mbgl/shaders/symbol_sdf.cpp | 193 +++++++++++++++++++++++-------------- 3 files changed, 184 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp index 5f733c6a1e..05f306ef65 100644 --- a/src/mbgl/shaders/collision_box.cpp +++ b/src/mbgl/shaders/collision_box.cpp @@ -8,44 +8,74 @@ namespace shaders { const char* collision_box::name = "collision_box"; const char* collision_box::vertexSource = R"MBGL_SHADER( attribute vec2 a_pos; +attribute vec2 a_anchor_pos; attribute vec2 a_extrude; attribute vec2 a_data; uniform mat4 u_matrix; uniform float u_scale; +uniform float u_pitch; +uniform float u_collision_y_stretch; +uniform float u_camera_to_center_distance; varying float v_max_zoom; varying float v_placement_zoom; +varying float v_perspective_zoom_adjust; +varying vec2 v_fade_tex; void main() { - gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0); + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = 1.0 + 0.5 * ((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); + + highp float incidence_stretch = camera_to_anchor_distance / (u_camera_to_center_distance * cos(u_pitch)); + highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch); + + gl_Position = u_matrix * vec4(a_pos + a_extrude * collision_perspective_ratio * collision_adjustment / u_scale, 0.0, 1.0); v_max_zoom = a_data.x; v_placement_zoom = a_data.y; + + v_perspective_zoom_adjust = log2(collision_perspective_ratio * collision_adjustment) * 10.0; + v_fade_tex = vec2((v_placement_zoom + v_perspective_zoom_adjust) / 255.0, 0.0); } )MBGL_SHADER"; const char* collision_box::fragmentSource = R"MBGL_SHADER( uniform float u_zoom; +// u_maxzoom is derived from the maximum scale considered by the CollisionTile +// Labels with placement zoom greater than this value will not be placed, +// regardless of perspective effects. uniform float u_maxzoom; +uniform sampler2D u_fadetexture; +// v_max_zoom is a collision-box-specific value that controls when line-following +// collision boxes are used. varying float v_max_zoom; varying float v_placement_zoom; +varying float v_perspective_zoom_adjust; +varying vec2 v_fade_tex; void main() { float alpha = 0.5; + // Green = no collisions, label is showing gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha; - if (v_placement_zoom > u_zoom) { + // Red = collision, label hidden + if (texture2D(u_fadetexture, v_fade_tex).a < 1.0) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha; } - if (u_zoom >= v_max_zoom) { + // Faded black = this collision box is not used at this zoom (for curved labels) + if (u_zoom >= v_max_zoom + v_perspective_zoom_adjust) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25; } + // Faded blue = the placement scale for this label is beyond the CollisionTile + // max scale, so it's impossible for this label to show without collision detection + // being run again (the label's glyphs haven't even been added to the symbol bucket) if (v_placement_zoom >= u_maxzoom) { gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2; } diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index bc570cf361..8960e02c28 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -7,17 +7,20 @@ namespace shaders { const char* symbol_icon::name = "symbol_icon"; const char* symbol_icon::vertexSource = R"MBGL_SHADER( - attribute vec4 a_pos_offset; +attribute vec2 a_label_pos; attribute vec4 a_data; // icon-size data (see symbol_sdf.vertex.glsl for more) attribute vec3 a_size; uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; -uniform mediump float u_size_t; // used to interpolate between zoom stops when size is a composite function -uniform mediump float u_size; // used when size is both zoom and feature constant -uniform mediump float u_layout_size; // used when size is feature constant +uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function +uniform highp float u_size; // used when size is both zoom and feature constant +uniform highp float u_layout_size; // used when size is feature constant +uniform highp float u_camera_to_center_distance; +uniform highp float u_pitch; +uniform highp float u_collision_y_stretch; #ifndef HAS_UNIFORM_u_opacity @@ -32,7 +35,7 @@ uniform lowp float u_opacity; uniform mat4 u_matrix; uniform bool u_is_text; -uniform mediump float u_zoom; +uniform highp float u_zoom; uniform bool u_rotate_with_map; uniform vec2 u_extrude_scale; @@ -53,11 +56,11 @@ void main() { vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; - mediump vec2 label_data = unpack_float(a_data[2]); - mediump float a_labelminzoom = label_data[0]; - mediump vec2 a_zoom = unpack_float(a_data[3]); - mediump float a_minzoom = a_zoom[0]; - mediump float a_maxzoom = a_zoom[1]; + highp vec2 label_data = unpack_float(a_data[2]); + highp float a_labelminzoom = label_data[0]; + highp vec2 a_zoom = unpack_float(a_data[3]); + highp float a_minzoom = a_zoom[0]; + highp float a_maxzoom = a_zoom[1]; float size; // In order to accommodate placing labels around corners in @@ -68,7 +71,7 @@ void main() { // currently rendered zoom level if text-size is zoom-dependent. // Thus, we compensate for this difference by calculating an adjustment // based on the scale of rendered text size relative to layout text size. - mediump float layoutSize; + highp float layoutSize; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { size = mix(a_size[0], a_size[1], u_size_t) / 10.0; layoutSize = a_size[2] / 10.0; @@ -85,12 +88,16 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - mediump float zoomAdjust = log2(size / layoutSize); - mediump float adjustedZoom = (u_zoom - zoomAdjust) * 10.0; + highp float zoomAdjust = log2(size / layoutSize); + highp float adjustedZoom = (u_zoom - zoomAdjust) * 10.0; // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise - mediump float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom)); + highp float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom)); + + vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); - vec2 extrude = fontScale * u_extrude_scale * (a_offset / 64.0); + vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0); if (u_rotate_with_map) { gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1); gl_Position.z += z * gl_Position.w; @@ -99,7 +106,12 @@ void main() { } v_tex = a_tex / u_texsize; - v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0); + // See comments in symbol_sdf.vertex + highp float incidence_stretch = camera_to_anchor_distance / (u_camera_to_center_distance * cos(u_pitch)); + highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch); + + highp float perspective_zoom_adjust = log2(perspective_ratio * collision_adjustment) * 10.0; + v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0); } )MBGL_SHADER"; diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index cce6b769a6..bae01a5b59 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -9,7 +9,10 @@ const char* symbol_sdf::name = "symbol_sdf"; const char* symbol_sdf::vertexSource = R"MBGL_SHADER( const float PI = 3.141592653589793; +// NOTE: the a_data attribute in this shader is manually bound (see https://github.com/mapbox/mapbox-gl-js/issues/4607). +// If removing or renaming a_data, revisit the manual binding in painter.js accordingly. attribute vec4 a_pos_offset; +attribute vec2 a_label_pos; attribute vec4 a_data; // contents of a_size vary based on the type of property value @@ -23,12 +26,12 @@ attribute vec4 a_data; attribute vec3 a_size; uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; -uniform mediump float u_size_t; // used to interpolate between zoom stops when size is a composite function -uniform mediump float u_size; // used when size is both zoom and feature constant -uniform mediump float u_layout_size; // used when size is feature constant +uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function +uniform highp float u_size; // used when size is both zoom and feature constant +uniform highp float u_layout_size; // used when size is feature constant -#ifndef HAS_UNIFORM_u_fill_color +#ifdef HAS_UNIFORM_u_fill_color uniform lowp float a_fill_color_t; attribute highp vec4 a_fill_color; varying highp vec4 fill_color; @@ -36,7 +39,8 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif -#ifndef HAS_UNIFORM_u_halo_color + +#ifdef HAS_UNIFORM_u_halo_color uniform lowp float a_halo_color_t; attribute highp vec4 a_halo_color; varying highp vec4 halo_color; @@ -44,7 +48,8 @@ varying highp vec4 halo_color; uniform highp vec4 u_halo_color; #endif -#ifndef HAS_UNIFORM_u_opacity + +#ifdef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; @@ -52,7 +57,8 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -#ifndef HAS_UNIFORM_u_halo_width + +#ifdef HAS_UNIFORM_u_halo_width uniform lowp float a_halo_width_t; attribute lowp vec2 a_halo_width; varying lowp float halo_width; @@ -60,7 +66,8 @@ varying lowp float halo_width; uniform lowp float u_halo_width; #endif -#ifndef HAS_UNIFORM_u_halo_blur + +#ifdef HAS_UNIFORM_u_halo_blur uniform lowp float a_halo_blur_t; attribute lowp vec2 a_halo_blur; varying lowp float halo_blur; @@ -68,68 +75,89 @@ varying lowp float halo_blur; uniform lowp float u_halo_blur; #endif + // matrix is for the vertex position. uniform mat4 u_matrix; uniform bool u_is_text; -uniform mediump float u_zoom; +uniform highp float u_zoom; uniform bool u_rotate_with_map; uniform bool u_pitch_with_map; -uniform mediump float u_pitch; -uniform mediump float u_bearing; -uniform mediump float u_aspect_ratio; +uniform highp float u_pitch; +uniform highp float u_bearing; +uniform highp float u_aspect_ratio; +uniform highp float u_camera_to_center_distance; +uniform highp float u_max_camera_distance; +uniform highp float u_collision_y_stretch; uniform vec2 u_extrude_scale; uniform vec2 u_texsize; -varying vec4 v_data0; -varying vec2 v_data1; +varying vec2 v_tex; +varying vec2 v_fade_tex; +varying float v_gamma_scale; +varying float v_size; + +// Used below to move the vertex out of the clip space for when the current +// zoom is out of the glyph's zoom range. +highp float clipUnusedGlyphAngles(const highp float render_size, + const highp float layout_size, + const highp float min_zoom, + const highp float max_zoom) { + highp float zoom_adjust = log2(render_size / layout_size); + highp float adjusted_zoom = (u_zoom - zoom_adjust) * 10.0; + // result: 0 if min_zoom <= adjusted_zoom < max_zoom, and 1 otherwise + return 2.0 - step(min_zoom, adjusted_zoom) - (1.0 - step(max_zoom, adjusted_zoom)); +} void main() { - + #ifndef HAS_UNIFORM_u_fill_color fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t); #else highp vec4 fill_color = u_fill_color; #endif + #ifndef HAS_UNIFORM_u_halo_color halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t); #else highp vec4 halo_color = u_halo_color; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_halo_width halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); #else lowp float halo_width = u_halo_width; #endif + #ifndef HAS_UNIFORM_u_halo_blur halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); #else lowp float halo_blur = u_halo_blur; #endif + vec2 a_pos = a_pos_offset.xy; vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; - mediump vec2 label_data = unpack_float(a_data[2]); - mediump float a_labelminzoom = label_data[0]; - mediump float a_labelangle = label_data[1]; - - mediump vec2 a_zoom = unpack_float(a_data[3]); - mediump float a_minzoom = a_zoom[0]; - mediump float a_maxzoom = a_zoom[1]; - float size; + highp vec2 label_data = unpack_float(a_data[2]); + highp float a_labelminzoom = label_data[0]; + highp float a_lineangle = (label_data[1] / 256.0 * 2.0 * PI); + highp vec2 a_zoom = unpack_float(a_data[3]); + highp float a_minzoom = a_zoom[0]; + highp float a_maxzoom = a_zoom[1]; // In order to accommodate placing labels around corners in // symbol-placement: line, each glyph in a label could have multiple @@ -139,79 +167,97 @@ void main() { // currently rendered zoom level if text-size is zoom-dependent. // Thus, we compensate for this difference by calculating an adjustment // based on the scale of rendered text size relative to layout text size. - mediump float layoutSize; + highp float layoutSize; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = mix(a_size[0], a_size[1], u_size_t) / 10.0; + v_size = mix(a_size[0], a_size[1], u_size_t) / 10.0; layoutSize = a_size[2] / 10.0; } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = a_size[0] / 10.0; - layoutSize = size; + v_size = a_size[0] / 10.0; + layoutSize = v_size; } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { - size = u_size; + v_size = u_size; layoutSize = u_layout_size; } else { - size = u_size; + v_size = u_size; layoutSize = u_size; } - float fontScale = u_is_text ? size / 24.0 : size; + float fontScale = u_is_text ? v_size / 24.0 : v_size; - mediump float zoomAdjust = log2(size / layoutSize); - mediump float adjustedZoom = (u_zoom - zoomAdjust) * 10.0; - // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise - // Used below to move the vertex out of the clip space for when the current - // zoom is out of the glyph's zoom range. - mediump float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom)); + vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); // pitch-alignment: map // rotation-alignment: map | viewport if (u_pitch_with_map) { - lowp float angle = u_rotate_with_map ? (a_labelangle / 256.0 * 2.0 * PI) : u_bearing; - lowp float asin = sin(angle); - lowp float acos = cos(angle); + highp float angle = u_rotate_with_map ? a_lineangle : u_bearing; + highp float asin = sin(angle); + highp float acos = cos(angle); mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos); vec2 offset = RotationMatrix * a_offset; - vec2 extrude = fontScale * u_extrude_scale * (offset / 64.0); + vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0); + gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1); - gl_Position.z += z * gl_Position.w; + gl_Position.z += clipUnusedGlyphAngles(v_size*perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w; // pitch-alignment: viewport // rotation-alignment: map } else if (u_rotate_with_map) { // foreshortening factor to apply on pitched maps // as a label goes from horizontal <=> vertical in angle // it goes from 0% foreshortening to up to around 70% foreshortening - lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75)); - - lowp float lineangle = a_labelangle / 256.0 * 2.0 * PI; + highp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75)); // use the lineangle to position points a,b along the line // project the points and calculate the label angle in projected space // this calculation allows labels to be rendered unskewed on pitched maps vec4 a = u_matrix * vec4(a_pos, 0, 1); - vec4 b = u_matrix * vec4(a_pos + vec2(cos(lineangle),sin(lineangle)), 0, 1); - lowp float angle = atan((b[1]/b[3] - a[1]/a[3])/u_aspect_ratio, b[0]/b[3] - a[0]/a[3]); - lowp float asin = sin(angle); - lowp float acos = cos(angle); + vec4 b = u_matrix * vec4(a_pos + vec2(cos(a_lineangle), sin(a_lineangle)), 0, 1); + highp float angle = atan((b[1] / b[3] - a[1] / a[3]) / u_aspect_ratio, b[0] / b[3] - a[0] / a[3]); + highp float asin = sin(angle); + highp float acos = cos(angle); mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos); + highp float foreshortening = (1.0 - pitchfactor) + (pitchfactor * cos(angle * 2.0)); + + vec2 offset = RotationMatrix * (vec2(foreshortening, 1.0) * a_offset); + vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0); - vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset); - vec2 extrude = fontScale * u_extrude_scale * (offset / 64.0); gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0); - gl_Position.z += z * gl_Position.w; + gl_Position.z += clipUnusedGlyphAngles(v_size * perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w; // pitch-alignment: viewport // rotation-alignment: viewport } else { - vec2 extrude = fontScale * u_extrude_scale * (a_offset / 64.0); + vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0); gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0); } - float gamma_scale = gl_Position.w; - - vec2 tex = a_tex / u_texsize; - vec2 fade_tex = vec2(a_labelminzoom / 255.0, 0.0); - - v_data0 = vec4(tex.x, tex.y, fade_tex.x, fade_tex.y); - v_data1 = vec2(gamma_scale, size); + gl_Position.z += + step(u_max_camera_distance * u_camera_to_center_distance, camera_to_anchor_distance) * gl_Position.w; + + v_gamma_scale = gl_Position.w / perspective_ratio; + + v_tex = a_tex / u_texsize; + // incidence_stretch is the ratio of how much y space a label takes up on a tile while drawn perpendicular to the viewport vs + // how much space it would take up if it were drawn flat on the tile + // Using law of sines, camera_to_anchor/sin(ground_angle) = camera_to_center/sin(incidence_angle) + // sin(incidence_angle) = 1/incidence_stretch + // Incidence angle 90 -> head on, sin(incidence_angle) = 1, no incidence stretch + // Incidence angle 1 -> very oblique, sin(incidence_angle) =~ 0, lots of incidence stretch + // ground_angle = u_pitch + PI/2 -> sin(ground_angle) = cos(u_pitch) + // This 2D calculation is only exactly correct when gl_Position.x is in the center of the viewport, + // but it's a close enough approximation for our purposes + highp float incidence_stretch = camera_to_anchor_distance / (u_camera_to_center_distance * cos(u_pitch)); + // incidence_stretch only applies to the y-axis, but without re-calculating the collision tile, we can't + // adjust the size of only one axis. So, we do a crude approximation at placement time to get the aspect ratio + // about right, and then do the rest of the adjustment here: there will be some extra padding on the x-axis, + // but hopefully not too much. + // Never make the adjustment less than 1.0: instead of allowing collisions on the x-axis, be conservative on + // the y-axis. + highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch); + + // Floor to 1/10th zoom to dodge precision issues that can cause partially hidden labels + highp float perspective_zoom_adjust = floor(log2(perspective_ratio * collision_adjustment) * 10.0); + v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0); } )MBGL_SHADER"; @@ -227,66 +273,73 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif + #ifndef HAS_UNIFORM_u_halo_color varying highp vec4 halo_color; #else uniform highp vec4 u_halo_color; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_halo_width varying lowp float halo_width; #else uniform lowp float u_halo_width; #endif + #ifndef HAS_UNIFORM_u_halo_blur varying lowp float halo_blur; #else uniform lowp float u_halo_blur; #endif + uniform sampler2D u_texture; uniform sampler2D u_fadetexture; uniform highp float u_gamma_scale; uniform bool u_is_text; -varying vec4 v_data0; -varying vec2 v_data1; +varying vec2 v_tex; +varying vec2 v_fade_tex; +varying float v_gamma_scale; +varying float v_size; void main() { - + #ifdef HAS_UNIFORM_u_fill_color highp vec4 fill_color = u_fill_color; #endif + #ifdef HAS_UNIFORM_u_halo_color highp vec4 halo_color = u_halo_color; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + #ifdef HAS_UNIFORM_u_halo_width lowp float halo_width = u_halo_width; #endif + #ifdef HAS_UNIFORM_u_halo_blur lowp float halo_blur = u_halo_blur; #endif - vec2 tex = v_data0.xy; - vec2 fade_tex = v_data0.zw; - float gamma_scale = v_data1.x; - float size = v_data1.y; - float fontScale = u_is_text ? size / 24.0 : size; + float fontScale = u_is_text ? v_size / 24.0 : v_size; lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); @@ -297,9 +350,9 @@ void main() { buff = (6.0 - halo_width / fontScale) / SDF_PX; } - lowp float dist = texture2D(u_texture, tex).a; - lowp float fade_alpha = texture2D(u_fadetexture, fade_tex).a; - highp float gamma_scaled = gamma * gamma_scale; + lowp float dist = texture2D(u_texture, v_tex).a; + lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a; + highp float gamma_scaled = gamma * v_gamma_scale; highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha; gl_FragColor = color * (alpha * opacity); -- cgit v1.2.1 From 72f6b73590722d5451623cd21c4b1abde74e8f69 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 25 May 2017 14:12:20 -0700 Subject: [core] Limit symbol re-placement on changed tile distance to pitch > 25. --- src/mbgl/text/placement_config.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/text/placement_config.hpp b/src/mbgl/text/placement_config.hpp index c5c013055a..1e1279341d 100644 --- a/src/mbgl/text/placement_config.hpp +++ b/src/mbgl/text/placement_config.hpp @@ -1,5 +1,7 @@ #pragma once +#include + namespace mbgl { class PlacementConfig { @@ -9,7 +11,11 @@ public: } bool operator==(const PlacementConfig& rhs) const { - return angle == rhs.angle && pitch == rhs.pitch && cameraToCenterDistance == rhs.cameraToCenterDistance && cameraToTileDistance == rhs.cameraToTileDistance && debug == rhs.debug; + return angle == rhs.angle && + pitch == rhs.pitch && + cameraToCenterDistance == rhs.cameraToCenterDistance && + (pitch * util::RAD2DEG < 25 || cameraToTileDistance == rhs.cameraToTileDistance) && + debug == rhs.debug; } bool operator!=(const PlacementConfig& rhs) const { -- cgit v1.2.1 From a432a289a35815beeadc8719a963f50f8dc07bbb Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 29 May 2017 12:47:32 -0700 Subject: [core] Change OverscaledTileID to also include a "wrap" value. This prevents TilePyramid from sharing wrapped copies of tiles. This is necessary because two wrapped tiles no longer share the same CollisionTile. --- src/mbgl/algorithm/update_renderables.hpp | 9 ++++----- src/mbgl/renderer/tile_pyramid.cpp | 7 ++----- src/mbgl/tile/tile_id.hpp | 33 ++++++++++++++++--------------- 3 files changed, 23 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/mbgl/algorithm/update_renderables.hpp b/src/mbgl/algorithm/update_renderables.hpp index a9c348b538..0c2266ff47 100644 --- a/src/mbgl/algorithm/update_renderables.hpp +++ b/src/mbgl/algorithm/update_renderables.hpp @@ -31,7 +31,7 @@ void updateRenderables(GetTileFn getTile, assert(idealRenderTileID.canonical.z <= zoomRange.max); assert(dataTileZoom >= idealRenderTileID.canonical.z); - const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.canonical); + const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.wrap, idealRenderTileID.canonical); auto tile = getTile(idealDataTileID); if (!tile) { tile = createTile(idealDataTileID); @@ -64,11 +64,11 @@ void updateRenderables(GetTileFn getTile, } else { // Check all four actual child tiles. for (const auto& childTileID : idealDataTileID.canonical.children()) { - const OverscaledTileID childDataTileID(overscaledZ, childTileID); + const OverscaledTileID childDataTileID(overscaledZ, idealRenderTileID.wrap, childTileID); tile = getTile(childDataTileID); if (tile && tile->isRenderable()) { retainTile(*tile, Resource::Necessity::Optional); - renderTile(childDataTileID.unwrapTo(idealRenderTileID.wrap), *tile); + renderTile(childDataTileID.toUnwrapped(), *tile); } else { // At least one child tile doesn't exist, so we are going to look for // parents as well. @@ -81,8 +81,7 @@ void updateRenderables(GetTileFn getTile, // We couldn't find child tiles that entirely cover the ideal tile. for (overscaledZ = dataTileZoom - 1; overscaledZ >= zoomRange.min; --overscaledZ) { const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ); - const auto parentRenderTileID = - parentDataTileID.unwrapTo(idealRenderTileID.wrap); + const auto parentRenderTileID = parentDataTileID.toUnwrapped(); if (checked.find(parentRenderTileID) != checked.end()) { // Break parent tile ascent, this route has been checked by another child diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 57e7f6d375..5b1e621743 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -176,15 +176,12 @@ void TilePyramid::update(const std::vector>& layer removeStaleTiles(retain); for (auto& pair : tiles) { - // TODO: Calculating yStretch based on tile distance means we can no longer use the same collision tile for two wrapped - // copies of the same data tile. For now the assumption that we're always at "wrap = 0" means collision detection is broken - // for wrapped tiles. const PlacementConfig config { parameters.transformState.getAngle(), parameters.transformState.getPitch(), parameters.transformState.getCameraToCenterDistance(), - parameters.transformState.getCameraToTileDistance(pair.first.unwrapTo(0)), + parameters.transformState.getCameraToTileDistance(pair.first.toUnwrapped()), parameters.debugOptions & MapDebugOptions::Collision }; - + pair.second->setPlacementConfig(config); } } diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp index 1ce3eea98e..811158e9b9 100644 --- a/src/mbgl/tile/tile_id.hpp +++ b/src/mbgl/tile/tile_id.hpp @@ -46,8 +46,8 @@ std::string toString(const CanonicalTileID&); // z/x/y describe the class OverscaledTileID { public: - OverscaledTileID(uint8_t overscaledZ, CanonicalTileID); - OverscaledTileID(uint8_t overscaledZ, uint8_t z, uint32_t x, uint32_t y); + OverscaledTileID(uint8_t overscaledZ, int16_t wrap, CanonicalTileID); + OverscaledTileID(uint8_t overscaledZ, int16_t wrap, uint8_t z, uint32_t x, uint32_t y); OverscaledTileID(uint8_t z, uint32_t x, uint32_t y); explicit OverscaledTileID(const CanonicalTileID&); explicit OverscaledTileID(CanonicalTileID&&); @@ -57,9 +57,10 @@ public: bool isChildOf(const OverscaledTileID&) const; uint32_t overscaleFactor() const; OverscaledTileID scaledTo(uint8_t z) const; - UnwrappedTileID unwrapTo(int16_t wrap) const; + UnwrappedTileID toUnwrapped() const; const uint8_t overscaledZ; + const int16_t wrap; const CanonicalTileID canonical; }; @@ -137,40 +138,40 @@ inline std::array CanonicalTileID::children() const { } }; } -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, CanonicalTileID canonical_) - : overscaledZ(overscaledZ_), canonical(std::move(canonical_)) { +inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, CanonicalTileID canonical_) + : overscaledZ(overscaledZ_), wrap(wrap_), canonical(std::move(canonical_)) { assert(overscaledZ >= canonical.z); } -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(overscaledZ_), canonical(z, x, y) { +inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, uint8_t z, uint32_t x, uint32_t y) + : overscaledZ(overscaledZ_), wrap(wrap_), canonical(z, x, y) { assert(overscaledZ >= canonical.z); } inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(z), canonical(z, x, y) { + : overscaledZ(z), wrap(0), canonical(z, x, y) { } inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) - : overscaledZ(canonical_.z), canonical(canonical_) { + : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) { assert(overscaledZ >= canonical.z); } inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) - : overscaledZ(canonical_.z), canonical(std::forward(canonical_)) { + : overscaledZ(canonical_.z), wrap(0), canonical(std::forward(canonical_)) { assert(overscaledZ >= canonical.z); } inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { - return overscaledZ == rhs.overscaledZ && canonical == rhs.canonical; + return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical; } inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { - return overscaledZ != rhs.overscaledZ || canonical != rhs.canonical; + return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical; } inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { - return std::tie(overscaledZ, canonical) < std::tie(rhs.overscaledZ, rhs.canonical); + return std::tie(overscaledZ, wrap, canonical) < std::tie(rhs.overscaledZ, rhs.wrap, rhs.canonical); } inline uint32_t OverscaledTileID::overscaleFactor() const { @@ -183,10 +184,10 @@ inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { } inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { - return { z, z >= canonical.z ? canonical : canonical.scaledTo(z) }; + return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(z) }; } -inline UnwrappedTileID OverscaledTileID::unwrapTo(int16_t wrap) const { +inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { return { wrap, canonical }; } @@ -232,7 +233,7 @@ inline std::array UnwrappedTileID::children() const { inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { assert(overscaledZ >= canonical.z); - return { overscaledZ, canonical }; + return { overscaledZ, wrap, canonical }; } inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { -- cgit v1.2.1 From a0e37fe35b1af9f607600d2e792e2ff56796af6e Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 6 Jun 2017 09:01:17 -0700 Subject: [core] Hold on to tile yStretch value for rendering old symbolBuckets while waiting for new ones. --- src/mbgl/tile/geometry_tile.cpp | 11 +++++++++-- src/mbgl/tile/geometry_tile.hpp | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index ad5c2edd4c..1ee303b50f 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -42,7 +42,8 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_, parameters.pixelRatio), glyphManager(parameters.glyphManager), imageManager(parameters.imageManager), - placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { + placementThrottler(Milliseconds(300), [this] { invokePlacement(); }), + lastYStretch(1.0f) { } GeometryTile::~GeometryTile() { @@ -143,6 +144,9 @@ void GeometryTile::onPlacement(PlacementResult result) { if (result.iconAtlasImage) { iconAtlasImage = std::move(*result.iconAtlasImage); } + if (collisionTile.get()) { + lastYStretch = collisionTile->yStretch; + } observer->onTileChanged(*this); } @@ -265,7 +269,10 @@ void GeometryTile::querySourceFeatures( } float GeometryTile::yStretch() const { - return collisionTile->yStretch; + // collisionTile gets reset in onLayout but we don't clear the symbolBuckets + // until a new placement result comes along, so keep the yStretch value in + // case we need to render them. + return lastYStretch; } } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 3e2efe1093..943296e01b 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -122,6 +122,7 @@ private: std::unique_ptr collisionTile; util::Throttler placementThrottler; + float lastYStretch; public: optional glyphAtlasTexture; -- cgit v1.2.1 From 77734cfe1b9e77a0058fa3e0db79e3c20a264165 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Thu, 29 Jun 2017 12:04:13 -0400 Subject: [core] fix transformMat4 It used to overwrite values in the middle of the calculation which would cause problems when `out` and `a` were a reference to the same vector. --- src/mbgl/util/mat4.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/mat4.cpp b/src/mbgl/util/mat4.cpp index d3d3617b7b..0ad0d371e5 100644 --- a/src/mbgl/util/mat4.cpp +++ b/src/mbgl/util/mat4.cpp @@ -336,10 +336,11 @@ void multiply(mat4& out, const mat4& a, const mat4& b) { } void transformMat4(vec4& out, const vec4& a, const mat4& m) { - out[0] = m[0] * a[0] + m[4] * a[1] + m[8] * a[2] + m[12] * a[3]; - out[1] = m[1] * a[0] + m[5] * a[1] + m[9] * a[2] + m[13] * a[3]; - out[2] = m[2] * a[0] + m[6] * a[1] + m[10] * a[2] + m[14] * a[3]; - out[3] = m[3] * a[0] + m[7] * a[1] + m[11] * a[2] + m[15] * a[3]; + double x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; } } // namespace matrix -- cgit v1.2.1 From e514138b691615be24f484986c40f486223df82a Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 16 Jun 2017 10:42:33 -0400 Subject: [core] improve legibility of labels that follow lines port https://github.com/mapbox/mapbox-gl-js/pull/4781 This improves legibility of labels that follow lines in pitched views. The previous approach used the limited information in the shader to calculate put the glyph in approximatelyright place. The new approach does this more accurately by doing it on the cpu where we have access to the entire line geometry. --- src/mbgl/gl/context.cpp | 9 +- src/mbgl/gl/context.hpp | 13 +- src/mbgl/gl/types.hpp | 6 + src/mbgl/layout/symbol_instance.cpp | 23 +- src/mbgl/layout/symbol_instance.hpp | 9 +- src/mbgl/layout/symbol_layout.cpp | 98 ++++---- src/mbgl/layout/symbol_layout.hpp | 9 +- src/mbgl/layout/symbol_projection.cpp | 266 ++++++++++++++++++++ src/mbgl/layout/symbol_projection.hpp | 25 ++ src/mbgl/programs/attributes.hpp | 1 + src/mbgl/programs/symbol_program.cpp | 39 ++- src/mbgl/programs/symbol_program.hpp | 203 ++++++--------- src/mbgl/programs/uniforms.hpp | 1 - src/mbgl/renderer/buckets/symbol_bucket.cpp | 4 +- src/mbgl/renderer/buckets/symbol_bucket.hpp | 24 ++ src/mbgl/renderer/frame_history.cpp | 4 + src/mbgl/renderer/frame_history.hpp | 1 + src/mbgl/renderer/layers/render_symbol_layer.cpp | 2 + src/mbgl/renderer/layers/render_symbol_layer.hpp | 1 + src/mbgl/renderer/painters/painter_symbol.cpp | 29 ++- src/mbgl/renderer/render_tile.cpp | 27 +- src/mbgl/renderer/render_tile.hpp | 4 +- src/mbgl/shaders/collision_box.cpp | 2 +- src/mbgl/shaders/symbol_icon.cpp | 70 +++--- src/mbgl/shaders/symbol_sdf.cpp | 208 +++++---------- src/mbgl/text/quads.cpp | 307 ++++------------------- src/mbgl/text/quads.hpp | 31 +-- src/mbgl/text/shaping.cpp | 14 +- 28 files changed, 714 insertions(+), 716 deletions(-) create mode 100644 src/mbgl/layout/symbol_projection.cpp create mode 100644 src/mbgl/layout/symbol_projection.hpp (limited to 'src') diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 1b4d6fbcb7..3508b92a79 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -164,15 +164,20 @@ void Context::verifyProgramLinkage(ProgramID program_) { throw std::runtime_error("program failed to link"); } -UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) { +UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsageType usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; vertexBuffer = result; - MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); + MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, static_cast(usage))); return result; } +void Context::updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) { + vertexBuffer = buffer; + MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data)); +} + UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 4f5b4c797c..f1f0ac7f8a 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -65,13 +65,19 @@ public: optional> getBinaryProgram(ProgramID) const; template - VertexBuffer createVertexBuffer(VertexVector&& v) { + VertexBuffer createVertexBuffer(VertexVector&& v, const BufferUsageType usage=BufferUsageType::StaticDraw) { return VertexBuffer { v.vertexSize(), - createVertexBuffer(v.data(), v.byteSize()) + createVertexBuffer(v.data(), v.byteSize(), usage) }; } + template + void updateVertexBuffer(VertexBuffer& buffer, VertexVector&& v) { + assert(v.vertexSize() == buffer.vertexCount); + updateVertexBuffer(buffer.buffer, v.data(), v.byteSize()); + } + template IndexBuffer createIndexBuffer(IndexVector&& v) { return IndexBuffer { @@ -239,7 +245,8 @@ private: State pointSize; #endif // MBGL_USE_GLES2 - UniqueBuffer createVertexBuffer(const void* data, std::size_t size); + UniqueBuffer createVertexBuffer(const void* data, std::size_t size, const BufferUsageType usage); + void updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit); void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit); diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 74ce67fba6..8997fcbf31 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -96,5 +96,11 @@ enum class UniformDataType : uint32_t { SamplerCube = 0x8B60, }; +enum class BufferUsageType : uint32_t { + StreamDraw = 0x88E0, + StaticDraw = 0x88E4, + DynamicDraw = 0x88E8, +}; + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index ffb70c7ca2..02fb800df6 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -5,8 +5,8 @@ namespace mbgl { using namespace style; -SymbolInstance::SymbolInstance(Anchor& anchor, - const GeometryCoordinates& line, +SymbolInstance::SymbolInstance(Anchor& anchor_, + GeometryCoordinates line_, const std::pair& shapedTextOrientations, optional shapedIcon, const SymbolLayoutProperties::Evaluated& layout, @@ -16,33 +16,38 @@ SymbolInstance::SymbolInstance(Anchor& anchor, const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement, + const std::array textOffset_, const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement, + const std::array iconOffset_, const GlyphPositionMap& positions, const IndexedSubfeature& indexedFeature, const std::size_t featureIndex_) : - point(anchor.point), + anchor(anchor_), + line(line_), index(index_), hasText(shapedTextOrientations.first || shapedTextOrientations.second), hasIcon(shapedIcon), // Create the collision features that will be used to check whether this symbol instance can be placed - textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature), - iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature), - featureIndex(featureIndex_) { + textCollisionFeature(line_, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature), + iconCollisionFeature(line_, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature), + featureIndex(featureIndex_), + textOffset(textOffset_), + iconOffset(iconOffset_) { // Create the quads used for rendering the icon and glyphs. if (addToBuffers) { if (shapedIcon) { - iconQuad = getIconQuad(anchor, *shapedIcon, line, layout, layoutTextSize, iconPlacement, shapedTextOrientations.first); + iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.first); } if (shapedTextOrientations.first) { - auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, positions); + auto quads = getGlyphQuads(shapedTextOrientations.first, layout, textPlacement, positions); glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end()); } if (shapedTextOrientations.second) { - auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, positions); + auto quads = getGlyphQuads(shapedTextOrientations.second, layout, textPlacement, positions); glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end()); } } diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index f199d929df..f1df416cd1 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -13,7 +13,7 @@ class IndexedSubfeature; class SymbolInstance { public: SymbolInstance(Anchor& anchor, - const GeometryCoordinates& line, + GeometryCoordinates line, const std::pair& shapedTextOrientations, optional shapedIcon, const style::SymbolLayoutProperties::Evaluated&, @@ -23,14 +23,17 @@ public: const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement, + const std::array textOffset, const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement, + const std::array iconOffset, const GlyphPositionMap&, const IndexedSubfeature&, const std::size_t featureIndex); - Point point; + Anchor anchor; + GeometryCoordinates line; uint32_t index; bool hasText; bool hasIcon; @@ -40,6 +43,8 @@ public: CollisionFeature iconCollisionFeature; WritingModeType writingModes; std::size_t featureIndex; + std::array textOffset; + std::array iconOffset; }; } // namespace mbgl diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index a664957489..e308da618f 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -305,6 +305,8 @@ void SymbolLayout::addFeature(const std::size_t index, const float layoutTextSize = layout.evaluate(zoom + 1, feature); const float layoutIconSize = layout.evaluate(zoom + 1, feature); + const std::array textOffset = layout.evaluate(zoom, feature); + const std::array iconOffset = layout.evaluate(zoom, feature); // To reduce the number of labels that jump around when zooming we need // to use a text-size value that is the same for all zoom levels. @@ -355,8 +357,8 @@ void SymbolLayout::addFeature(const std::size_t index, symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout.evaluate(zoom, feature), layoutTextSize, addToBuffers, symbolInstances.size(), - textBoxScale, textPadding, textPlacement, - iconBoxScale, iconPadding, iconPlacement, + textBoxScale, textPadding, textPlacement, textOffset, + iconBoxScale, iconPadding, iconPlacement, iconOffset, glyphPositionMap, indexedFeature, index); }; @@ -455,8 +457,8 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) const float cos = std::cos(collisionTile.config.angle); std::sort(symbolInstances.begin(), symbolInstances.end(), [sin, cos](SymbolInstance &a, SymbolInstance &b) { - const int32_t aRotated = sin * a.point.x + cos * a.point.y; - const int32_t bRotated = sin * b.point.x + cos * b.point.y; + const int32_t aRotated = sin * a.anchor.point.x + cos * a.anchor.point.y; + const int32_t bRotated = sin * b.anchor.point.x + cos * b.anchor.point.y; return aRotated != bRotated ? aRotated < bRotated : a.index > b.index; @@ -501,10 +503,21 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) const float placementZoom = util::max(util::log2(glyphScale) + zoom, 0.0f); collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get()); if (glyphScale < collisionTile.maxScale) { + + const float labelAngle = std::fmod((symbolInstance.anchor.angle + collisionTile.config.angle) + 2 * M_PI, 2 * M_PI); + const bool inVerticalRange = ( + (labelAngle > M_PI * 1.0 / 4.0 && labelAngle <= M_PI * 3.0 / 4) || + (labelAngle > M_PI * 5.0 / 4.0 && labelAngle <= M_PI * 7.0 / 4)); + const bool useVerticalMode = symbolInstance.writingModes & WritingModeType::Vertical && inVerticalRange; + + const Range sizeData = bucket->textSizeBinder->getVertexSizeData(feature); + bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, + symbolInstance.textOffset, placementZoom, useVerticalMode, symbolInstance.line); + for (const auto& symbol : symbolInstance.glyphQuads) { addSymbol( - bucket->text, *bucket->textSizeBinder, symbol, feature, placementZoom, - keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); + bucket->text, sizeData, symbol, placementZoom, + keepUpright, textPlacement, symbolInstance.anchor, bucket->text.placedSymbols.back()); } } } @@ -513,9 +526,12 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) const float placementZoom = util::max(util::log2(iconScale) + zoom, 0.0f); collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get()); if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) { + const Range sizeData = bucket->iconSizeBinder->getVertexSizeData(feature); + bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, + symbolInstance.iconOffset, placementZoom, false, symbolInstance.line); addSymbol( - bucket->icon, *bucket->iconSizeBinder, *symbolInstance.iconQuad, feature, placementZoom, - keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes, symbolInstance.point); + bucket->icon, sizeData, *symbolInstance.iconQuad, placementZoom, + keepUpright, iconPlacement, symbolInstance.anchor, bucket->icon.placedSymbols.back()); } } @@ -534,15 +550,13 @@ std::unique_ptr SymbolLayout::place(CollisionTile& collisionTile) template void SymbolLayout::addSymbol(Buffer& buffer, - SymbolSizeBinder& sizeBinder, + const Range sizeData, const SymbolQuad& symbol, - const SymbolFeature& feature, const float placementZoom, const bool keepUpright, const style::SymbolPlacementType placement, - const float placementAngle, - const WritingModeType writingModes, - const Point labelAnchor) { + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol) { constexpr const uint16_t vertexLength = 4; const auto &tl = symbol.tl; @@ -551,30 +565,9 @@ void SymbolLayout::addSymbol(Buffer& buffer, const auto &br = symbol.br; const auto &tex = symbol.tex; - float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom); - float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F); - const auto &anchorPoint = symbol.anchorPoint; - - // drop incorrectly oriented glyphs - const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2); - if (writingModes & WritingModeType::Vertical) { - if (placement == style::SymbolPlacementType::Line && symbol.writingMode == WritingModeType::Vertical) { - if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 5 / 4) || a > (M_PI * 7 / 4))) - return; - } else if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 3 / 4) || a > (M_PI * 5 / 4))) - return; - } else if (keepUpright && placement == style::SymbolPlacementType::Line && - (a <= M_PI / 2 || a > M_PI * 3 / 2)) { - return; - } - - if (maxZoom <= minZoom) - return; - - // Lower min zoom so that while fading out the label - // it can be shown outside of collision-free zoom levels - if (minZoom == placementZoom) { - minZoom = 0; + if (placement == style::SymbolPlacementType::Line && keepUpright) { + // drop incorrectly oriented glyphs + if ((symbol.writingMode == WritingModeType::Vertical) != placedSymbol.useVerticalMode) return; } if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits::max()) { @@ -587,20 +580,17 @@ void SymbolLayout::addSymbol(Buffer& buffer, assert(segment.vertexLength <= std::numeric_limits::max()); uint16_t index = segment.vertexLength; - // Encode angle of glyph - uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256); - // coordinates (2 triangles) - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tl, labelAnchor, tex.x, tex.y, - minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, labelAnchor, tex.x + tex.w, tex.y, - minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, labelAnchor, tex.x, tex.y + tex.h, - minZoom, maxZoom, placementZoom, glyphAngle)); - buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, labelAnchor, tex.x + tex.w, tex.y + tex.h, - minZoom, maxZoom, placementZoom, glyphAngle)); + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(labelAnchor.point, tl, symbol.glyphOffset.y, tex.x, tex.y, sizeData)); + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(labelAnchor.point, tr, symbol.glyphOffset.y, tex.x + tex.w, tex.y, sizeData)); + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(labelAnchor.point, bl, symbol.glyphOffset.y, tex.x, tex.y + tex.h, sizeData)); + buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(labelAnchor.point, br, symbol.glyphOffset.y, tex.x + tex.w, tex.y + tex.h, sizeData)); - sizeBinder.populateVertexVector(feature); + auto dynamicVertex = SymbolDynamicLayoutAttributes::vertex(labelAnchor.point, 0, placementZoom); + buffer.dynamicVertices.emplace_back(dynamicVertex); + buffer.dynamicVertices.emplace_back(dynamicVertex); + buffer.dynamicVertices.emplace_back(dynamicVertex); + buffer.dynamicVertices.emplace_back(dynamicVertex); // add the two triangles, referencing the four coordinates we just inserted. buffer.triangles.emplace_back(index + 0, index + 1, index + 2); @@ -608,6 +598,8 @@ void SymbolLayout::addSymbol(Buffer& buffer, segment.vertexLength += vertexLength; segment.indexLength += 6; + + placedSymbol.glyphOffsets.push_back(symbol.glyphOffset.x); } void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& bucket) { @@ -647,10 +639,10 @@ void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& auto& segment = collisionBox.segments.back(); uint16_t index = segment.vertexLength; - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, tl, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, tr, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, br, maxZoom, placementZoom)); - collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.point, bl, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.anchor.point, tl, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.anchor.point, tr, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.anchor.point, br, maxZoom, placementZoom)); + collisionBox.vertices.emplace_back(CollisionBoxProgram::vertex(anchor, symbolInstance.anchor.point, bl, maxZoom, placementZoom)); collisionBox.lines.emplace_back(index + 0, index + 1); collisionBox.lines.emplace_back(index + 1, index + 2); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 5dc0f3eb76..90f5b3c91d 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -20,6 +20,7 @@ class CollisionTile; class SymbolBucket; class Anchor; class RenderLayer; +class PlacedSymbol; namespace style { class Filter; @@ -58,15 +59,13 @@ private: // Adds placed items to the buffer. template void addSymbol(Buffer&, - SymbolSizeBinder& sizeBinder, + const Range sizeData, const SymbolQuad&, - const SymbolFeature& feature, float scale, const bool keepUpright, const style::SymbolPlacementType, - const float placementAngle, - WritingModeType writingModes, - const Point labelAnchor); + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp new file mode 100644 index 0000000000..99555f7997 --- /dev/null +++ b/src/mbgl/layout/symbol_projection.cpp @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + + /* + * # Overview of coordinate spaces + * + * ## Tile coordinate spaces + * Each label has an anchor. Some labels have corresponding line geometries. + * The points for both anchors and lines are stored in tile units. Each tile has it's own + * coordinate space going from (0, 0) at the top left to (EXTENT, EXTENT) at the bottom right. + * + * ## GL coordinate space + * At the end of everything, the vertex shader needs to produce a position in GL coordinate space, + * which is (-1, 1) at the top left and (1, -1) in the bottom right. + * + * ## Map pixel coordinate spaces + * Each tile has a pixel coordinate space. It's just the tile units scaled so that one unit is + * whatever counts as 1 pixel at the current zoom. + * This space is used for pitch-alignment=map, rotation-alignment=map + * + * ## Rotated map pixel coordinate spaces + * Like the above, but rotated so axis of the space are aligned with the viewport instead of the tile. + * This space is used for pitch-alignment=map, rotation-alignment=viewport + * + * ## Viewport pixel coordinate space + * (0, 0) is at the top left of the canvas and (pixelWidth, pixelHeight) is at the bottom right corner + * of the canvas. This space is used for pitch-alignment=viewport + * + * + * # Vertex projection + * It goes roughly like this: + * 1. project the anchor and line from tile units into the correct label coordinate space + * - map pixel space pitch-alignment=map rotation-alignment=map + * - rotated map pixel space pitch-alignment=map rotation-alignment=viewport + * - viewport pixel space pitch-alignment=viewport rotation-alignment=* + * 2. if the label follows a line, find the point along the line that is the correct distance from the anchor. + * 3. add the glyph's corner offset to the point from step 3 + * 4. convert from the label coordinate space to gl coordinates + * + * For horizontal labels we want to do step 1 in the shader for performance reasons (no cpu work). + * This is what `u_label_plane_matrix` is used for. + * For labels aligned with lines we have to steps 1 and 2 on the cpu since we need access to the line geometry. + * This is what `updateLineLabels(...)` does. + * Since the conversion is handled on the cpu we just set `u_label_plane_matrix` to an identity matrix. + * + * Steps 3 and 4 are done in the shaders for all labels. + */ + + /* + * Returns a matrix for converting from tile units to the correct label coordinate space. + */ + mat4 getLabelPlaneMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits) { + mat4 m; + matrix::identity(m); + if (pitchWithMap) { + matrix::scale(m, m, 1 / pixelsToTileUnits, 1 / pixelsToTileUnits, 1); + if (!rotateWithMap) { + matrix::rotate_z(m, m, state.getAngle()); + } + } else { + matrix::scale(m, m, state.getSize().width / 2.0, -(state.getSize().height / 2.0), 1.0); + matrix::translate(m, m, 1, -1, 0); + matrix::multiply(m, m, posMatrix); + } + return m; + } + + /* + * Returns a matrix for converting from the correct label coordinate space to gl coords. + */ + mat4 getGlCoordMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits) { + mat4 m; + matrix::identity(m); + if (pitchWithMap) { + matrix::multiply(m, m, posMatrix); + matrix::scale(m, m, pixelsToTileUnits, pixelsToTileUnits, 1); + if (!rotateWithMap) { + matrix::rotate_z(m, m, -state.getAngle()); + } + } else { + matrix::scale(m, m, 1, -1, 1); + matrix::translate(m, m, -1, -1, 0); + matrix::scale(m, m, 2.0 / state.getSize().width, 2.0 / state.getSize().height, 1.0); + } + return m; + } + + + Point project(const Point& point, const mat4& matrix) { + vec4 pos = {{ point.x, point.y, 0, 1 }}; + matrix::transformMat4(pos, pos, matrix); + return { static_cast(pos[0] / pos[3]), static_cast(pos[1] / pos[3]) }; + } + + float evaluateSizeForFeature(const ZoomEvaluatedSize& zoomEvaluatedSize, const PlacedSymbol& placedSymbol) { + if (zoomEvaluatedSize.isFeatureConstant) { + return zoomEvaluatedSize.size; + } else { + if (zoomEvaluatedSize.isZoomConstant) { + return placedSymbol.lowerSize; + } else { + return placedSymbol.lowerSize + zoomEvaluatedSize.sizeT * (placedSymbol.upperSize - placedSymbol.lowerSize); + } + } + } + + bool isVisible(const vec4& anchorPos, const float placementZoom, const std::array& clippingBuffer, const FrameHistory& frameHistory) { + const float x = anchorPos[0] / anchorPos[3]; + const float y = anchorPos[1] / anchorPos[3]; + const bool inPaddedViewport = ( + x >= -clippingBuffer[0] && + x <= clippingBuffer[0] && + y >= -clippingBuffer[1] && + y <= clippingBuffer[1]); + return inPaddedViewport && frameHistory.isVisible(placementZoom); + } + + void addDynamicAttributes(const Point& anchorPoint, const float angle, const float placementZoom, + gl::VertexVector& dynamicVertexArray) { + auto dynamicVertex = SymbolDynamicLayoutAttributes::vertex(anchorPoint, angle, placementZoom); + dynamicVertexArray.emplace_back(dynamicVertex); + dynamicVertexArray.emplace_back(dynamicVertex); + dynamicVertexArray.emplace_back(dynamicVertex); + dynamicVertexArray.emplace_back(dynamicVertex); + } + + void hideGlyphs(size_t numGlyphs, gl::VertexVector& dynamicVertexArray) { + const Point offscreenPoint = { -INFINITY, -INFINITY }; + for (size_t i = 0; i < numGlyphs; i++) { + addDynamicAttributes(offscreenPoint, 0, 25, dynamicVertexArray); + } + } + + struct PlacedGlyph { + PlacedGlyph(Point point_, float angle_) : point(point_), angle(angle_) {} + Point point; + float angle; + }; + + optional placeGlyphAlongLine(const float offsetX, const float lineOffsetX, const float lineOffsetY, const bool flip, + Point anchorPoint, const uint16_t anchorSegment, const GeometryCoordinates& line, const mat4& labelPlaneMatrix) { + + const float combinedOffsetX = flip ? + offsetX - lineOffsetX : + offsetX + lineOffsetX; + + int16_t dir = combinedOffsetX > 0 ? 1 : -1; + + float angle = 0.0; + if (flip) { + // The label needs to be flipped to keep text upright. + // Iterate in the reverse direction. + dir *= -1; + angle = M_PI; + } + + if (dir < 0) angle += M_PI; + + int32_t currentIndex = dir > 0 ? anchorSegment : anchorSegment + 1; + + Point current = anchorPoint; + Point prev = anchorPoint; + float distanceToPrev = 0.0; + float currentSegmentDistance = 0.0; + const float absOffsetX = std::abs(combinedOffsetX); + + while (distanceToPrev + currentSegmentDistance <= absOffsetX) { + currentIndex += dir; + + // offset does not fit on the projected line + if (currentIndex < 0 || currentIndex >= static_cast(line.size())) return {}; + + prev = current; + current = project(convertPoint(line.at(currentIndex)), labelPlaneMatrix); + + distanceToPrev += currentSegmentDistance; + currentSegmentDistance = util::dist(prev, current); + } + + // The point is on the current segment. Interpolate to find it. + const float segmentInterpolationT = (absOffsetX - distanceToPrev) / currentSegmentDistance; + const Point prevToCurrent = current - prev; + Point p = (prevToCurrent * segmentInterpolationT) + prev; + + // offset the point from the line to text-offset and icon-offset + p += util::perp(prevToCurrent) * static_cast(lineOffsetY * dir / util::mag(prevToCurrent)); + + const float segmentAngle = angle + std::atan2(current.y - prev.y, current.x - prev.x); + + return {{ p, segmentAngle }}; + } + + void placeGlyphsAlongLine(const PlacedSymbol& symbol, const float fontSize, const bool flip, const mat4& labelPlaneMatrix, + gl::VertexVector& dynamicVertexArray) { + const float fontScale = fontSize / 24.0; + const float lineOffsetX = symbol.lineOffset[0] * fontSize; + const float lineOffsetY = symbol.lineOffset[1] * fontSize; + + const Point anchorPoint = project(symbol.anchorPoint, labelPlaneMatrix); + + std::vector placedGlyphs; + for (auto glyphOffsetX : symbol.glyphOffsets) { + auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); + if (placedGlyph) { + placedGlyphs.push_back(*placedGlyph); + } else { + hideGlyphs(symbol.glyphOffsets.size(), dynamicVertexArray); + return; + } + } + + for (auto& placedGlyph : placedGlyphs) { + addDynamicAttributes(placedGlyph.point, placedGlyph.angle, symbol.placementZoom, dynamicVertexArray); + } + } + + void reprojectLineLabels(gl::VertexVector& dynamicVertexArray, const std::vector& placedSymbols, + const mat4& posMatrix, const style::SymbolPropertyValues& values, + const RenderTile& tile, const SymbolSizeBinder& sizeBinder, const TransformState& state, const FrameHistory& frameHistory) { + + const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(state.getZoom()); + + const std::array clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height * 2.0 + 1.0 }}; + + const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, values.pitchAlignment == style::AlignmentType::Map, + values.rotationAlignment == style::AlignmentType::Map, state, tile.id.pixelsToTileUnits(1, state.getZoom())); + + dynamicVertexArray.clear(); + + for (auto& placedSymbol : placedSymbols) { + vec4 anchorPos = {{ placedSymbol.anchorPoint.x, placedSymbol.anchorPoint.y, 0, 1 }}; + matrix::transformMat4(anchorPos, anchorPos, posMatrix); + + // Don't bother calculating the correct point for invisible labels. + if (!isVisible(anchorPos, placedSymbol.placementZoom, clippingBuffer, frameHistory)) { + hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray); + continue; + } + + bool flip = false; + if (values.keepUpright) { + const Point a = project(convertPoint(placedSymbol.line.at(placedSymbol.segment)), posMatrix); + const Point b = project(convertPoint(placedSymbol.line.at(placedSymbol.segment + 1)), posMatrix); + flip = placedSymbol.useVerticalMode ? b.y > a.y : b.x < a.x; + } + + const float cameraToAnchorDistance = anchorPos[3]; + const float perspectiveRatio = 1 + 0.5 * ((cameraToAnchorDistance / state.getCameraToCenterDistance()) - 1.0); + + const float fontSize = evaluateSizeForFeature(partiallyEvaluatedSize, placedSymbol); + const float pitchScaledFontSize = values.pitchAlignment == style::AlignmentType::Map ? + fontSize * perspectiveRatio : + fontSize / perspectiveRatio; + + placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, flip, labelPlaneMatrix, dynamicVertexArray); + } + } +} // end namespace mbgl diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp new file mode 100644 index 0000000000..2652fe7ace --- /dev/null +++ b/src/mbgl/layout/symbol_projection.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace mbgl { + + class TransformState; + class RenderTile; + class FrameHistory; + class SymbolSizeBinder; + class PlacedSymbol; + namespace style { + class SymbolPropertyValues; + } // end namespace style + + mat4 getLabelPlaneMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits); + mat4 getGlCoordMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits); + + void reprojectLineLabels(gl::VertexVector&, const std::vector&, + const mat4& posMatrix, const style::SymbolPropertyValues&, + const RenderTile&, const SymbolSizeBinder& sizeBinder, const TransformState&, const FrameHistory& frameHistory); + +} // end namespace mbgl diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index f39af2deec..684d9d6099 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -23,6 +23,7 @@ inline uint16_t packUint8Pair(T a, T b) { MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); +MBGL_DEFINE_ATTRIBUTE(float, 3, a_projected_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_label_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index bd43237b8f..8790adcc63 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -10,7 +11,7 @@ namespace mbgl { using namespace style; -static_assert(sizeof(SymbolLayoutVertex) == 20, "expected SymbolLayoutVertex size"); +static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size"); std::unique_ptr SymbolSizeBinder::create(const float tileZoom, const style::DataDrivenPropertyValue& sizeProperty, @@ -33,6 +34,7 @@ Values makeValues(const bool isText, const style::SymbolPropertyValues& values, const Size& texsize, const std::array& pixelsToGLUnits, + const bool alongLine, const RenderTile& tile, const TransformState& state, Args&&... args) { @@ -46,21 +48,41 @@ Values makeValues(const bool isText, pixelsToGLUnits[1] * state.getCameraToCenterDistance() }}; } + + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom()); + const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map; + const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map; + + mat4 labelPlaneMatrix; + if (alongLine) { + // For labels that follow lines the first part of the projection is handled on the cpu. + // Pass an identity matrix because no transformation needs to be done in the vertex shader. + matrix::identity(labelPlaneMatrix); + } else { + labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); + } + + mat4 glCoordMatrix = getGlCoordMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); return Values { uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate, values.translateAnchor, state) }, + uniforms::u_label_plane_matrix::Value{labelPlaneMatrix}, + uniforms::u_gl_coord_matrix::Value{ tile.translateVtxMatrix(glCoordMatrix, + values.translate, + values.translateAnchor, + state, + true) }, uniforms::u_extrude_scale::Value{ extrudeScale }, uniforms::u_texsize::Value{ texsize }, - uniforms::u_zoom::Value{ float(state.getZoom()) }, - uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map }, uniforms::u_texture::Value{ 0 }, uniforms::u_fadetexture::Value{ 1 }, uniforms::u_is_text::Value{ isText }, uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, uniforms::u_pitch::Value{ state.getPitch() }, + uniforms::u_pitch_with_map::Value{ pitchWithMap }, uniforms::u_max_camera_distance::Value{ values.maxCameraDistance }, std::forward(args)... }; @@ -71,6 +93,7 @@ SymbolIconProgram::uniformValues(const bool isText, const style::SymbolPropertyValues& values, const Size& texsize, const std::array& pixelsToGLUnits, + const bool alongLine, const RenderTile& tile, const TransformState& state) { @@ -79,6 +102,7 @@ SymbolIconProgram::uniformValues(const bool isText, values, texsize, pixelsToGLUnits, + alongLine, tile, state ); @@ -90,25 +114,24 @@ typename SymbolSDFProgram::UniformValues SymbolSDFProgram& pixelsToGLUnits, + const bool alongLine, const RenderTile& tile, const TransformState& state, const SymbolSDFPart part) { const float gammaScale = (values.pitchAlignment == AlignmentType::Map - ? std::cos(state.getPitch()) - : 1.0) * state.getCameraToCenterDistance(); + ? std::cos(state.getPitch()) * state.getCameraToCenterDistance() + : 1.0); return makeValues::UniformValues>( isText, values, texsize, pixelsToGLUnits, + alongLine, tile, state, uniforms::u_gamma_scale::Value{ gammaScale }, - uniforms::u_bearing::Value{ -1.0f * state.getAngle() }, - uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) }, - uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map }, uniforms::u_is_halo::Value{ part == SymbolSDFPart::Halo } ); } diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 130e556b46..79a961ad21 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -29,9 +29,9 @@ class RenderTile; class TransformState; namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map); +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_gl_coord_matrix); +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_label_plane_matrix); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo); MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); @@ -40,57 +40,58 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_layout_size); MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance); } // namespace uniforms struct SymbolLayoutAttributes : gl::Attributes< attributes::a_pos_offset, - attributes::a_label_pos, attributes::a_data> { - static Vertex vertex(Point a, + static Vertex vertex(Point labelAnchor, Point o, - Point labelAnchor, + float glyphOffsetY, uint16_t tx, uint16_t ty, - float minzoom, - float maxzoom, - float labelminzoom, - uint8_t labelangle) { + const Range& sizeData) { return Vertex { // combining pos and offset to reduce number of vertex attributes passed to shader (8 max for some devices) - {{ - static_cast(a.x), - static_cast(a.y), - static_cast(::round(o.x * 64)), // use 1/64 pixels for placement - static_cast(::round(o.y * 64)) - }}, {{ static_cast(labelAnchor.x), - static_cast(labelAnchor.y) + static_cast(labelAnchor.y), + static_cast(::round(o.x * 64)), // use 1/64 pixels for placement + static_cast(::round((o.y + glyphOffsetY) * 64)) }}, {{ tx, ty, - mbgl::attributes::packUint8Pair( - static_cast(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 - static_cast(labelangle) - ), - mbgl::attributes::packUint8Pair( - static_cast(minzoom * 10), - static_cast(::fmin(maxzoom, 25) * 10) - ) + static_cast(sizeData.min * 10), + static_cast(sizeData.max * 10) }} }; } }; + +struct SymbolDynamicLayoutAttributes : gl::Attributes { + static Vertex vertex(Point anchorPoint, float labelAngle, float labelminzoom) { + return Vertex { + {{ + anchorPoint.x, + anchorPoint.y, + static_cast(mbgl::attributes::packUint8Pair( + static_cast(std::fmod(labelAngle + 2 * M_PI, 2 * M_PI) / (2 * M_PI) * 255), + static_cast(labelminzoom * 10))) + }} + }; + } +}; -class SymbolSizeAttributes : public gl::Attributes { -public: - using Attribute = attributes::a_size::Type; +struct ZoomEvaluatedSize { + bool isZoomConstant; + bool isFeatureConstant; + float sizeT; + float size; + float layoutSize; }; - // Mimic the PaintPropertyBinder technique specifically for the {text,icon}-size layout properties // in order to provide a 'custom' scheme for encoding the necessary attribute data. As with // PaintPropertyBinder, SymbolSizeBinder is an abstract class whose implementations handle the @@ -103,18 +104,25 @@ public: uniforms::u_is_size_zoom_constant, uniforms::u_is_size_feature_constant, uniforms::u_size_t, - uniforms::u_size, - uniforms::u_layout_size>; + uniforms::u_size>; using UniformValues = Uniforms::Values; static std::unique_ptr create(const float tileZoom, const style::DataDrivenPropertyValue& sizeProperty, const float defaultValue); - virtual SymbolSizeAttributes::Bindings attributeBindings() const = 0; - virtual void populateVertexVector(const GeometryTileFeature& feature) = 0; - virtual UniformValues uniformValues(float currentZoom) const = 0; - virtual void upload(gl::Context&) = 0; + virtual Range getVertexSizeData(const GeometryTileFeature& feature) = 0; + virtual ZoomEvaluatedSize evaluateForZoom(float currentZoom) const = 0; + + UniformValues uniformValues(float currentZoom) const { + const ZoomEvaluatedSize u = evaluateForZoom(currentZoom); + return UniformValues { + uniforms::u_is_size_zoom_constant::Value{ u.isZoomConstant }, + uniforms::u_is_size_feature_constant::Value{ u.isFeatureConstant}, + uniforms::u_size_t::Value{ u.sizeT }, + uniforms::u_size::Value{ u.size } + }; + } }; // Return the smallest range of stops that covers the interval [lowerZoom, upperZoom] @@ -160,14 +168,9 @@ public: ); } - SymbolSizeAttributes::Bindings attributeBindings() const override { - return SymbolSizeAttributes::Bindings { gl::DisabledAttribute() }; - } - - void upload(gl::Context&) override {} - void populateVertexVector(const GeometryTileFeature&) override {}; + Range getVertexSizeData(const GeometryTileFeature&) override { return { 0.0f, 0.0f }; }; - UniformValues uniformValues(float currentZoom) const override { + ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override { float size = layoutSize; bool isZoomConstant = !(coveringRanges || function); if (coveringRanges) { @@ -186,14 +189,9 @@ public: } else if (function) { size = function->evaluate(currentZoom); } - - return UniformValues { - uniforms::u_is_size_zoom_constant::Value{ isZoomConstant }, - uniforms::u_is_size_feature_constant::Value{ true }, - uniforms::u_size_t::Value{ 0.0f }, // unused - uniforms::u_size::Value{ size }, - uniforms::u_layout_size::Value{ layoutSize } - }; + + const float unused = 0.0f; + return { isZoomConstant, true, unused, size, layoutSize }; } float layoutSize; @@ -215,49 +213,22 @@ public: defaultValue(defaultValue_) { } - SymbolSizeAttributes::Bindings attributeBindings() const override { - return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0, 1) }; - } - - void populateVertexVector(const GeometryTileFeature& feature) override { - const auto sizeVertex = Vertex { - {{ - static_cast(function.evaluate(feature, defaultValue) * 10) - }} - }; - - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); + Range getVertexSizeData(const GeometryTileFeature& feature) override { + const float size = function.evaluate(feature, defaultValue); + return { size, size }; }; - UniformValues uniformValues(float) const override { - return UniformValues { - uniforms::u_is_size_zoom_constant::Value{ true }, - uniforms::u_is_size_feature_constant::Value{ false }, - uniforms::u_size_t::Value{ 0.0f }, // unused - uniforms::u_size::Value{ 0.0f }, // unused - uniforms::u_layout_size::Value{ 0.0f } // unused - }; - } - - void upload(gl::Context& context) override { - buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) }; + ZoomEvaluatedSize evaluateForZoom(float) const override { + const float unused = 0.0f; + return { true, false, unused, unused, unused }; } const style::SourceFunction& function; const float defaultValue; - - VertexVector vertices; - optional buffer; }; class CompositeFunctionSymbolSizeBinder final : public SymbolSizeBinder { public: - using Vertex = SymbolSizeAttributes::Vertex; - using VertexVector = gl::VertexVector; - using VertexBuffer = gl::VertexBuffer; CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction& function_, const float defaultValue_) : function(function_), @@ -268,51 +239,27 @@ public: return getCoveringStops(stops, tileZoom, tileZoom + 1); })) {} - SymbolSizeAttributes::Bindings attributeBindings() const override { - return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0) }; - } - - void populateVertexVector(const GeometryTileFeature& feature) override { - const auto sizeVertex = Vertex { - {{ - static_cast(function.evaluate(coveringZoomStops.min, feature, defaultValue) * 10), - static_cast(function.evaluate(coveringZoomStops.max, feature, defaultValue) * 10), - static_cast(function.evaluate(layoutZoom, feature, defaultValue) * 10) - }} + Range getVertexSizeData(const GeometryTileFeature& feature) override { + return { + function.evaluate(coveringZoomStops.min, feature, defaultValue), + function.evaluate(coveringZoomStops.max, feature, defaultValue) }; - - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); - vertices.emplace_back(sizeVertex); }; - UniformValues uniformValues(float currentZoom) const override { + ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override { float sizeInterpolationT = util::clamp( util::interpolationFactor(1.0f, coveringZoomStops, currentZoom), 0.0f, 1.0f ); - return UniformValues { - uniforms::u_is_size_zoom_constant::Value{ false }, - uniforms::u_is_size_feature_constant::Value{ false }, - uniforms::u_size_t::Value{ sizeInterpolationT }, - uniforms::u_size::Value{ 0.0f }, // unused - uniforms::u_layout_size::Value{ 0.0f } // unused - }; - } - - void upload(gl::Context& context) override { - buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) }; + const float unused = 0.0f; + return { false, false, sizeInterpolationT, unused, unused }; } const style::CompositeFunction& function; const float defaultValue; float layoutZoom; Range coveringZoomStops; - - VertexVector vertices; - optional buffer; }; @@ -326,7 +273,7 @@ public: using LayoutAttributes = LayoutAttrs; using LayoutVertex = typename LayoutAttributes::Vertex; - using LayoutAndSizeAttributes = gl::ConcatenateAttributes; + using LayoutAndSizeAttributes = gl::ConcatenateAttributes; using PaintProperties = PaintProps; using PaintPropertyBinders = typename PaintProperties::Binders; @@ -359,6 +306,7 @@ public: gl::ColorMode colorMode, UniformValues&& uniformValues, const gl::VertexBuffer& layoutVertexBuffer, + const gl::VertexBuffer& dynamicLayoutVertexBuffer, const SymbolSizeBinder& symbolSizeBinder, const gl::IndexBuffer& indexBuffer, const gl::SegmentVector& segments, @@ -375,7 +323,7 @@ public: .concat(symbolSizeBinder.uniformValues(currentZoom)) .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)), LayoutAttributes::bindings(layoutVertexBuffer) - .concat(symbolSizeBinder.attributeBindings()) + .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer)) .concat(paintPropertyBinders.attributeBindings(currentProperties)), indexBuffer, segments @@ -389,16 +337,17 @@ class SymbolIconProgram : public SymbolProgram< SymbolLayoutAttributes, gl::Uniforms< uniforms::u_matrix, + uniforms::u_label_plane_matrix, + uniforms::u_gl_coord_matrix, uniforms::u_extrude_scale, uniforms::u_texsize, - uniforms::u_zoom, - uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, uniforms::u_collision_y_stretch, uniforms::u_camera_to_center_distance, uniforms::u_pitch, + uniforms::u_pitch_with_map, uniforms::u_max_camera_distance>, style::IconPaintProperties> { @@ -409,6 +358,7 @@ public: const style::SymbolPropertyValues&, const Size& texsize, const std::array& pixelsToGLUnits, + const bool alongLine, const RenderTile&, const TransformState&); }; @@ -425,21 +375,19 @@ class SymbolSDFProgram : public SymbolProgram< SymbolLayoutAttributes, gl::Uniforms< uniforms::u_matrix, + uniforms::u_label_plane_matrix, + uniforms::u_gl_coord_matrix, uniforms::u_extrude_scale, uniforms::u_texsize, - uniforms::u_zoom, - uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, uniforms::u_collision_y_stretch, uniforms::u_camera_to_center_distance, uniforms::u_pitch, + uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, uniforms::u_gamma_scale, - uniforms::u_bearing, - uniforms::u_aspect_ratio, - uniforms::u_pitch_with_map, uniforms::u_is_halo>, PaintProperties> { @@ -449,21 +397,19 @@ public: SymbolLayoutAttributes, gl::Uniforms< uniforms::u_matrix, + uniforms::u_label_plane_matrix, + uniforms::u_gl_coord_matrix, uniforms::u_extrude_scale, uniforms::u_texsize, - uniforms::u_zoom, - uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, uniforms::u_is_text, uniforms::u_collision_y_stretch, uniforms::u_camera_to_center_distance, uniforms::u_pitch, + uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, uniforms::u_gamma_scale, - uniforms::u_bearing, - uniforms::u_aspect_ratio, - uniforms::u_pitch_with_map, uniforms::u_is_halo>, PaintProperties>; @@ -477,6 +423,7 @@ public: const style::SymbolPropertyValues&, const Size& texsize, const std::array& pixelsToGLUnits, + const bool alongLine, const RenderTile&, const TransformState&, const SymbolSDFPart); diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index 861f3271c9..285d243251 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -15,7 +15,6 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur); MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom); MBGL_DEFINE_UNIFORM_SCALAR(float, u_collision_y_stretch); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch); MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing); MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius); diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 28e6a47250..194a5d6bd8 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -38,14 +38,14 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); + text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsageType::StreamDraw); text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); - textSizeBinder->upload(context); } if (hasIconData()) { icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); + icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsageType::StreamDraw); icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); - iconSizeBinder->upload(context); } if (!collisionBox.vertices.empty()) { diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 002b6e28b3..ffa22e9021 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -15,6 +15,23 @@ namespace mbgl { +class PlacedSymbol { +public: + PlacedSymbol(Point anchorPoint_, uint16_t segment_, float lowerSize_, float upperSize_, + std::array lineOffset_, float placementZoom_, bool useVerticalMode_, GeometryCoordinates line_) : + anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_), + lineOffset(lineOffset_), placementZoom(placementZoom_), useVerticalMode(useVerticalMode_), line(std::move(line_)) {} + Point anchorPoint; + uint16_t segment; + float lowerSize; + float upperSize; + std::array lineOffset; + float placementZoom; + bool useVerticalMode; + GeometryCoordinates line; + std::vector glyphOffsets; +}; + class SymbolBucket : public Bucket { public: SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated, @@ -44,10 +61,13 @@ public: struct TextBuffer { gl::VertexVector vertices; + gl::VertexVector dynamicVertices; gl::IndexVector triangles; gl::SegmentVector segments; + std::vector placedSymbols; optional> vertexBuffer; + optional> dynamicVertexBuffer; optional> indexBuffer; } text; @@ -55,11 +75,14 @@ public: struct IconBuffer { gl::VertexVector vertices; + gl::VertexVector dynamicVertices; gl::IndexVector triangles; gl::SegmentVector segments; + std::vector placedSymbols; PremultipliedImage atlasImage; optional> vertexBuffer; + optional> dynamicVertexBuffer; optional> indexBuffer; } icon; @@ -69,6 +92,7 @@ public: gl::SegmentVector segments; optional> vertexBuffer; + optional> dynamicVertexBuffer; optional> indexBuffer; } collisionBox; }; diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp index 869222b4eb..de153b6963 100644 --- a/src/mbgl/renderer/frame_history.cpp +++ b/src/mbgl/renderer/frame_history.cpp @@ -74,4 +74,8 @@ void FrameHistory::bind(gl::Context& context, uint32_t unit) { context.bindTexture(*texture, unit); } +bool FrameHistory::isVisible(const float zoom) const { + return opacities.data[std::floor(zoom * 10)] != 0; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp index f2b11f5f41..75a8b60a71 100644 --- a/src/mbgl/renderer/frame_history.hpp +++ b/src/mbgl/renderer/frame_history.hpp @@ -22,6 +22,7 @@ public: bool needsAnimation(const Duration&) const; void bind(gl::Context&, uint32_t); void upload(gl::Context&, uint32_t); + bool isVisible(const float zoom) const; private: std::array changeTimes; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 573e9db72e..2fe6dd971e 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -84,6 +84,7 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S return style::SymbolPropertyValues { layout_.get(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment layout_.get(), + layout_.get(), evaluated.get(), evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && @@ -109,6 +110,7 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S return style::SymbolPropertyValues { layout_.get(), layout_.get(), + layout_.get(), evaluated.get(), evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index e788336cbd..a201b6298f 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -40,6 +40,7 @@ public: // Layout AlignmentType pitchAlignment; AlignmentType rotationAlignment; + bool keepUpright; // Paint std::array translate; diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index dc80f096f4..51c3967ae7 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -52,6 +53,7 @@ void Painter::renderSymbol(PaintParameters& parameters, colorModeForRenderPass(), std::move(uniformValues), *buffers.vertexBuffer, + *buffers.dynamicVertexBuffer, *symbolSizeBinder, *buffers.indexBuffer, buffers.segments, @@ -64,10 +66,19 @@ void Painter::renderSymbol(PaintParameters& parameters, assert(dynamic_cast(&tile.tile)); GeometryTile& geometryTile = static_cast(tile.tile); + if (bucket.hasIconData()) { auto values = layer.iconPropertyValues(layout); auto paintPropertyValues = layer.iconPaintProperties(); + const bool alongLine = bucket.layout.get() == SymbolPlacementType::Line && + bucket.layout.get() == AlignmentType::Map; + + if (alongLine) { + reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols, tile.matrix, values, tile, *(bucket.iconSizeBinder), state, frameHistory); + context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices)); + } + const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0; @@ -80,7 +91,7 @@ void Painter::renderSymbol(PaintParameters& parameters, if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), + SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, alongLine, tile, state, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, @@ -90,7 +101,7 @@ void Painter::renderSymbol(PaintParameters& parameters, if (values.hasFill) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), + SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, alongLine, tile, state, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, @@ -99,7 +110,7 @@ void Painter::renderSymbol(PaintParameters& parameters, } } else { draw(parameters.programs.symbolIcon, - SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state), + SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, alongLine, tile, state), bucket.icon, bucket.iconSizeBinder, values, @@ -114,11 +125,19 @@ void Painter::renderSymbol(PaintParameters& parameters, auto values = layer.textPropertyValues(layout); auto paintPropertyValues = layer.textPaintProperties(); + const bool alongLine = bucket.layout.get() == SymbolPlacementType::Line && + bucket.layout.get() == AlignmentType::Map; + + if (alongLine) { + reprojectLineLabels(bucket.text.dynamicVertices, bucket.text.placedSymbols, tile.matrix, values, tile, *(bucket.textSizeBinder), state, frameHistory); + context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); + } + const Size texsize = geometryTile.glyphAtlasTexture->size; if (values.hasHalo) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo), + SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, alongLine, tile, state, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, @@ -128,7 +147,7 @@ void Painter::renderSymbol(PaintParameters& parameters, if (values.hasFill) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill), + SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, alongLine, tile, state, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 59c3ea076b..7e7e3e6d23 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { @@ -10,24 +11,26 @@ using namespace style; mat4 RenderTile::translateVtxMatrix(const mat4& tileMatrix, const std::array& translation, TranslateAnchorType anchor, - const TransformState& state) const { + const TransformState& state, + const bool inViewportPixelUnits) const { if (translation[0] == 0 && translation[1] == 0) { return tileMatrix; } mat4 vtxMatrix; - if (anchor == TranslateAnchorType::Viewport) { - const double sin_a = std::sin(-state.getAngle()); - const double cos_a = std::cos(-state.getAngle()); - matrix::translate(vtxMatrix, tileMatrix, - id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()), - id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()), - 0); + const float angle = inViewportPixelUnits ? + (anchor == TranslateAnchorType::Map ? state.getAngle() : 0) : + (anchor == TranslateAnchorType::Viewport ? -state.getAngle() : 0); + + Point translate = util::rotate(Point{ translation[0], translation[1] }, angle); + + if (inViewportPixelUnits) { + matrix::translate(vtxMatrix, tileMatrix, translate.x, translate.y, 0); } else { matrix::translate(vtxMatrix, tileMatrix, - id.pixelsToTileUnits(translation[0], state.getZoom()), - id.pixelsToTileUnits(translation[1], state.getZoom()), + id.pixelsToTileUnits(translate.x, state.getZoom()), + id.pixelsToTileUnits(translate.y, state.getZoom()), 0); } @@ -37,13 +40,13 @@ mat4 RenderTile::translateVtxMatrix(const mat4& tileMatrix, mat4 RenderTile::translatedMatrix(const std::array& translation, TranslateAnchorType anchor, const TransformState& state) const { - return translateVtxMatrix(matrix, translation, anchor, state); + return translateVtxMatrix(matrix, translation, anchor, state, false); } mat4 RenderTile::translatedClipMatrix(const std::array& translation, TranslateAnchorType anchor, const TransformState& state) const { - return translateVtxMatrix(nearClippedMatrix, translation, anchor, state); + return translateVtxMatrix(nearClippedMatrix, translation, anchor, state, false); } void RenderTile::startRender(Painter& painter) { diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 07e2d699f7..6d374c29cb 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -38,11 +38,11 @@ public: void startRender(Painter&); -private: mat4 translateVtxMatrix(const mat4& tileMatrix, const std::array& translation, style::TranslateAnchorType anchor, - const TransformState& state) const; + const TransformState& state, + const bool inViewportPixelUnits) const; }; } // namespace mbgl diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp index 05f306ef65..07fa94e338 100644 --- a/src/mbgl/shaders/collision_box.cpp +++ b/src/mbgl/shaders/collision_box.cpp @@ -36,7 +36,7 @@ void main() { v_max_zoom = a_data.x; v_placement_zoom = a_data.y; - v_perspective_zoom_adjust = log2(collision_perspective_ratio * collision_adjustment) * 10.0; + v_perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0); v_fade_tex = vec2((v_placement_zoom + v_perspective_zoom_adjust) / 255.0, 0.0); } diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index 8960e02c28..cb00cdad05 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -7,17 +7,16 @@ namespace shaders { const char* symbol_icon::name = "symbol_icon"; const char* symbol_icon::vertexSource = R"MBGL_SHADER( +const float PI = 3.141592653589793; + attribute vec4 a_pos_offset; -attribute vec2 a_label_pos; attribute vec4 a_data; +attribute vec3 a_projected_pos; -// icon-size data (see symbol_sdf.vertex.glsl for more) -attribute vec3 a_size; uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function uniform highp float u_size; // used when size is both zoom and feature constant -uniform highp float u_layout_size; // used when size is feature constant uniform highp float u_camera_to_center_distance; uniform highp float u_pitch; uniform highp float u_collision_y_stretch; @@ -31,13 +30,12 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -// matrix is for the vertex position. uniform mat4 u_matrix; +uniform mat4 u_label_plane_matrix; +uniform mat4 u_gl_coord_matrix; uniform bool u_is_text; -uniform highp float u_zoom; -uniform bool u_rotate_with_map; -uniform vec2 u_extrude_scale; +uniform bool u_pitch_with_map; uniform vec2 u_texsize; @@ -56,61 +54,49 @@ void main() { vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; - highp vec2 label_data = unpack_float(a_data[2]); - highp float a_labelminzoom = label_data[0]; - highp vec2 a_zoom = unpack_float(a_data[3]); - highp float a_minzoom = a_zoom[0]; - highp float a_maxzoom = a_zoom[1]; + vec2 a_size = a_data.zw; + + highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]); + highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI; + mediump float a_labelminzoom = angle_labelminzoom[1]; float size; - // In order to accommodate placing labels around corners in - // symbol-placement: line, each glyph in a label could have multiple - // "quad"s only one of which should be shown at a given zoom level. - // The min/max zoom assigned to each quad is based on the font size at - // the vector tile's zoom level, which might be different than at the - // currently rendered zoom level if text-size is zoom-dependent. - // Thus, we compensate for this difference by calculating an adjustment - // based on the scale of rendered text size relative to layout text size. - highp float layoutSize; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { size = mix(a_size[0], a_size[1], u_size_t) / 10.0; - layoutSize = a_size[2] / 10.0; } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { size = a_size[0] / 10.0; - layoutSize = size; } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { size = u_size; - layoutSize = u_layout_size; } else { size = u_size; - layoutSize = u_size; } - float fontScale = u_is_text ? size / 24.0 : size; + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // See comments in symbol_sdf.vertex + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = 0.5 + 0.5 * distance_ratio; - highp float zoomAdjust = log2(size / layoutSize); - highp float adjustedZoom = (u_zoom - zoomAdjust) * 10.0; - // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise - highp float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom)); + size *= perspective_ratio; - vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1); - highp float camera_to_anchor_distance = projectedPoint.w; - highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); + float fontScale = u_is_text ? size / 24.0 : size; - vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0); - if (u_rotate_with_map) { - gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1); - gl_Position.z += z * gl_Position.w; - } else { - gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0); - } + highp float angle_sin = sin(segment_angle); + highp float angle_cos = cos(segment_angle); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 64.0 * fontScale), 0.0, 1.0); v_tex = a_tex / u_texsize; // See comments in symbol_sdf.vertex highp float incidence_stretch = camera_to_anchor_distance / (u_camera_to_center_distance * cos(u_pitch)); highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch); - highp float perspective_zoom_adjust = log2(perspective_ratio * collision_adjustment) * 10.0; + highp float collision_perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); + highp float perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0); v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0); } diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index bae01a5b59..b4158bacc5 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -9,11 +9,9 @@ const char* symbol_sdf::name = "symbol_sdf"; const char* symbol_sdf::vertexSource = R"MBGL_SHADER( const float PI = 3.141592653589793; -// NOTE: the a_data attribute in this shader is manually bound (see https://github.com/mapbox/mapbox-gl-js/issues/4607). -// If removing or renaming a_data, revisit the manual binding in painter.js accordingly. attribute vec4 a_pos_offset; -attribute vec2 a_label_pos; attribute vec4 a_data; +attribute vec3 a_projected_pos; // contents of a_size vary based on the type of property value // used for {text,icon}-size. @@ -21,17 +19,14 @@ attribute vec4 a_data; // For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. // For composite functions: // [ text-size(lowerZoomStop, feature), -// text-size(upperZoomStop, feature), -// layoutSize == text-size(layoutZoomLevel, feature) ] -attribute vec3 a_size; +// text-size(upperZoomStop, feature) ] uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function uniform highp float u_size; // used when size is both zoom and feature constant -uniform highp float u_layout_size; // used when size is feature constant -#ifdef HAS_UNIFORM_u_fill_color +#ifndef HAS_UNIFORM_u_fill_color uniform lowp float a_fill_color_t; attribute highp vec4 a_fill_color; varying highp vec4 fill_color; @@ -39,8 +34,7 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif - -#ifdef HAS_UNIFORM_u_halo_color +#ifndef HAS_UNIFORM_u_halo_color uniform lowp float a_halo_color_t; attribute highp vec4 a_halo_color; varying highp vec4 halo_color; @@ -48,8 +42,7 @@ varying highp vec4 halo_color; uniform highp vec4 u_halo_color; #endif - -#ifdef HAS_UNIFORM_u_opacity +#ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; @@ -57,8 +50,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif - -#ifdef HAS_UNIFORM_u_halo_width +#ifndef HAS_UNIFORM_u_halo_width uniform lowp float a_halo_width_t; attribute lowp vec2 a_halo_width; varying lowp float halo_width; @@ -66,8 +58,7 @@ varying lowp float halo_width; uniform lowp float u_halo_width; #endif - -#ifdef HAS_UNIFORM_u_halo_blur +#ifndef HAS_UNIFORM_u_halo_blur uniform lowp float a_halo_blur_t; attribute lowp vec2 a_halo_blur; varying lowp float halo_blur; @@ -75,168 +66,100 @@ varying lowp float halo_blur; uniform lowp float u_halo_blur; #endif - -// matrix is for the vertex position. uniform mat4 u_matrix; +uniform mat4 u_label_plane_matrix; +uniform mat4 u_gl_coord_matrix; uniform bool u_is_text; -uniform highp float u_zoom; -uniform bool u_rotate_with_map; uniform bool u_pitch_with_map; uniform highp float u_pitch; -uniform highp float u_bearing; -uniform highp float u_aspect_ratio; uniform highp float u_camera_to_center_distance; -uniform highp float u_max_camera_distance; uniform highp float u_collision_y_stretch; -uniform vec2 u_extrude_scale; uniform vec2 u_texsize; -varying vec2 v_tex; -varying vec2 v_fade_tex; -varying float v_gamma_scale; -varying float v_size; - -// Used below to move the vertex out of the clip space for when the current -// zoom is out of the glyph's zoom range. -highp float clipUnusedGlyphAngles(const highp float render_size, - const highp float layout_size, - const highp float min_zoom, - const highp float max_zoom) { - highp float zoom_adjust = log2(render_size / layout_size); - highp float adjusted_zoom = (u_zoom - zoom_adjust) * 10.0; - // result: 0 if min_zoom <= adjusted_zoom < max_zoom, and 1 otherwise - return 2.0 - step(min_zoom, adjusted_zoom) - (1.0 - step(max_zoom, adjusted_zoom)); -} +varying vec4 v_data0; +varying vec2 v_data1; void main() { - + #ifndef HAS_UNIFORM_u_fill_color fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t); #else highp vec4 fill_color = u_fill_color; #endif - #ifndef HAS_UNIFORM_u_halo_color halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t); #else highp vec4 halo_color = u_halo_color; #endif - #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif - #ifndef HAS_UNIFORM_u_halo_width halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); #else lowp float halo_width = u_halo_width; #endif - #ifndef HAS_UNIFORM_u_halo_blur halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); #else lowp float halo_blur = u_halo_blur; #endif - vec2 a_pos = a_pos_offset.xy; vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]); + highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI; + mediump float a_labelminzoom = angle_labelminzoom[1]; + float size; - highp vec2 label_data = unpack_float(a_data[2]); - highp float a_labelminzoom = label_data[0]; - highp float a_lineangle = (label_data[1] / 256.0 * 2.0 * PI); - highp vec2 a_zoom = unpack_float(a_data[3]); - highp float a_minzoom = a_zoom[0]; - highp float a_maxzoom = a_zoom[1]; - - // In order to accommodate placing labels around corners in - // symbol-placement: line, each glyph in a label could have multiple - // "quad"s only one of which should be shown at a given zoom level. - // The min/max zoom assigned to each quad is based on the font size at - // the vector tile's zoom level, which might be different than at the - // currently rendered zoom level if text-size is zoom-dependent. - // Thus, we compensate for this difference by calculating an adjustment - // based on the scale of rendered text size relative to layout text size. - highp float layoutSize; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { - v_size = mix(a_size[0], a_size[1], u_size_t) / 10.0; - layoutSize = a_size[2] / 10.0; + size = mix(a_size[0], a_size[1], u_size_t) / 10.0; } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { - v_size = a_size[0] / 10.0; - layoutSize = v_size; + size = a_size[0] / 10.0; } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { - v_size = u_size; - layoutSize = u_layout_size; + size = u_size; } else { - v_size = u_size; - layoutSize = u_size; + size = u_size; } - float fontScale = u_is_text ? v_size / 24.0 : v_size; - - vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1); + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); highp float camera_to_anchor_distance = projectedPoint.w; - highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); - - // pitch-alignment: map - // rotation-alignment: map | viewport - if (u_pitch_with_map) { - highp float angle = u_rotate_with_map ? a_lineangle : u_bearing; - highp float asin = sin(angle); - highp float acos = cos(angle); - mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos); - vec2 offset = RotationMatrix * a_offset; - vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0); - - gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1); - gl_Position.z += clipUnusedGlyphAngles(v_size*perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w; - // pitch-alignment: viewport - // rotation-alignment: map - } else if (u_rotate_with_map) { - // foreshortening factor to apply on pitched maps - // as a label goes from horizontal <=> vertical in angle - // it goes from 0% foreshortening to up to around 70% foreshortening - highp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75)); - - // use the lineangle to position points a,b along the line - // project the points and calculate the label angle in projected space - // this calculation allows labels to be rendered unskewed on pitched maps - vec4 a = u_matrix * vec4(a_pos, 0, 1); - vec4 b = u_matrix * vec4(a_pos + vec2(cos(a_lineangle), sin(a_lineangle)), 0, 1); - highp float angle = atan((b[1] / b[3] - a[1] / a[3]) / u_aspect_ratio, b[0] / b[3] - a[0] / a[3]); - highp float asin = sin(angle); - highp float acos = cos(angle); - mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos); - highp float foreshortening = (1.0 - pitchfactor) + (pitchfactor * cos(angle * 2.0)); - - vec2 offset = RotationMatrix * (vec2(foreshortening, 1.0) * a_offset); - vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0); - - gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0); - gl_Position.z += clipUnusedGlyphAngles(v_size * perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w; - // pitch-alignment: viewport - // rotation-alignment: viewport - } else { - vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0); - gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0); - } - - gl_Position.z += - step(u_max_camera_distance * u_camera_to_center_distance, camera_to_anchor_distance) * gl_Position.w; - - v_gamma_scale = gl_Position.w / perspective_ratio; - - v_tex = a_tex / u_texsize; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = 0.5 + 0.5 * distance_ratio; + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float angle_sin = sin(segment_angle); + highp float angle_cos = cos(segment_angle); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 64.0 * fontScale), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 tex = a_tex / u_texsize; // incidence_stretch is the ratio of how much y space a label takes up on a tile while drawn perpendicular to the viewport vs // how much space it would take up if it were drawn flat on the tile // Using law of sines, camera_to_anchor/sin(ground_angle) = camera_to_center/sin(incidence_angle) @@ -256,8 +179,12 @@ void main() { highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch); // Floor to 1/10th zoom to dodge precision issues that can cause partially hidden labels - highp float perspective_zoom_adjust = floor(log2(perspective_ratio * collision_adjustment) * 10.0); - v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0); + highp float collision_perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0); + highp float perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0); + vec2 fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0); + + v_data0 = vec4(tex.x, tex.y, fade_tex.x, fade_tex.y); + v_data1 = vec2(gamma_scale, size); } )MBGL_SHADER"; @@ -273,73 +200,66 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif - #ifndef HAS_UNIFORM_u_halo_color varying highp vec4 halo_color; #else uniform highp vec4 u_halo_color; #endif - #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif - #ifndef HAS_UNIFORM_u_halo_width varying lowp float halo_width; #else uniform lowp float u_halo_width; #endif - #ifndef HAS_UNIFORM_u_halo_blur varying lowp float halo_blur; #else uniform lowp float u_halo_blur; #endif - uniform sampler2D u_texture; uniform sampler2D u_fadetexture; uniform highp float u_gamma_scale; uniform bool u_is_text; -varying vec2 v_tex; -varying vec2 v_fade_tex; -varying float v_gamma_scale; -varying float v_size; +varying vec4 v_data0; +varying vec2 v_data1; void main() { - + #ifdef HAS_UNIFORM_u_fill_color highp vec4 fill_color = u_fill_color; #endif - #ifdef HAS_UNIFORM_u_halo_color highp vec4 halo_color = u_halo_color; #endif - #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif - #ifdef HAS_UNIFORM_u_halo_width lowp float halo_width = u_halo_width; #endif - #ifdef HAS_UNIFORM_u_halo_blur lowp float halo_blur = u_halo_blur; #endif + vec2 tex = v_data0.xy; + vec2 fade_tex = v_data0.zw; + float gamma_scale = v_data1.x; + float size = v_data1.y; - float fontScale = u_is_text ? v_size / 24.0 : v_size; + float fontScale = u_is_text ? size / 24.0 : size; lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); @@ -350,9 +270,9 @@ void main() { buff = (6.0 - halo_width / fontScale) / SDF_PX; } - lowp float dist = texture2D(u_texture, v_tex).a; - lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a; - highp float gamma_scaled = gamma * v_gamma_scale; + lowp float dist = texture2D(u_texture, tex).a; + lowp float fade_alpha = texture2D(u_fadetexture, fade_tex).a; + highp float gamma_scaled = gamma * gamma_scale; highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha; gl_FragColor = color * (alpha * opacity); diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index ab10c5a6b7..7908ea4abc 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -13,14 +13,9 @@ namespace mbgl { using namespace style; -const float globalMinScale = 0.5f; // underscale by 1 zoom level - -SymbolQuad getIconQuad(const Anchor& anchor, - const PositionedIcon& shapedIcon, - const GeometryCoordinates& line, +SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, const SymbolLayoutProperties::Evaluated& layout, const float layoutTextSize, - const style::SymbolPlacementType placement, const Shaping& shapedText) { const ImagePosition& image = shapedIcon.image(); @@ -71,18 +66,7 @@ SymbolQuad getIconQuad(const Anchor& anchor, bl = {left, bottom}; } - float angle = shapedIcon.angle(); - if (placement == style::SymbolPlacementType::Line) { - assert(static_cast(anchor.segment) < line.size()); - const GeometryCoordinate &prev= line[anchor.segment]; - if (anchor.point.y == prev.y && anchor.point.x == prev.x && - static_cast(anchor.segment + 1) < line.size()) { - const GeometryCoordinate &next= line[anchor.segment + 1]; - angle += std::atan2(anchor.point.y - next.y, anchor.point.x - next.x) + M_PI; - } else { - angle += std::atan2(anchor.point.y - prev.y, anchor.point.x - prev.x); - } - } + const float angle = shapedIcon.angle(); if (angle) { // Compute the transformation matrix. @@ -104,212 +88,19 @@ SymbolQuad getIconQuad(const Anchor& anchor, static_cast(image.textureRect.h + border * 2) }; - return SymbolQuad { tl, tr, bl, br, textureRect, 0, 0, anchor.point, globalMinScale, std::numeric_limits::infinity(), shapedText.writingMode }; -} - -struct GlyphInstance { - explicit GlyphInstance(Point anchorPoint_) : anchorPoint(std::move(anchorPoint_)) {} - explicit GlyphInstance(Point anchorPoint_, bool upsideDown_, float minScale_, float maxScale_, - float angle_) - : anchorPoint(std::move(anchorPoint_)), upsideDown(upsideDown_), minScale(minScale_), maxScale(maxScale_), angle(angle_) {} - - const Point anchorPoint; - const bool upsideDown = false; - const float minScale = globalMinScale; - const float maxScale = std::numeric_limits::infinity(); - const float angle = 0.0f; -}; - -using GlyphInstances = std::vector; - -struct VirtualSegment { - Point anchor; - Point end; - size_t index; - float minScale; - float maxScale; -}; - -inline void insertSegmentGlyph(std::back_insert_iterator glyphs, - const VirtualSegment& virtualSegment, - const bool glyphIsLogicallyForward, - const bool upsideDown) { - float segmentAngle = std::atan2(virtualSegment.end.y - virtualSegment.anchor.y, virtualSegment.end.x - virtualSegment.anchor.x); - // If !glyphIsLogicallyForward, we're iterating through the segments in reverse logical order as well, so we need to flip the segment angle - float glyphAngle = glyphIsLogicallyForward ? segmentAngle : segmentAngle + M_PI; - - // Insert a glyph rotated at this angle for display in the range from [scale, previous(larger) scale]. - glyphs = GlyphInstance{ - /* anchor */ virtualSegment.anchor, - /* upsideDown */ upsideDown, - /* minScale */ virtualSegment.minScale, - /* maxScale */ virtualSegment.maxScale, - /* angle */ static_cast(std::fmod((glyphAngle + 2.0 * M_PI), (2.0 * M_PI)))}; -} - -/** - Given the distance along the line from the label anchor to the beginning of the current segment, - project a "virtual anchor" point at the same distance along the line extending out from this segment. - - B <-- beginning of current segment -* . . . . . . . *--------* E <-- end of current segment -VA | - / VA = "virtual segment anchor" - / - ---*-----` - A = label anchor - - Distance _along line_ from A to B == straight-line distance from VA to B. - */ -inline Point getVirtualSegmentAnchor(const Point& segmentBegin, const Point& segmentEnd, float distanceFromAnchorToSegmentBegin) { - Point segmentDirectionUnitVector = util::normal(segmentBegin, segmentEnd); - return segmentBegin - (segmentDirectionUnitVector * distanceFromAnchorToSegmentBegin); -} - -/* - Given the segment joining `segmentAnchor` and `segmentEnd` and a desired offset - `glyphDistanceFromAnchor` at which a glyph is to be placed, calculate the minimum - "scale" at which the glyph will fall on the segment (i.e., not past the end) - - "Scale" here refers to the ratio between the *rendered* zoom level and the text-layout - zoom level, which is 1 + (source tile's zoom level). `glyphDistanceFromAnchor`, although - passed in units consistent with the text-layout zoom level, is based on text size. So - when the tile is being rendered at z < text-layout zoom, the glyph's actual distance from - the anchor is larger relative to the segment's length than at layout time: - - - GLYPH - z == layout-zoom, scale == 1: segmentAnchor *--------------^-------------* segmentEnd - z == layout-zoom - 1, scale == 0.5: segmentAnchor *--------------^* segmentEnd - - <--------------> - Anchor-to-glyph distance stays visually fixed, - so it changes relative to the segment. -*/ -inline float getMinScaleForSegment(const float glyphDistanceFromAnchor, - const Point& segmentAnchor, - const Point& segmentEnd) { - const auto distanceFromAnchorToEnd = util::dist(segmentAnchor, segmentEnd); - return glyphDistanceFromAnchor / distanceFromAnchorToEnd; -} - -inline Point getSegmentEnd(const bool glyphIsLogicallyForward, - const GeometryCoordinates& line, - const size_t segmentIndex) { - return convertPoint(glyphIsLogicallyForward ? line[segmentIndex+1] : line[segmentIndex]); -} - -optional getNextVirtualSegment(const VirtualSegment& previousVirtualSegment, - const GeometryCoordinates& line, - const float glyphDistanceFromAnchor, - const bool glyphIsLogicallyForward) { - auto nextSegmentBegin = previousVirtualSegment.end; - - auto end = nextSegmentBegin; - size_t index = previousVirtualSegment.index; - - // skip duplicate nodes - while (end == nextSegmentBegin) { - // look ahead by 2 points in the line because the segment index refers to the beginning - // of the segment, and we need an endpoint too - if (glyphIsLogicallyForward && (index + 2 < line.size())) { - index += 1; - } else if (!glyphIsLogicallyForward && index != 0) { - index -= 1; - } else { - return {}; - } - - end = getSegmentEnd(glyphIsLogicallyForward, line, index); - } - - const auto anchor = getVirtualSegmentAnchor(nextSegmentBegin, end, - util::dist(previousVirtualSegment.anchor, - previousVirtualSegment.end)); - return VirtualSegment { - anchor, - end, - index, - getMinScaleForSegment(glyphDistanceFromAnchor, anchor, end), - previousVirtualSegment.minScale - }; -} - -/* - Given (1) a glyph positioned relative to an anchor point and (2) a line to follow, - calculates which segment of the line the glyph will fall on for each possible - scale range, and for each range produces a "virtual" anchor point and an angle that will - place the glyph on the right segment and rotated to the correct angle. - - Because one glyph quad is made ahead of time for each possible orientation, the - symbol_sdf shader can quickly handle changing layout as we zoom in and out - - If the "keepUpright" property is set, we call getLineGlyphs twice (once upright and - once "upside down"). This will generate two sets of glyphs following the line in opposite - directions. Later, SymbolLayout::place will look at the glyphs and based on the placement - angle determine if their original anchor was "upright" or not -- based on that, it throws - away one set of glyphs or the other (this work has to be done in the CPU, but it's just a - filter so it's fast) - */ -void getLineGlyphs(std::back_insert_iterator glyphs, - Anchor& anchor, - float glyphHorizontalOffsetFromAnchor, - const GeometryCoordinates& line, - size_t anchorSegment, - bool upsideDown) { - assert(line.size() > anchorSegment+1); - - // This is true if the glyph is "logically forward" of the anchor point, based on the ordering of line segments - // The actual angle of the line is irrelevant - // If "upsideDown" is set, everything is flipped - const bool glyphIsLogicallyForward = (glyphHorizontalOffsetFromAnchor >= 0) ^ upsideDown; - const float glyphDistanceFromAnchor = std::fabs(glyphHorizontalOffsetFromAnchor); - - const auto initialSegmentEnd = getSegmentEnd(glyphIsLogicallyForward, line, anchorSegment); - VirtualSegment virtualSegment = { - anchor.point, - initialSegmentEnd, - anchorSegment, - getMinScaleForSegment(glyphDistanceFromAnchor, anchor.point, initialSegmentEnd), - std::numeric_limits::infinity() - }; - - while (true) { - insertSegmentGlyph(glyphs, - virtualSegment, - glyphIsLogicallyForward, - upsideDown); - - if (virtualSegment.minScale <= anchor.scale) { - // No need to calculate below the scale where the label starts showing - return; - } - - optional nextVirtualSegment = getNextVirtualSegment(virtualSegment, - line, - glyphDistanceFromAnchor, - glyphIsLogicallyForward); - if (!nextVirtualSegment) { - // There are no more segments, so we can't fit this glyph on the line at a lower scale - // This implies we can't show the label at all at lower scale, so we update the anchor's min scale - anchor.scale = virtualSegment.minScale; - return; - } else { - virtualSegment = *nextVirtualSegment; - } - } - + return SymbolQuad { tl, tr, bl, br, textureRect, shapedText.writingMode, { 0.0f, 0.0f } }; } -SymbolQuads getGlyphQuads(Anchor& anchor, - const Shaping& shapedText, - const float boxScale, - const GeometryCoordinates& line, +SymbolQuads getGlyphQuads(const Shaping& shapedText, const SymbolLayoutProperties::Evaluated& layout, const style::SymbolPlacementType placement, const GlyphPositionMap& positions) { const float textRotate = layout.get() * util::DEG2RAD; - const bool keepUpright = layout.get(); + + const float oneEm = 24.0; + std::array textOffset = layout.get(); + textOffset[0] *= oneEm; + textOffset[1] *= oneEm; SymbolQuads quads; @@ -320,67 +111,55 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const GlyphPosition& glyph = positionsIt->second; const Rect& rect = glyph.rect; - const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale; - - GlyphInstances glyphInstances; - if (placement == style::SymbolPlacementType::Line) { - getLineGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, false); - if (keepUpright) - getLineGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, true); - } else { - glyphInstances.emplace_back(GlyphInstance{anchor.point}); - } // The rects have an addditional buffer that is not included in their size; const float glyphPadding = 1.0f; const float rectBuffer = 3.0f + glyphPadding; - const float x1 = positionedGlyph.x + glyph.metrics.left - rectBuffer; - const float y1 = positionedGlyph.y - glyph.metrics.top - rectBuffer; + const float halfAdvance = glyph.metrics.advance / 2.0; + const bool alongLine = layout.get() == AlignmentType::Map && placement == SymbolPlacementType::Line; + + const Point glyphOffset = alongLine ? + Point{ positionedGlyph.x + halfAdvance, positionedGlyph.y } : + Point{ 0.0f, 0.0f }; + + const Point builtInOffset = alongLine ? + Point{ 0.0f, 0.0f } : + Point{ positionedGlyph.x + halfAdvance + textOffset[0], positionedGlyph.y + textOffset[1] }; + + + const float x1 = glyph.metrics.left - rectBuffer - halfAdvance + builtInOffset.x; + const float y1 = -glyph.metrics.top - rectBuffer + builtInOffset.y; const float x2 = x1 + rect.w; const float y2 = y1 + rect.h; - const Point center{positionedGlyph.x, static_cast(static_cast(glyph.metrics.advance) / 2.0)}; + const Point center{builtInOffset.x - halfAdvance, static_cast(static_cast(glyph.metrics.advance) / 2.0)}; - Point otl{x1, y1}; - Point otr{x2, y1}; - Point obl{x1, y2}; - Point obr{x2, y2}; + Point tl{x1, y1}; + Point tr{x2, y1}; + Point bl{x1, y2}; + Point br{x2, y2}; if (positionedGlyph.angle != 0) { - otl = util::rotate(otl - center, positionedGlyph.angle) + center; - otr = util::rotate(otr - center, positionedGlyph.angle) + center; - obl = util::rotate(obl - center, positionedGlyph.angle) + center; - obr = util::rotate(obr - center, positionedGlyph.angle) + center; + tl = util::rotate(tl - center, positionedGlyph.angle) + center; + tr = util::rotate(tr - center, positionedGlyph.angle) + center; + bl = util::rotate(bl - center, positionedGlyph.angle) + center; + br = util::rotate(br - center, positionedGlyph.angle) + center; } - for (const GlyphInstance &instance : glyphInstances) { - Point tl = otl; - Point tr = otr; - Point bl = obl; - Point br = obr; + if (textRotate) { + // Compute the transformation matrix. + float angle_sin = std::sin(textRotate); + float angle_cos = std::cos(textRotate); + std::array matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; - if (textRotate) { - // Compute the transformation matrix. - float angle_sin = std::sin(textRotate); - float angle_cos = std::cos(textRotate); - std::array matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; - - tl = util::matrixMultiply(matrix, tl); - tr = util::matrixMultiply(matrix, tr); - bl = util::matrixMultiply(matrix, bl); - br = util::matrixMultiply(matrix, br); - } - - // Prevent label from extending past the end of the line - const float glyphMinScale = std::max(instance.minScale, anchor.scale); - - // All the glyphs for a label are tagged with either the "right side up" or "upside down" anchor angle, - // which is used at placement time to determine which set to show - const float anchorAngle = std::fmod((anchor.angle + (instance.upsideDown ? M_PI : 0.0) + 2 * M_PI), (2 * M_PI)); - const float glyphAngle = std::fmod((instance.angle + (instance.upsideDown ? M_PI : 0.0) + 2 * M_PI), (2 * M_PI)); - quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale, shapedText.writingMode); + tl = util::matrixMultiply(matrix, tl); + tr = util::matrixMultiply(matrix, tr); + bl = util::matrixMultiply(matrix, bl); + br = util::matrixMultiply(matrix, br); } + + quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset); } return quads; diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index b29f6b0ad3..33d003c935 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -19,50 +19,33 @@ public: Point bl_, Point br_, Rect tex_, - float anchorAngle_, - float glyphAngle_, - Point anchorPoint_, - float minScale_, - float maxScale_, - WritingModeType writingMode_) + WritingModeType writingMode_, + Point glyphOffset_) : tl(std::move(tl_)), tr(std::move(tr_)), bl(std::move(bl_)), br(std::move(br_)), tex(std::move(tex_)), - anchorAngle(anchorAngle_), - glyphAngle(glyphAngle_), - anchorPoint(std::move(anchorPoint_)), - minScale(minScale_), - maxScale(maxScale_), - writingMode(writingMode_) {} + writingMode(writingMode_), + glyphOffset(glyphOffset_) {} Point tl; Point tr; Point bl; Point br; Rect tex; - float anchorAngle, glyphAngle; - Point anchorPoint; - float minScale; - float maxScale; WritingModeType writingMode; + Point glyphOffset; }; using SymbolQuads = std::vector; -SymbolQuad getIconQuad(const Anchor& anchor, - const PositionedIcon& shapedIcon, - const GeometryCoordinates& line, +SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, const style::SymbolLayoutProperties::Evaluated&, const float layoutTextSize, - style::SymbolPlacementType placement, const Shaping& shapedText); -SymbolQuads getGlyphQuads(Anchor& anchor, - const Shaping& shapedText, - const float boxScale, - const GeometryCoordinates& line, +SymbolQuads getGlyphQuads(const Shaping& shapedText, const style::SymbolLayoutProperties::Evaluated&, style::SymbolPlacementType placement, const GlyphPositionMap& positions); diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 338abe2e43..c81f25d4eb 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -27,12 +27,9 @@ void align(Shaping& shaping, const float verticalAlign, const float maxLineLength, const float lineHeight, - const std::size_t lineCount, - const Point& translate) { - const float shiftX = - (justify - horizontalAlign) * maxLineLength + ::round(translate.x); - const float shiftY = - (-verticalAlign * lineCount + 0.5) * lineHeight + ::round(translate.y); + const std::size_t lineCount) { + const float shiftX = (justify - horizontalAlign) * maxLineLength; + const float shiftY = (-verticalAlign * lineCount + 0.5) * lineHeight; for (auto& glyph : shaping.positionedGlyphs) { glyph.x += shiftX; @@ -205,7 +202,6 @@ void shapeLines(Shaping& shaping, const float horizontalAlign, const float verticalAlign, const float justify, - const Point& translate, const float verticalHeight, const WritingModeType writingMode, const Glyphs& glyphs) { @@ -259,7 +255,7 @@ void shapeLines(Shaping& shaping, } align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, - lines.size(), translate); + lines.size()); const uint32_t height = lines.size() * lineHeight; // Calculate the bounding box @@ -288,7 +284,7 @@ const Shaping getShaping(const std::u16string& logicalInput, determineLineBreaks(logicalInput, spacing, maxWidth, writingMode, glyphs)); shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign, - justify, translate, verticalHeight, writingMode, glyphs); + justify, verticalHeight, writingMode, glyphs); return shaping; } -- cgit v1.2.1 From d661b4ba61a7bd7770c96464c190bfadf9a42414 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 Jun 2017 15:38:43 -0400 Subject: [core] port pitch-label collision hack https://github.com/mapbox/mapbox-gl-js/pull/4781/commits/81363951ed56c54f331ffc8d88e4e5079226a224 --- src/mbgl/text/collision_feature.cpp | 30 +++++++++++++++++++++++++----- src/mbgl/text/collision_feature.hpp | 9 +++++++-- src/mbgl/text/collision_tile.cpp | 29 +++++++++++++++++------------ src/mbgl/text/collision_tile.hpp | 2 +- 4 files changed, 50 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp index 58a7949a8e..022ee50644 100644 --- a/src/mbgl/text/collision_feature.cpp +++ b/src/mbgl/text/collision_feature.cpp @@ -42,7 +42,7 @@ CollisionFeature::CollisionFeature(const GeometryCoordinates& line, bboxifyLabel(line, anchorPoint, anchor.segment, length, height); } } else { - boxes.emplace_back(anchor.point, x1, y1, x2, y2, std::numeric_limits::infinity()); + boxes.emplace_back(anchor.point, Point{ 0, 0 }, x1, y1, x2, y2, std::numeric_limits::infinity()); } } @@ -50,10 +50,10 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo const int segment, const float labelLength, const float boxSize) { const float step = boxSize / 2; const int nBoxes = std::floor(labelLength / step); - // We calculate line collision boxes out to 150% of what would normally be our + // We calculate line collision boxes out to 300% of what would normally be our // max size, to allow collision detection to work on labels that expand as // they move into the distance - const int nPitchPaddingBoxes = std::floor(nBoxes / 4); + const int nPitchPaddingBoxes = std::floor(nBoxes / 2); // offset the center of the first box by half a box so that the edge of the // box is at the edge of the label. @@ -90,7 +90,13 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo for (int i = -nPitchPaddingBoxes; i < nBoxes + nPitchPaddingBoxes; i++) { // the distance the box will be from the anchor - const float boxDistanceToAnchor = labelStartDistance + i * step; + const float boxOffset = i * step; + float boxDistanceToAnchor = labelStartDistance + boxOffset; + + // make the distance between pitch padding boxes bigger + if (boxOffset < 0) boxDistanceToAnchor += boxOffset; + if (boxOffset > labelLength) boxDistanceToAnchor += boxOffset - labelLength; + if (boxDistanceToAnchor < anchorDistance) { // The line doesn't extend far enough back for this box, skip it // (This could allow for line collisions on distant tiles) @@ -143,8 +149,22 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo maxScale = std::min(maxScale, 0.99f); } - boxes.emplace_back(boxAnchor, -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale); + boxes.emplace_back(boxAnchor, boxAnchor - convertPoint(anchorPoint), -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale); } } +float CollisionBox::adjustedMaxScale(const std::array& rotationMatrix, const float yStretch) const { + // When the map is pitched the distance covered by a line changes. + // Adjust the max scale by (approximatePitchedLength / approximateRegularLength) + // to compensate for this. + const Point rotatedOffset = util::matrixMultiply(rotationMatrix, offset); + const float xSqr = rotatedOffset.x * rotatedOffset.x; + const float ySqr = rotatedOffset.y * rotatedOffset.y; + const float yStretchSqr = ySqr * yStretch * yStretch; + const float adjustmentFactor = xSqr + ySqr != 0 ? + std::sqrt((xSqr + yStretchSqr) / (xSqr + ySqr)) : + 1.0f; + return maxScale * adjustmentFactor; +} + } // namespace mbgl diff --git a/src/mbgl/text/collision_feature.hpp b/src/mbgl/text/collision_feature.hpp index c94ec23513..3b6e461a26 100644 --- a/src/mbgl/text/collision_feature.hpp +++ b/src/mbgl/text/collision_feature.hpp @@ -11,11 +11,16 @@ namespace mbgl { class CollisionBox { public: - CollisionBox(Point _anchor, float _x1, float _y1, float _x2, float _y2, float _maxScale) : - anchor(std::move(_anchor)), x1(_x1), y1(_y1), x2(_x2), y2(_y2), maxScale(_maxScale) {} + CollisionBox(Point _anchor, Point _offset, float _x1, float _y1, float _x2, float _y2, float _maxScale) : + anchor(std::move(_anchor)), offset(_offset), x1(_x1), y1(_y1), x2(_x2), y2(_y2), maxScale(_maxScale) {} + + float adjustedMaxScale(const std::array& rotationMatrix, const float yStretch) const; // the box is centered around the anchor point Point anchor; + + // the offset of the box from the label's anchor point + Point offset; // distances to the edges from the anchor float x1; diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp index 520f66ead8..b3fbe6f8a3 100644 --- a/src/mbgl/text/collision_tile.cpp +++ b/src/mbgl/text/collision_tile.cpp @@ -34,7 +34,7 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ } -float CollisionTile::findPlacementScale(const Point& anchor, const CollisionBox& box, const Point& blockingAnchor, const CollisionBox& blocking) { +float CollisionTile::findPlacementScale(const Point& anchor, const CollisionBox& box, const float boxMaxScale, const Point& blockingAnchor, const CollisionBox& blocking) { float minPlacementScale = minScale; // Find the lowest scale at which the two boxes can fit side by side without overlapping. @@ -55,10 +55,10 @@ float CollisionTile::findPlacementScale(const Point& anchor, const Collis collisionFreeScale = blocking.maxScale; } - if (collisionFreeScale > box.maxScale) { + if (collisionFreeScale > boxMaxScale) { // If the box can only be shown after it is visible, then the box can never be shown. // But the label can be shown after this box is not visible. - collisionFreeScale = box.maxScale; + collisionFreeScale = boxMaxScale; } if (collisionFreeScale > minPlacementScale && @@ -77,13 +77,13 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, bool allowOve static const float infinity = std::numeric_limits::infinity(); static const std::array edges {{ // left - CollisionBox(Point(0, 0), 0, -infinity, 0, infinity, infinity), + CollisionBox(Point(0, 0), { 0, 0 }, 0, -infinity, 0, infinity, infinity), // right - CollisionBox(Point(util::EXTENT, 0), 0, -infinity, 0, infinity, infinity), + CollisionBox(Point(util::EXTENT, 0), { 0, 0 }, 0, -infinity, 0, infinity, infinity), // top - CollisionBox(Point(0, 0), -infinity, 0, infinity, 0, infinity), + CollisionBox(Point(0, 0), { 0, 0 }, -infinity, 0, infinity, 0, infinity), // bottom - CollisionBox(Point(0, util::EXTENT), -infinity, 0, infinity, 0, infinity) + CollisionBox(Point(0, util::EXTENT), { 0, 0 }, -infinity, 0, infinity, 0, infinity) }}; float minPlacementScale = minScale; @@ -91,12 +91,14 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, bool allowOve for (auto& box : feature.boxes) { const auto anchor = util::matrixMultiply(rotationMatrix, box.anchor); + const float boxMaxScale = box.adjustedMaxScale(rotationMatrix, yStretch); + if (!allowOverlap) { for (auto it = tree.qbegin(bgi::intersects(getTreeBox(anchor, box))); it != tree.qend(); ++it) { const CollisionBox& blocking = std::get<1>(*it); Point blockingAnchor = util::matrixMultiply(rotationMatrix, blocking.anchor); - minPlacementScale = util::max(minPlacementScale, findPlacementScale(anchor, box, blockingAnchor, blocking)); + minPlacementScale = util::max(minPlacementScale, findPlacementScale(anchor, box, boxMaxScale, blockingAnchor, blocking)); if (minPlacementScale >= maxScale) return minPlacementScale; } } @@ -107,14 +109,15 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, bool allowOve const Point rbl = util::matrixMultiply(reverseRotationMatrix, { box.x1, box.y2 }); const Point rbr = util::matrixMultiply(reverseRotationMatrix, { box.x2, box.y2 }); CollisionBox rotatedBox(box.anchor, + box.offset, util::min(rtl.x, rtr.x, rbl.x, rbr.x), util::min(rtl.y, rtr.y, rbl.y, rbr.y), util::max(rtl.x, rtr.x, rbl.x, rbr.x), util::max(rtl.y, rtr.y, rbl.y, rbr.y), - box.maxScale); + boxMaxScale); for (auto& blocking : edges) { - minPlacementScale = util::max(minPlacementScale, findPlacementScale(box.anchor, rotatedBox, blocking.anchor, blocking)); + minPlacementScale = util::max(minPlacementScale, findPlacementScale(box.anchor, rotatedBox, boxMaxScale, blocking.anchor, blocking)); if (minPlacementScale >= maxScale) return minPlacementScale; } } @@ -131,7 +134,9 @@ void CollisionTile::insertFeature(CollisionFeature& feature, float minPlacementS if (minPlacementScale < maxScale) { std::vector treeBoxes; for (auto& box : feature.boxes) { - treeBoxes.emplace_back(getTreeBox(util::matrixMultiply(rotationMatrix, box.anchor), box), box, feature.indexedFeature); + CollisionBox adjustedBox = box; + box.maxScale = box.adjustedMaxScale(rotationMatrix, yStretch); + treeBoxes.emplace_back(getTreeBox(util::matrixMultiply(rotationMatrix, box.anchor), box), std::move(adjustedBox), feature.indexedFeature); } if (ignorePlacement) { ignoredTree.insert(treeBoxes.begin(), treeBoxes.end()); @@ -215,7 +220,7 @@ std::vector CollisionTile::queryRenderedSymbols(const Geometr // Check if feature is rendered (collision free) at current scale. auto visibleAtScale = [&] (const CollisionTreeBox& treeBox) -> bool { const CollisionBox& box = std::get<1>(treeBox); - return roundedScale >= box.placementScale && roundedScale <= box.maxScale; + return roundedScale >= box.placementScale && roundedScale <= box.adjustedMaxScale(rotationMatrix, yStretch); }; // Check if query polygon intersects with the feature box at current scale. diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp index dbff6a007b..9868266aa2 100644 --- a/src/mbgl/text/collision_tile.hpp +++ b/src/mbgl/text/collision_tile.hpp @@ -58,7 +58,7 @@ public: private: float findPlacementScale( - const Point& anchor, const CollisionBox& box, + const Point& anchor, const CollisionBox& box, const float boxMaxScale, const Point& blockingAnchor, const CollisionBox& blocking); Box getTreeBox(const Point& anchor, const CollisionBox& box, const float scale = 1.0); -- cgit v1.2.1 From eac297185da7c34c69c5265b6cb8c193d5537e61 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 7 Jul 2017 10:45:34 -0400 Subject: [core] add static asserts for more gl constants and rename BufferUsageType to BufferUsage --- src/mbgl/gl/context.cpp | 49 ++++++++++++++++++++++++++++- src/mbgl/gl/context.hpp | 4 +-- src/mbgl/gl/types.hpp | 2 +- src/mbgl/renderer/buckets/symbol_bucket.cpp | 4 +-- 4 files changed, 53 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 3508b92a79..86ca9c0607 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -16,6 +16,31 @@ namespace gl { static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch"); static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Byte) == GL_BYTE, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Short) == GL_SHORT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedShort) == GL_UNSIGNED_SHORT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Integer) == GL_INT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedInteger) == GL_UNSIGNED_INT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Float) == GL_FLOAT, "OpenGL type mismatch"); + +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8_OES, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8_OES, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT16, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 + + static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch"); static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch"); static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch"); @@ -36,6 +61,28 @@ static_assert(std::is_same, GLenum>::value static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec4) == GL_FLOAT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Int) == GL_INT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec2) == GL_INT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec3) == GL_INT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec4) == GL_INT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Bool) == GL_BOOL, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec2) == GL_BOOL_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec3) == GL_BOOL_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec4) == GL_BOOL_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat2) == GL_FLOAT_MAT2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat3) == GL_FLOAT_MAT3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch"); + +static_assert(underlying_type(BufferUsage::StreamDraw) == GL_STREAM_DRAW, "OpenGL type mismatch"); +static_assert(underlying_type(BufferUsage::StaticDraw) == GL_STATIC_DRAW, "OpenGL type mismatch"); +static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "OpenGL type mismatch"); + static_assert(std::is_same::value, "OpenGL type mismatch"); Context::Context() = default; @@ -164,7 +211,7 @@ void Context::verifyProgramLinkage(ProgramID program_) { throw std::runtime_error("program failed to link"); } -UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsageType usage) { +UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index f1f0ac7f8a..2e594618d2 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -65,7 +65,7 @@ public: optional> getBinaryProgram(ProgramID) const; template - VertexBuffer createVertexBuffer(VertexVector&& v, const BufferUsageType usage=BufferUsageType::StaticDraw) { + VertexBuffer createVertexBuffer(VertexVector&& v, const BufferUsage usage=BufferUsage::StaticDraw) { return VertexBuffer { v.vertexSize(), createVertexBuffer(v.data(), v.byteSize(), usage) @@ -245,7 +245,7 @@ private: State pointSize; #endif // MBGL_USE_GLES2 - UniqueBuffer createVertexBuffer(const void* data, std::size_t size, const BufferUsageType usage); + UniqueBuffer createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage); void updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit); diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 8997fcbf31..1fce878c6f 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -96,7 +96,7 @@ enum class UniformDataType : uint32_t { SamplerCube = 0x8B60, }; -enum class BufferUsageType : uint32_t { +enum class BufferUsage : uint32_t { StreamDraw = 0x88E0, StaticDraw = 0x88E4, DynamicDraw = 0x88E8, diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 194a5d6bd8..1bd73e95dd 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -38,13 +38,13 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); - text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsageType::StreamDraw); + text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); } if (hasIconData()) { icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); - icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsageType::StreamDraw); + icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); } -- cgit v1.2.1 From 3b49ec3a0b4bab40ddb9a2a9789e787089870c93 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sat, 6 Aug 2016 00:50:34 +0300 Subject: [core] Prefer std:: functions over POSIX s/unlink/std::remove --- src/mbgl/util/io.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp index 9adc3b8988..6a6ed7b250 100644 --- a/src/mbgl/util/io.cpp +++ b/src/mbgl/util/io.cpp @@ -6,8 +6,6 @@ #include #include -#include - namespace mbgl { namespace util { @@ -43,8 +41,8 @@ optional readFile(const std::string &filename) { } void deleteFile(const std::string& filename) { - const int ret = unlink(filename.c_str()); - if (ret == -1) { + const int ret = std::remove(filename.c_str()); + if (ret != 0) { throw IOException(errno, "failed to unlink file"); } } -- cgit v1.2.1 From 0d7d3d895955dcf6f852b8eba8b146f7dddad529 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sat, 6 Aug 2016 01:15:50 +0300 Subject: [core] Use std::to_string on Windows Clang on Window's can't parse rapidjson's dtoa. --- src/mbgl/util/dtoa.cpp | 14 ++++++++++++++ src/mbgl/util/dtoa.hpp | 1 - 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/util/dtoa.cpp b/src/mbgl/util/dtoa.cpp index dd4fba0f89..6ca3e19c3d 100644 --- a/src/mbgl/util/dtoa.cpp +++ b/src/mbgl/util/dtoa.cpp @@ -1,10 +1,16 @@ #include "dtoa.hpp" +// Clang/C2 on Windows 64-bits can't parse rapidjson's dtoa +// and it was causing the compiler to crash. +#if !defined(_WINDOWS) #include +#endif namespace mbgl { namespace util { +#if !defined(_WINDOWS) + namespace { // From https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h @@ -101,5 +107,13 @@ std::string dtoa(double value) { return data; } +#else + +std::string dtoa(double value) { + return std::to_string(value); +} + +#endif + } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/dtoa.hpp b/src/mbgl/util/dtoa.hpp index db7d309452..4cb81a94be 100644 --- a/src/mbgl/util/dtoa.hpp +++ b/src/mbgl/util/dtoa.hpp @@ -5,7 +5,6 @@ namespace mbgl { namespace util { -char* dtoa(double value, char* buffer); std::string dtoa(double value); } // end namespace util -- cgit v1.2.1 From 70e557a6f853f93f8ddab590b95196b2d0584a13 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sat, 6 Aug 2016 01:34:20 +0300 Subject: [core] Use gmtime_s on Windows gmtime_r is POSIX --- src/mbgl/util/chrono.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp index 5c8fd3c0ff..a880093b74 100644 --- a/src/mbgl/util/chrono.cpp +++ b/src/mbgl/util/chrono.cpp @@ -3,6 +3,13 @@ #include #include +#include + +#if defined(_WINDOWS) +#define _gmtime(t, i) gmtime_s(i, t) +#else +#define _gmtime(t, i) gmtime_r(t, i) +#endif namespace mbgl { namespace util { @@ -14,7 +21,7 @@ static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", std::string rfc1123(Timestamp timestamp) { std::time_t time = std::chrono::system_clock::to_time_t(timestamp); std::tm info; - gmtime_r(&time, &info); + _gmtime(&time, &info); char buffer[30]; snprintf(buffer, 30, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[info.tm_wday], info.tm_mday, months[info.tm_mon], 1900 + info.tm_year, info.tm_hour, info.tm_min, info.tm_sec); @@ -24,7 +31,7 @@ std::string rfc1123(Timestamp timestamp) { std::string iso8601(Timestamp timestamp) { std::time_t time = std::chrono::system_clock::to_time_t(timestamp); std::tm info; - gmtime_r(&time, &info); + _gmtime(&time, &info); char buffer[30]; std::strftime(buffer, sizeof(buffer), "%F %T", &info); return buffer; -- cgit v1.2.1 From f1ac757bd28351fd57113a1e16f6c2e00ab193c1 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 15:11:14 +0300 Subject: [core] GCC 4.9 does not fully support custom variable templates --- src/mbgl/gl/attribute.cpp | 20 +++++++++++--------- src/mbgl/gl/attribute.hpp | 5 +---- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index 4e6f78e689..4569e3cb32 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -55,14 +55,16 @@ void DisabledAttribute::bind(Context&, AttributeLocation location, std::size_t) MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); } -template DataType DataTypeOf = static_cast(0); -template <> DataType DataTypeOf< int8_t> = DataType::Byte; -template <> DataType DataTypeOf = DataType::UnsignedByte; -template <> DataType DataTypeOf< int16_t> = DataType::Short; -template <> DataType DataTypeOf = DataType::UnsignedShort; -template <> DataType DataTypeOf< int32_t> = DataType::Integer; -template <> DataType DataTypeOf = DataType::UnsignedInteger; -template <> DataType DataTypeOf = DataType::Float; +template +constexpr DataType DataTypeOf() { + return std::is_same::value ? DataType::Byte : + std::is_same::value ? DataType::UnsignedByte : + std::is_same::value ? DataType::Short : + std::is_same::value ? DataType::UnsignedShort : + std::is_same::value ? DataType::Integer : + std::is_same::value ? DataType::UnsignedInteger : + std::is_same::value ? DataType::Float : static_cast(0); +} template void AttributeBinding::bind(Context& context, AttributeLocation location, std::size_t vertexOffset) const { @@ -76,7 +78,7 @@ void AttributeBinding::bind(Context& context, AttributeLocation location, MBGL_CHECK_ERROR(glVertexAttribPointer( location, static_cast(attributeSize), - static_cast(DataTypeOf), + static_cast(DataTypeOf()), static_cast(false), static_cast(vertexSize), reinterpret_cast(attributeOffset + (vertexSize * vertexOffset)))); diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index f018a1d261..bc02b54bd2 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -240,9 +240,6 @@ public: using Vertex = detail::Vertex; - template - static constexpr std::size_t Index = TypeIndex::value; - static Locations bindLocations(const ProgramID& id) { std::set activeAttributes = getActiveAttributes(id); @@ -266,7 +263,7 @@ public: template static Bindings bindings(const VertexBuffer& buffer) { - return Bindings { As::Type::binding(buffer, Index)... }; + return Bindings { As::Type::binding(buffer, TypeIndex::value)... }; } static void bind(Context& context, -- cgit v1.2.1 From 3afbfa2de74d26f1d9099a85cc1b6ed70251666f Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 15:16:06 +0300 Subject: [core] GCC 4.9 shadow member warnings --- src/mbgl/renderer/possibly_evaluated_property_value.hpp | 2 +- src/mbgl/tile/geometry_tile.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index 8a5dfbe4ea..e662d5dfb1 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -45,7 +45,7 @@ public: template T evaluate(const Feature& feature, float zoom, T defaultValue) const { return this->match( - [&] (const T& constant) { return constant; }, + [&] (const T& constant_) { return constant_; }, [&] (const style::SourceFunction& function) { return function.evaluate(feature, defaultValue); }, diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 1ee303b50f..4f1bc9e759 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -174,18 +174,18 @@ void GeometryTile::getImages(ImageDependencies imageDependencies) { } void GeometryTile::upload(gl::Context& context) { - auto upload = [&] (Bucket& bucket) { + auto uploadFn = [&] (Bucket& bucket) { if (bucket.needsUpload()) { bucket.upload(context); } }; for (auto& entry : nonSymbolBuckets) { - upload(*entry.second); + uploadFn(*entry.second); } for (auto& entry : symbolBuckets) { - upload(*entry.second); + uploadFn(*entry.second); } if (glyphAtlasImage) { -- cgit v1.2.1 From 6282b28b6fe218390b843a8a71bb5cc2b63dd05c Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 15:32:51 +0300 Subject: [core] Added MBGL_CONSTEXPR to satisfy GCC 4.9 --- src/mbgl/gl/gl.cpp | 3 ++- src/mbgl/map/update.hpp | 7 ++++--- src/mbgl/renderer/render_pass.hpp | 7 ++++--- src/mbgl/text/glyph.hpp | 11 ++++++----- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/gl.cpp b/src/mbgl/gl/gl.cpp index 8999468dbd..bd6d7b192d 100644 --- a/src/mbgl/gl/gl.cpp +++ b/src/mbgl/gl/gl.cpp @@ -1,12 +1,13 @@ #include #include +#include namespace mbgl { namespace gl { namespace { -constexpr const char* stringFromError(GLenum err) { +MBGL_CONSTEXPR const char* stringFromError(GLenum err) { switch (err) { case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp index 82d98284f5..ab8b10c651 100644 --- a/src/mbgl/map/update.hpp +++ b/src/mbgl/map/update.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace mbgl { @@ -11,15 +12,15 @@ enum class Update { AnnotationData = 1 << 7 }; -constexpr Update operator|(Update lhs, Update rhs) { +MBGL_CONSTEXPR Update operator|(Update lhs, Update rhs) { return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs)); } -constexpr Update& operator|=(Update& lhs, const Update& rhs) { +MBGL_CONSTEXPR Update& operator|=(Update& lhs, const Update& rhs) { return (lhs = lhs | rhs); } -constexpr bool operator& (Update lhs, Update rhs) { +MBGL_CONSTEXPR bool operator& (Update lhs, Update rhs) { return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); } diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp index d273e34ff7..ae2b923ba1 100644 --- a/src/mbgl/renderer/render_pass.hpp +++ b/src/mbgl/renderer/render_pass.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -12,15 +13,15 @@ enum class RenderPass : uint8_t { Translucent = 1 << 1, }; -constexpr RenderPass operator|(RenderPass a, RenderPass b) { +MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) { return RenderPass(mbgl::underlying_type(a) | mbgl::underlying_type(b)); } -constexpr RenderPass& operator|=(RenderPass& a, RenderPass b) { +MBGL_CONSTEXPR RenderPass& operator|=(RenderPass& a, RenderPass b) { return (a = a | b); } -constexpr RenderPass operator&(RenderPass a, RenderPass b) { +MBGL_CONSTEXPR RenderPass operator&(RenderPass a, RenderPass b) { return RenderPass(mbgl::underlying_type(a) & mbgl::underlying_type(b)); } diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index b9eaedd302..19ecdfd17c 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -89,23 +90,23 @@ enum class WritingModeType : uint8_t { Vertical = 1 << 1, }; -constexpr WritingModeType operator|(WritingModeType a, WritingModeType b) { +MBGL_CONSTEXPR WritingModeType operator|(WritingModeType a, WritingModeType b) { return WritingModeType(mbgl::underlying_type(a) | mbgl::underlying_type(b)); } -constexpr WritingModeType& operator|=(WritingModeType& a, WritingModeType b) { +MBGL_CONSTEXPR WritingModeType& operator|=(WritingModeType& a, WritingModeType b) { return (a = a | b); } -constexpr bool operator&(WritingModeType lhs, WritingModeType rhs) { +MBGL_CONSTEXPR bool operator&(WritingModeType lhs, WritingModeType rhs) { return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); } -constexpr WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) { +MBGL_CONSTEXPR WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) { return (lhs = WritingModeType(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs))); } -constexpr WritingModeType operator~(WritingModeType value) { +MBGL_CONSTEXPR WritingModeType operator~(WritingModeType value) { return WritingModeType(~mbgl::underlying_type(value)); } -- cgit v1.2.1 From 21031b624ffabf92bf284c830b3d13a3ae045460 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 16:34:34 +0300 Subject: [core] Added missing header includes --- src/mbgl/programs/binary_program.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/mbgl/programs/binary_program.cpp b/src/mbgl/programs/binary_program.cpp index 09b9acc514..57f2cc0d2c 100644 --- a/src/mbgl/programs/binary_program.cpp +++ b/src/mbgl/programs/binary_program.cpp @@ -3,6 +3,7 @@ #include #include #include +#include template static std::pair parseBinding(protozero::pbf_reader&& pbf) { -- cgit v1.2.1 From 2fae373fc9da1a5ed61b5114d8c982073734826d Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 19:15:10 +0300 Subject: [core] GCC 4.9 is unable to deduce ctors when using bracket init --- src/mbgl/gl/texture.hpp | 20 +++++++++++++++---- src/mbgl/renderer/tile_parameters.hpp | 27 ++++++++++++++++++++++--- src/mbgl/renderer/update_parameters.hpp | 35 ++++++++++++++++++++++++++++++++- src/mbgl/tile/geometry_tile.hpp | 24 ++++++++++++++++++++-- 4 files changed, 96 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp index 5330689ac2..625e69233a 100644 --- a/src/mbgl/gl/texture.hpp +++ b/src/mbgl/gl/texture.hpp @@ -8,12 +8,24 @@ namespace gl { class Texture { public: + Texture(Size size_, UniqueTexture texture_, + TextureFilter filter_ = TextureFilter::Nearest, + TextureMipMap mipmap_ = TextureMipMap::No, + TextureWrap wrapX_ = TextureWrap::Clamp, + TextureWrap wrapY_ = TextureWrap::Clamp) + : size(std::move(size_)), + texture(std::move(texture_)), + filter(filter_), + mipmap(mipmap_), + wrapX(wrapX_), + wrapY(wrapY_) {} + Size size; UniqueTexture texture; - TextureFilter filter = TextureFilter::Nearest; - TextureMipMap mipmap = TextureMipMap::No; - TextureWrap wrapX = TextureWrap::Clamp; - TextureWrap wrapY = TextureWrap::Clamp; + TextureFilter filter; + TextureMipMap mipmap; + TextureWrap wrapX; + TextureWrap wrapY; }; } // namespace gl diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp index 9769ae6897..333f796331 100644 --- a/src/mbgl/renderer/tile_parameters.hpp +++ b/src/mbgl/renderer/tile_parameters.hpp @@ -13,8 +13,29 @@ class GlyphManager; class TileParameters { public: - float pixelRatio; - MapDebugOptions debugOptions; + TileParameters(const float pixelRatio_, + const MapDebugOptions debugOptions_, + const TransformState& transformState_, + Scheduler& workerScheduler_, + FileSource& fileSource_, + const MapMode mode_, + AnnotationManager& annotationManager_, + ImageManager& imageManager_, + GlyphManager& glyphManager_, + const uint8_t prefetchZoomDelta_) + : pixelRatio(pixelRatio_), + debugOptions(debugOptions_), + transformState(std::move(transformState_)), + workerScheduler(workerScheduler_), + fileSource(fileSource_), + mode(mode_), + annotationManager(annotationManager_), + imageManager(imageManager_), + glyphManager(glyphManager_), + prefetchZoomDelta(prefetchZoomDelta_) {} + + const float pixelRatio; + const MapDebugOptions debugOptions; const TransformState& transformState; Scheduler& workerScheduler; FileSource& fileSource; @@ -22,7 +43,7 @@ public: AnnotationManager& annotationManager; ImageManager& imageManager; GlyphManager& glyphManager; - const uint8_t prefetchZoomDelta = 0; + const uint8_t prefetchZoomDelta; }; } // namespace mbgl diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp index 8ebcd11e21..04b59699b3 100644 --- a/src/mbgl/renderer/update_parameters.hpp +++ b/src/mbgl/renderer/update_parameters.hpp @@ -16,6 +16,39 @@ class AnnotationManager; class UpdateParameters { public: + UpdateParameters(const MapMode mode_, + const float pixelRatio_, + const MapDebugOptions debugOptions_, + const TimePoint timePoint_, + const TransformState TransformState_, + const std::string glyphURL_, + const bool spriteLoaded_, + const style::TransitionOptions transitionOptions_, + const Immutable light_, + const Immutable>> images_, + const Immutable>> sources_, + const Immutable>> layers_, + Scheduler& scheduler_, + FileSource& fileSource_, + AnnotationManager& annotationManager_, + const uint8_t prefetchZoomDelta_) + : mode(mode_), + pixelRatio(pixelRatio_), + debugOptions(debugOptions_), + timePoint(std::move(timePoint_)), + transformState(std::move(TransformState_)), + glyphURL(std::move(glyphURL_)), + spriteLoaded(spriteLoaded_), + transitionOptions(std::move(transitionOptions_)), + light(std::move(light_)), + images(std::move(images_)), + sources(std::move(sources_)), + layers(std::move(layers_)), + scheduler(scheduler_), + fileSource(fileSource_), + annotationManager(annotationManager_), + prefetchZoomDelta(prefetchZoomDelta_) {} + const MapMode mode; const float pixelRatio; const MapDebugOptions debugOptions; @@ -34,7 +67,7 @@ public: FileSource& fileSource; AnnotationManager& annotationManager; - const uint8_t prefetchZoomDelta = 0; + const uint8_t prefetchZoomDelta; }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 943296e01b..c45762742b 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -5,9 +5,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -17,8 +19,6 @@ namespace mbgl { class GeometryTileData; -class FeatureIndex; -class CollisionTile; class RenderStyle; class RenderLayer; class SourceQueryOptions; @@ -71,6 +71,15 @@ public: std::unique_ptr featureIndex; std::unique_ptr tileData; uint64_t correlationID; + + LayoutResult(std::unordered_map> nonSymbolBuckets_, + std::unique_ptr featureIndex_, + std::unique_ptr tileData_, + uint64_t correlationID_) + : nonSymbolBuckets(std::move(nonSymbolBuckets_)), + featureIndex(std::move(featureIndex_)), + tileData(std::move(tileData_)), + correlationID(correlationID_) {} }; void onLayout(LayoutResult); @@ -81,6 +90,17 @@ public: optional glyphAtlasImage; optional iconAtlasImage; uint64_t correlationID; + + PlacementResult(std::unordered_map> symbolBuckets_, + std::unique_ptr collisionTile_, + optional glyphAtlasImage_, + optional iconAtlasImage_, + uint64_t correlationID_) + : symbolBuckets(std::move(symbolBuckets_)), + collisionTile(std::move(collisionTile_)), + glyphAtlasImage(std::move(glyphAtlasImage_)), + iconAtlasImage(std::move(iconAtlasImage_)), + correlationID(correlationID_) {} }; void onPlacement(PlacementResult); -- cgit v1.2.1 From 4014aa6721e53318e4ac92814776b3e01b4589cb Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 11 Jul 2017 19:19:04 +0300 Subject: [core] GCC 4.9 bracket initialization issues --- src/mbgl/annotation/fill_annotation_impl.cpp | 2 +- src/mbgl/annotation/line_annotation_impl.cpp | 2 +- src/mbgl/gl/uniform.hpp | 4 +++- src/mbgl/map/map.cpp | 2 +- src/mbgl/renderer/sources/render_image_source.cpp | 4 ++-- src/mbgl/renderer/sources/render_raster_source.cpp | 4 ++-- 6 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mbgl/annotation/fill_annotation_impl.cpp b/src/mbgl/annotation/fill_annotation_impl.cpp index 5dc36edab0..9c73aeb796 100644 --- a/src/mbgl/annotation/fill_annotation_impl.cpp +++ b/src/mbgl/annotation/fill_annotation_impl.cpp @@ -9,7 +9,7 @@ using namespace style; FillAnnotationImpl::FillAnnotationImpl(AnnotationID id_, FillAnnotation annotation_, uint8_t maxZoom_) : ShapeAnnotationImpl(id_, maxZoom_), - annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.color, annotation_.outlineColor }) { + annotation(ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.color, annotation_.outlineColor) { } void FillAnnotationImpl::updateStyle(Style::Impl& style) const { diff --git a/src/mbgl/annotation/line_annotation_impl.cpp b/src/mbgl/annotation/line_annotation_impl.cpp index 8954ecfa58..d35b956888 100644 --- a/src/mbgl/annotation/line_annotation_impl.cpp +++ b/src/mbgl/annotation/line_annotation_impl.cpp @@ -9,7 +9,7 @@ using namespace style; LineAnnotationImpl::LineAnnotationImpl(AnnotationID id_, LineAnnotation annotation_, uint8_t maxZoom_) : ShapeAnnotationImpl(id_, maxZoom_), - annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.width, annotation_.color }) { + annotation(ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.width, annotation_.color) { } void LineAnnotationImpl::updateStyle(Style::Impl& style) const { diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 829192bcca..4ed2419764 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -48,6 +48,8 @@ public: class State { public: + State(UniformLocation location_) : location(std::move(location_)) {} + void operator=(const Value& value) { if (location >= 0 && (!current || *current != value.t)) { current = value.t; @@ -106,7 +108,7 @@ public: template static State loadNamedLocations(const Program& program) { - return State{ { program.uniformLocation(Us::name()) }... }; + return State(typename Us::State(program.uniformLocation(Us::name()))...); } static NamedLocations getNamedLocations(const State& state) { diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 565d39c515..26795f7814 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -111,7 +111,7 @@ Map::Map(Backend& backend, GLContextMode contextMode, ConstrainMode constrainMode, ViewportMode viewportMode, - const optional& programCacheDir) + optional programCacheDir) : impl(std::make_unique(*this, backend, pixelRatio, diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index f5068b9d7f..6a3cb33fec 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -60,11 +60,11 @@ RenderImageSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, const RenderStyle&, const RenderedQueryOptions&) const { - return {}; + return std::unordered_map>(); } std::vector RenderImageSource::querySourceFeatures(const SourceQueryOptions&) const { - return {}; + return std::vector(); } void RenderImageSource::update(Immutable baseImpl_, diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index 2006e31628..6bf9caa1b4 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -73,11 +73,11 @@ RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, const RenderStyle&, const RenderedQueryOptions&) const { - return {}; + return std::unordered_map>(); } std::vector RenderRasterSource::querySourceFeatures(const SourceQueryOptions&) const { - return {}; + return std::vector(); } void RenderRasterSource::onLowMemory() { -- cgit v1.2.1 From 8ef9fcdf3ee9d1266771878205568944aedc7aa6 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 10 Jul 2017 15:41:17 -0700 Subject: [core] Base label "keep-upright" orientation on start and end of label Fixes issue #9457. --- src/mbgl/layout/symbol_projection.cpp | 94 ++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index 99555f7997..8ccd6a0410 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -144,6 +144,12 @@ namespace mbgl { Point point; float angle; }; + + enum PlacementResult { + OK, + NotEnoughRoom, + NeedsFlipping + }; optional placeGlyphAlongLine(const float offsetX, const float lineOffsetX, const float lineOffsetY, const bool flip, Point anchorPoint, const uint16_t anchorSegment, const GeometryCoordinates& line, const mat4& labelPlaneMatrix) { @@ -198,8 +204,14 @@ namespace mbgl { return {{ p, segmentAngle }}; } - void placeGlyphsAlongLine(const PlacedSymbol& symbol, const float fontSize, const bool flip, const mat4& labelPlaneMatrix, - gl::VertexVector& dynamicVertexArray) { + PlacementResult placeGlyphsAlongLine(const PlacedSymbol& symbol, + const float fontSize, + const bool flip, + const bool keepUpright, + const mat4& posMatrix, + const mat4& labelPlaneMatrix, + const mat4& glCoordMatrix, + gl::VertexVector& dynamicVertexArray) { const float fontScale = fontSize / 24.0; const float lineOffsetX = symbol.lineOffset[0] * fontSize; const float lineOffsetY = symbol.lineOffset[1] * fontSize; @@ -207,19 +219,60 @@ namespace mbgl { const Point anchorPoint = project(symbol.anchorPoint, labelPlaneMatrix); std::vector placedGlyphs; - for (auto glyphOffsetX : symbol.glyphOffsets) { - auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); - if (placedGlyph) { + if (symbol.glyphOffsets.size() > 1) { + + const float firstGlyphOffset = symbol.glyphOffsets.front(); + const float lastGlyphOffset = symbol.glyphOffsets.back(); + + optional firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); + if (!firstPlacedGlyph) + return PlacementResult::NotEnoughRoom; + + optional lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); + if (!lastPlacedGlyph) + return PlacementResult::NotEnoughRoom; + + const Point firstPoint = project(firstPlacedGlyph->point, glCoordMatrix); + const Point lastPoint = project(lastPlacedGlyph->point, glCoordMatrix); + + if (keepUpright && !flip && + (symbol.useVerticalMode ? firstPoint.y < lastPoint.y : firstPoint.x > lastPoint.x)) { + return PlacementResult::NeedsFlipping; + } + + placedGlyphs.push_back(*firstPlacedGlyph); + for (size_t glyphIndex = 1; glyphIndex < symbol.glyphOffsets.size() - 1; glyphIndex++) { + const float glyphOffsetX = symbol.glyphOffsets[glyphIndex]; + // Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed + auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix); placedGlyphs.push_back(*placedGlyph); - } else { - hideGlyphs(symbol.glyphOffsets.size(), dynamicVertexArray); - return; } + placedGlyphs.push_back(*lastPlacedGlyph); + } else { + // Only a single glyph to place + // So, determine whether to flip based on projected angle of the line segment it's on + if (keepUpright && !flip) { + const Point a = project(convertPoint(symbol.line.at(symbol.segment)), posMatrix); + const Point b = project(convertPoint(symbol.line.at(symbol.segment + 1)), posMatrix); + if (symbol.useVerticalMode ? b.y > a.y : b.x < a.x) { + return PlacementResult::NeedsFlipping; + } + } + assert(symbol.glyphOffsets.size() == 1); // We are relying on SymbolInstance.hasText filtering out symbols without any glyphs at all + const float glyphOffsetX = symbol.glyphOffsets.front(); + optional singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, + symbol.line, labelPlaneMatrix); + if (!singleGlyph) + return PlacementResult::NotEnoughRoom; + + placedGlyphs.push_back(*singleGlyph); } for (auto& placedGlyph : placedGlyphs) { addDynamicAttributes(placedGlyph.point, placedGlyph.angle, symbol.placementZoom, dynamicVertexArray); } + + return PlacementResult::OK; } void reprojectLineLabels(gl::VertexVector& dynamicVertexArray, const std::vector& placedSymbols, @@ -229,9 +282,15 @@ namespace mbgl { const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(state.getZoom()); const std::array clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height * 2.0 + 1.0 }}; + + const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map; + const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map; + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1, state.getZoom()); - const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, values.pitchAlignment == style::AlignmentType::Map, - values.rotationAlignment == style::AlignmentType::Map, state, tile.id.pixelsToTileUnits(1, state.getZoom())); + const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, pitchWithMap, + rotateWithMap, state, pixelsToTileUnits); + + const mat4 glCoordMatrix = getGlCoordMatrix(posMatrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); dynamicVertexArray.clear(); @@ -245,13 +304,6 @@ namespace mbgl { continue; } - bool flip = false; - if (values.keepUpright) { - const Point a = project(convertPoint(placedSymbol.line.at(placedSymbol.segment)), posMatrix); - const Point b = project(convertPoint(placedSymbol.line.at(placedSymbol.segment + 1)), posMatrix); - flip = placedSymbol.useVerticalMode ? b.y > a.y : b.x < a.x; - } - const float cameraToAnchorDistance = anchorPos[3]; const float perspectiveRatio = 1 + 0.5 * ((cameraToAnchorDistance / state.getCameraToCenterDistance()) - 1.0); @@ -260,7 +312,13 @@ namespace mbgl { fontSize * perspectiveRatio : fontSize / perspectiveRatio; - placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, flip, labelPlaneMatrix, dynamicVertexArray); + PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray); + + if (placeUnflipped == PlacementResult::NotEnoughRoom || + (placeUnflipped == PlacementResult::NeedsFlipping && + placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray) == PlacementResult::NotEnoughRoom)) { + hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray); + } } } } // end namespace mbgl -- cgit v1.2.1 From e8657becc56c2aee5b070357092da028e752d461 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 11 Jul 2017 11:22:39 -0700 Subject: [core] Update shaders. Implements 'icon-pitch-alignment' (issue #9345) Fixes issue #9456 (map-aligned point label regression) --- src/mbgl/layout/symbol_layout.cpp | 5 ++++- src/mbgl/programs/symbol_program.cpp | 7 +++++++ src/mbgl/programs/symbol_program.hpp | 10 +++++++++- src/mbgl/renderer/layers/render_symbol_layer.cpp | 2 +- src/mbgl/shaders/symbol_icon.cpp | 17 +++++++++++++++-- src/mbgl/shaders/symbol_sdf.cpp | 19 +++++++++++++++++-- src/mbgl/style/layers/symbol_layer.cpp | 16 ++++++++++++++++ src/mbgl/style/layers/symbol_layer_properties.hpp | 6 ++++++ 8 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index e308da618f..956ba770dd 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -75,10 +75,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, } } - // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment` + // If unspecified `*-pitch-alignment` inherits `*-rotation-alignment` if (layout.get() == AlignmentType::Auto) { layout.get() = layout.get(); } + if (layout.get() == AlignmentType::Auto) { + layout.get() = layout.get(); + } const bool hasText = has(layout) && !layout.get().empty(); const bool hasIcon = has(layout); diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 8790adcc63..58174ff8a7 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -52,6 +52,11 @@ Values makeValues(const bool isText, const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom()); const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map; const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map; + + // Line label rotation happens in `updateLineLabels` + // Pitched point labels are automatically rotated by the labelPlaneMatrix projection + // Unpitched point labels need to have their rotation applied after projection + const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine; mat4 labelPlaneMatrix; if (alongLine) { @@ -84,6 +89,8 @@ Values makeValues(const bool isText, uniforms::u_pitch::Value{ state.getPitch() }, uniforms::u_pitch_with_map::Value{ pitchWithMap }, uniforms::u_max_camera_distance::Value{ values.maxCameraDistance }, + uniforms::u_rotate_symbol::Value{ rotateInShader }, + uniforms::u_aspect_ratio::Value{ state.getSize().aspectRatio() }, std::forward(args)... }; } diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 79a961ad21..c74837b121 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -41,6 +41,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); } // namespace uniforms struct SymbolLayoutAttributes : gl::Attributes< @@ -348,7 +350,9 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_camera_to_center_distance, uniforms::u_pitch, uniforms::u_pitch_with_map, - uniforms::u_max_camera_distance>, + uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio>, style::IconPaintProperties> { public: @@ -387,6 +391,8 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_pitch, uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio, uniforms::u_gamma_scale, uniforms::u_is_halo>, PaintProperties> @@ -409,6 +415,8 @@ public: uniforms::u_pitch, uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio, uniforms::u_gamma_scale, uniforms::u_is_halo>, PaintProperties>; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 2fe6dd971e..2af7b2f7ca 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -82,7 +82,7 @@ style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProper style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { return style::SymbolPropertyValues { - layout_.get(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment + layout_.get(), layout_.get(), layout_.get(), evaluated.get(), diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index cb00cdad05..c0e3a0ac01 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -19,6 +19,8 @@ uniform highp float u_size_t; // used to interpolate between zoom stops when siz uniform highp float u_size; // used when size is both zoom and feature constant uniform highp float u_camera_to_center_distance; uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; uniform highp float u_collision_y_stretch; @@ -83,8 +85,19 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - highp float angle_sin = sin(segment_angle); - highp float angle_cos = cos(segment_angle); + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // See comments in symbol_sdf.vertex + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index b4158bacc5..2050886957 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -73,6 +73,8 @@ uniform mat4 u_gl_coord_matrix; uniform bool u_is_text; uniform bool u_pitch_with_map; uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; uniform highp float u_camera_to_center_distance; uniform highp float u_collision_y_stretch; @@ -151,8 +153,21 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - highp float angle_sin = sin(segment_angle); - highp float angle_cos = cos(segment_angle); + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 182b4b0a48..c102c64a94 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -332,6 +332,22 @@ void SymbolLayer::setIconOffset(DataDrivenPropertyValue> va baseImpl = std::move(impl_); observer->onLayerChanged(*this); } +PropertyValue SymbolLayer::getDefaultIconPitchAlignment() { + return IconPitchAlignment::defaultValue(); +} + +PropertyValue SymbolLayer::getIconPitchAlignment() const { + return impl().layout.get(); +} + +void SymbolLayer::setIconPitchAlignment(PropertyValue value) { + if (value == getIconPitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} PropertyValue SymbolLayer::getDefaultTextPitchAlignment() { return TextPitchAlignment::defaultValue(); } diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index f7ceaecdaa..4b2bff01b8 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -87,6 +87,11 @@ struct IconOffset : DataDrivenLayoutProperty> { static std::array defaultValue() { return {{ 0, 0 }}; } }; +struct IconPitchAlignment : LayoutProperty { + static constexpr const char * key = "icon-pitch-alignment"; + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + struct TextPitchAlignment : LayoutProperty { static constexpr const char * key = "text-pitch-alignment"; static AlignmentType defaultValue() { return AlignmentType::Auto; } @@ -254,6 +259,7 @@ class SymbolLayoutProperties : public Properties< IconPadding, IconKeepUpright, IconOffset, + IconPitchAlignment, TextPitchAlignment, TextRotationAlignment, TextField, -- cgit v1.2.1 From 8fb212dbb3f43c51f75747629db5c39f44b0c28a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 5 Jul 2017 14:45:34 -0700 Subject: [core] Include what you use --- src/mbgl/gl/program.hpp | 2 +- src/mbgl/renderer/render_style.cpp | 1 + src/mbgl/renderer/sources/render_image_source.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 583d53e4ec..ce2b5a335b 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -9,11 +9,11 @@ #include #include +#include #include #include #include - #include namespace mbgl { diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index 25dbba76f6..47639a57e7 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace mbgl { diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 6a3cb33fec..f1860b6b62 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace mbgl { -- cgit v1.2.1 From fedfaa2f6e582e87b190f5d423302f9f95d147d9 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 3 Jul 2017 14:05:12 -0700 Subject: [core] Inline getActiveAttributes details --- src/mbgl/gl/attribute.cpp | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index 4569e3cb32..5583cfd916 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -13,39 +13,25 @@ AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location return location; } -int32_t getActiveAttributeCount(ProgramID id) { - GLint numAttributes; - MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &numAttributes)); - return numAttributes; -} +std::set getActiveAttributes(ProgramID id) { + std::set activeAttributes; -int32_t getMaxAttributeNameLength(ProgramID id) { - GLint nameLength; - MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameLength)); - return nameLength; -} + GLint attributeCount; + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &attributeCount)); + + GLint maxAttributeLength; + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeLength)); -std::string getAttributeName(ProgramID id, int32_t maxLength, AttributeLocation location) { std::string attributeName; - attributeName.resize(maxLength); + attributeName.resize(maxAttributeLength); + GLsizei actualLength; GLint size; GLenum type; - MBGL_CHECK_ERROR(glGetActiveAttrib(id, static_cast(location), - static_cast(maxLength), &actualLength, &size, &type, - const_cast(attributeName.data()))); - attributeName.resize(actualLength); - return attributeName; -} - -std::set getActiveAttributes(ProgramID id) { - std::set activeAttributes; - - GLint attributeCount = getActiveAttributeCount(id); - GLint maxAttributeLength = getMaxAttributeNameLength(id); for (int32_t i = 0; i < attributeCount; i++) { - activeAttributes.emplace(getAttributeName(id, maxAttributeLength, i)); + MBGL_CHECK_ERROR(glGetActiveAttrib(id, i, maxAttributeLength, &actualLength, &size, &type, &attributeName[0])); + activeAttributes.emplace(std::string(attributeName, 0, actualLength)); } return activeAttributes; -- cgit v1.2.1 From c61041b44cd9181641db2351f4657cc356300226 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 3 Jul 2017 14:05:12 -0700 Subject: [core] Rework attribute binding (again) These changes are necessary for programs whose set of active attributes is not fixed at compile time by a template parameter pack, but rather varies based on the generated shader text at runtime. In such cases, the attribute location of a given named attribute may vary between instances of the same Program. Previously, attribute bindings were implicitly associated with a location based on template parameter order, and -1 was used to indicate an inactive attribute. This left us unable to disable the appropriate attribute when it went from active to inactive. Now, the state tracker for bindings explicitly associates locations and state, and an empty optional is used to indicate an inactive attribute. In addition, a gl::VertexArray class is now exposed, allowing more flexibility in the relationship between Programs, Segments, and attribute bindings. In this commit, that relationship does not change, but the subsequent commit adjusts it to match gl-js, reduce rebinds, and work around buggy VAO implementations. VertexArray uses a pimpl idiom in order to support implementations that lack the VAO extension. In that case, all VertexArrays share global binding state, reflecting the platform reality in the absence of VAOs, while still providing a uniform API. --- src/mbgl/gl/attribute.cpp | 63 +-------- src/mbgl/gl/attribute.hpp | 150 +++++++++++---------- src/mbgl/gl/context.cpp | 31 +++-- src/mbgl/gl/context.hpp | 12 +- src/mbgl/gl/object.cpp | 4 +- src/mbgl/gl/program.hpp | 26 ++-- src/mbgl/gl/segment.cpp | 7 - src/mbgl/gl/segment.hpp | 73 ---------- src/mbgl/gl/types.hpp | 2 +- src/mbgl/gl/uniform.hpp | 2 +- src/mbgl/gl/value.cpp | 18 +++ src/mbgl/gl/value.hpp | 7 + src/mbgl/gl/vertex_array.cpp | 18 +++ src/mbgl/gl/vertex_array.hpp | 58 ++++++++ src/mbgl/programs/binary_program.cpp | 4 +- src/mbgl/programs/binary_program.hpp | 4 +- src/mbgl/programs/program.hpp | 42 +++--- src/mbgl/programs/segment.cpp | 7 + src/mbgl/programs/segment.hpp | 40 ++++++ src/mbgl/programs/symbol_program.hpp | 46 ++++--- src/mbgl/renderer/buckets/circle_bucket.hpp | 4 +- src/mbgl/renderer/buckets/debug_bucket.hpp | 2 +- src/mbgl/renderer/buckets/fill_bucket.hpp | 6 +- .../renderer/buckets/fill_extrusion_bucket.hpp | 4 +- src/mbgl/renderer/buckets/line_bucket.hpp | 4 +- src/mbgl/renderer/buckets/raster_bucket.hpp | 2 +- src/mbgl/renderer/buckets/symbol_bucket.hpp | 8 +- src/mbgl/renderer/layers/render_custom_layer.cpp | 2 +- src/mbgl/renderer/paint_property_binder.hpp | 15 ++- src/mbgl/renderer/painter.cpp | 2 +- src/mbgl/renderer/painter.hpp | 8 +- 31 files changed, 363 insertions(+), 308 deletions(-) delete mode 100644 src/mbgl/gl/segment.cpp delete mode 100644 src/mbgl/gl/segment.hpp create mode 100644 src/mbgl/gl/vertex_array.cpp create mode 100644 src/mbgl/gl/vertex_array.hpp create mode 100644 src/mbgl/programs/segment.cpp create mode 100644 src/mbgl/programs/segment.hpp (limited to 'src') diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index 5583cfd916..bb5b2ddc34 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -1,16 +1,14 @@ #include -#include #include -#include - namespace mbgl { namespace gl { -AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { - assert(location < 8); +void bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { + if (location >= MAX_ATTRIBUTES) { + throw gl::Error("too many vertex attributes"); + } MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); - return location; } std::set getActiveAttributes(ProgramID id) { @@ -37,58 +35,5 @@ std::set getActiveAttributes(ProgramID id) { return activeAttributes; } -void DisabledAttribute::bind(Context&, AttributeLocation location, std::size_t) const { - MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); -} - -template -constexpr DataType DataTypeOf() { - return std::is_same::value ? DataType::Byte : - std::is_same::value ? DataType::UnsignedByte : - std::is_same::value ? DataType::Short : - std::is_same::value ? DataType::UnsignedShort : - std::is_same::value ? DataType::Integer : - std::is_same::value ? DataType::UnsignedInteger : - std::is_same::value ? DataType::Float : static_cast(0); -} - -template -void AttributeBinding::bind(Context& context, AttributeLocation location, std::size_t vertexOffset) const { - // FillProgram will attempt to bind at location -1 because it includes - // a fill-outline-color paint property but does not use it or have an - // a_outline_color shader attribute - in this case, we have nothing to bind. - if (location == -1) return; - - context.vertexBuffer = vertexBuffer; - MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); - MBGL_CHECK_ERROR(glVertexAttribPointer( - location, - static_cast(attributeSize), - static_cast(DataTypeOf()), - static_cast(false), - static_cast(vertexSize), - reinterpret_cast(attributeOffset + (vertexSize * vertexOffset)))); -} - -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; - -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; - -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; - -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; -template class AttributeBinding; - } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index bc02b54bd2..1f60c8c980 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -1,59 +1,51 @@ #pragma once #include -#include +#include #include #include -#include +#include #include #include #include #include +#include +#include namespace mbgl { namespace gl { -class DisabledAttribute { -public: - void bind(Context&, AttributeLocation, std::size_t vertexOffset) const; +static constexpr std::size_t MAX_ATTRIBUTES = 8; - friend bool operator==(const DisabledAttribute&, - const DisabledAttribute&) { - return true; - } -}; +template struct DataTypeOf; +template <> struct DataTypeOf< int8_t> : std::integral_constant {}; +template <> struct DataTypeOf : std::integral_constant {}; +template <> struct DataTypeOf< int16_t> : std::integral_constant {}; +template <> struct DataTypeOf : std::integral_constant {}; +template <> struct DataTypeOf< int32_t> : std::integral_constant {}; +template <> struct DataTypeOf : std::integral_constant {}; +template <> struct DataTypeOf : std::integral_constant {}; -template class AttributeBinding { public: - AttributeBinding(BufferID vertexBuffer_, - std::size_t vertexSize_, - std::size_t attributeOffset_, - std::size_t attributeSize_ = N) - : vertexBuffer(vertexBuffer_), - vertexSize(vertexSize_), - attributeOffset(attributeOffset_), - attributeSize(attributeSize_) - {} - - void bind(Context&, AttributeLocation, std::size_t vertexOffset) const; + DataType attributeType; + std::size_t attributeSize; + std::size_t attributeOffset; + + BufferID vertexBuffer; + std::size_t vertexSize; + std::size_t vertexOffset; friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) { - return lhs.vertexBuffer == rhs.vertexBuffer - && lhs.vertexSize == rhs.vertexSize - && lhs.attributeOffset == rhs.attributeOffset - && lhs.attributeSize == rhs.attributeSize; + return std::tie(lhs.attributeType, lhs.attributeSize, lhs.attributeOffset, lhs.vertexBuffer, lhs.vertexSize, lhs.vertexOffset) + == std::tie(rhs.attributeType, rhs.attributeSize, rhs.attributeOffset, rhs.vertexBuffer, rhs.vertexSize, rhs.vertexOffset); } - -private: - BufferID vertexBuffer; - std::size_t vertexSize; - std::size_t attributeOffset; - std::size_t attributeSize; }; +using AttributeBindingArray = std::array, MAX_ATTRIBUTES>; + /* gl::Attribute manages the binding of a vertex buffer to a GL program attribute. - T is the underlying primitive type (exposed as Attribute::ValueType) @@ -67,10 +59,7 @@ public: using Value = std::array; using Location = AttributeLocation; - - using Binding = variant< - DisabledAttribute, - AttributeBinding>; + using Binding = AttributeBinding; /* Create a binding for this attribute. The `attributeSize` parameter may be used to @@ -82,28 +71,24 @@ public: std::size_t attributeIndex, std::size_t attributeSize = N) { static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); - return AttributeBinding { + return AttributeBinding { + DataTypeOf::value, + attributeSize, + Vertex::attributeOffsets[attributeIndex], buffer.buffer, sizeof(Vertex), - Vertex::attributeOffsets[attributeIndex], - attributeSize + 0, }; } - static void bind(Context& context, - const Location& location, - Binding& oldBinding, - const Binding& newBinding, - std::size_t vertexOffset) { - if (oldBinding == newBinding) { - return; + static optional offsetBinding(const optional& binding, std::size_t vertexOffset) { + if (binding) { + AttributeBinding result = *binding; + result.vertexOffset = vertexOffset; + return result; + } else { + return binding; } - - Binding::visit(newBinding, [&] (const auto& binding) { - binding.bind(context, location, vertexOffset); - }); - - oldBinding = newBinding; } }; @@ -223,7 +208,7 @@ const std::size_t Vertex::attributeOffsets[5] = { } // namespace detail -AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); +void bindAttributeLocation(ProgramID, AttributeLocation, const char * name); std::set getActiveAttributes(ProgramID); template @@ -232,10 +217,10 @@ public: using Types = TypeList; using Locations = IndexedTuple< TypeList, - TypeList>; + TypeList...>>; using Bindings = IndexedTuple< TypeList, - TypeList>; + TypeList...>>; using NamedLocations = std::vector>; using Vertex = detail::Vertex; @@ -243,13 +228,17 @@ public: static Locations bindLocations(const ProgramID& id) { std::set activeAttributes = getActiveAttributes(id); - AttributeLocation location = -1; - auto bindAndIncrement = [&](const char* name) { - location++; - return bindAttributeLocation(id, location, name); + AttributeLocation location = 0; + auto maybeBindLocation = [&](const char* name) -> optional { + if (activeAttributes.count(name)) { + bindAttributeLocation(id, location, name); + return location++; + } else { + return {}; + } }; - return Locations{ (activeAttributes.count(As::name()) ? bindAndIncrement(As::name()) - : -1)... }; + + return Locations { maybeBindLocation(As::name())... }; } template @@ -258,7 +247,17 @@ public: } static NamedLocations getNamedLocations(const Locations& locations) { - return NamedLocations{ { As::name(), locations.template get() }... }; + NamedLocations result; + + auto maybeAddLocation = [&] (const std::string& name, const optional& location) { + if (location) { + result.emplace_back(name, *location); + } + }; + + util::ignore({ (maybeAddLocation(As::name(), locations.template get()), 0)... }); + + return result; } template @@ -266,16 +265,23 @@ public: return Bindings { As::Type::binding(buffer, TypeIndex::value)... }; } - static void bind(Context& context, - const Locations& locations, - Bindings& oldBindings, - const Bindings& newBindings, - std::size_t vertexOffset) { - util::ignore({ (As::Type::bind(context, - locations.template get(), - oldBindings.template get(), - newBindings.template get(), - vertexOffset), 0)... }); + static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) { + return Bindings { As::Type::offsetBinding(bindings.template get(), vertexOffset)... }; + } + + static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) { + AttributeBindingArray result; + + auto maybeAddBinding = [&] (const optional& location, + const optional& binding) { + if (location) { + result.at(*location) = binding; + } + }; + + util::ignore({ (maybeAddBinding(locations.template get(), bindings.template get()), 0)... }); + + return result; } }; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 86ca9c0607..f7d210d52e 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -229,8 +229,8 @@ UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; - vertexArrayObject = 0; - elementBuffer = result; + bindVertexArray = 0; + globalVertexArrayState.indexBuffer = result; MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); return result; } @@ -281,11 +281,16 @@ optional> Context::getBinaryProgram( } #endif -UniqueVertexArray Context::createVertexArray() { - assert(supportsVertexArrays()); - VertexArrayID id = 0; - MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); - return UniqueVertexArray(std::move(id), { this }); +VertexArray Context::createVertexArray() { + if (supportsVertexArrays()) { + VertexArrayID id = 0; + MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); + return { std::make_unique(UniqueVertexArray(std::move(id), { this }), *this) }; + } else { + // On GL implementations which do not support vertex arrays, attribute bindings are global state. + // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. + return { UniqueVertexArrayState(&globalVertexArrayState, [] (VertexArrayState*) {}) }; + } } UniqueFramebuffer Context::createFramebuffer() { @@ -553,8 +558,8 @@ void Context::setDirtyState() { tex.setDirty(); } vertexBuffer.setDirty(); - elementBuffer.setDirty(); - vertexArrayObject.setDirty(); + bindVertexArray.setDirty(); + globalVertexArrayState.setDirty(); } void Context::clear(optional color, @@ -673,8 +678,8 @@ void Context::performCleanup() { for (const auto id : abandonedBuffers) { if (vertexBuffer == id) { vertexBuffer.setDirty(); - } else if (elementBuffer == id) { - elementBuffer.setDirty(); + } else if (globalVertexArrayState.indexBuffer == id) { + globalVertexArrayState.indexBuffer.setDirty(); } } MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); @@ -694,8 +699,8 @@ void Context::performCleanup() { if (!abandonedVertexArrays.empty()) { assert(supportsVertexArrays()); for (const auto id : abandonedVertexArrays) { - if (vertexArrayObject == id) { - vertexArrayObject.setDirty(); + if (bindVertexArray == id) { + bindVertexArray.setDirty(); } } MBGL_CHECK_ERROR(vertexArray->deleteVertexArrays(int(abandonedVertexArrays.size()), diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 2e594618d2..0dd67d2ed7 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -53,9 +54,7 @@ public: void verifyProgramLinkage(ProgramID); void linkProgram(ProgramID); UniqueTexture createTexture(); - - bool supportsVertexArrays() const; - UniqueVertexArray createVertexArray(); + VertexArray createVertexArray(); #if MBGL_HAS_BINARY_PROGRAMS bool supportsProgramBinaries() const; @@ -207,10 +206,11 @@ public: State viewport; State scissorTest; std::array, 2> texture; - State vertexArrayObject { *this }; State program; State vertexBuffer; - State elementBuffer; + + State bindVertexArray { *this }; + VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }), *this }; State pixelStorePack; State pixelStoreUnpack; @@ -257,6 +257,8 @@ private: void drawPixels(Size size, const void* data, TextureFormat); #endif // MBGL_USE_GLES2 + bool supportsVertexArrays() const; + friend detail::ProgramDeleter; friend detail::ShaderDeleter; friend detail::BufferDeleter; diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp index e2d476e0c0..2c5f1bca1f 100644 --- a/src/mbgl/gl/object.cpp +++ b/src/mbgl/gl/object.cpp @@ -33,7 +33,9 @@ void TextureDeleter::operator()(TextureID id) const { void VertexArrayDeleter::operator()(VertexArrayID id) const { assert(context); - context->abandonedVertexArrays.push_back(id); + if (id != 0) { + context->abandonedVertexArrays.push_back(id); + } } void FramebufferDeleter::operator()(FramebufferID id) const { diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index ce2b5a335b..9d8b0a5b04 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -116,10 +117,12 @@ public: DepthMode depthMode, StencilMode stencilMode, ColorMode colorMode, - UniformValues&& uniformValues, - AttributeBindings&& attributeBindings, + const UniformValues& uniformValues, + VertexArray& vertexArray, + const AttributeBindings& attributeBindings, const IndexBuffer& indexBuffer, - const SegmentVector& segments) { + std::size_t indexOffset, + std::size_t indexLength) { static_assert(std::is_same::value, "incompatible draw mode"); context.setDrawMode(drawMode); @@ -129,18 +132,15 @@ public: context.program = program; - Uniforms::bind(uniformsState, std::move(uniformValues)); + Uniforms::bind(uniformsState, uniformValues); - for (const auto& segment : segments) { - segment.bind(context, - indexBuffer.buffer, - attributeLocations, - attributeBindings); + vertexArray.bind(context, + indexBuffer.buffer, + Attributes::toBindingArray(attributeLocations, attributeBindings)); - context.draw(drawMode.primitiveType, - segment.indexOffset, - segment.indexLength); - } + context.draw(drawMode.primitiveType, + indexOffset, + indexLength); } private: diff --git a/src/mbgl/gl/segment.cpp b/src/mbgl/gl/segment.cpp deleted file mode 100644 index aabdc83cd4..0000000000 --- a/src/mbgl/gl/segment.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -namespace mbgl { -namespace gl { - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp deleted file mode 100644 index fe0658bf8e..0000000000 --- a/src/mbgl/gl/segment.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace mbgl { -namespace gl { - -template -class Segment { -public: - Segment(std::size_t vertexOffset_, - std::size_t indexOffset_, - std::size_t vertexLength_ = 0, - std::size_t indexLength_ = 0) - : vertexOffset(vertexOffset_), - indexOffset(indexOffset_), - vertexLength(vertexLength_), - indexLength(indexLength_) {} - - const std::size_t vertexOffset; - const std::size_t indexOffset; - - std::size_t vertexLength; - std::size_t indexLength; - - void bind(Context& context, - BufferID indexBuffer_, - const typename Attributes::Locations& attributeLocations, - const typename Attributes::Bindings& attributeBindings_) const { - if (context.supportsVertexArrays()) { - if (!vao) { - vao = context.createVertexArray(); - context.vertexBuffer.setDirty(); - } - context.vertexArrayObject = *vao; - if (indexBuffer != indexBuffer_) { - indexBuffer = indexBuffer_; - context.elementBuffer.setDirty(); - context.elementBuffer = indexBuffer_; - } - } else { - // No VAO support. Force attributes to be rebound. - context.elementBuffer = indexBuffer_; - attributeBindings = {}; - } - - Attributes::bind(context, - attributeLocations, - attributeBindings, - attributeBindings_, - vertexOffset); - } - -private: - mutable optional vao; - mutable optional indexBuffer; - mutable typename Attributes::Bindings attributeBindings; -}; - -template -class SegmentVector : public std::vector> { -public: - SegmentVector() = default; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 1fce878c6f..058bc226b8 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -15,7 +15,7 @@ using VertexArrayID = uint32_t; using FramebufferID = uint32_t; using RenderbufferID = uint32_t; -using AttributeLocation = int32_t; +using AttributeLocation = uint32_t; using UniformLocation = int32_t; using TextureUnit = uint8_t; diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 4ed2419764..5a78068fc8 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -115,7 +115,7 @@ public: return NamedLocations{ { Us::name(), state.template get().location }... }; } - static void bind(State& state, Values&& values) { + static void bind(State& state, const Values& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } }; diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp index 2b825fb2bd..89014fe6bc 100644 --- a/src/mbgl/gl/value.cpp +++ b/src/mbgl/gl/value.cpp @@ -365,6 +365,24 @@ BindVertexArray::Type BindVertexArray::Get(const Context& context) { return binding; } +const optional VertexAttribute::Default {}; + +void VertexAttribute::Set(const optional& binding, Context& context, AttributeLocation location) { + if (binding) { + context.vertexBuffer = binding->vertexBuffer; + MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttribPointer( + location, + static_cast(binding->attributeSize), + static_cast(binding->attributeType), + static_cast(false), + static_cast(binding->vertexSize), + reinterpret_cast(binding->attributeOffset + (binding->vertexSize * binding->vertexOffset)))); + } else { + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + } +} + const constexpr PixelStorePack::Type PixelStorePack::Default; void PixelStorePack::Set(const Type& value) { diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp index d4c7b5cdc3..19e9af194f 100644 --- a/src/mbgl/gl/value.hpp +++ b/src/mbgl/gl/value.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -239,6 +240,12 @@ struct BindVertexArray { static Type Get(const Context&); }; +struct VertexAttribute { + using Type = optional; + static const Type Default; + static void Set(const Type&, Context&, AttributeLocation); +}; + struct PixelStorePack { using Type = PixelStorageType; static const constexpr Type Default = { 4 }; diff --git a/src/mbgl/gl/vertex_array.cpp b/src/mbgl/gl/vertex_array.cpp new file mode 100644 index 0000000000..68a500ac45 --- /dev/null +++ b/src/mbgl/gl/vertex_array.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +namespace mbgl { +namespace gl { + +void VertexArray::bind(Context& context, BufferID indexBuffer, const AttributeBindingArray& bindings) { + context.bindVertexArray = state->vertexArray; + state->indexBuffer = indexBuffer; + + for (AttributeLocation location = 0; location < MAX_ATTRIBUTES; ++location) { + state->bindings[location] = bindings[location]; + } +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp new file mode 100644 index 0000000000..9ccf48d9bd --- /dev/null +++ b/src/mbgl/gl/vertex_array.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace gl { + +class Context; + +class VertexArrayState { +public: + VertexArrayState(UniqueVertexArray vertexArray_, Context& context) + : vertexArray(std::move(vertexArray_)), + bindings(makeBindings(context, std::make_index_sequence())) { + } + + void setDirty() { + indexBuffer.setDirty(); + for (auto& binding : bindings) { + binding.setDirty(); + } + } + + UniqueVertexArray vertexArray; + State indexBuffer; + + using AttributeState = State; + std::array bindings; + +private: + template + std::array makeBindings(Context& context, std::index_sequence) { + return {{ AttributeState { context, I }... }}; + } +}; + +using UniqueVertexArrayState = std::unique_ptr>; + +class VertexArray { +public: + VertexArray(UniqueVertexArrayState state_) + : state(std::move(state_)) { + } + + void bind(Context&, BufferID indexBuffer, const AttributeBindingArray&); + +private: + UniqueVertexArrayState state; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/programs/binary_program.cpp b/src/mbgl/programs/binary_program.cpp index 57f2cc0d2c..da629194b4 100644 --- a/src/mbgl/programs/binary_program.cpp +++ b/src/mbgl/programs/binary_program.cpp @@ -98,7 +98,7 @@ std::string BinaryProgram::serialize() const { return data; } -gl::AttributeLocation BinaryProgram::attributeLocation(const std::string& name) const { +optional BinaryProgram::attributeLocation(const std::string& name) const { for (const auto& pair : attributes) { if (pair.first == name) { return pair.second; @@ -113,7 +113,7 @@ gl::UniformLocation BinaryProgram::uniformLocation(const std::string& name) cons return pair.second; } } - return {}; + return -1; } } // namespace mbgl diff --git a/src/mbgl/programs/binary_program.hpp b/src/mbgl/programs/binary_program.hpp index b77cf1a510..8690f3fd6f 100644 --- a/src/mbgl/programs/binary_program.hpp +++ b/src/mbgl/programs/binary_program.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -29,7 +30,8 @@ public: const std::string& identifier() const { return binaryIdentifier; } - gl::AttributeLocation attributeLocation(const std::string& name) const; + + optional attributeLocation(const std::string& name) const; gl::UniformLocation uniformLocation(const std::string& name) const; private: diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 3a38f30a86..0199752b06 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -51,26 +52,37 @@ public: gl::DepthMode depthMode, gl::StencilMode stencilMode, gl::ColorMode colorMode, - UniformValues&& uniformValues, + const UniformValues& uniformValues, const gl::VertexBuffer& layoutVertexBuffer, const gl::IndexBuffer& indexBuffer, - const gl::SegmentVector& segments, + const SegmentVector& segments, const PaintPropertyBinders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, float currentZoom) { - program.draw( - context, - std::move(drawMode), - std::move(depthMode), - std::move(stencilMode), - std::move(colorMode), - uniformValues - .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)), - LayoutAttributes::bindings(layoutVertexBuffer) - .concat(paintPropertyBinders.attributeBindings(currentProperties)), - indexBuffer, - segments - ); + typename AllUniforms::Values allUniformValues = uniformValues + .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); + + typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer) + .concat(paintPropertyBinders.attributeBindings(currentProperties)); + + for (auto& segment : segments) { + if (!segment.vertexArray) { + segment.vertexArray = context.createVertexArray(); + } + + program.draw( + context, + std::move(drawMode), + std::move(depthMode), + std::move(stencilMode), + std::move(colorMode), + allUniformValues, + *segment.vertexArray, + Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), + indexBuffer, + segment.indexOffset, + segment.indexLength); + } } }; diff --git a/src/mbgl/programs/segment.cpp b/src/mbgl/programs/segment.cpp new file mode 100644 index 0000000000..bb09843e21 --- /dev/null +++ b/src/mbgl/programs/segment.cpp @@ -0,0 +1,7 @@ +#include + +namespace mbgl { +namespace gl { + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/programs/segment.hpp b/src/mbgl/programs/segment.hpp new file mode 100644 index 0000000000..d8cc9679d7 --- /dev/null +++ b/src/mbgl/programs/segment.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace mbgl { + +template +class Segment { +public: + Segment(std::size_t vertexOffset_, + std::size_t indexOffset_, + std::size_t vertexLength_ = 0, + std::size_t indexLength_ = 0) + : vertexOffset(vertexOffset_), + indexOffset(indexOffset_), + vertexLength(vertexLength_), + indexLength(indexLength_) {} + + const std::size_t vertexOffset; + const std::size_t indexOffset; + + std::size_t vertexLength; + std::size_t indexLength; + + mutable optional vertexArray; +}; + +template +class SegmentVector : public std::vector> { +public: + SegmentVector() = default; +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index c74837b121..8c59cfd5a2 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -306,30 +307,41 @@ public: gl::DepthMode depthMode, gl::StencilMode stencilMode, gl::ColorMode colorMode, - UniformValues&& uniformValues, + const UniformValues& uniformValues, const gl::VertexBuffer& layoutVertexBuffer, const gl::VertexBuffer& dynamicLayoutVertexBuffer, const SymbolSizeBinder& symbolSizeBinder, const gl::IndexBuffer& indexBuffer, - const gl::SegmentVector& segments, + const SegmentVector& segments, const PaintPropertyBinders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, float currentZoom) { - program.draw( - context, - std::move(drawMode), - std::move(depthMode), - std::move(stencilMode), - std::move(colorMode), - uniformValues - .concat(symbolSizeBinder.uniformValues(currentZoom)) - .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)), - LayoutAttributes::bindings(layoutVertexBuffer) - .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer)) - .concat(paintPropertyBinders.attributeBindings(currentProperties)), - indexBuffer, - segments - ); + typename AllUniforms::Values allUniformValues = uniformValues + .concat(symbolSizeBinder.uniformValues(currentZoom)) + .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); + + typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer) + .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer)) + .concat(paintPropertyBinders.attributeBindings(currentProperties)); + + for (auto& segment : segments) { + if (!segment.vertexArray) { + segment.vertexArray = context.createVertexArray(); + } + + program.draw( + context, + std::move(drawMode), + std::move(depthMode), + std::move(stencilMode), + std::move(colorMode), + allUniformValues, + *segment.vertexArray, + Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), + indexBuffer, + segment.indexOffset, + segment.indexLength); + } } }; diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index b048fd7675..0f27e2a7e3 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ public: gl::VertexVector vertices; gl::IndexVector triangles; - gl::SegmentVector segments; + SegmentVector segments; optional> vertexBuffer; optional> indexBuffer; diff --git a/src/mbgl/renderer/buckets/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp index 756e58a6de..fc3128e944 100644 --- a/src/mbgl/renderer/buckets/debug_bucket.hpp +++ b/src/mbgl/renderer/buckets/debug_bucket.hpp @@ -33,7 +33,7 @@ public: const optional expires; const MapDebugOptions debugMode; - gl::SegmentVector segments; + SegmentVector segments; optional> vertexBuffer; optional> indexBuffer; }; diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index 421d8b332b..d3cd92d451 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -30,8 +30,8 @@ public: gl::VertexVector vertices; gl::IndexVector lines; gl::IndexVector triangles; - gl::SegmentVector lineSegments; - gl::SegmentVector triangleSegments; + SegmentVector lineSegments; + SegmentVector triangleSegments; optional> vertexBuffer; optional> lineIndexBuffer; diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index c54805d743..d1e695c5a3 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -27,7 +27,7 @@ public: gl::VertexVector vertices; gl::IndexVector triangles; - gl::SegmentVector triangleSegments; + SegmentVector triangleSegments; optional> vertexBuffer; optional> indexBuffer; diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index 34d8935953..c0a0614d33 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -34,7 +34,7 @@ public: gl::VertexVector vertices; gl::IndexVector triangles; - gl::SegmentVector segments; + SegmentVector segments; optional> vertexBuffer; optional> indexBuffer; diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index b5cf7997d5..44b9111b81 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -31,7 +31,7 @@ public: // Raster Tile Sources use the default buffers from Painter gl::VertexVector vertices; gl::IndexVector indices; - gl::SegmentVector segments; + SegmentVector segments; optional> vertexBuffer; optional> indexBuffer; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index ffa22e9021..424c9d0f74 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ public: gl::VertexVector vertices; gl::VertexVector dynamicVertices; gl::IndexVector triangles; - gl::SegmentVector segments; + SegmentVector segments; std::vector placedSymbols; optional> vertexBuffer; @@ -77,7 +77,7 @@ public: gl::VertexVector vertices; gl::VertexVector dynamicVertices; gl::IndexVector triangles; - gl::SegmentVector segments; + SegmentVector segments; std::vector placedSymbols; PremultipliedImage atlasImage; @@ -89,7 +89,7 @@ public: struct CollisionBoxBuffer { gl::VertexVector vertices; gl::IndexVector lines; - gl::SegmentVector segments; + SegmentVector segments; optional> vertexBuffer; optional> dynamicVertexBuffer; diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index 4d6084075d..81b8ac301b 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -48,7 +48,7 @@ void RenderCustomLayer::render(Painter& painter, PaintParameters& paintParameter const TransformState& state = painter.state; // Reset GL state to a known state so the CustomLayer always has a clean slate. - context.vertexArrayObject = 0; + context.bindVertexArray = 0; context.setDepthMode(painter.depthModeForSublayer(0, gl::DepthMode::ReadOnly)); context.setStencilMode(gl::StencilMode::disabled()); context.setColorMode(painter.colorModeForRenderPass()); diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index f78147fc87..652948c8df 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ public: virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) = 0; virtual void upload(gl::Context& context) = 0; - virtual AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const = 0; + virtual optional attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const = 0; virtual float interpolationFactor(float currentZoom) const = 0; virtual T uniformValue(const PossiblyEvaluatedPropertyValue& currentValue) const = 0; @@ -103,8 +104,8 @@ public: void populateVertexVector(const GeometryTileFeature&, std::size_t) override {} void upload(gl::Context&) override {} - AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue&) const override { - return gl::DisabledAttribute(); + optional attributeBinding(const PossiblyEvaluatedPropertyValue&) const override { + return {}; } float interpolationFactor(float) const override { @@ -147,9 +148,9 @@ public: vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); } - AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const override { + optional attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const override { if (currentValue.isConstant()) { - return gl::DisabledAttribute(); + return {}; } else { return Attribute::binding(*vertexBuffer, 0, BaseAttribute::Dimensions); } @@ -208,9 +209,9 @@ public: vertexBuffer = context.createVertexBuffer(std::move(vertexVector)); } - AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const override { + optional attributeBinding(const PossiblyEvaluatedPropertyValue& currentValue) const override { if (currentValue.isConstant()) { - return gl::DisabledAttribute(); + return {}; } else { return Attribute::binding(*vertexBuffer, 0); } diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index a3decdb603..35d03e7cb4 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -262,7 +262,7 @@ void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { context.activeTexture = 0; context.texture[0] = 0; - context.vertexArrayObject = 0; + context.bindVertexArray = 0; } } diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 7e966adefa..0b6ee3497e 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -172,10 +172,10 @@ public: gl::IndexBuffer quadTriangleIndexBuffer; gl::IndexBuffer tileBorderIndexBuffer; - gl::SegmentVector tileTriangleSegments; - gl::SegmentVector tileBorderSegments; - gl::SegmentVector rasterSegments; - gl::SegmentVector extrusionTextureSegments; + SegmentVector tileTriangleSegments; + SegmentVector tileBorderSegments; + SegmentVector rasterSegments; + SegmentVector extrusionTextureSegments; }; } // namespace mbgl -- cgit v1.2.1 From 358b0305ae1f52b477ae145bcca4b7af242dd5c3 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 6 Jul 2017 08:06:12 -0700 Subject: [core] Per-segment-per-layer vertex arrays Reduces rebinding, matches gl-js, and works around the buggy VAO implementation on PowerVR SGX544 GPUs. --- src/mbgl/programs/program.hpp | 11 +++++++---- src/mbgl/programs/segment.hpp | 9 ++++++++- src/mbgl/programs/symbol_program.hpp | 11 +++++++---- src/mbgl/renderer/painter.cpp | 15 +++++++++++---- src/mbgl/renderer/painters/painter_background.cpp | 6 ++++-- src/mbgl/renderer/painters/painter_circle.cpp | 3 ++- src/mbgl/renderer/painters/painter_clipping.cpp | 3 ++- src/mbgl/renderer/painters/painter_debug.cpp | 6 ++++-- src/mbgl/renderer/painters/painter_fill.cpp | 6 ++++-- src/mbgl/renderer/painters/painter_fill_extrusion.cpp | 6 ++++-- src/mbgl/renderer/painters/painter_line.cpp | 3 ++- src/mbgl/renderer/painters/painter_raster.cpp | 3 ++- src/mbgl/renderer/painters/painter_symbol.cpp | 6 ++++-- 13 files changed, 61 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 0199752b06..71d7569f53 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -58,7 +58,8 @@ public: const SegmentVector& segments, const PaintPropertyBinders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, - float currentZoom) { + float currentZoom, + const std::string& layerID) { typename AllUniforms::Values allUniformValues = uniformValues .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); @@ -66,8 +67,10 @@ public: .concat(paintPropertyBinders.attributeBindings(currentProperties)); for (auto& segment : segments) { - if (!segment.vertexArray) { - segment.vertexArray = context.createVertexArray(); + optional& vertexArray = segment.vertexArrays[layerID]; + + if (!vertexArray) { + vertexArray = context.createVertexArray(); } program.draw( @@ -77,7 +80,7 @@ public: std::move(stencilMode), std::move(colorMode), allUniformValues, - *segment.vertexArray, + *vertexArray, Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), indexBuffer, segment.indexOffset, diff --git a/src/mbgl/programs/segment.hpp b/src/mbgl/programs/segment.hpp index d8cc9679d7..74bf4a75c5 100644 --- a/src/mbgl/programs/segment.hpp +++ b/src/mbgl/programs/segment.hpp @@ -28,7 +28,14 @@ public: std::size_t vertexLength; std::size_t indexLength; - mutable optional vertexArray; + // One VertexArray per layer ID. This minimizes rebinding in cases where + // several layers share buckets but have different sets of active attributes. + // This can happen: + // * when two layers have the same layout properties, but differing + // data-driven paint properties + // * when two fill layers have the same layout properties, but one + // uses fill-color and the other uses fill-pattern + mutable std::map> vertexArrays; }; template diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 8c59cfd5a2..ee4855cf8f 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -315,7 +315,8 @@ public: const SegmentVector& segments, const PaintPropertyBinders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, - float currentZoom) { + float currentZoom, + const std::string& layerID) { typename AllUniforms::Values allUniformValues = uniformValues .concat(symbolSizeBinder.uniformValues(currentZoom)) .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); @@ -325,8 +326,10 @@ public: .concat(paintPropertyBinders.attributeBindings(currentProperties)); for (auto& segment : segments) { - if (!segment.vertexArray) { - segment.vertexArray = context.createVertexArray(); + optional& vertexArray = segment.vertexArrays[layerID]; + + if (!vertexArray) { + vertexArray = context.createVertexArray(); } program.draw( @@ -336,7 +339,7 @@ public: std::move(stencilMode), std::move(colorMode), allUniformValues, - *segment.vertexArray, + *vertexArray, Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), indexBuffer, segment.indexOffset, diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 35d03e7cb4..9ab50e83b0 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -316,16 +316,23 @@ void Painter::renderPass(PaintParameters& parameters, const Properties<>::PossiblyEvaluated properties; parameters.programs.extrusionTexture.draw( - context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), + context, + gl::Triangles(), + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), colorModeForRenderPass(), ExtrusionTextureProgram::UniformValues{ uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, uniforms::u_image::Value{ 0 }, uniforms::u_opacity::Value{ layer.as() ->evaluated.get() } }, - extrusionTextureVertexBuffer, quadTriangleIndexBuffer, extrusionTextureSegments, - ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, - state.getZoom()); + extrusionTextureVertexBuffer, + quadTriangleIndexBuffer, + extrusionTextureSegments, + ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, + properties, + state.getZoom(), + layer.getID()); } else { renderItem(parameters, item); } diff --git a/src/mbgl/renderer/painters/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp index 577d7d6cda..661da0cc99 100644 --- a/src/mbgl/renderer/painters/painter_background.cpp +++ b/src/mbgl/renderer/painters/painter_background.cpp @@ -54,7 +54,8 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou tileTriangleSegments, paintAttibuteData, properties, - state.getZoom() + state.getZoom(), + layer.getID() ); } } else { @@ -74,7 +75,8 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou tileTriangleSegments, paintAttibuteData, properties, - state.getZoom() + state.getZoom(), + layer.getID() ); } } diff --git a/src/mbgl/renderer/painters/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp index a077f557fc..72a17d19fb 100644 --- a/src/mbgl/renderer/painters/painter_circle.cpp +++ b/src/mbgl/renderer/painters/painter_circle.cpp @@ -52,7 +52,8 @@ void Painter::renderCircle(PaintParameters& parameters, bucket.segments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom() + state.getZoom(), + layer.getID() ); } diff --git a/src/mbgl/renderer/painters/painter_clipping.cpp b/src/mbgl/renderer/painters/painter_clipping.cpp index cad092594e..025019b5c7 100644 --- a/src/mbgl/renderer/painters/painter_clipping.cpp +++ b/src/mbgl/renderer/painters/painter_clipping.cpp @@ -30,7 +30,8 @@ void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& cl tileTriangleSegments, paintAttibuteData, properties, - state.getZoom() + state.getZoom(), + "clipping" ); } diff --git a/src/mbgl/renderer/painters/painter_debug.cpp b/src/mbgl/renderer/painters/painter_debug.cpp index ee76aee54c..989bbab5e5 100644 --- a/src/mbgl/renderer/painters/painter_debug.cpp +++ b/src/mbgl/renderer/painters/painter_debug.cpp @@ -39,7 +39,8 @@ void Painter::renderTileDebug(const RenderTile& renderTile) { segments, paintAttibuteData, properties, - state.getZoom() + state.getZoom(), + "debug" ); }; @@ -100,7 +101,8 @@ void Painter::renderTileDebug(const mat4& matrix) { tileBorderSegments, paintAttibuteData, properties, - state.getZoom() + state.getZoom(), + "debug" ); } } diff --git a/src/mbgl/renderer/painters/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp index 3a0bfed454..3ca3bdf6b8 100644 --- a/src/mbgl/renderer/painters/painter_fill.cpp +++ b/src/mbgl/renderer/painters/painter_fill.cpp @@ -61,7 +61,8 @@ void Painter::renderFill(PaintParameters& parameters, segments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom() + state.getZoom(), + layer.getID() ); }; @@ -105,7 +106,8 @@ void Painter::renderFill(PaintParameters& parameters, segments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom() + state.getZoom(), + layer.getID() ); }; diff --git a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp index 165476944b..d7310dc208 100644 --- a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp +++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp @@ -58,7 +58,8 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, bucket.triangleSegments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom()); + state.getZoom(), + layer.getID()); } else { parameters.programs.fillExtrusion.get(properties).draw( @@ -79,7 +80,8 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, bucket.triangleSegments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom()); + state.getZoom(), + layer.getID()); }; } diff --git a/src/mbgl/renderer/painters/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp index 58f4131d96..667e19283d 100644 --- a/src/mbgl/renderer/painters/painter_line.cpp +++ b/src/mbgl/renderer/painters/painter_line.cpp @@ -36,7 +36,8 @@ void Painter::renderLine(PaintParameters& parameters, bucket.segments, bucket.paintPropertyBinders.at(layer.getID()), properties, - state.getZoom() + state.getZoom(), + layer.getID() ); }; diff --git a/src/mbgl/renderer/painters/painter_raster.cpp b/src/mbgl/renderer/painters/painter_raster.cpp index 56e38ae8f4..d0ab480616 100644 --- a/src/mbgl/renderer/painters/painter_raster.cpp +++ b/src/mbgl/renderer/painters/painter_raster.cpp @@ -82,7 +82,8 @@ void Painter::renderRaster(PaintParameters& parameters, useBucketBuffers ? bucket.segments : rasterSegments, paintAttributeData, properties, - state.getZoom() + state.getZoom(), + layer.getID() ); } diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 51c3967ae7..183d09fa86 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -59,7 +59,8 @@ void Painter::renderSymbol(PaintParameters& parameters, buffers.segments, binders, paintProperties, - state.getZoom() + state.getZoom(), + layer.getID() ); }; @@ -181,7 +182,8 @@ void Painter::renderSymbol(PaintParameters& parameters, bucket.collisionBox.segments, paintAttributeData, properties, - state.getZoom() + state.getZoom(), + layer.getID() ); } } -- cgit v1.2.1 From 01aff0127458cc334e5d4d9f45f57fc96e314574 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Jul 2017 11:49:25 -0700 Subject: [core] Use a type alias for SegmentVector --- src/mbgl/programs/segment.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/segment.hpp b/src/mbgl/programs/segment.hpp index 74bf4a75c5..ceb6b1536c 100644 --- a/src/mbgl/programs/segment.hpp +++ b/src/mbgl/programs/segment.hpp @@ -39,9 +39,6 @@ public: }; template -class SegmentVector : public std::vector> { -public: - SegmentVector() = default; -}; +using SegmentVector = std::vector>; } // namespace mbgl -- cgit v1.2.1 From 49726cdc7592eddb2c9dc37cd7af79e668755ce1 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Jul 2017 11:54:02 -0700 Subject: [core] Remove segment.cpp --- src/mbgl/programs/segment.cpp | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/mbgl/programs/segment.cpp (limited to 'src') diff --git a/src/mbgl/programs/segment.cpp b/src/mbgl/programs/segment.cpp deleted file mode 100644 index bb09843e21..0000000000 --- a/src/mbgl/programs/segment.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -namespace mbgl { -namespace gl { - -} // namespace gl -} // namespace mbgl -- cgit v1.2.1 From 4c42132183f81bd9263f8513b1fa9f610035ed57 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Jul 2017 12:19:23 -0700 Subject: [core] Reduce memory requirements of VertexArrays --- src/mbgl/gl/attribute.hpp | 22 ++++++++++++++-------- src/mbgl/gl/context.cpp | 5 +++-- src/mbgl/gl/types.hpp | 2 +- src/mbgl/gl/vertex_array.hpp | 17 ++++++++++++++++- 4 files changed, 34 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 1f60c8c980..fa6c2ddeab 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace mbgl { namespace gl { @@ -30,12 +31,12 @@ template <> struct DataTypeOf : std::integral_constant::value, "vertex type must use standard layout"); + assert(attributeSize >= 1); + assert(attributeSize <= 4); + assert(Vertex::attributeOffsets[attributeIndex] <= std::numeric_limits::max()); + static_assert(sizeof(Vertex) <= std::numeric_limits::max(), "vertex too large"); return AttributeBinding { DataTypeOf::value, - attributeSize, - Vertex::attributeOffsets[attributeIndex], + static_cast(attributeSize), + static_cast(Vertex::attributeOffsets[attributeIndex]), buffer.buffer, - sizeof(Vertex), + static_cast(sizeof(Vertex)), 0, }; } static optional offsetBinding(const optional& binding, std::size_t vertexOffset) { + assert(vertexOffset <= std::numeric_limits::max()); if (binding) { AttributeBinding result = *binding; - result.vertexOffset = vertexOffset; + result.vertexOffset = static_cast(vertexOffset); return result; } else { return binding; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index f7d210d52e..35683cff89 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -285,11 +285,12 @@ VertexArray Context::createVertexArray() { if (supportsVertexArrays()) { VertexArrayID id = 0; MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); - return { std::make_unique(UniqueVertexArray(std::move(id), { this }), *this) }; + UniqueVertexArray vao(std::move(id), { this }); + return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })}; } else { // On GL implementations which do not support vertex arrays, attribute bindings are global state. // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. - return { UniqueVertexArrayState(&globalVertexArrayState, [] (VertexArrayState*) {}) }; + return { UniqueVertexArrayState(&globalVertexArrayState, VertexArrayStateDeleter { false }) }; } } diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 058bc226b8..452c882ac9 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -24,7 +24,7 @@ enum class ShaderType : uint32_t { Fragment = 0x8B30 }; -enum class DataType : uint32_t { +enum class DataType : uint16_t { Byte = 0x1400, UnsignedByte = 0x1401, Short = 0x1402, diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp index 9ccf48d9bd..46c67017bb 100644 --- a/src/mbgl/gl/vertex_array.hpp +++ b/src/mbgl/gl/vertex_array.hpp @@ -40,7 +40,22 @@ private: } }; -using UniqueVertexArrayState = std::unique_ptr>; +class VertexArrayStateDeleter { +public: + VertexArrayStateDeleter(bool destroy_) + : destroy(destroy_) {} + + void operator()(VertexArrayState* ptr) const { + if (destroy) { + delete ptr; + } + } + +private: + bool destroy; +}; + +using UniqueVertexArrayState = std::unique_ptr; class VertexArray { public: -- cgit v1.2.1 From 2691fe165d06e0cc015b28a52815e1b024472a97 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Jul 2017 12:25:03 -0700 Subject: [core] Add comments explaining typing of AttributeLocation and UniformLocation --- src/mbgl/gl/types.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 452c882ac9..da08195e58 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -15,8 +15,16 @@ using VertexArrayID = uint32_t; using FramebufferID = uint32_t; using RenderbufferID = uint32_t; +// OpenGL does not formally define a type for attribute locations, but most APIs use +// GLuint. The exception is glGetAttribLocation, which returns GLint so that -1 can +// be used as an error indicator. using AttributeLocation = uint32_t; + +// OpenGL does not formally define a type for uniform locations, but all APIs use GLint. +// The value -1 is special, typically used as a placeholder for an unused uniform and +// "silently ignored". using UniformLocation = int32_t; + using TextureUnit = uint8_t; enum class ShaderType : uint32_t { -- cgit v1.2.1 From 86ee821c6e8e6e68a984c65492523fdf94425ea7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Jul 2017 12:31:46 -0700 Subject: [core] No need for optional in map of VertexArrays --- src/mbgl/programs/program.hpp | 8 ++++---- src/mbgl/programs/segment.hpp | 3 +-- src/mbgl/programs/symbol_program.hpp | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 71d7569f53..bcdb270b9c 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -67,10 +67,10 @@ public: .concat(paintPropertyBinders.attributeBindings(currentProperties)); for (auto& segment : segments) { - optional& vertexArray = segment.vertexArrays[layerID]; + auto vertexArrayIt = segment.vertexArrays.find(layerID); - if (!vertexArray) { - vertexArray = context.createVertexArray(); + if (vertexArrayIt == segment.vertexArrays.end()) { + vertexArrayIt = segment.vertexArrays.emplace(layerID, context.createVertexArray()).first; } program.draw( @@ -80,7 +80,7 @@ public: std::move(stencilMode), std::move(colorMode), allUniformValues, - *vertexArray, + vertexArrayIt->second, Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), indexBuffer, segment.indexOffset, diff --git a/src/mbgl/programs/segment.hpp b/src/mbgl/programs/segment.hpp index ceb6b1536c..f729683ac9 100644 --- a/src/mbgl/programs/segment.hpp +++ b/src/mbgl/programs/segment.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -35,7 +34,7 @@ public: // data-driven paint properties // * when two fill layers have the same layout properties, but one // uses fill-color and the other uses fill-pattern - mutable std::map> vertexArrays; + mutable std::map vertexArrays; }; template diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index ee4855cf8f..a7abf94f56 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -326,10 +326,10 @@ public: .concat(paintPropertyBinders.attributeBindings(currentProperties)); for (auto& segment : segments) { - optional& vertexArray = segment.vertexArrays[layerID]; + auto vertexArrayIt = segment.vertexArrays.find(layerID); - if (!vertexArray) { - vertexArray = context.createVertexArray(); + if (vertexArrayIt == segment.vertexArrays.end()) { + vertexArrayIt = segment.vertexArrays.emplace(layerID, context.createVertexArray()).first; } program.draw( @@ -339,7 +339,7 @@ public: std::move(stencilMode), std::move(colorMode), allUniformValues, - *vertexArray, + vertexArrayIt->second, Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset), indexBuffer, segment.indexOffset, -- cgit v1.2.1 From c0d6a07a8e44c69267c2df98278d54c055c06ca4 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 11 Jul 2017 14:11:59 -0700 Subject: [core] Pass correct sources to programIdentifier --- src/mbgl/gl/program.hpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 9d8b0a5b04..3b54ec194a 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -52,15 +52,13 @@ public: const char* name, const char* vertexSource_, const char* fragmentSource_) { + const std::string vertexSource = shaders::vertexSource(programParameters, vertexSource_); + const std::string fragmentSource = shaders::fragmentSource(programParameters, fragmentSource_); + #if MBGL_HAS_BINARY_PROGRAMS optional cachePath = programParameters.cachePath(name); if (cachePath && context.supportsProgramBinaries()) { - const std::string vertexSource = - shaders::vertexSource(programParameters, vertexSource_); - const std::string fragmentSource = - shaders::fragmentSource(programParameters, fragmentSource_); - const std::string identifier = - shaders::programIdentifier(vertexSource, fragmentSource_); + const std::string identifier = shaders::programIdentifier(vertexSource, fragmentSource); try { if (auto cachedBinaryProgram = util::readFile(*cachePath)) { @@ -94,11 +92,9 @@ public: return std::move(result); } #endif + (void)name; - return Program { - context, shaders::vertexSource(programParameters, vertexSource_), - shaders::fragmentSource(programParameters, fragmentSource_) - }; + return Program { context, vertexSource, fragmentSource }; } template -- cgit v1.2.1 From 1176eade34114834e3c36c602b949ce84c7b356b Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 11 Jul 2017 14:11:02 -0700 Subject: [android] Force previously cached program binaries to be regenerated --- src/mbgl/shaders/shaders.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/mbgl/shaders/shaders.cpp b/src/mbgl/shaders/shaders.cpp index 31ff405f02..2e5a318024 100644 --- a/src/mbgl/shaders/shaders.cpp +++ b/src/mbgl/shaders/shaders.cpp @@ -22,6 +22,7 @@ std::string programIdentifier(const std::string& vertexSource, const std::string ss << std::setfill('0') << std::setw(sizeof(size_t) * 2) << std::hex; ss << std::hash()(vertexSource); ss << std::hash()(fragmentSource); + ss << "v2"; return ss.str(); } -- cgit v1.2.1 From 13d6920661432afcbfbd6c956708964efc366dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Thu, 13 Jul 2017 16:57:31 +0200 Subject: [core] fix division by zero when defaultFadeDuration is 0 --- src/mbgl/renderer/cross_faded_property_evaluator.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.cpp b/src/mbgl/renderer/cross_faded_property_evaluator.cpp index ee3c86614f..4dff9dbf12 100644 --- a/src/mbgl/renderer/cross_faded_property_evaluator.cpp +++ b/src/mbgl/renderer/cross_faded_property_evaluator.cpp @@ -27,7 +27,10 @@ Faded CrossFadedPropertyEvaluator::calculate(const T& min, const T& mid, c const float z = parameters.z; const float fraction = z - std::floor(z); const std::chrono::duration d = parameters.defaultFadeDuration; - const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f); + const float t = + d != std::chrono::duration::zero() + ? std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f) + : 1.0f; return z > parameters.zoomHistory.lastIntegerZoom ? Faded { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t } -- cgit v1.2.1 From 6b954677c0e57b1c1b8201210aa31d956d79c9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 14 Jul 2017 12:00:53 +0200 Subject: [core] fix undefined behavior for division through 0 --- src/mbgl/text/collision_feature.cpp | 2 +- src/mbgl/text/collision_tile.cpp | 25 ++++++++++++++++--------- src/mbgl/util/math.hpp | 13 +++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp index 022ee50644..3eb08da8d1 100644 --- a/src/mbgl/text/collision_feature.cpp +++ b/src/mbgl/text/collision_feature.cpp @@ -135,7 +135,7 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo // This makes our calculation spot-on at scale=2, and on the conservative side for // lower scales const float distanceToInnerEdge = std::max(std::fabs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0.0f); - float maxScale = labelLength / 2 / distanceToInnerEdge; + float maxScale = util::division(labelLength / 2, distanceToInnerEdge, std::numeric_limits::infinity()); // The box maxScale calculations are designed to be conservative on collisions in the scale range // [1,2]. At scale=1, each box has 50% overlap, and at scale=2, the boxes are lined up edge diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp index b3fbe6f8a3..cc9b602f08 100644 --- a/src/mbgl/text/collision_tile.cpp +++ b/src/mbgl/text/collision_tile.cpp @@ -20,7 +20,11 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ rotationMatrix = { { angle_cos, -angle_sin, angle_sin, angle_cos } }; reverseRotationMatrix = { { angle_cos, angle_sin, -angle_sin, angle_cos } }; - perspectiveRatio = 1.0f + 0.5f * ((config.cameraToTileDistance / config.cameraToCenterDistance) - 1.0f); + perspectiveRatio = + 1.0f + + 0.5f * (util::division(config.cameraToTileDistance, config.cameraToCenterDistance, 1.0f) - + 1.0f); + minScale /= perspectiveRatio; maxScale /= perspectiveRatio; @@ -30,22 +34,25 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ // purposes, but we still want to use the yStretch approximation // here because we can't adjust the aspect ratio of the collision // boxes at render time. - yStretch = util::max(1.0f, config.cameraToTileDistance / (config.cameraToCenterDistance * std::cos(config.pitch))); + yStretch = util::max( + 1.0f, util::division(config.cameraToTileDistance, + config.cameraToCenterDistance * std::cos(config.pitch), 1.0f)); } - float CollisionTile::findPlacementScale(const Point& anchor, const CollisionBox& box, const float boxMaxScale, const Point& blockingAnchor, const CollisionBox& blocking) { float minPlacementScale = minScale; // Find the lowest scale at which the two boxes can fit side by side without overlapping. // Original algorithm: - float s1 = (blocking.x1 - box.x2) / (anchor.x - blockingAnchor.x); // scale at which new box is to the left of old box - float s2 = (blocking.x2 - box.x1) / (anchor.x - blockingAnchor.x); // scale at which new box is to the right of old box - float s3 = (blocking.y1 - box.y2) * yStretch / (anchor.y - blockingAnchor.y); // scale at which new box is to the top of old box - float s4 = (blocking.y2 - box.y1) * yStretch / (anchor.y - blockingAnchor.y); // scale at which new box is to the bottom of old box - if (std::isnan(s1) || std::isnan(s2)) s1 = s2 = 1; - if (std::isnan(s3) || std::isnan(s4)) s3 = s4 = 1; + const float s1 = util::division(blocking.x1 - box.x2, anchor.x - blockingAnchor.x, + 1.0f); // scale at which new box is to the left of old box + const float s2 = util::division(blocking.x2 - box.x1, anchor.x - blockingAnchor.x, + 1.0f); // scale at which new box is to the right of old box + const float s3 = util::division((blocking.y1 - box.y2) * yStretch, anchor.y - blockingAnchor.y, + 1.0f); // scale at which new box is to the top of old box + const float s4 = util::division((blocking.y2 - box.y1) * yStretch, anchor.y - blockingAnchor.y, + 1.0f); // scale at which new box is to the bottom of old box float collisionFreeScale = util::min(util::max(s1, s2), util::max(s3, s4)); diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp index f969ecaedd..eb3c7d0fde 100644 --- a/src/mbgl/util/math.hpp +++ b/src/mbgl/util/math.hpp @@ -106,5 +106,18 @@ T smoothstep(T edge0, T edge1, T x) { return t * t * (T(3) - T(2) * t); } +template +inline T division(const T dividend, const T divisor, const T nan) { + if (divisor == 0) { + if (dividend == 0) { + return nan; + } else { + return std::copysign(std::numeric_limits::infinity(), dividend); + } + } else { + return dividend / divisor; + } +} + } // namespace util } // namespace mbgl -- cgit v1.2.1 From fdfd5f91f51f7185f731783ad8b2b4ff9c3e2f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 14 Jul 2017 15:30:27 +0200 Subject: [core] abort early when the dimension is 0 --- src/mbgl/map/transform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 50f979437d..ab10b21cc1 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -168,7 +168,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima double angle = camera.angle.value_or(getAngle()); double pitch = camera.pitch.value_or(getPitch()); - if (std::isnan(zoom)) { + if (std::isnan(zoom) || state.size.isEmpty()) { return; } -- cgit v1.2.1 From 1d15ed64dcf78daa9459247127857513608c18ad Mon Sep 17 00:00:00 2001 From: Asheem Mamoowala Date: Tue, 20 Jun 2017 11:09:19 -0700 Subject: [core] Use shared pointer to manage Image source raster data and speed up change detection --- src/mbgl/renderer/buckets/raster_bucket.cpp | 19 +++++- src/mbgl/renderer/buckets/raster_bucket.hpp | 5 +- src/mbgl/renderer/sources/render_image_source.cpp | 75 ++++++++++++++--------- src/mbgl/renderer/sources/render_image_source.hpp | 2 +- src/mbgl/style/sources/image_source_impl.cpp | 8 +-- src/mbgl/style/sources/image_source_impl.hpp | 6 +- 6 files changed, 74 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index 49ec0065c3..61548ee333 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -9,12 +9,19 @@ namespace mbgl { using namespace style; -RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)) { +RasterBucket::RasterBucket(UnassociatedImage&& image_) { + image = std::make_shared(std::move(image_)); } +RasterBucket::RasterBucket(std::shared_ptr image_): image(image_) { + +} void RasterBucket::upload(gl::Context& context) { + if (!hasData()) { + return; + } if (!texture) { - texture = context.createTexture(image); + texture = context.createTexture(*image); } if (!vertices.empty()) { vertexBuffer = context.createVertexBuffer(std::move(vertices)); @@ -32,6 +39,12 @@ void RasterBucket::clear() { uploaded = false; } + +void RasterBucket::setImage(std::shared_ptr image_) { + image = std::move(image_); + texture = {}; + uploaded = false; +} void RasterBucket::render(Painter& painter, PaintParameters& parameters, const RenderLayer& layer, @@ -47,7 +60,7 @@ void RasterBucket::render(Painter& painter, } bool RasterBucket::hasData() const { - return true; + return !!image; } } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index 44b9111b81..e92e4b51f7 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -14,7 +14,7 @@ namespace mbgl { class RasterBucket : public Bucket { public: RasterBucket(UnassociatedImage&&); - + RasterBucket(std::shared_ptr); void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override; void render(Painter& painter, @@ -24,7 +24,8 @@ public: bool hasData() const override; void clear(); - UnassociatedImage image; + void setImage(std::shared_ptr); + std::shared_ptr image; optional texture; // Bucket specific vertices are used for Image Sources only diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index f1860b6b62..a17f97ee2f 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -14,7 +14,7 @@ namespace mbgl { using namespace style; RenderImageSource::RenderImageSource(Immutable impl_) - : RenderSource(impl_), shouldRender(false) { + : RenderSource(impl_) { } RenderImageSource::~RenderImageSource() = default; @@ -42,13 +42,13 @@ void RenderImageSource::startRender(Painter& painter) { matrices.push_back(matrix); } - if (bucket->needsUpload() && shouldRender) { + if (bucket->needsUpload()) { bucket->upload(painter.context); } } void RenderImageSource::finishRender(Painter& painter) { - if (!isLoaded() || !shouldRender) { + if (!isLoaded()) { return; } for (auto matrix : matrices) { @@ -73,15 +73,24 @@ void RenderImageSource::update(Immutable baseImpl_, const bool needsRendering, const bool, const TileParameters& parameters) { - std::swap(baseImpl, baseImpl_); - enabled = needsRendering; + if (!needsRendering) { + return; + } auto transformState = parameters.transformState; - auto size = transformState.getSize(); - double viewportHeight = size.height; + std::swap(baseImpl, baseImpl_); auto coords = impl().getCoordinates(); + std::shared_ptr image = impl().getImage(); + + if (!image || !image->valid()) { + enabled = false; + return; + } + + auto size = transformState.getSize(); + const double viewportHeight = size.height; // Compute the screen coordinates at wrap=0 for the given LatLng ScreenCoordinate nePixel = { -INFINITY, -INFINITY }; @@ -94,38 +103,51 @@ void RenderImageSource::update(Immutable baseImpl_, swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y); nePixel.y = std::max(nePixel.y, viewportHeight - pixel.y); } - double width = nePixel.x - swPixel.x; - double height = nePixel.y - swPixel.y; + const double width = nePixel.x - swPixel.x; + const double height = nePixel.y - swPixel.y; // Don't bother drawing the ImageSource unless it occupies >4 screen pixels - shouldRender = (width * height > 4); - if (!shouldRender) { + enabled = (width * height > 4); + if (!enabled) { return; } // Calculate the optimum zoom level to determine the tile ids to use for transforms double minScale = INFINITY; - if (width > 0 || height > 0) { - double scaleX = double(size.width) / width; - double scaleY = double(size.height) / height; - minScale = util::min(scaleX, scaleY); - } + double scaleX = double(size.width) / width; + double scaleY = double(size.height) / height; + minScale = util::min(scaleX, scaleY); double zoom = transformState.getZoom() + util::log2(minScale); - zoom = util::clamp(zoom, transformState.getMinZoom(), transformState.getMaxZoom()); - + zoom = std::floor(util::clamp(zoom, transformState.getMinZoom(), transformState.getMaxZoom())); auto imageBounds = LatLngBounds::hull(coords[0], coords[1]); imageBounds.extend(coords[2]); imageBounds.extend(coords[3]); - auto tileCover = util::tileCover(imageBounds, ::floor(zoom)); + auto tileCover = util::tileCover(imageBounds, zoom); tileIds.clear(); tileIds.push_back(tileCover[0]); + bool hasVisibleTile = false; // Add additional wrapped tile ids if neccessary auto idealTiles = util::tileCover(transformState, transformState.getZoom()); for (auto tile : idealTiles) { if (tile.wrap != 0 && tileCover[0].canonical.isChildOf(tile.canonical)) { tileIds.push_back({ tile.wrap, tileCover[0].canonical }); + hasVisibleTile = true; } + else if (!hasVisibleTile) { + for (auto coveringTile: tileCover) { + if(coveringTile.canonical == tile.canonical || + coveringTile.canonical.isChildOf(tile.canonical) || + tile.canonical.isChildOf(coveringTile.canonical)) { + hasVisibleTile = true; + } + } + } + } + + enabled = hasVisibleTile; + if (!enabled) { + return; } // Calculate Geometry Coordinates based on tile cover at ideal zoom @@ -135,16 +157,13 @@ void RenderImageSource::update(Immutable baseImpl_, auto gc = TileCoordinate::toGeometryCoordinate(tileIds[0], tc.p); geomCoords.push_back(gc); } - - const UnassociatedImage& image = impl().getImage(); - if (!image.valid()) { - return; - } - - if (!bucket || image != bucket->image) { - bucket = std::make_unique(image.clone()); + if (!bucket) { + bucket = std::make_unique(image); } else { bucket->clear(); + if (image != bucket->image) { + bucket->setImage(image); + } } // Set Bucket Vertices, Indices, and segments @@ -166,7 +185,7 @@ void RenderImageSource::update(Immutable baseImpl_, void RenderImageSource::render(Painter& painter, PaintParameters& parameters, const RenderLayer& layer) { - if (isLoaded() && !bucket->needsUpload() && shouldRender) { + if (isEnabled() && isLoaded() && !bucket->needsUpload()) { for (auto matrix : matrices) { bucket->render(painter, parameters, layer, matrix); } diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 41c4bd5483..6389251709 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -8,6 +8,7 @@ namespace mbgl { class RenderLayer; class PaintParameters; class RasterBucket; +class LatLng; namespace gl { class Context; @@ -52,7 +53,6 @@ private: std::vector tileIds; std::unique_ptr bucket; std::vector matrices; - bool shouldRender; }; template <> diff --git a/src/mbgl/style/sources/image_source_impl.cpp b/src/mbgl/style/sources/image_source_impl.cpp index 98f3cc9db9..eb3e2635e5 100644 --- a/src/mbgl/style/sources/image_source_impl.cpp +++ b/src/mbgl/style/sources/image_source_impl.cpp @@ -12,17 +12,17 @@ ImageSource::Impl::Impl(std::string id_, std::array coords_) ImageSource::Impl::Impl(const Impl& other, std::array coords_) : Source::Impl(other), coords(std::move(coords_)), - image(other.image.clone()) { + image(other.image) { } -ImageSource::Impl::Impl(const Impl& rhs, UnassociatedImage image_) +ImageSource::Impl::Impl(const Impl& rhs, UnassociatedImage&& image_) : Source::Impl(rhs), coords(rhs.coords), - image(std::move(image_)) { + image(std::make_shared(std::move(image_))) { } ImageSource::Impl::~Impl() = default; -const UnassociatedImage& ImageSource::Impl::getImage() const { +std::shared_ptr ImageSource::Impl::getImage() const { return image; } diff --git a/src/mbgl/style/sources/image_source_impl.hpp b/src/mbgl/style/sources/image_source_impl.hpp index 5fd41ac6e6..e0999c34a5 100644 --- a/src/mbgl/style/sources/image_source_impl.hpp +++ b/src/mbgl/style/sources/image_source_impl.hpp @@ -13,17 +13,17 @@ class ImageSource::Impl : public Source::Impl { public: Impl(std::string id, std::array coords); Impl(const Impl& rhs, std::array coords); - Impl(const Impl& rhs, UnassociatedImage image); + Impl(const Impl& rhs, UnassociatedImage&& image); ~Impl() final; - const UnassociatedImage& getImage() const; + std::shared_ptr getImage() const; std::array getCoordinates() const; optional getAttribution() const final; private: std::array coords; - UnassociatedImage image; + std::shared_ptr image; }; } // namespace style -- cgit v1.2.1 From 8ae70105463db78699ef3743fb24503ed8feb054 Mon Sep 17 00:00:00 2001 From: Asheem Mamoowala Date: Tue, 11 Jul 2017 14:31:05 -0700 Subject: [core][ios][android][macos] Use premultiplied image directly for RasterTile and ImageSource, un-premultiply in the shader for blending --- src/mbgl/renderer/buckets/raster_bucket.cpp | 8 ++++---- src/mbgl/renderer/buckets/raster_bucket.hpp | 8 ++++---- src/mbgl/renderer/sources/render_image_source.cpp | 2 +- src/mbgl/shaders/raster.cpp | 6 ++++++ src/mbgl/style/sources/image_source.cpp | 5 ++--- src/mbgl/style/sources/image_source_impl.cpp | 6 +++--- src/mbgl/style/sources/image_source_impl.hpp | 6 +++--- src/mbgl/tile/raster_tile_worker.cpp | 2 +- 8 files changed, 24 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index 61548ee333..8a2f1227a5 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -9,11 +9,11 @@ namespace mbgl { using namespace style; -RasterBucket::RasterBucket(UnassociatedImage&& image_) { - image = std::make_shared(std::move(image_)); +RasterBucket::RasterBucket(PremultipliedImage&& image_) { + image = std::make_shared(std::move(image_)); } -RasterBucket::RasterBucket(std::shared_ptr image_): image(image_) { +RasterBucket::RasterBucket(std::shared_ptr image_): image(image_) { } void RasterBucket::upload(gl::Context& context) { @@ -40,7 +40,7 @@ void RasterBucket::clear() { uploaded = false; } -void RasterBucket::setImage(std::shared_ptr image_) { +void RasterBucket::setImage(std::shared_ptr image_) { image = std::move(image_); texture = {}; uploaded = false; diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index e92e4b51f7..1b0d787bcd 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -13,8 +13,8 @@ namespace mbgl { class RasterBucket : public Bucket { public: - RasterBucket(UnassociatedImage&&); - RasterBucket(std::shared_ptr); + RasterBucket(PremultipliedImage&&); + RasterBucket(std::shared_ptr); void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override; void render(Painter& painter, @@ -24,8 +24,8 @@ public: bool hasData() const override; void clear(); - void setImage(std::shared_ptr); - std::shared_ptr image; + void setImage(std::shared_ptr); + std::shared_ptr image; optional texture; // Bucket specific vertices are used for Image Sources only diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index a17f97ee2f..3ffff5c8c6 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -82,7 +82,7 @@ void RenderImageSource::update(Immutable baseImpl_, std::swap(baseImpl, baseImpl_); auto coords = impl().getCoordinates(); - std::shared_ptr image = impl().getImage(); + std::shared_ptr image = impl().getImage(); if (!image || !image->valid()) { enabled = false; diff --git a/src/mbgl/shaders/raster.cpp b/src/mbgl/shaders/raster.cpp index eb7a2db240..f454078310 100644 --- a/src/mbgl/shaders/raster.cpp +++ b/src/mbgl/shaders/raster.cpp @@ -45,6 +45,12 @@ void main() { // read and cross-fade colors from the main and parent tiles vec4 color0 = texture2D(u_image0, v_pos0); vec4 color1 = texture2D(u_image1, v_pos1); + if (color0.a > 0.0) { + color0.rgb = color0.rgb / color0.a; + } + if (color1.a > 0.0) { + color1.rgb = color1.rgb / color1.a; + } vec4 color = mix(color0, color1, u_fade_t); color.a *= u_opacity; vec3 rgb = color.rgb; diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp index 9313d8da4a..9b60ba1a48 100644 --- a/src/mbgl/style/sources/image_source.cpp +++ b/src/mbgl/style/sources/image_source.cpp @@ -37,7 +37,7 @@ void ImageSource::setURL(const std::string& url_) { } } -void ImageSource::setImage(UnassociatedImage&& image_) { +void ImageSource::setImage(PremultipliedImage&& image_) { url = {}; if (req) { req.reset(); @@ -70,8 +70,7 @@ void ImageSource::loadDescription(FileSource& fileSource) { observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty image url"))); } else { try { - UnassociatedImage image = util::unpremultiply(decodeImage(*res.data)); - baseImpl = makeMutable(impl(), std::move(image)); + baseImpl = makeMutable(impl(), decodeImage(*res.data)); } catch (...) { observer->onSourceError(*this, std::current_exception()); } diff --git a/src/mbgl/style/sources/image_source_impl.cpp b/src/mbgl/style/sources/image_source_impl.cpp index eb3e2635e5..c1f31dbdc6 100644 --- a/src/mbgl/style/sources/image_source_impl.cpp +++ b/src/mbgl/style/sources/image_source_impl.cpp @@ -15,14 +15,14 @@ ImageSource::Impl::Impl(const Impl& other, std::array coords_) image(other.image) { } -ImageSource::Impl::Impl(const Impl& rhs, UnassociatedImage&& image_) +ImageSource::Impl::Impl(const Impl& rhs, PremultipliedImage&& image_) : Source::Impl(rhs), coords(rhs.coords), - image(std::make_shared(std::move(image_))) { + image(std::make_shared(std::move(image_))) { } ImageSource::Impl::~Impl() = default; -std::shared_ptr ImageSource::Impl::getImage() const { +std::shared_ptr ImageSource::Impl::getImage() const { return image; } diff --git a/src/mbgl/style/sources/image_source_impl.hpp b/src/mbgl/style/sources/image_source_impl.hpp index e0999c34a5..1e1b005a32 100644 --- a/src/mbgl/style/sources/image_source_impl.hpp +++ b/src/mbgl/style/sources/image_source_impl.hpp @@ -13,17 +13,17 @@ class ImageSource::Impl : public Source::Impl { public: Impl(std::string id, std::array coords); Impl(const Impl& rhs, std::array coords); - Impl(const Impl& rhs, UnassociatedImage&& image); + Impl(const Impl& rhs, PremultipliedImage&& image); ~Impl() final; - std::shared_ptr getImage() const; + std::shared_ptr getImage() const; std::array getCoordinates() const; optional getAttribution() const final; private: std::array coords; - std::shared_ptr image; + std::shared_ptr image; }; } // namespace style diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp index 86fb5f181d..3c8af97b40 100644 --- a/src/mbgl/tile/raster_tile_worker.cpp +++ b/src/mbgl/tile/raster_tile_worker.cpp @@ -17,7 +17,7 @@ void RasterTileWorker::parse(std::shared_ptr data) { } try { - auto bucket = std::make_unique(util::unpremultiply(decodeImage(*data))); + auto bucket = std::make_unique(decodeImage(*data)); parent.invoke(&RasterTile::onParsed, std::move(bucket)); } catch (...) { parent.invoke(&RasterTile::onError, std::current_exception()); -- cgit v1.2.1 From e35cbbae55ab01f33690b1bb2e918c5f8393b854 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 22 Jun 2017 14:33:21 -0700 Subject: [core] mutate style on annotation mutations immediately --- src/mbgl/annotation/annotation_manager.cpp | 87 +++++++++++++----------------- src/mbgl/annotation/annotation_manager.hpp | 20 ++++--- src/mbgl/map/map.cpp | 20 ++++--- src/mbgl/map/update.hpp | 1 - 4 files changed, 60 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index a69dba1bf2..ec5a360a90 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -18,9 +19,20 @@ using namespace style; const std::string AnnotationManager::SourceID = "com.mapbox.annotations"; const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; -AnnotationManager::AnnotationManager() = default; +AnnotationManager::AnnotationManager(Style& style_) + : style(style_) { +}; + AnnotationManager::~AnnotationManager() = default; +void AnnotationManager::setStyle(Style& style_) { + style = style_; +} + +void AnnotationManager::onStyleLoaded() { + updateStyle(); +} + AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, const uint8_t maxZoom) { std::lock_guard lock(mutex); AnnotationID id = nextID++; @@ -51,13 +63,13 @@ void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& anno void AnnotationManager::add(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) { ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id, std::make_unique(id, annotation, maxZoom)).first->second; - obsoleteShapeAnnotationLayers.erase(impl.layerID); + impl.updateStyle(*style.get().impl); } void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) { ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id, std::make_unique(id, annotation, maxZoom)).first->second; - obsoleteShapeAnnotationLayers.erase(impl.layerID); + impl.updateStyle(*style.get().impl); } Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) { @@ -71,16 +83,11 @@ Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& const SymbolAnnotation& existing = it->second->annotation; - if (existing.geometry != annotation.geometry) { + if (existing.geometry != annotation.geometry || existing.icon != annotation.icon) { result |= Update::AnnotationData; - } - - if (existing.icon != annotation.icon) { - result |= Update::AnnotationData | Update::AnnotationStyle; - } - if (result != Update::Nothing) { - removeAndAdd(id, annotation, maxZoom); + remove(id); + add(id, annotation, maxZoom); } return result; @@ -93,8 +100,9 @@ Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& a return Update::Nothing; } - removeAndAdd(id, annotation, maxZoom); - return Update::AnnotationData | Update::AnnotationStyle; + shapeAnnotations.erase(it); + add(id, annotation, maxZoom); + return Update::AnnotationData; } Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) { @@ -104,15 +112,9 @@ Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& a return Update::Nothing; } - removeAndAdd(id, annotation, maxZoom); - return Update::AnnotationData | Update::AnnotationStyle; -} - -void AnnotationManager::removeAndAdd(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) { - remove(id); - Annotation::visit(annotation, [&] (const auto& annotation_) { - this->add(id, annotation_, maxZoom); - }); + shapeAnnotations.erase(it); + add(id, annotation, maxZoom); + return Update::AnnotationData; } void AnnotationManager::remove(const AnnotationID& id) { @@ -120,8 +122,9 @@ void AnnotationManager::remove(const AnnotationID& id) { symbolTree.remove(symbolAnnotations.at(id)); symbolAnnotations.erase(id); } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) { - obsoleteShapeAnnotationLayers.insert(shapeAnnotations.at(id)->layerID); - shapeAnnotations.erase(id); + auto it = shapeAnnotations.find(id); + *style.get().impl->removeLayer(it->second->layerID); + shapeAnnotations.erase(it); } else { assert(false); // Should never happen } @@ -149,11 +152,11 @@ std::unique_ptr AnnotationManager::getTileData(const Canonic return tileData; } -void AnnotationManager::updateStyle(Style::Impl& style) { +void AnnotationManager::updateStyle() { // Create annotation source, point layer, and point bucket. We do everything via Style::Impl // because we don't want annotation mutations to trigger Style::Impl::styleMutated to be set. - if (!style.getSource(SourceID)) { - style.addSource(std::make_unique()); + if (!style.get().impl->getSource(SourceID)) { + style.get().impl->addSource(std::make_unique()); std::unique_ptr layer = std::make_unique(PointLayerID, SourceID); @@ -162,13 +165,13 @@ void AnnotationManager::updateStyle(Style::Impl& style) { layer->setIconAllowOverlap(true); layer->setIconIgnorePlacement(true); - style.addLayer(std::move(layer)); + style.get().impl->addLayer(std::move(layer)); } std::lock_guard lock(mutex); for (const auto& shape : shapeAnnotations) { - shape.second->updateStyle(style); + shape.second->updateStyle(*style.get().impl); } for (const auto& image : images) { @@ -178,23 +181,8 @@ void AnnotationManager::updateStyle(Style::Impl& style) { // of which images need to be added because we don't know if the style is the same // instance as in the last updateStyle call. If it's a new style, we need to add all // images.) - style.addImage(std::make_unique(image.second)); - } - - for (const auto& layer : obsoleteShapeAnnotationLayers) { - if (style.getLayer(layer)) { - style.removeLayer(layer); - } - } - - for (const auto& image : obsoleteImages) { - if (style.getImage(image)) { - style.removeImage(image); - } + style.get().impl->addImage(std::make_unique(image.second)); } - - obsoleteShapeAnnotationLayers.clear(); - obsoleteImages.clear(); } void AnnotationManager::updateData() { @@ -225,16 +213,17 @@ void AnnotationManager::addImage(std::unique_ptr image) { std::lock_guard lock(mutex); const std::string id = prefixedImageID(image->getID()); images.erase(id); - images.emplace(id, - style::Image(id, image->getImage().clone(), image->getPixelRatio(), image->isSdf())); - obsoleteImages.erase(id); + auto inserted = images.emplace(id, style::Image(id, image->getImage().clone(), + image->getPixelRatio(), image->isSdf())); + + style.get().impl->addImage(std::make_unique(inserted.first->second)); } void AnnotationManager::removeImage(const std::string& id_) { std::lock_guard lock(mutex); const std::string id = prefixedImageID(id_); images.erase(id); - obsoleteImages.insert(id); + style.get().impl->removeImage(id); } double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id_) { diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp index 6906791db7..dee823bc0f 100644 --- a/src/mbgl/annotation/annotation_manager.hpp +++ b/src/mbgl/annotation/annotation_manager.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -21,9 +20,13 @@ class AnnotationTileData; class SymbolAnnotationImpl; class ShapeAnnotationImpl; +namespace style { +class Style; +} // namespace style + class AnnotationManager : private util::noncopyable { public: - AnnotationManager(); + AnnotationManager(style::Style&); ~AnnotationManager(); AnnotationID addAnnotation(const Annotation&, const uint8_t maxZoom); @@ -34,7 +37,9 @@ public: void removeImage(const std::string&); double getTopOffsetPixelsForImage(const std::string&); - void updateStyle(style::Style::Impl&); + void setStyle(style::Style&); + void onStyleLoaded(); + void updateData(); void addTile(AnnotationTile&); @@ -52,12 +57,14 @@ private: Update update(const AnnotationID&, const LineAnnotation&, const uint8_t); Update update(const AnnotationID&, const FillAnnotation&, const uint8_t); - void removeAndAdd(const AnnotationID&, const Annotation&, const uint8_t); - void remove(const AnnotationID&); + void updateStyle(); + std::unique_ptr getTileData(const CanonicalTileID&); + std::reference_wrapper style; + std::mutex mutex; AnnotationID nextID = 0; @@ -73,8 +80,7 @@ private: SymbolAnnotationMap symbolAnnotations; ShapeAnnotationMap shapeAnnotations; ImageMap images; - std::unordered_set obsoleteShapeAnnotationLayers; - std::unordered_set obsoleteImages; + std::unordered_set tiles; friend class AnnotationTile; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 26795f7814..e644f91c4f 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -87,11 +87,12 @@ public: Update updateFlags = Update::Nothing; - AnnotationManager annotationManager; std::unique_ptr painter; std::unique_ptr