summaryrefslogtreecommitdiff
path: root/src/mbgl/geometry/line_atlas.cpp
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2019-10-25 11:57:09 +0200
committerKonstantin Käfer <mail@kkaefer.com>2019-10-25 12:31:10 +0200
commit5e7456d95fb5259f297c342c4888ba3a86667b05 (patch)
tree59c6f29d4cae7795efe66258dd673f6803da0752 /src/mbgl/geometry/line_atlas.cpp
parent646d4e3996513ed3e9247e958d39ce9e9b506652 (diff)
downloadqtlocation-mapboxgl-5e7456d95fb5259f297c342c4888ba3a86667b05.tar.gz
[core] use individual textures for line dash patternsupstream/individual-line-dash-pattern-textures
This moves the LineAtlas from a shared texture that contained SDF dash patterns to use individual textures. Previously, the texture space was limited to a texture of 512 pixels height. Dash patterns were never removed (and are still never removed as of this patch), which means that this texture could fill up for styles that use a lot of different dash patterns. In particular, dash patterns for lines with a round line cap take up 15 pixels of texture height, limiting the amount of unique dash patterns to 34. While this was probably enough for rendering a single style, we quickly exhausted this number when reusing the Map object to render different styles. Instead of a global shared texture, we're now creating individual textures for every dash pattern. These textures are still cached so that we don't need to re-upload the texture on every frame.
Diffstat (limited to 'src/mbgl/geometry/line_atlas.cpp')
-rw-r--r--src/mbgl/geometry/line_atlas.cpp128
1 files changed, 76 insertions, 52 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