diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/geometry/line_atlas.cpp | 128 | ||||
-rw-r--r-- | src/mbgl/geometry/line_atlas.hpp | 50 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_line_layer.cpp | 41 | ||||
-rw-r--r-- | src/mbgl/renderer/render_orchestrator.cpp | 24 |
4 files changed, 141 insertions, 102 deletions
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 106a24d015..2e4de3edbe 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,50 +1,33 @@ #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/gfx/upload_pass.hpp> +#include <mbgl/math/minmax.hpp> +#include <mbgl/util/hash.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/platform.hpp> -#include <mbgl/util/hash.hpp> #include <cmath> namespace mbgl { +namespace { -LineAtlas::LineAtlas(const Size size) - : image(size), - dirty(true) { -} - -LineAtlas::~LineAtlas() = default; - -LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray, - LinePatternCap patternCap) { - size_t key = patternCap == LinePatternCap::Round ? std::numeric_limits<size_t>::min() - : std::numeric_limits<size_t>::max(); +size_t getDashPatternHash(const std::vector<float>& dasharray, const LinePatternCap patternCap) { + size_t key = + patternCap == LinePatternCap::Round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max(); for (const float part : dasharray) { util::hash_combine<float>(key, part); } - - // Note: We're not handling hash collisions here. - const auto it = positions.find(key); - if (it == positions.end()) { - auto inserted = positions.emplace(key, addDash(dasharray, patternCap)); - assert(inserted.second); - return inserted.first->second; - } else { - return it->second; - } + return key; } -LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatternCap patternCap) { +LinePatternPos addDashPattern(AlphaImage& image, + const int32_t yOffset, + const std::vector<float>& dasharray, + const LinePatternCap patternCap) { const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; - const uint8_t dashheight = 2 * n + 1; - const uint8_t offset = 128; + constexpr const uint8_t offset = 128; if (dasharray.size() < 2) { - return LinePatternPos(); - } - - if (nextRow + dashheight > image.size.height) { - Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); + Log::Warning(Event::ParseStyle, "line dasharray requires at least two elements"); return LinePatternPos(); } @@ -60,7 +43,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte bool oddLength = dasharray.size() % 2 == 1; for (int y = -n; y <= n; y++) { - int row = nextRow + n + y; + int row = yOffset + n + y; int index = image.size.width * row; float left = 0; @@ -72,7 +55,6 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte } for (uint32_t x = 0; x < image.size.width; x++) { - while (right < x / stretch) { left = right; if (partIndex >= dasharray.size()) { @@ -111,37 +93,79 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte } LinePatternPos position; - position.y = (0.5 + nextRow + n) / image.size.height; - position.height = (2.0 * n) / image.size.height; + position.y = (0.5 + yOffset + n) / image.size.height; + position.height = (2.0 * n + 1) / image.size.height; position.width = length; - nextRow += dashheight; - - dirty = true; - return position; } -Size LineAtlas::getSize() const { - return image.size; +} // namespace + +DashPatternTexture::DashPatternTexture(const std::vector<float>& from_, + const std::vector<float>& to_, + const LinePatternCap cap) { + const bool patternsIdentical = from_ == to_; + const int32_t patternHeight = cap == LinePatternCap::Round ? 15 : 1; + + AlphaImage image({256, static_cast<uint32_t>((patternsIdentical ? 1 : 2) * patternHeight)}); + + from = addDashPattern(image, 0, from_, cap); + to = patternsIdentical ? from : addDashPattern(image, patternHeight, to_, cap); + + texture = std::move(image); } -void LineAtlas::upload(gfx::UploadPass& uploadPass) { - if (!texture) { - texture = uploadPass.createTexture(image); - } else if (dirty) { - uploadPass.updateTexture(*texture, image); +void DashPatternTexture::upload(gfx::UploadPass& uploadPass) { + if (texture.is<AlphaImage>()) { + texture = uploadPass.createTexture(texture.get<AlphaImage>()); } +} + +gfx::TextureBinding DashPatternTexture::textureBinding() const { + // The texture needs to have been uploaded already. + assert(texture.is<gfx::Texture>()); + return {texture.get<gfx::Texture>().getResource(), + gfx::TextureFilterType::Linear, + gfx::TextureMipMapType::No, + gfx::TextureWrapType::Repeat, + gfx::TextureWrapType::Clamp}; +} - dirty = false; +Size DashPatternTexture::getSize() const { + return texture.match([](const auto& obj) { return obj.size; }); } -gfx::TextureBinding LineAtlas::textureBinding() { - assert(texture); - // All _changes_ to the texture should've been made and uploaded already. - assert(!dirty); - return { texture->getResource(), gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No, - gfx::TextureWrapType::Repeat, gfx::TextureWrapType::Clamp }; +LineAtlas::LineAtlas() = default; + +LineAtlas::~LineAtlas() = default; + +DashPatternTexture& LineAtlas::getDashPatternTexture(const std::vector<float>& from, + const std::vector<float>& to, + const LinePatternCap cap) { + const size_t hash = util::hash(getDashPatternHash(from, cap), getDashPatternHash(to, cap)); + + // Note: We're not handling hash collisions here. + const auto it = textures.find(hash); + if (it == textures.end()) { + auto inserted = textures.emplace( + std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(from, to, cap)); + assert(inserted.second); + needsUpload.emplace_back(hash); + return inserted.first->second; + } else { + return it->second; + } +} + +void LineAtlas::upload(gfx::UploadPass& uploadPass) { + for (const size_t hash : needsUpload) { + const auto it = textures.find(hash); + if (it != textures.end()) { + it->second.upload(uploadPass); + } + } + needsUpload.clear(); } } // namespace mbgl diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index b43583c9c8..853305d138 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -3,10 +3,11 @@ #include <mbgl/gfx/texture.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> -#include <vector> -#include <unordered_map> +#include <map> #include <memory> +#include <vector> namespace mbgl { @@ -26,29 +27,46 @@ enum class LinePatternCap : bool { Round = true, }; -class LineAtlas { +class DashPatternTexture { public: - LineAtlas(Size); - ~LineAtlas(); - - // Binds the atlas texture to the GPU, and uploads data if it is out of date. - gfx::TextureBinding textureBinding(); + DashPatternTexture(const std::vector<float>& from, const std::vector<float>& to, LinePatternCap); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; - // the texture is only bound when the data is out of date (=dirty). + // the texture is only bound when the data is uploaded for the first time. void upload(gfx::UploadPass&); - LinePatternPos getDashPosition(const std::vector<float>&, LinePatternCap); - LinePatternPos addDash(const std::vector<float>& dasharray, LinePatternCap); + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + gfx::TextureBinding textureBinding() const; + // Returns the size of the texture image. Size getSize() const; + const LinePatternPos& getFrom() const { return from; } + const LinePatternPos& getTo() const { return to; } + private: - const AlphaImage image; - bool dirty; - optional<gfx::Texture> texture; - uint32_t nextRow = 0; - std::unordered_map<size_t, LinePatternPos> positions; + LinePatternPos from, to; + variant<AlphaImage, gfx::Texture> texture; +}; + +class LineAtlas { +public: + LineAtlas(); + ~LineAtlas(); + + // Obtains or creates a texture that has both line patterns in it + DashPatternTexture& getDashPatternTexture(const std::vector<float>& from, + const std::vector<float>& to, + LinePatternCap); + + // Uploads the textures to the GPU to be available when we need it. + void upload(gfx::UploadPass&); + +private: + std::map<size_t, DashPatternTexture> textures; + + // Stores a list of hashes of texture objcts that need uploading. + std::vector<size_t> needsUpload; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 36665c1db4..e5bbe74bf9 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -78,8 +78,8 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; // Ensures that the dash data gets added to the atlas. - params.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap); - params.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap); + params.lineAtlas.getDashPatternTexture( + evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); } } @@ -146,27 +146,26 @@ void RenderLineLayer::render(PaintParameters& parameters) { }; if (!evaluated.get<LineDasharray>().from.empty()) { - const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round - ? LinePatternCap::Round : LinePatternCap::Square; - LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap); - LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap); + const LinePatternCap cap = + bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; + const auto& dashPatternTexture = parameters.lineAtlas.getDashPatternTexture( + evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); draw(parameters.programs.getLineLayerPrograms().lineSDF, - LineSDFProgram::layoutUniformValues( - evaluated, - parameters.pixelRatio, - tile, - parameters.state, - parameters.pixelsToGLUnits, - posA, - posB, - crossfade, - parameters.lineAtlas.getSize().width), - {}, - {}, - LineSDFProgram::TextureBindings{ - parameters.lineAtlas.textureBinding(), - }); + LineSDFProgram::layoutUniformValues(evaluated, + parameters.pixelRatio, + tile, + parameters.state, + parameters.pixelsToGLUnits, + dashPatternTexture.getFrom(), + dashPatternTexture.getTo(), + crossfade, + dashPatternTexture.getSize().width), + {}, + {}, + LineSDFProgram::TextureBindings{ + dashPatternTexture.textureBinding(), + }); } else if (!unevaluated.get<LinePattern>().isUndefined()) { const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<std::basic_string<char>>{ "", ""}); diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 50077784b5..e13a439ae4 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -103,19 +103,17 @@ public: } // namespace -RenderOrchestrator::RenderOrchestrator( - bool backgroundLayerAsColor_, - optional<std::string> localFontFamily_) - : observer(&nullObserver()) - , glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(std::move(localFontFamily_)))) - , imageManager(std::make_unique<ImageManager>()) - , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })) - , patternAtlas(std::make_unique<PatternAtlas>()) - , imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()) - , sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()) - , layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()) - , renderLight(makeMutable<Light::Impl>()) - , backgroundLayerAsColor(backgroundLayerAsColor_) { +RenderOrchestrator::RenderOrchestrator(bool backgroundLayerAsColor_, optional<std::string> localFontFamily_) + : observer(&nullObserver()), + glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(std::move(localFontFamily_)))), + imageManager(std::make_unique<ImageManager>()), + lineAtlas(std::make_unique<LineAtlas>()), + patternAtlas(std::make_unique<PatternAtlas>()), + imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()), + sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()), + layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()), + renderLight(makeMutable<Light::Impl>()), + backgroundLayerAsColor(backgroundLayerAsColor_) { glyphManager->setObserver(this); imageManager->setObserver(this); } |