summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-05-29 16:06:56 +0300
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-05-29 16:13:10 +0300
commitc212d9aeda273c6a820eafa87ed1bede22e89919 (patch)
tree4b86c49dc5171f6482421a0c00f14c7691c903b5
parent967e466448bf2ce7070c66c8565c7d68c052ea97 (diff)
downloadqtlocation-mapboxgl-upstream/mikhail_image_manager.tar.gz
[core] Introduce PatternAtlasupstream/mikhail_image_manager
-rw-r--r--src/core-files.json2
-rw-r--r--src/mbgl/renderer/image_manager.cpp110
-rw-r--r--src/mbgl/renderer/image_manager.hpp53
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp23
-rw-r--r--src/mbgl/renderer/paint_parameters.cpp6
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp7
-rw-r--r--src/mbgl/renderer/pattern_atlas.cpp109
-rw-r--r--src/mbgl/renderer/pattern_atlas.hpp53
-rw-r--r--src/mbgl/renderer/render_layer.hpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp14
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile.hpp10
-rw-r--r--test/renderer/image_manager.test.cpp47
-rw-r--r--test/renderer/pattern_atlas.test.cpp82
-rw-r--r--test/test-files.json1
15 files changed, 309 insertions, 212 deletions
diff --git a/src/core-files.json b/src/core-files.json
index eb581f7959..dc38554152 100644
--- a/src/core-files.json
+++ b/src/core-files.json
@@ -124,6 +124,7 @@
"src/mbgl/renderer/layers/render_raster_layer.cpp",
"src/mbgl/renderer/layers/render_symbol_layer.cpp",
"src/mbgl/renderer/paint_parameters.cpp",
+ "src/mbgl/renderer/pattern_atlas.cpp",
"src/mbgl/renderer/render_layer.cpp",
"src/mbgl/renderer/render_light.cpp",
"src/mbgl/renderer/render_source.cpp",
@@ -635,6 +636,7 @@
"mbgl/renderer/paint_parameters.hpp": "src/mbgl/renderer/paint_parameters.hpp",
"mbgl/renderer/paint_property_binder.hpp": "src/mbgl/renderer/paint_property_binder.hpp",
"mbgl/renderer/paint_property_statistics.hpp": "src/mbgl/renderer/paint_property_statistics.hpp",
+ "mbgl/renderer/pattern_atlas.hpp": "src/mbgl/renderer/pattern_atlas.hpp",
"mbgl/renderer/possibly_evaluated_property_value.hpp": "src/mbgl/renderer/possibly_evaluated_property_value.hpp",
"mbgl/renderer/property_evaluation_parameters.hpp": "src/mbgl/renderer/property_evaluation_parameters.hpp",
"mbgl/renderer/property_evaluator.hpp": "src/mbgl/renderer/property_evaluator.hpp",
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
index d5fe864fa7..ff4c20eefb 100644
--- a/src/mbgl/renderer/image_manager.cpp
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -1,16 +1,19 @@
#include <mbgl/renderer/image_manager.hpp>
-#include <mbgl/util/constants.hpp>
+
#include <mbgl/actor/actor.hpp>
#include <mbgl/actor/scheduler.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/gfx/upload_pass.hpp>
-#include <mbgl/gfx/context.hpp>
#include <mbgl/renderer/image_manager_observer.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
static ImageManagerObserver nullObserver;
+ImageManager::ImageManager() = default;
+
+ImageManager::~ImageManager() = default;
+
void ImageManager::setObserver(ImageManagerObserver* observer_) {
observer = observer_ ? observer_ : &nullObserver;
}
@@ -62,7 +65,6 @@ bool ImageManager::updateImage(Immutable<style::Image::Impl> image_) {
updatedImageVersions[image_->id]++;
}
- removePattern(image_->id);
oldImage->second = std::move(image_);
return sizeChanged;
@@ -79,22 +81,6 @@ void ImageManager::removeImage(const std::string& id) {
requestedImages.erase(requestedIt);
}
images.erase(it);
- removePattern(id);
-}
-
-void ImageManager::removePattern(const std::string& id) {
- auto it = patterns.find(id);
- if (it != patterns.end()) {
- // Clear pattern from the atlas image.
- const uint32_t x = it->second.bin->x;
- const uint32_t y = it->second.bin->y;
- const uint32_t w = it->second.bin->w;
- const uint32_t h = it->second.bin->h;
- PremultipliedImage::clear(atlasImage, { x, y }, { w, h });
-
- shelfPack.unref(*it->second.bin);
- patterns.erase(it);
- }
}
const style::Image::Impl* ImageManager::getImage(const std::string& id) const {
@@ -243,88 +229,6 @@ void ImageManager::dumpDebugLogs() const {
Log::Info(Event::General, "ImageManager::loaded: %d", loaded);
}
-// When copied into the atlas texture, image data is padded by one pixel on each side. Icon
-// images are padded with fully transparent pixels, while pattern images are padded with a
-// copy of the image data wrapped from the opposite side. In both cases, this ensures the
-// correct behavior of GL_LINEAR texture sampling mode.
-static constexpr uint16_t padding = 1;
-
-static mapbox::ShelfPack::ShelfPackOptions shelfPackOptions() {
- mapbox::ShelfPack::ShelfPackOptions options;
- options.autoResize = true;
- return options;
-}
-
-ImageManager::ImageManager()
- : shelfPack(64, 64, shelfPackOptions()) {
-}
-
-ImageManager::~ImageManager() = default;
-
-optional<ImagePosition> ImageManager::getPattern(const std::string& id) {
- auto it = patterns.find(id);
- if (it != patterns.end()) {
- return it->second.position;
- }
-
- const style::Image::Impl* image = getImage(id);
- if (!image) {
- return {};
- }
-
- const uint16_t width = image->image.size.width + padding * 2;
- const uint16_t height = image->image.size.height + padding * 2;
-
- mapbox::Bin* bin = shelfPack.packOne(-1, width, height);
- if (!bin) {
- return {};
- }
-
- atlasImage.resize(getPixelSize());
-
- const PremultipliedImage& src = image->image;
-
- const uint32_t x = bin->x + padding;
- const uint32_t y = bin->y + padding;
- const uint32_t w = src.size.width;
- const uint32_t h = src.size.height;
-
- PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y }, { w, h });
-
- // Add 1 pixel wrapped padding on each side of the image.
- PremultipliedImage::copy(src, atlasImage, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
- PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y + h }, { w, 1 }); // B
- PremultipliedImage::copy(src, atlasImage, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
- PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x + w, y }, { 1, h }); // R
-
- dirty = true;
-
- return patterns.emplace(id, Pattern { bin, { *bin, *image } }).first->second.position;
-}
-
-Size ImageManager::getPixelSize() const {
- return Size {
- static_cast<uint32_t>(shelfPack.width()),
- static_cast<uint32_t>(shelfPack.height())
- };
-}
-
-void ImageManager::upload(gfx::UploadPass& uploadPass) {
- if (!atlasTexture) {
- atlasTexture = uploadPass.createTexture(atlasImage);
- } else if (dirty) {
- uploadPass.updateTexture(*atlasTexture, atlasImage);
- }
-
- dirty = false;
-}
-
-gfx::TextureBinding ImageManager::textureBinding() {
- assert(atlasTexture);
- assert(!dirty);
- return { atlasTexture->getResource(), gfx::TextureFilterType::Linear };
-}
-
ImageRequestor::ImageRequestor(ImageManager& imageManager_) : imageManager(imageManager_) {
}
diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp
index f20d55415b..5305358513 100644
--- a/src/mbgl/renderer/image_manager.hpp
+++ b/src/mbgl/renderer/image_manager.hpp
@@ -1,16 +1,9 @@
#pragma once
#include <mbgl/style/image_impl.hpp>
-#include <mbgl/renderer/image_atlas.hpp>
-#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/immutable.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/gfx/texture.hpp>
-#include <mbgl/renderer/image_manager_observer.hpp>
-#include <mapbox/shelf-pack.hpp>
-
-#include <set>
+#include <map>
#include <string>
namespace mbgl {
@@ -22,21 +15,17 @@ namespace gfx {
class UploadPass;
} // namespace gfx
+class ImageManagerObserver;
class ImageRequestor;
-/*
- ImageManager does two things:
-
- 1. Tracks requests for icon images from tile workers and sends responses when the requests are fulfilled.
- 2. Builds a texture atlas for pattern images.
-
- These are disparate responsibilities and should eventually be handled by different classes. When we implement
- data-driven support for `*-pattern`, we'll likely use per-bucket pattern atlases, and that would be a good time
- to refactor this.
-*/
-class ImageManager : public util::noncopyable {
+/**
+ * @brief tracks requests for icon images from tile workers and sends responses when the requests are fulfilled.
+ */
+class ImageManager {
public:
ImageManager();
+ ImageManager(const ImageManager&) = delete;
+ ImageManager& operator=(const ImageManager&) = delete;
~ImageManager();
void setObserver(ImageManagerObserver*);
@@ -80,32 +69,6 @@ private:
ImageMap images;
ImageManagerObserver* observer = nullptr;
-
-// Pattern stuff
-public:
- optional<ImagePosition> getPattern(const std::string& name);
-
- gfx::TextureBinding textureBinding();
- void upload(gfx::UploadPass&);
-
- Size getPixelSize() const;
-
- // Only for use in tests.
- const PremultipliedImage& getAtlasImage() const {
- return atlasImage;
- }
-
-private:
- struct Pattern {
- mapbox::Bin* bin;
- ImagePosition position;
- };
-
- mapbox::ShelfPack shelfPack;
- std::unordered_map<std::string, Pattern> patterns;
- PremultipliedImage atlasImage;
- mbgl::optional<gfx::Texture> atlasTexture;
- bool dirty = true;
};
class ImageRequestor {
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index 9d78315afa..be18e2ccb2 100644
--- a/src/mbgl/renderer/layers/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -3,6 +3,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/renderer/upload_parameters.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/pattern_atlas.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/programs/programs.hpp>
@@ -90,8 +91,8 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) {
const auto& evaluated = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).evaluated;
const auto& crossfade = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).crossfade;
if (!evaluated.get<BackgroundPattern>().to.empty()) {
- optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().from);
- optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().to);
+ optional<ImagePosition> imagePosA = parameters.patternAtlas.getPattern(evaluated.get<BackgroundPattern>().from);
+ optional<ImagePosition> imagePosB = parameters.patternAtlas.getPattern(evaluated.get<BackgroundPattern>().to);
if (!imagePosA || !imagePosB)
return;
@@ -102,7 +103,7 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) {
BackgroundPatternProgram::layoutUniformValues(
parameters.matrixForTile(tileID),
evaluated.get<BackgroundOpacity>(),
- parameters.imageManager.getPixelSize(),
+ parameters.patternAtlas.getPixelSize(),
*imagePosA,
*imagePosB,
crossfade,
@@ -110,7 +111,7 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) {
parameters.state
),
BackgroundPatternProgram::TextureBindings{
- textures::image::Value{ parameters.imageManager.textureBinding() },
+ textures::image::Value{ parameters.patternAtlas.textureBinding() },
},
tileID
);
@@ -140,12 +141,22 @@ optional<Color> RenderBackgroundLayer::getSolidBackground() const {
return { evaluated.get<BackgroundColor>() * evaluated.get<BackgroundOpacity>() };
}
+namespace {
+void addPatternIfNeeded(const std::string& id, const LayerPrepareParameters& params) {
+ if (!params.patternAtlas.getPattern(id)) {
+ if (auto* image = params.imageManager.getImage(id)) {
+ params.patternAtlas.addPattern(*image);
+ }
+ }
+}
+} // namespace
+
void RenderBackgroundLayer::prepare(const LayerPrepareParameters& params) {
const auto& evaluated = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).evaluated;
if (!evaluated.get<BackgroundPattern>().to.empty()) {
// Ensures that the texture gets added and uploaded to the atlas.
- params.imageManager.getPattern(evaluated.get<BackgroundPattern>().from);
- params.imageManager.getPattern(evaluated.get<BackgroundPattern>().to);
+ addPatternIfNeeded(evaluated.get<BackgroundPattern>().from, params);
+ addPatternIfNeeded(evaluated.get<BackgroundPattern>().to, params);
}
}
diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp
index 2e7cae4d3a..f4498f66b1 100644
--- a/src/mbgl/renderer/paint_parameters.cpp
+++ b/src/mbgl/renderer/paint_parameters.cpp
@@ -32,8 +32,8 @@ PaintParameters::PaintParameters(gfx::Context& context_,
const EvaluatedLight& evaluatedLight_,
const TransformParameters& transformParams_,
RenderStaticData& staticData_,
- ImageManager& imageManager_,
- LineAtlas& lineAtlas_)
+ LineAtlas& lineAtlas_,
+ PatternAtlas& patternAtlas_)
: context(context_),
backend(backend_),
encoder(context.createCommandEncoder()),
@@ -41,8 +41,8 @@ PaintParameters::PaintParameters(gfx::Context& context_,
evaluatedLight(evaluatedLight_),
transformParams(transformParams_),
staticData(staticData_),
- imageManager(imageManager_),
lineAtlas(lineAtlas_),
+ patternAtlas(patternAtlas_),
mapMode(updateParameters.mode),
debugOptions(updateParameters.debugOptions),
timePoint(updateParameters.timePoint),
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index e57e49a615..89084e9e52 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -20,6 +20,7 @@ class Programs;
class TransformState;
class ImageManager;
class LineAtlas;
+class PatternAtlas;
class UnwrappedTileID;
class RenderSource;
class RenderTile;
@@ -50,8 +51,8 @@ public:
const EvaluatedLight&,
const TransformParameters&,
RenderStaticData&,
- ImageManager&,
- LineAtlas&);
+ LineAtlas&,
+ PatternAtlas&);
~PaintParameters();
gfx::Context& context;
@@ -64,8 +65,8 @@ public:
const TransformParameters& transformParams;
RenderStaticData& staticData;
- ImageManager& imageManager;
LineAtlas& lineAtlas;
+ PatternAtlas& patternAtlas;
RenderPass pass = RenderPass::Opaque;
MapMode mapMode;
diff --git a/src/mbgl/renderer/pattern_atlas.cpp b/src/mbgl/renderer/pattern_atlas.cpp
new file mode 100644
index 0000000000..320412685b
--- /dev/null
+++ b/src/mbgl/renderer/pattern_atlas.cpp
@@ -0,0 +1,109 @@
+#include <mbgl/renderer/pattern_atlas.hpp>
+#include <mbgl/gfx/upload_pass.hpp>
+#include <mbgl/gfx/context.hpp>
+
+namespace mbgl {
+
+namespace {
+
+// When copied into the atlas texture, image data is padded by one pixel on each side. Icon
+// images are padded with fully transparent pixels, while pattern images are padded with a
+// copy of the image data wrapped from the opposite side. In both cases, this ensures the
+// correct behavior of GL_LINEAR texture sampling mode.
+const uint16_t padding = 1;
+
+mapbox::ShelfPack::ShelfPackOptions shelfPackOptions() {
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ return options;
+}
+
+} // namespace
+
+PatternAtlas::PatternAtlas()
+ : shelfPack(64, 64, shelfPackOptions()) {
+}
+
+PatternAtlas::~PatternAtlas() = default;
+
+optional<ImagePosition> PatternAtlas::getPattern(const std::string& id) const {
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ return it->second.position;
+ }
+ return nullopt;
+}
+
+optional<ImagePosition> PatternAtlas::addPattern(const style::Image::Impl& image) {
+ if (patterns.find(image.id) != patterns.end()) {
+ return nullopt;
+ }
+ const uint16_t width = image.image.size.width + padding * 2;
+ const uint16_t height = image.image.size.height + padding * 2;
+
+ mapbox::Bin* bin = shelfPack.packOne(-1, width, height);
+ if (!bin) {
+ return nullopt;
+ }
+
+ atlasImage.resize(getPixelSize());
+
+ const PremultipliedImage& src = image.image;
+
+ const uint32_t x = bin->x + padding;
+ const uint32_t y = bin->y + padding;
+ const uint32_t w = src.size.width;
+ const uint32_t h = src.size.height;
+
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y }, { w, h });
+
+ // Add 1 pixel wrapped padding on each side of the image.
+ PremultipliedImage::copy(src, atlasImage, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y + h }, { w, 1 }); // B
+ PremultipliedImage::copy(src, atlasImage, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x + w, y }, { 1, h }); // R
+
+ dirty = true;
+
+ return patterns.emplace(image.id, Pattern { bin, { *bin, image } }).first->second.position;
+}
+
+void PatternAtlas::removePattern(const std::string& id) {
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ // Clear pattern from the atlas image.
+ const uint32_t x = it->second.bin->x;
+ const uint32_t y = it->second.bin->y;
+ const uint32_t w = it->second.bin->w;
+ const uint32_t h = it->second.bin->h;
+ PremultipliedImage::clear(atlasImage, { x, y }, { w, h });
+
+ shelfPack.unref(*it->second.bin);
+ patterns.erase(it);
+ }
+}
+
+Size PatternAtlas::getPixelSize() const {
+ return {
+ static_cast<uint32_t>(shelfPack.width()),
+ static_cast<uint32_t>(shelfPack.height())
+ };
+}
+
+void PatternAtlas::upload(gfx::UploadPass& uploadPass) {
+ if (!atlasTexture) {
+ atlasTexture = uploadPass.createTexture(atlasImage);
+ } else if (dirty) {
+ uploadPass.updateTexture(*atlasTexture, atlasImage);
+ }
+
+ dirty = false;
+}
+
+gfx::TextureBinding PatternAtlas::textureBinding() const {
+ assert(atlasTexture);
+ assert(!dirty);
+ return { atlasTexture->getResource(), gfx::TextureFilterType::Linear };
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/pattern_atlas.hpp b/src/mbgl/renderer/pattern_atlas.hpp
new file mode 100644
index 0000000000..f39ba25233
--- /dev/null
+++ b/src/mbgl/renderer/pattern_atlas.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <mapbox/shelf-pack.hpp>
+#include <mbgl/gfx/texture.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <unordered_map>
+#include <string>
+
+namespace mbgl {
+
+template <class T>
+class Actor;
+
+namespace gfx {
+class UploadPass;
+} // namespace gfx
+
+class PatternAtlas {
+public:
+ PatternAtlas();
+ PatternAtlas(const PatternAtlas&) = delete;
+ PatternAtlas& operator=(const PatternAtlas&) = delete;
+ ~PatternAtlas();
+
+ optional<ImagePosition> getPattern(const std::string&) const;
+ optional<ImagePosition> addPattern(const style::Image::Impl&);
+ void removePattern(const std::string&);
+
+ gfx::TextureBinding textureBinding() const;
+
+ void upload(gfx::UploadPass&);
+ Size getPixelSize() const;
+
+ const PremultipliedImage& getAtlasImageForTests() const {
+ return atlasImage;
+ }
+
+private:
+ struct Pattern {
+ mapbox::Bin* bin;
+ ImagePosition position;
+ };
+ mapbox::ShelfPack shelfPack;
+ std::unordered_map<std::string, Pattern> patterns;
+ PremultipliedImage atlasImage;
+ mbgl::optional<gfx::Texture> atlasTexture;
+ bool dirty = true;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index 887acdfb59..94d7384ba4 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -18,6 +18,7 @@ class PaintParameters;
class RenderSource;
class RenderTile;
class TransformState;
+class PatternAtlas;
class LayerRenderData {
public:
@@ -35,6 +36,7 @@ class LayerPrepareParameters {
public:
RenderSource* source;
ImageManager& imageManager;
+ PatternAtlas& patternAtlas;
const TransformState& state;
};
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 9d1bedfd89..a8caba0b4d 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -7,6 +7,7 @@
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/renderer/upload_parameters.hpp>
+#include <mbgl/renderer/pattern_atlas.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/transition_parameters.hpp>
#include <mbgl/renderer/property_evaluation_parameters.hpp>
@@ -52,6 +53,7 @@ Renderer::Impl::Impl(gfx::RendererBackend& backend_,
, glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(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>>>())
@@ -143,6 +145,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
// Remove removed images from sprite atlas.
for (const auto& entry : imageDiff.removed) {
imageManager->removeImage(entry.first);
+ patternAtlas->removePattern(entry.first);
}
// Add added images to sprite atlas.
@@ -152,7 +155,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
// Update changed images.
for (const auto& entry : imageDiff.changed) {
- hasImageDiff = imageManager->updateImage(entry.second.after) || hasImageDiff;
+ if (imageManager->updateImage(entry.second.after)) {
+ patternAtlas->removePattern(entry.first);
+ hasImageDiff = true;
+ }
}
imageManager->notifyIfMissingImageAdded();
@@ -302,7 +308,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
for (auto& renderItem : renderItems) {
RenderLayer& renderLayer = renderItem.layer;
- renderLayer.prepare({renderItem.source, *imageManager, updateParameters.transformState});
+ renderLayer.prepare({renderItem.source, *imageManager, *patternAtlas, updateParameters.transformState});
if (renderLayer.needsPlacement()) {
layersNeedPlacement.emplace_back(renderLayer);
}
@@ -362,8 +368,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
renderLight.getEvaluated(),
transformParams,
*staticData,
- *imageManager,
*lineAtlas,
+ *patternAtlas
};
parameters.symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint);
@@ -393,8 +399,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
staticData->upload(*uploadPass);
- imageManager->upload(*uploadPass);
lineAtlas->upload(*uploadPass);
+ patternAtlas->upload(*uploadPass);
}
// - 3D PASS -------------------------------------------------------------------------------------
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 7bcbdbbf7c..fae79b6d52 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -29,6 +29,7 @@ class SourceQueryOptions;
class GlyphManager;
class ImageManager;
class LineAtlas;
+class PatternAtlas;
class CrossTileSymbolIndex;
namespace gfx {
@@ -116,6 +117,7 @@ private:
std::unique_ptr<GlyphManager> glyphManager;
std::unique_ptr<ImageManager> imageManager;
std::unique_ptr<LineAtlas> lineAtlas;
+ std::unique_ptr<PatternAtlas> patternAtlas;
std::unique_ptr<RenderStaticData> staticData;
Immutable<std::vector<Immutable<style::Image::Impl>>> imageImpls;
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 768948a82d..cbc94deed0 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -1,12 +1,14 @@
#pragma once
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/tile/geometry_tile_worker.hpp>
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/gfx/texture.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/geometry_tile_worker.hpp>
#include <mbgl/util/feature.hpp>
-#include <mbgl/actor/actor.hpp>
-#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/util/optional.hpp>
#include <atomic>
#include <memory>
diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp
index 443a8539b6..0b72578c35 100644
--- a/test/renderer/image_manager.test.cpp
+++ b/test/renderer/image_manager.test.cpp
@@ -28,51 +28,10 @@ TEST(ImageManager, Basic) {
util::read_file("test/fixtures/annotations/emerald.json"));
for (auto& image : images) {
imageManager.addImage(image->baseImpl);
+ auto* stored = imageManager.getImage(image->getID());
+ ASSERT_TRUE(stored);
+ EXPECT_EQ(image->getImage().size, stored->image.size);
}
-
- auto metro = *imageManager.getPattern("metro");
- EXPECT_EQ(1, metro.tl()[0]);
- EXPECT_EQ(1, metro.tl()[1]);
- EXPECT_EQ(19, metro.br()[0]);
- EXPECT_EQ(19, metro.br()[1]);
- EXPECT_EQ(18, metro.displaySize()[0]);
- EXPECT_EQ(18, metro.displaySize()[1]);
- EXPECT_EQ(1.0f, metro.pixelRatio);
- EXPECT_EQ(imageManager.getPixelSize(), imageManager.getAtlasImage().size);
-
- test::checkImage("test/fixtures/image_manager/basic", imageManager.getAtlasImage());
-}
-
-TEST(ImageManager, Updates) {
- ImageManager imageManager;
-
- PremultipliedImage imageA({ 16, 12 });
- imageA.fill(255);
- imageManager.addImage(makeMutable<style::Image::Impl>("one", std::move(imageA), 1));
-
- auto a = *imageManager.getPattern("one");
- EXPECT_EQ(1, a.tl()[0]);
- EXPECT_EQ(1, a.tl()[1]);
- EXPECT_EQ(17, a.br()[0]);
- EXPECT_EQ(13, a.br()[1]);
- EXPECT_EQ(16, a.displaySize()[0]);
- EXPECT_EQ(12, a.displaySize()[1]);
- EXPECT_EQ(1.0f, a.pixelRatio);
- test::checkImage("test/fixtures/image_manager/updates_before", imageManager.getAtlasImage());
-
- PremultipliedImage imageB({ 5, 5 });
- imageA.fill(200);
- imageManager.updateImage(makeMutable<style::Image::Impl>("one", std::move(imageB), 1));
-
- auto b = *imageManager.getPattern("one");
- EXPECT_EQ(1, b.tl()[0]);
- EXPECT_EQ(1, b.tl()[1]);
- EXPECT_EQ(6, b.br()[0]);
- EXPECT_EQ(6, b.br()[1]);
- EXPECT_EQ(5, b.displaySize()[0]);
- EXPECT_EQ(5, b.displaySize()[1]);
- EXPECT_EQ(1.0f, b.pixelRatio);
- test::checkImage("test/fixtures/image_manager/updates_after", imageManager.getAtlasImage());
}
TEST(ImageManager, AddRemove) {
diff --git a/test/renderer/pattern_atlas.test.cpp b/test/renderer/pattern_atlas.test.cpp
new file mode 100644
index 0000000000..2a19e463bd
--- /dev/null
+++ b/test/renderer/pattern_atlas.test.cpp
@@ -0,0 +1,82 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/fixture_log_observer.hpp>
+#include <mbgl/test/stub_style_observer.hpp>
+
+#include <mbgl/renderer/pattern_atlas.hpp>
+#include <mbgl/sprite/sprite_parser.hpp>
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <utility>
+
+using namespace mbgl;
+
+TEST(PatternAtlas, Basic) {
+ FixtureLog log;
+ PatternAtlas patternAtlas;
+
+ auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
+ util::read_file("test/fixtures/annotations/emerald.json"));
+ for (auto& image : images) {
+ if (image->getID() == "metro") {
+ ASSERT_TRUE(patternAtlas.addPattern(*image->baseImpl));
+ }
+ }
+ auto found = patternAtlas.getPattern("metro");
+ ASSERT_TRUE(found);
+
+ auto metro = *found;
+ EXPECT_EQ(1, metro.tl()[0]);
+ EXPECT_EQ(1, metro.tl()[1]);
+ EXPECT_EQ(19, metro.br()[0]);
+ EXPECT_EQ(19, metro.br()[1]);
+ EXPECT_EQ(18, metro.displaySize()[0]);
+ EXPECT_EQ(18, metro.displaySize()[1]);
+ EXPECT_EQ(1.0f, metro.pixelRatio);
+ EXPECT_EQ(patternAtlas.getPixelSize(), patternAtlas.getAtlasImageForTests().size);
+
+ test::checkImage("test/fixtures/image_manager/basic", patternAtlas.getAtlasImageForTests());
+}
+
+TEST(PatternAtlas, Updates) {
+ PatternAtlas patternAtlas;
+
+ PremultipliedImage imageA({ 16, 12 });
+ imageA.fill(255);
+
+ auto added = patternAtlas.addPattern(*makeMutable<style::Image::Impl>("one", std::move(imageA), 1));
+ ASSERT_TRUE(added);
+ auto found = patternAtlas.getPattern("one");
+ ASSERT_TRUE(found);
+ EXPECT_EQ(added->textureRect, found->textureRect);
+
+ auto a = *found;
+ EXPECT_EQ(1, a.tl()[0]);
+ EXPECT_EQ(1, a.tl()[1]);
+ EXPECT_EQ(17, a.br()[0]);
+ EXPECT_EQ(13, a.br()[1]);
+ EXPECT_EQ(16, a.displaySize()[0]);
+ EXPECT_EQ(12, a.displaySize()[1]);
+ EXPECT_EQ(1.0f, a.pixelRatio);
+ test::checkImage("test/fixtures/image_manager/updates_before", patternAtlas.getAtlasImageForTests());
+
+ auto imageB = makeMutable<style::Image::Impl>("one", PremultipliedImage({ 5, 5 }), 1);
+ EXPECT_FALSE(patternAtlas.addPattern(*imageB)); // Already added.
+
+ patternAtlas.removePattern("one");
+ ASSERT_FALSE(patternAtlas.getPattern("one"));
+ EXPECT_TRUE(patternAtlas.addPattern(*imageB));
+
+ auto b = *patternAtlas.getPattern("one");
+ EXPECT_EQ(1, b.tl()[0]);
+ EXPECT_EQ(1, b.tl()[1]);
+ EXPECT_EQ(6, b.br()[0]);
+ EXPECT_EQ(6, b.br()[1]);
+ EXPECT_EQ(5, b.displaySize()[0]);
+ EXPECT_EQ(5, b.displaySize()[1]);
+ EXPECT_EQ(1.0f, b.pixelRatio);
+ test::checkImage("test/fixtures/image_manager/updates_after", patternAtlas.getAtlasImageForTests());
+}
diff --git a/test/test-files.json b/test/test-files.json
index 6ed78d4e61..e46f833269 100644
--- a/test/test-files.json
+++ b/test/test-files.json
@@ -26,6 +26,7 @@
"test/programs/symbol_program.test.cpp",
"test/renderer/backend_scope.test.cpp",
"test/renderer/image_manager.test.cpp",
+ "test/renderer/pattern_atlas.test.cpp",
"test/sprite/sprite_loader.test.cpp",
"test/sprite/sprite_parser.test.cpp",
"test/src/mbgl/test/fixture_log_observer.cpp",