diff options
author | Molly Lloyd <mollymerp@users.noreply.github.com> | 2018-01-23 10:49:23 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-23 10:49:23 -0800 |
commit | f3294200c6c866e5ab031ad8346c59a76aa37249 (patch) | |
tree | 6d9aedb552552607641a15c415a60be99a0877d5 /src/mbgl/renderer | |
parent | 2d15aed43c9faa875a8f625c3afc286f1175e0ce (diff) | |
download | qtlocation-mapboxgl-f3294200c6c866e5ab031ad8346c59a76aa37249.tar.gz |
[core] add raster-dem source type and hillshade layer type (#10642)
Diffstat (limited to 'src/mbgl/renderer')
-rw-r--r-- | src/mbgl/renderer/buckets/hillshade_bucket.cpp | 113 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/hillshade_bucket.hpp | 58 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_hillshade_layer.cpp | 158 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_hillshade_layer.hpp | 38 | ||||
-rw-r--r-- | src/mbgl/renderer/render_layer.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/render_source.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/render_source.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/renderer_impl.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_raster_dem_source.cpp | 165 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_raster_dem_source.hpp | 54 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.hpp | 1 |
12 files changed, 602 insertions, 3 deletions
diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.cpp b/src/mbgl/renderer/buckets/hillshade_bucket.cpp new file mode 100644 index 0000000000..8011681ee0 --- /dev/null +++ b/src/mbgl/renderer/buckets/hillshade_bucket.cpp @@ -0,0 +1,113 @@ +#include <mbgl/renderer/buckets/hillshade_bucket.hpp> +#include <mbgl/renderer/layers/render_hillshade_layer.hpp> +#include <mbgl/programs/hillshade_program.hpp> +#include <mbgl/programs/hillshade_prepare_program.hpp> +#include <mbgl/gl/context.hpp> + +namespace mbgl { + +using namespace style; + +HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_): demdata(image_) { +} + +HillshadeBucket::HillshadeBucket(DEMData&& demdata_) : demdata(std::move(demdata_)) { +} + +const DEMData& HillshadeBucket::getDEMData() const { + return demdata; +} + +DEMData& HillshadeBucket::getDEMData() { + return demdata; +} + +void HillshadeBucket::upload(gl::Context& context) { + if (!hasData()) { + return; + } + + + const PremultipliedImage* image = demdata.getImage(); + dem = context.createTexture(*image); + + if (!segments.empty()) { + vertexBuffer = context.createVertexBuffer(std::move(vertices)); + indexBuffer = context.createIndexBuffer(std::move(indices)); + } + uploaded = true; +} + +void HillshadeBucket::clear() { + vertexBuffer = {}; + indexBuffer = {}; + segments.clear(); + vertices.clear(); + indices.clear(); + + uploaded = false; +} + +void HillshadeBucket::setMask(TileMask&& mask_) { + if (mask == mask_) { + return; + } + + mask = std::move(mask_); + clear(); + + if (mask == TileMask{ { 0, 0, 0 } }) { + // We want to render the full tile, and keeping the segments/vertices/indices empty means + // using the global shared buffers for covering the entire tile. + return; + } + + // Create a new segment so that we will upload (empty) buffers even when there is nothing to + // draw for this tile. + segments.emplace_back(0, 0); + + constexpr const uint16_t vertexLength = 4; + + // Create the vertex buffer for the specified tile mask. + for (const auto& id : mask) { + // Create a quad for every masked tile. + const int32_t vertexExtent = util::EXTENT >> id.z; + + const Point<int16_t> tlVertex = { static_cast<int16_t>(id.x * vertexExtent), + static_cast<int16_t>(id.y * vertexExtent) }; + const Point<int16_t> brVertex = { static_cast<int16_t>(tlVertex.x + vertexExtent), + static_cast<int16_t>(tlVertex.y + vertexExtent) }; + + if (segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + // Move to a new segments because the old one can't hold the geometry. + segments.emplace_back(vertices.vertexSize(), indices.indexSize()); + } + + vertices.emplace_back( + HillshadeProgram::layoutVertex({ tlVertex.x, tlVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(tlVertex.y) })); + vertices.emplace_back( + HillshadeProgram::layoutVertex({ brVertex.x, tlVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(tlVertex.y) })); + vertices.emplace_back( + HillshadeProgram::layoutVertex({ tlVertex.x, brVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(brVertex.y) })); + vertices.emplace_back( + HillshadeProgram::layoutVertex({ brVertex.x, brVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(brVertex.y) })); + + auto& segment = segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + const uint16_t offset = segment.vertexLength; + + // 0, 1, 2 + // 1, 2, 3 + indices.emplace_back(offset, offset + 1, offset + 2); + indices.emplace_back(offset + 1, offset + 2, offset + 3); + + segment.vertexLength += vertexLength; + segment.indexLength += 6; + } +} + +bool HillshadeBucket::hasData() const { + return demdata.getImage()->valid(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.hpp b/src/mbgl/renderer/buckets/hillshade_bucket.hpp new file mode 100644 index 0000000000..3d9f6c61af --- /dev/null +++ b/src/mbgl/renderer/buckets/hillshade_bucket.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/gl/texture.hpp> +#include <mbgl/gl/vertex_buffer.hpp> +#include <mbgl/programs/hillshade_program.hpp> +#include <mbgl/programs/hillshade_prepare_program.hpp> +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/renderer/tile_mask.hpp> +#include <mbgl/geometry/dem_data.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/optional.hpp> + +namespace mbgl { + +class HillshadeBucket : public Bucket { +public: + HillshadeBucket(PremultipliedImage&&); + HillshadeBucket(std::shared_ptr<PremultipliedImage>); + HillshadeBucket(DEMData&&); + + + void upload(gl::Context&) override; + bool hasData() const override; + + void clear(); + void setMask(TileMask&&); + + optional<gl::Texture> dem; + optional<gl::Texture> texture; + + TileMask mask{ { 0, 0, 0 } }; + + const DEMData& getDEMData() const; + DEMData& getDEMData(); + + bool isPrepared() const { + return prepared; + } + + void setPrepared (bool preparedState) { + prepared = preparedState; + } + + // Raster-DEM Tile Sources use the default buffers from Painter + gl::VertexVector<HillshadeLayoutVertex> vertices; + gl::IndexVector<gl::Triangles> indices; + SegmentVector<HillshadeAttributes> segments; + + optional<gl::VertexBuffer<HillshadeLayoutVertex>> vertexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; +private: + DEMData demdata; + bool prepared = false; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp new file mode 100644 index 0000000000..7a767522c0 --- /dev/null +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -0,0 +1,158 @@ +#include <mbgl/renderer/layers/render_hillshade_layer.hpp> +#include <mbgl/renderer/buckets/hillshade_bucket.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/renderer/render_static_data.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/hillshade_program.hpp> +#include <mbgl/programs/hillshade_prepare_program.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/style/layers/hillshade_layer_impl.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/offscreen_texture.hpp> + +namespace mbgl { + +using namespace style; +RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl) + : RenderLayer(style::LayerType::Hillshade, _impl), + unevaluated(impl().paint.untransitioned()) { +} + +const style::HillshadeLayer::Impl& RenderHillshadeLayer::impl() const { + return static_cast<const style::HillshadeLayer::Impl&>(*baseImpl); +} + +std::unique_ptr<Bucket> RenderHillshadeLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { + assert(false); + return nullptr; +} + +const std::array<float, 2> RenderHillshadeLayer::getLatRange(const UnwrappedTileID& id) { + const LatLng latlng0 = LatLng(id); + const LatLng latlng1 = LatLng(UnwrappedTileID(id.canonical.z, id.canonical.x, id.canonical.y + 1)); + return {{ (float)latlng0.latitude(), (float)latlng1.latitude() }}; +} + +const std::array<float, 2> RenderHillshadeLayer::getLight(const PaintParameters& parameters){ + float azimuthal = evaluated.get<HillshadeIlluminationDirection>() * util::DEG2RAD; + if (evaluated.get<HillshadeIlluminationAnchor>() == HillshadeIlluminationAnchorType::Viewport) azimuthal = azimuthal - parameters.state.getAngle(); + return {{evaluated.get<HillshadeExaggeration>(), azimuthal}}; +} + +void RenderHillshadeLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); +} + +void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& parameters) { + evaluated = unevaluated.evaluate(parameters); + passes = (evaluated.get<style::HillshadeExaggeration >() > 0) + ? (RenderPass::Translucent | RenderPass::Pass3D) + : RenderPass::None; +} + +bool RenderHillshadeLayer::hasTransition() const { + return unevaluated.hasTransition(); +} + +void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource*) { + if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) + return; + + auto draw = [&] (const mat4& matrix, + const auto& vertexBuffer, + const auto& indexBuffer, + const auto& segments, + const UnwrappedTileID& id) { + parameters.programs.hillshade.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + HillshadeProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_image::Value{ 0 }, + uniforms::u_highlight::Value{ evaluated.get<HillshadeHighlightColor>() }, + uniforms::u_shadow::Value{ evaluated.get<HillshadeShadowColor>() }, + uniforms::u_accent::Value{ evaluated.get<HillshadeAccentColor>() }, + uniforms::u_light::Value{ getLight(parameters) }, + uniforms::u_latrange::Value{ getLatRange(id) }, + }, + vertexBuffer, + indexBuffer, + segments, + HillshadeProgram::PaintPropertyBinders { evaluated, 0 }, + evaluated, + parameters.state.getZoom(), + getID() + ); + }; + + mat4 mat; + matrix::ortho(mat, 0, util::EXTENT, -util::EXTENT, 0, 0, 1); + matrix::translate(mat, mat, 0, -util::EXTENT, 0); + + for (const RenderTile& tile : renderTiles) { + assert(dynamic_cast<HillshadeBucket*>(tile.tile.getBucket(*baseImpl))); + HillshadeBucket& bucket = *reinterpret_cast<HillshadeBucket*>(tile.tile.getBucket(*baseImpl)); + if (!bucket.hasData()){ + continue; + } + + if (!bucket.isPrepared() && parameters.pass == RenderPass::Pass3D) { + const uint16_t tilesize = bucket.getDEMData().dim; + OffscreenTexture view(parameters.context, { tilesize, tilesize }); + view.bind(); + + parameters.context.bindTexture(*bucket.dem, 0, gl::TextureFilter::Nearest, gl::TextureMipMap::No, gl::TextureWrap::Clamp, gl::TextureWrap::Clamp); + const Properties<>::PossiblyEvaluated properties; + + parameters.programs.hillshadePrepare.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + HillshadePrepareProgram::UniformValues { + uniforms::u_matrix::Value { mat }, + uniforms::u_dimension::Value { {{uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} }, + uniforms::u_zoom::Value{ float(tile.id.canonical.z) }, + uniforms::u_image::Value{ 0 } + }, + parameters.staticData.rasterVertexBuffer, + parameters.staticData.quadTriangleIndexBuffer, + parameters.staticData.rasterSegments, + HillshadePrepareProgram::PaintPropertyBinders { properties, 0 }, + properties, + parameters.state.getZoom(), + getID() + ); + bucket.texture = std::move(view.getTexture()); + bucket.setPrepared(true); + } else if (parameters.pass == RenderPass::Translucent) { + assert(bucket.texture); + parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear, gl::TextureMipMap::No, gl::TextureWrap::Clamp, gl::TextureWrap::Clamp); + + if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { + // Draw only the parts of the tile that aren't drawn by another tile in the layer. + draw(tile.matrix, + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.segments, + tile.id); + } else { + // Draw the full tile. + draw(tile.matrix, + parameters.staticData.rasterVertexBuffer, + parameters.staticData.quadTriangleIndexBuffer, + parameters.staticData.rasterSegments, + tile.id); + } + } + + + } +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.hpp b/src/mbgl/renderer/layers/render_hillshade_layer.hpp new file mode 100644 index 0000000000..e9b9db1ec3 --- /dev/null +++ b/src/mbgl/renderer/layers/render_hillshade_layer.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/layers/hillshade_layer_impl.hpp> +#include <mbgl/style/layers/hillshade_layer_properties.hpp> +#include <mbgl/tile/tile_id.hpp> + +namespace mbgl { + +class RenderHillshadeLayer: public RenderLayer { +public: + RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl>); + ~RenderHillshadeLayer() final = default; + + void transition(const TransitionParameters&) override; + void evaluate(const PropertyEvaluationParameters&) override; + bool hasTransition() const override; + + void render(PaintParameters&, RenderSource*) override; + + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; + + // Paint properties + style::HillshadePaintProperties::Unevaluated unevaluated; + style::HillshadePaintProperties::PossiblyEvaluated evaluated; + + const style::HillshadeLayer::Impl& impl() const; +private: + const std::array<float, 2> getLatRange(const UnwrappedTileID& id); + const std::array<float, 2> getLight(const PaintParameters& parameters); +}; + +template <> +inline bool RenderLayer::is<RenderHillshadeLayer>() const { + return type == style::LayerType::Hillshade; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index eb2b74ffe0..248905f834 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -4,6 +4,7 @@ #include <mbgl/renderer/layers/render_custom_layer.hpp> #include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> #include <mbgl/renderer/layers/render_fill_layer.hpp> +#include <mbgl/renderer/layers/render_hillshade_layer.hpp> #include <mbgl/renderer/layers/render_line_layer.hpp> #include <mbgl/renderer/layers/render_raster_layer.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> @@ -26,6 +27,8 @@ std::unique_ptr<RenderLayer> RenderLayer::create(Immutable<Layer::Impl> impl) { return std::make_unique<RenderSymbolLayer>(staticImmutableCast<SymbolLayer::Impl>(impl)); case LayerType::Raster: return std::make_unique<RenderRasterLayer>(staticImmutableCast<RasterLayer::Impl>(impl)); + case LayerType::Hillshade: + return std::make_unique<RenderHillshadeLayer>(staticImmutableCast<HillshadeLayer::Impl>(impl)); case LayerType::Background: return std::make_unique<RenderBackgroundLayer>(staticImmutableCast<BackgroundLayer::Impl>(impl)); case LayerType::Custom: diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp index 6624bb7d96..d160eb16e3 100644 --- a/src/mbgl/renderer/render_source.cpp +++ b/src/mbgl/renderer/render_source.cpp @@ -2,6 +2,7 @@ #include <mbgl/renderer/render_source_observer.hpp> #include <mbgl/renderer/sources/render_geojson_source.hpp> #include <mbgl/renderer/sources/render_raster_source.hpp> +#include <mbgl/renderer/sources/render_raster_dem_source.hpp> #include <mbgl/renderer/sources/render_vector_source.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/annotation/render_annotation_source.hpp> @@ -19,6 +20,8 @@ std::unique_ptr<RenderSource> RenderSource::create(Immutable<Source::Impl> impl) return std::make_unique<RenderVectorSource>(staticImmutableCast<VectorSource::Impl>(impl)); case SourceType::Raster: return std::make_unique<RenderRasterSource>(staticImmutableCast<RasterSource::Impl>(impl)); + case SourceType::RasterDEM: + return std::make_unique<RenderRasterDEMSource>(staticImmutableCast<RasterSource::Impl>(impl)); case SourceType::GeoJSON: return std::make_unique<RenderGeoJSONSource>(staticImmutableCast<GeoJSONSource::Impl>(impl)); case SourceType::Video: diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index 8c84af4f1e..db88230e53 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -84,7 +84,7 @@ protected: bool enabled = false; - void onTileChanged(Tile&) final; + void onTileChanged(Tile&) override; void onTileError(Tile&, std::exception_ptr) final; }; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index c38f1d56cb..61e7d17242 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -14,6 +14,7 @@ #include <mbgl/renderer/layers/render_background_layer.hpp> #include <mbgl/renderer/layers/render_custom_layer.hpp> #include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/layers/render_hillshade_layer.hpp> #include <mbgl/renderer/style_diff.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/backend_scope.hpp> @@ -289,7 +290,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { RenderLayer* layer = getRenderLayer(layerImpl->id); assert(layer); - if (!parameters.staticData.has3D && layer->is<RenderFillExtrusionLayer>()) { + if (!parameters.staticData.has3D && (layer->is<RenderFillExtrusionLayer>() || layer->is<RenderHillshadeLayer>())) { parameters.staticData.has3D = true; } diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.cpp b/src/mbgl/renderer/sources/render_raster_dem_source.cpp new file mode 100644 index 0000000000..76716518d7 --- /dev/null +++ b/src/mbgl/renderer/sources/render_raster_dem_source.cpp @@ -0,0 +1,165 @@ +#include <mbgl/renderer/sources/render_raster_dem_source.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/tile/raster_dem_tile.hpp> +#include <mbgl/algorithm/update_tile_masks.hpp> +#include <mbgl/geometry/dem_data.hpp> +#include <mbgl/renderer/buckets/hillshade_bucket.hpp> +#include <iostream> + +namespace mbgl { + +using namespace style; + +RenderRasterDEMSource::RenderRasterDEMSource(Immutable<style::RasterSource::Impl> impl_) + : RenderSource(impl_) { + tilePyramid.setObserver(this); +} + +const style::RasterSource::Impl& RenderRasterDEMSource::impl() const { + return static_cast<const style::RasterSource::Impl&>(*baseImpl); +} + +bool RenderRasterDEMSource::isLoaded() const { + return tilePyramid.isLoaded(); +} + +void RenderRasterDEMSource::update(Immutable<style::Source::Impl> baseImpl_, + const std::vector<Immutable<Layer::Impl>>& layers, + const bool needsRendering, + const bool needsRelayout, + const TileParameters& parameters) { + std::swap(baseImpl, baseImpl_); + + enabled = needsRendering; + + optional<Tileset> tileset = impl().getTileset(); + + if (!tileset) { + return; + } + + if (tileURLTemplates != tileset->tiles) { + tileURLTemplates = tileset->tiles; + + // TODO: this removes existing buckets, and will cause flickering. + // Should instead refresh tile data in place. + tilePyramid.tiles.clear(); + tilePyramid.renderTiles.clear(); + tilePyramid.cache.clear(); + } + + tilePyramid.update(layers, + needsRendering, + needsRelayout, + parameters, + SourceType::RasterDEM, + impl().getTileSize(), + tileset->zoomRange, + tileset->bounds, + [&] (const OverscaledTileID& tileID) { + return std::make_unique<RasterDEMTile>(tileID, parameters, *tileset); + }); +} + +void RenderRasterDEMSource::onTileChanged(Tile& tile){ + RasterDEMTile& demtile = static_cast<RasterDEMTile&>(tile); + + std::map<DEMTileNeighbors, DEMTileNeighbors> opposites = { + { DEMTileNeighbors::Left, DEMTileNeighbors::Right }, + { DEMTileNeighbors::Right, DEMTileNeighbors::Left }, + { DEMTileNeighbors::TopLeft, DEMTileNeighbors::BottomRight }, + { DEMTileNeighbors::TopCenter, DEMTileNeighbors::BottomCenter }, + { DEMTileNeighbors::TopRight, DEMTileNeighbors::BottomLeft }, + { DEMTileNeighbors::BottomRight, DEMTileNeighbors::TopLeft }, + { DEMTileNeighbors::BottomCenter, DEMTileNeighbors:: TopCenter }, + { DEMTileNeighbors::BottomLeft, DEMTileNeighbors::TopRight } + }; + + if (tile.isRenderable() && demtile.neighboringTiles != DEMTileNeighbors::Complete) { + const CanonicalTileID canonical = tile.id.canonical; + const uint32_t dim = std::pow(2, canonical.z); + const uint32_t px = (canonical.x - 1 + dim) % dim; + const int pxw = canonical.x == 0 ? tile.id.wrap - 1 : tile.id.wrap; + const uint32_t nx = (canonical.x + 1 + dim) % dim; + const int nxw = (canonical.x + 1 == dim) ? tile.id.wrap + 1 : tile.id.wrap; + + auto getNeighbor = [&] (DEMTileNeighbors mask){ + if (mask == DEMTileNeighbors::Left){ + return OverscaledTileID(tile.id.overscaledZ, pxw, canonical.z, px, canonical.y); + } else if (mask == DEMTileNeighbors::Right){ + return OverscaledTileID(tile.id.overscaledZ, nxw, canonical.z, nx, canonical.y); + } else if (mask == DEMTileNeighbors::TopLeft){ + return OverscaledTileID(tile.id.overscaledZ, pxw, canonical.z, px, canonical.y - 1); + } else if (mask == DEMTileNeighbors::TopCenter){ + return OverscaledTileID(tile.id.overscaledZ, tile.id.wrap, canonical.z, canonical.x, canonical.y - 1); + } else if (mask == DEMTileNeighbors::TopRight){ + return OverscaledTileID(tile.id.overscaledZ, nxw, canonical.z, nx, canonical.y - 1); + } else if (mask == DEMTileNeighbors::BottomLeft){ + return OverscaledTileID(tile.id.overscaledZ, pxw, canonical.z, px, canonical.y + 1); + } else if (mask == DEMTileNeighbors::BottomCenter){ + return OverscaledTileID(tile.id.overscaledZ, tile.id.wrap, canonical.z, canonical.x, canonical.y + 1); + } else if (mask == DEMTileNeighbors::BottomRight){ + return OverscaledTileID(tile.id.overscaledZ, nxw, canonical.z, nx, canonical.y + 1); + } else{ + throw std::runtime_error("mask is not a valid tile neighbor"); + } + }; + + for (uint8_t i = 0; i < 8; i++) { + DEMTileNeighbors mask = DEMTileNeighbors(std::pow(2,i)); + // only backfill if this neighbor has not been previously backfilled + if ((demtile.neighboringTiles & mask) != mask) { + OverscaledTileID neighborid = getNeighbor(mask); + Tile* renderableNeighbor = tilePyramid.getTile(neighborid); + if (renderableNeighbor != nullptr && renderableNeighbor->isRenderable()) { + RasterDEMTile& borderTile = static_cast<RasterDEMTile&>(*renderableNeighbor); + demtile.backfillBorder(borderTile, mask); + + // if the border tile has not been backfilled by a previous instance of the main + // tile, backfill its corresponding neighbor as well. + const DEMTileNeighbors& borderMask = opposites[mask]; + if ((borderTile.neighboringTiles & borderMask) != borderMask){ + borderTile.backfillBorder(demtile, borderMask); + } + } + } + } + } + RenderSource::onTileChanged(tile); +} + +void RenderRasterDEMSource::startRender(PaintParameters& parameters) { + algorithm::updateTileMasks(tilePyramid.getRenderTiles()); + tilePyramid.startRender(parameters); +} + +void RenderRasterDEMSource::finishRender(PaintParameters& parameters) { + tilePyramid.finishRender(parameters); +} + +std::vector<std::reference_wrapper<RenderTile>> RenderRasterDEMSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderRasterDEMSource::queryRenderedFeatures(const ScreenLineString&, + const TransformState&, + const std::vector<const RenderLayer*>&, + const RenderedQueryOptions&, + const CollisionIndex& ) const { + return std::unordered_map<std::string, std::vector<Feature>> {}; +} + +std::vector<Feature> RenderRasterDEMSource::querySourceFeatures(const SourceQueryOptions&) const { + return {}; +} + +void RenderRasterDEMSource::onLowMemory() { + tilePyramid.onLowMemory(); +} + +void RenderRasterDEMSource::dumpDebugLogs() const { + tilePyramid.dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.hpp b/src/mbgl/renderer/sources/render_raster_dem_source.hpp new file mode 100644 index 0000000000..b6b8bf977c --- /dev/null +++ b/src/mbgl/renderer/sources/render_raster_dem_source.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/style/sources/raster_source_impl.hpp> + +namespace mbgl { + +class RenderRasterDEMSource : public RenderSource { +public: + RenderRasterDEMSource(Immutable<style::RasterSource::Impl>); + + bool isLoaded() const final; + + void update(Immutable<style::Source::Impl>, + const std::vector<Immutable<style::Layer::Impl>>&, + bool needsRendering, + bool needsRelayout, + const TileParameters&) final; + + void startRender(PaintParameters&) final; + void finishRender(PaintParameters&) final; + + std::vector<std::reference_wrapper<RenderTile>> getRenderTiles() final; + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const std::vector<const RenderLayer*>& layers, + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const final; + + std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const final; + + void onLowMemory() final; + void dumpDebugLogs() const final; + +private: + const style::RasterSource::Impl& impl() const; + + TilePyramid tilePyramid; + optional<std::vector<std::string>> tileURLTemplates; + +protected: + void onTileChanged(Tile&) final; +}; + +template <> +inline bool RenderSource::is<RenderRasterDEMSource>() const { + return baseImpl->type == style::SourceType::RasterDEM; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index f6eb62f655..07239b7a1c 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -56,6 +56,11 @@ std::vector<std::reference_wrapper<RenderTile>> TilePyramid::getRenderTiles() { return { renderTiles.begin(), renderTiles.end() }; } +Tile* TilePyramid::getTile(const OverscaledTileID& tileID){ + auto it = tiles.find(tileID); + return it == tiles.end() ? cache.get(tileID) : it->second.get(); +} + void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layers, const bool needsRendering, const bool needsRelayout, @@ -147,7 +152,7 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer if (tileRange && !tileRange->contains(tileID.canonical)) { return nullptr; } - std::unique_ptr<Tile> tile = cache.get(tileID); + std::unique_ptr<Tile> tile = cache.pop(tileID); if (!tile) { tile = createTile(tileID); if (tile) { diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index 3755cee06d..ad3f91bf88 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -47,6 +47,7 @@ public: void finishRender(PaintParameters&); std::vector<std::reference_wrapper<RenderTile>> getRenderTiles(); + Tile* getTile(const OverscaledTileID&); std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, |