summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mbgl/geometry/line_atlas.cpp128
-rw-r--r--src/mbgl/geometry/line_atlas.hpp50
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp41
-rw-r--r--src/mbgl/renderer/render_orchestrator.cpp24
-rw-r--r--test/geometry/line_atlas.test.cpp4
5 files changed, 143 insertions, 104 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);
}
diff --git a/test/geometry/line_atlas.test.cpp b/test/geometry/line_atlas.test.cpp
index 960e4ad7ad..1d817220e1 100644
--- a/test/geometry/line_atlas.test.cpp
+++ b/test/geometry/line_atlas.test.cpp
@@ -13,7 +13,7 @@ TEST(LineAtlas, Random) {
std::normal_distribution<float> lengthDistribution(3, 5);
for (size_t it = 0; it < 100; it++) {
- LineAtlas atlas{ Size{ 128, 1024 } };
+ LineAtlas atlas;
std::vector<float> dasharray;
dasharray.reserve(8);
for (size_t j = 0; j < 100; j++) {
@@ -25,7 +25,7 @@ TEST(LineAtlas, Random) {
const LinePatternCap patternCap =
capStyleDistribution(generator) > 0 ? LinePatternCap::Round : LinePatternCap::Square;
- atlas.addDash(dasharray, patternCap);
+ atlas.getDashPatternTexture(dasharray, dasharray, patternCap);
}
}
}