[core] Introduce PatternAtlas
This commit is contained in:
@@ -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",
|
||||
@@ -636,6 +637,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",
|
||||
|
||||
@@ -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_) {
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
109
src/mbgl/renderer/pattern_atlas.cpp
Normal file
109
src/mbgl/renderer/pattern_atlas.cpp
Normal file
@@ -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
|
||||
53
src/mbgl/renderer/pattern_atlas.hpp
Normal file
53
src/mbgl/renderer/pattern_atlas.hpp
Normal file
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 -------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/tile/tile.hpp>
|
||||
#include <mbgl/tile/geometry_tile_worker.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
#include <mbgl/util/feature.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/util/optional.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
82
test/renderer/pattern_atlas.test.cpp
Normal file
82
test/renderer/pattern_atlas.test.cpp
Normal file
@@ -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());
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user