Implement dynamic texture atlas (#3198)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bart Louwers <bart@emeel.net>
Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Alex Cristici
2025-05-14 18:38:47 +03:00
committed by GitHub
parent a537956529
commit 8a81444c43
74 changed files with 763 additions and 400 deletions

View File

@@ -157,6 +157,8 @@ list(APPEND INCLUDE_FILES
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_tweaker.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_atlases_tweaker.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_custom_layer_host_tweaker.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/dynamic_texture.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/dynamic_texture_atlas.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/gpu_expression.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_buffer.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/vertex_attribute.hpp
@@ -175,6 +177,8 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder_impl.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_atlases_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_custom_layer_host_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/dynamic_texture.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/dynamic_texture_atlas.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/gpu_expression.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/hillshade_prepare_drawable_data.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp
@@ -616,8 +620,6 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/data_driven_property_evaluator.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/group_by_layout.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/group_by_layout.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_atlas.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_atlas.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager_observer.hpp
@@ -881,8 +883,6 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/text/get_anchors.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/get_anchors.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph_atlas.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph_atlas.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph_manager.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph_manager.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/text/glyph_manager_observer.hpp

View File

@@ -286,8 +286,6 @@ MLN_CORE_SOURCE = [
"src/mbgl/renderer/data_driven_property_evaluator.hpp",
"src/mbgl/renderer/group_by_layout.cpp",
"src/mbgl/renderer/group_by_layout.hpp",
"src/mbgl/renderer/image_atlas.cpp",
"src/mbgl/renderer/image_atlas.hpp",
"src/mbgl/renderer/image_manager.cpp",
"src/mbgl/renderer/image_manager.hpp",
"src/mbgl/renderer/image_manager_observer.hpp",
@@ -528,8 +526,6 @@ MLN_CORE_SOURCE = [
"src/mbgl/text/get_anchors.cpp",
"src/mbgl/text/get_anchors.hpp",
"src/mbgl/text/glyph.cpp",
"src/mbgl/text/glyph_atlas.cpp",
"src/mbgl/text/glyph_atlas.hpp",
"src/mbgl/text/glyph_manager.cpp",
"src/mbgl/text/glyph_manager.hpp",
"src/mbgl/text/glyph_manager_observer.hpp",
@@ -944,6 +940,8 @@ MLN_DRAWABLES_SOURCE = [
"src/mbgl/gfx/drawable_builder_impl.cpp",
"src/mbgl/gfx/drawable_atlases_tweaker.cpp",
"src/mbgl/gfx/drawable_custom_layer_host_tweaker.cpp",
"src/mbgl/gfx/dynamic_texture.cpp",
"src/mbgl/gfx/dynamic_texture_atlas.cpp",
"src/mbgl/gfx/gpu_expression.cpp",
"src/mbgl/gfx/hillshade_prepare_drawable_data.hpp",
"src/mbgl/gfx/image_drawable_data.hpp",
@@ -1000,6 +998,8 @@ MLN_DRAWABLES_HEADERS = [
"include/mbgl/gfx/drawable_tweaker.hpp",
"include/mbgl/gfx/drawable_atlases_tweaker.hpp",
"include/mbgl/gfx/drawable_custom_layer_host_tweaker.hpp",
"include/mbgl/gfx/dynamic_texture.hpp",
"include/mbgl/gfx/dynamic_texture_atlas.hpp",
"include/mbgl/gfx/gpu_expression.hpp",
"include/mbgl/gfx/uniform_buffer.hpp",
"include/mbgl/gfx/vertex_attribute.hpp",

View File

@@ -0,0 +1,81 @@
#pragma once
#include <mbgl/gfx/types.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/rect.hpp>
#include <mapbox/shelf-pack.hpp>
#include <optional>
#include <mutex>
namespace mbgl {
namespace gfx {
class Context;
class Texture2D;
using Texture2DPtr = std::shared_ptr<gfx::Texture2D>;
class TextureHandle {
public:
TextureHandle(const mapbox::Bin& bin)
: id(bin.id),
rectangle(bin.x, bin.y, bin.w, bin.h),
needsUpload(bin.refcount() == 1) {};
~TextureHandle() = default;
int32_t getId() const { return id; }
const Rect<uint16_t>& getRectangle() const { return rectangle; }
bool isUploadNeeded() const { return needsUpload; }
bool operator==(const TextureHandle& other) const { return (id == other.id); }
struct Hasher {
size_t operator()(const TextureHandle& texHandle) const { return texHandle.id; }
};
private:
int32_t id = 0;
Rect<uint16_t> rectangle;
bool needsUpload = false;
friend class DynamicTexture;
};
class DynamicTexture {
public:
DynamicTexture(Context& context, Size size, TexturePixelType pixelType);
~DynamicTexture() = default;
const Texture2DPtr& getTexture() const;
TexturePixelType getPixelFormat() const;
bool isEmpty() const;
std::optional<TextureHandle> reserveSize(const Size& size, int32_t uniqueId);
void uploadImage(const uint8_t* pixelData, TextureHandle& texHandle);
template <typename Image>
std::optional<TextureHandle> addImage(const Image& image, int32_t uniqueId = -1) {
return addImage(image.data ? image.data.get() : nullptr, image.size, uniqueId);
}
std::optional<TextureHandle> addImage(const uint8_t* pixelData, const Size& imageSize, int32_t uniqueId = -1);
void uploadDeferredImages();
void removeTexture(const TextureHandle& texHandle);
using ImagesToUpload = std::unordered_map<TextureHandle, std::unique_ptr<uint8_t[]>, TextureHandle::Hasher>;
private:
Texture2DPtr texture;
mapbox::ShelfPack shelfPack;
int numTextures = 0;
bool deferredCreation = false;
ImagesToUpload imagesToUpload;
std::mutex mutex;
};
#define MLN_DEFER_UPLOAD_ON_RENDER_THREAD (MLN_RENDER_BACKEND_OPENGL || MLN_RENDER_BACKEND_VULKAN)
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,49 @@
#pragma once
#include <mbgl/gfx/dynamic_texture.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/style/image_impl.hpp>
namespace mbgl {
namespace gfx {
using DynamicTexturePtr = std::shared_ptr<gfx::DynamicTexture>;
class GlyphAtlas {
public:
GlyphPositions glyphPositions;
std::vector<TextureHandle> textureHandles;
DynamicTexturePtr dynamicTexture;
};
class ImageAtlas {
public:
ImagePositions iconPositions;
ImagePositions patternPositions;
std::vector<TextureHandle> textureHandles;
DynamicTexturePtr dynamicTexture;
};
class DynamicTextureAtlas {
public:
DynamicTextureAtlas(Context& context_)
: context(context_) {}
~DynamicTextureAtlas() = default;
GlyphAtlas uploadGlyphs(const GlyphMap& glyphs);
ImageAtlas uploadIconsAndPatterns(const ImageMap& icons,
const ImageMap& patterns,
const ImageVersionMap& versionMap);
void removeTextures(const std::vector<TextureHandle>& textureHandles, const DynamicTexturePtr& dynamicTexture);
private:
Context& context;
std::vector<DynamicTexturePtr> dynamicTextures;
std::unordered_map<TexturePixelType, DynamicTexturePtr> dummyDynamicTexture;
std::mutex mutex;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -53,6 +53,10 @@ public:
/// @param image_ Image data to transfer
virtual Texture2D& setImage(std::shared_ptr<PremultipliedImage> image_) noexcept = 0;
/// @brief Get the pixel format of the texture
/// @return Pixel format of the texture
virtual TexturePixelType getFormat() const noexcept = 0;
/// @brief Get the size of the texture
/// @return Size of the texture
virtual Size getSize() const noexcept = 0;

View File

@@ -26,6 +26,8 @@ public: // gfx::Texture2D
Texture2D& setImage(std::shared_ptr<PremultipliedImage> image_) noexcept override;
gfx::TexturePixelType getFormat() const noexcept override { return pixelFormat; }
Size getSize() const noexcept override { return size; }
size_t getDataSize() const noexcept override;

View File

@@ -29,6 +29,8 @@ public:
gfx::Texture2D& setImage(std::shared_ptr<PremultipliedImage>) noexcept override;
gfx::TexturePixelType getFormat() const noexcept override { return pixelFormat; }
Size getSize() const noexcept override { return size; }
size_t getDataSize() const noexcept override;

View File

@@ -131,4 +131,12 @@ enum class WritingModeType : uint8_t {
using GlyphDependencies = std::map<FontStack, GlyphIDs>;
using GlyphRangeDependencies = std::map<FontStack, std::unordered_set<GlyphRange>>;
struct GlyphPosition {
Rect<uint16_t> rect;
GlyphMetrics metrics;
};
using GlyphPositionMap = std::map<GlyphID, GlyphPosition>;
using GlyphPositions = std::map<FontStackHash, GlyphPositionMap>;
} // end namespace mbgl

View File

@@ -54,6 +54,7 @@ public:
gfx::Texture2D& setImage(std::shared_ptr<PremultipliedImage>) noexcept override;
gfx::Texture2D& setUsage(Texture2DUsage) noexcept;
gfx::TexturePixelType getFormat() const noexcept override { return pixelFormat; }
Size getSize() const noexcept override { return size; }
size_t getDataSize() const noexcept override;
size_t getPixelStride() const noexcept override;

View File

@@ -8,6 +8,7 @@ filegroup(
"ignores/**",
"ios-render-test-runner/**", # iOS only
"expectations/platform-ios/**", # iOS only
"expectations/platform-linux/**",
],
) + select({
"//:metal_renderer": glob(["expectations/platform-ios-metal/**"]), # iOS Metal only

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -2,6 +2,7 @@
"base_test_path": "integration",
"cache_path": "cache-style.db",
"expectation_paths": [
"expectations/platform-linux"
],
"ignore_paths": [
"ignores/platform-all.json",

View File

@@ -2,6 +2,7 @@
"base_test_path": "integration",
"cache_path": "cache-style.db",
"expectation_paths": [
"expectations/platform-linux"
],
"ignore_paths": [
"ignores/platform-all.json",

View File

@@ -2,6 +2,7 @@
"base_test_path": "integration",
"cache_path": "cache-style.db",
"expectation_paths": [
"expectations/platform-windows"
],
"ignore_paths": [
"ignores/platform-all.json",

View File

@@ -2,6 +2,7 @@
"base_test_path": "integration",
"cache_path": "cache-style.db",
"expectation_paths": [
"expectations/platform-windows"
],
"ignore_paths": [
"ignores/platform-all.json",

View File

@@ -2,6 +2,7 @@
"base_test_path": "integration",
"cache_path": "cache-style.db",
"expectation_paths": [
"expectations/platform-windows"
],
"ignore_paths": [
"ignores/platform-all.json",

View File

@@ -202,6 +202,7 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
ignoreReason = it->second;
if (ignoreReason.rfind("skip", 0) == 0) {
printf(ANSI_COLOR_GRAY "* skipped %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
mbgl::Log::Info(mbgl::Event::General, "* skipped " + id + "(" + ignoreReason + ")");
continue;
}
}
@@ -222,12 +223,14 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
color = "#E8A408";
stats.ignorePassedTests++;
printf(ANSI_COLOR_YELLOW "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
mbgl::Log::Info(mbgl::Event::General, "* ignore " + id + " (" + ignoreReason + ")");
} else {
status = "ignored failed";
color = "#9E9E9E";
stats.ignoreFailedTests++;
printf(
ANSI_COLOR_LIGHT_GRAY "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
mbgl::Log::Info(mbgl::Event::General, "* ignore " + id + " (" + ignoreReason + ")");
}
} else {
// Only fail the bots on render errors, this is a CI limitation that
@@ -244,6 +247,7 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
color = "green";
stats.passedTests++;
printf(ANSI_COLOR_GREEN "* passed %s" ANSI_COLOR_RESET "\n", id.c_str());
mbgl::Log::Info(mbgl::Event::General, "* passed " + id);
} else if (errored) {
status = "errored";
color = "red";
@@ -251,12 +255,15 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
returnCode = 2;
printf(ANSI_COLOR_RED "* errored %s" ANSI_COLOR_RESET "\n", id.c_str());
printf(ANSI_COLOR_RED "* error: %s" ANSI_COLOR_RESET "\n", metadata.errorMessage.c_str());
mbgl::Log::Info(mbgl::Event::General, "* errored " + id);
mbgl::Log::Info(mbgl::Event::General, "* error " + metadata.errorMessage);
} else {
status = "failed";
color = "red";
stats.failedTests++;
returnCode = 3;
printf(ANSI_COLOR_RED "* failed %s" ANSI_COLOR_RESET "\n", id.c_str());
mbgl::Log::Info(mbgl::Event::General, "* failed " + id);
}
}
@@ -278,26 +285,32 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
printf(ANSI_COLOR_GREEN "%u passed (%.1lf%%)" ANSI_COLOR_RESET "\n",
stats.passedTests,
100.0 * stats.passedTests / count);
mbgl::Log::Info(mbgl::Event::General, std::to_string(stats.passedTests) + " passed tests");
}
if (stats.ignorePassedTests) {
printf(ANSI_COLOR_YELLOW "%u passed but were ignored (%.1lf%%)" ANSI_COLOR_RESET "\n",
stats.ignorePassedTests,
100.0 * stats.ignorePassedTests / count);
mbgl::Log::Info(mbgl::Event::General,
std::to_string(stats.ignorePassedTests) + " passed tests but were ignored");
}
if (stats.ignoreFailedTests) {
printf(ANSI_COLOR_LIGHT_GRAY "%u ignored (%.1lf%%)" ANSI_COLOR_RESET "\n",
stats.ignoreFailedTests,
100.0 * stats.ignoreFailedTests / count);
mbgl::Log::Info(mbgl::Event::General, std::to_string(stats.ignoreFailedTests) + " ignored tests");
}
if (stats.failedTests) {
printf(ANSI_COLOR_RED "%u failed (%.1lf%%)" ANSI_COLOR_RESET "\n",
stats.failedTests,
100.0 * stats.failedTests / count);
mbgl::Log::Info(mbgl::Event::General, std::to_string(stats.failedTests) + " failed tests");
}
if (stats.erroredTests) {
printf(ANSI_COLOR_RED "%u errored (%.1lf%%)" ANSI_COLOR_RESET "\n",
stats.erroredTests,
100.0 * stats.erroredTests / count);
mbgl::Log::Info(mbgl::Event::General, std::to_string(stats.erroredTests) + " errored tests");
}
printf("Results at: %s\n", mbgl::filesystem::canonical(resultPath).generic_string().c_str());

View File

@@ -10,11 +10,13 @@ namespace gfx {
void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable, const bool linearFilterForIcons) {
if (const auto& shader = drawable.getShader()) {
if (glyphTextureId) {
if (atlases) {
if (glyphTextureId && atlases) {
if (atlases->glyph) {
atlases->glyph->setSamplerConfiguration({.filter = TextureFilterType::Linear,
.wrapU = TextureWrapType::Clamp,
.wrapV = TextureWrapType::Clamp});
}
if (atlases->icon) {
atlases->icon->setSamplerConfiguration(
{.filter = linearFilterForIcons ? TextureFilterType::Linear : TextureFilterType::Nearest,
.wrapU = TextureWrapType::Clamp,

View File

@@ -0,0 +1,104 @@
#include <mbgl/gfx/dynamic_texture.hpp>
#include <mbgl/gfx/texture2d.hpp>
#include <mbgl/gfx/context.hpp>
namespace mbgl {
namespace gfx {
DynamicTexture::DynamicTexture(Context& context, Size size, TexturePixelType pixelType) {
mapbox::ShelfPack::ShelfPackOptions options;
options.autoResize = false;
shelfPack = mapbox::ShelfPack(size.width, size.height, options);
texture = context.createTexture2D();
texture->setSize(size);
texture->setFormat(pixelType, TextureChannelDataType::UnsignedByte);
texture->setSamplerConfiguration(
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
#if MLN_DEFER_UPLOAD_ON_RENDER_THREAD
deferredCreation = true;
#else
texture->create();
#endif
}
const Texture2DPtr& DynamicTexture::getTexture() const {
assert(texture);
return texture;
}
TexturePixelType DynamicTexture::getPixelFormat() const {
assert(texture);
return texture->getFormat();
}
bool DynamicTexture::isEmpty() const {
return (numTextures == 0);
}
std::optional<TextureHandle> DynamicTexture::reserveSize(const Size& size, int32_t uniqueId) {
std::lock_guard<std::mutex> lock(mutex);
mapbox::Bin* bin = shelfPack.packOne(uniqueId, size.width, size.height);
if (!bin) {
return std::nullopt;
}
if (bin->refcount() == 1) {
numTextures++;
}
return TextureHandle(*bin);
}
void DynamicTexture::uploadImage(const uint8_t* pixelData, TextureHandle& texHandle) {
std::lock_guard<std::mutex> lock(mutex);
const auto& rect = texHandle.getRectangle();
const auto imageSize = Size(rect.w, rect.h);
#if MLN_DEFER_UPLOAD_ON_RENDER_THREAD
auto size = imageSize.area() * texture->getPixelStride();
auto imageData = std::make_unique<uint8_t[]>(size);
std::copy(pixelData, pixelData + size, imageData.get());
imagesToUpload.emplace(texHandle, std::move(imageData));
#else
texture->uploadSubRegion(pixelData, imageSize, rect.x, rect.y);
#endif
texHandle.needsUpload = false;
}
std::optional<TextureHandle> DynamicTexture::addImage(const uint8_t* pixelData,
const Size& imageSize,
int32_t uniqueId) {
auto texHandle = reserveSize(imageSize, uniqueId);
if (texHandle && texHandle->isUploadNeeded()) {
uploadImage(pixelData, *texHandle);
}
return texHandle;
}
void DynamicTexture::uploadDeferredImages() {
std::lock_guard<std::mutex> lock(mutex);
if (deferredCreation) {
texture->create();
deferredCreation = false;
}
for (const auto& pair : imagesToUpload) {
const auto& rect = pair.first.getRectangle();
texture->uploadSubRegion(pair.second.get(), Size(rect.w, rect.h), rect.x, rect.y);
}
imagesToUpload.clear();
}
void DynamicTexture::removeTexture(const TextureHandle& texHandle) {
std::lock_guard<std::mutex> lock(mutex);
auto* bin = shelfPack.getBin(texHandle.getId());
if (!bin) {
return;
}
auto refcount = shelfPack.unref(*bin);
if (refcount == 0) {
numTextures--;
imagesToUpload.erase(texHandle);
}
}
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,256 @@
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <mbgl/gfx/context.hpp>
#include <cmath>
namespace mbgl {
namespace gfx {
constexpr const uint16_t extraPadding = 1;
constexpr const uint16_t padding = ImagePosition::padding + extraPadding;
constexpr const Size startSize = {512, 512};
Rect<uint16_t> rectWithoutExtraPadding(const Rect<uint16_t>& rect) {
return Rect<uint16_t>(
rect.x + extraPadding, rect.y + extraPadding, rect.w - 2 * extraPadding, rect.h - 2 * extraPadding);
}
GlyphAtlas DynamicTextureAtlas::uploadGlyphs(const GlyphMap& glyphs) {
using GlyphsToUpload = std::vector<std::tuple<TextureHandle, Immutable<Glyph>, FontStackHash>>;
std::lock_guard<std::mutex> lock(mutex);
GlyphAtlas glyphAtlas;
if (!glyphs.size()) {
glyphAtlas.dynamicTexture = dummyDynamicTexture[TexturePixelType::Alpha];
if (!glyphAtlas.dynamicTexture) {
glyphAtlas.dynamicTexture = std::make_shared<gfx::DynamicTexture>(
context, Size(1, 1), TexturePixelType::Alpha);
dummyDynamicTexture[TexturePixelType::Alpha] = glyphAtlas.dynamicTexture;
}
return glyphAtlas;
}
size_t dynTexIndex = 0;
Size dynTexSize = startSize;
GlyphsToUpload glyphsToUpload;
while (!glyphAtlas.dynamicTexture) {
if (dynTexIndex < dynamicTextures.size()) {
glyphAtlas.dynamicTexture = dynamicTextures[dynTexIndex++];
} else {
glyphAtlas.dynamicTexture = std::make_shared<gfx::DynamicTexture>(
context, dynTexSize, TexturePixelType::Alpha);
dynTexSize = Size(dynTexSize.width * 2, dynTexSize.height * 2);
dynTexIndex++;
}
if (glyphAtlas.dynamicTexture->getPixelFormat() != TexturePixelType::Alpha) {
glyphAtlas.dynamicTexture = nullptr;
continue;
}
bool hasSpace = true;
for (const auto& glyphMapEntry : glyphs) {
FontStackHash fontStack = glyphMapEntry.first;
for (const auto& glyphEntry : glyphMapEntry.second) {
const auto& glyph = glyphEntry.second;
if (glyph.has_value() && glyph.value()->bitmap.valid()) {
int32_t uniqueId = static_cast<int32_t>(sqrt(fontStack) / 2 + glyph.value()->id);
const auto size = Size(glyph.value()->bitmap.size.width + 2 * padding,
glyph.value()->bitmap.size.height + 2 * padding);
const auto& texHandle = glyphAtlas.dynamicTexture->reserveSize(size, uniqueId);
if (!texHandle) {
hasSpace = false;
break;
}
glyphsToUpload.emplace_back(std::make_tuple(*texHandle, glyph.value(), fontStack));
}
}
if (!hasSpace) {
for (const auto& [texHandle, glyph, fontStack_] : glyphsToUpload) {
glyphAtlas.dynamicTexture->removeTexture(texHandle);
}
glyphsToUpload.clear();
glyphAtlas.dynamicTexture = nullptr;
break;
}
}
}
if (dynTexIndex > dynamicTextures.size()) {
dynamicTextures.emplace_back(glyphAtlas.dynamicTexture);
}
for (auto& [texHandle, glyph, fontStack] : glyphsToUpload) {
const auto& rect = texHandle.getRectangle();
if (texHandle.isUploadNeeded()) {
AlphaImage paddedImage(Size{rect.w, rect.h});
paddedImage.fill(0);
AlphaImage::copy(glyph->bitmap, paddedImage, {0, 0}, {padding, padding}, glyph->bitmap.size);
glyphAtlas.dynamicTexture->uploadImage(paddedImage.data.get(), texHandle);
}
glyphAtlas.textureHandles.emplace_back(texHandle);
glyphAtlas.glyphPositions[fontStack].emplace(glyph->id,
GlyphPosition{rectWithoutExtraPadding(rect), glyph->metrics});
}
return glyphAtlas;
}
ImageAtlas DynamicTextureAtlas::uploadIconsAndPatterns(const ImageMap& icons,
const ImageMap& patterns,
const ImageVersionMap& versionMap) {
using ImagesToUpload = std::vector<std::pair<TextureHandle, Immutable<style::Image::Impl>>>;
std::lock_guard<std::mutex> lock(mutex);
ImageAtlas imageAtlas;
if (!icons.size() && !patterns.size()) {
imageAtlas.dynamicTexture = dummyDynamicTexture[TexturePixelType::RGBA];
if (!imageAtlas.dynamicTexture) {
imageAtlas.dynamicTexture = std::make_shared<gfx::DynamicTexture>(
context, Size(1, 1), TexturePixelType::RGBA);
dummyDynamicTexture[TexturePixelType::RGBA] = imageAtlas.dynamicTexture;
}
return imageAtlas;
}
size_t dynTexIndex = 0;
Size dynTexSize = startSize;
ImagesToUpload iconsToUpload;
ImagesToUpload patternsToUpload;
iconsToUpload.reserve(icons.size());
patternsToUpload.reserve(patterns.size());
while (!imageAtlas.dynamicTexture) {
if (dynTexIndex < dynamicTextures.size()) {
imageAtlas.dynamicTexture = dynamicTextures[dynTexIndex++];
} else {
imageAtlas.dynamicTexture = std::make_shared<gfx::DynamicTexture>(
context, dynTexSize, TexturePixelType::RGBA);
dynTexSize = Size(dynTexSize.width * 2, dynTexSize.height * 2);
dynTexIndex++;
}
if (imageAtlas.dynamicTexture->getPixelFormat() != TexturePixelType::RGBA) {
imageAtlas.dynamicTexture = nullptr;
continue;
}
bool hasSpace = true;
for (const auto& iconEntry : icons) {
const auto& icon = iconEntry.second;
auto imageHash = util::hash(icon->id);
int32_t uniqueId = static_cast<int32_t>(sqrt(imageHash) / 2 + icon->image.size.area());
const auto size = Size(icon->image.size.width + 2 * padding, icon->image.size.height + 2 * padding);
const auto& texHandle = imageAtlas.dynamicTexture->reserveSize(size, uniqueId);
if (!texHandle) {
hasSpace = false;
break;
}
iconsToUpload.emplace_back(std::make_pair(*texHandle, icon));
}
if (hasSpace) {
for (const auto& patternEntry : patterns) {
const auto& pattern = patternEntry.second;
auto patternHash = util::hash(pattern->id);
int32_t uniqueId = static_cast<int32_t>(sqrt(patternHash) / 2 + pattern->image.size.area());
const auto size = Size(pattern->image.size.width + 2 * padding,
pattern->image.size.height + 2 * padding);
const auto& texHandle = imageAtlas.dynamicTexture->reserveSize(size, uniqueId);
if (!texHandle) {
hasSpace = false;
break;
}
patternsToUpload.emplace_back(std::make_pair(*texHandle, pattern));
}
}
if (!hasSpace) {
for (const auto& [texHandle, icon] : iconsToUpload) {
imageAtlas.dynamicTexture->removeTexture(texHandle);
}
iconsToUpload.clear();
for (const auto& [texHandle, pattern] : patternsToUpload) {
imageAtlas.dynamicTexture->removeTexture(texHandle);
}
patternsToUpload.clear();
imageAtlas.dynamicTexture = nullptr;
continue;
}
}
if (dynTexIndex > dynamicTextures.size()) {
dynamicTextures.emplace_back(imageAtlas.dynamicTexture);
}
imageAtlas.iconPositions.reserve(icons.size());
for (auto& [texHandle, icon] : iconsToUpload) {
const auto& rect = texHandle.getRectangle();
if (texHandle.isUploadNeeded()) {
PremultipliedImage paddedImage(Size{rect.w, rect.h});
paddedImage.fill(0);
PremultipliedImage::copy(icon->image, paddedImage, {0, 0}, {padding, padding}, icon->image.size);
imageAtlas.dynamicTexture->uploadImage(paddedImage.data.get(), texHandle);
}
imageAtlas.textureHandles.emplace_back(texHandle);
const auto it = versionMap.find(icon->id);
const auto version = it != versionMap.end() ? it->second : 0;
imageAtlas.iconPositions.emplace(icon->id, ImagePosition{rectWithoutExtraPadding(rect), *icon, version});
}
imageAtlas.patternPositions.reserve(patterns.size());
for (auto& [texHandle, pattern] : patternsToUpload) {
const auto& rect = texHandle.getRectangle();
if (texHandle.isUploadNeeded()) {
PremultipliedImage paddedImage(Size{rect.w, rect.h});
paddedImage.fill(0);
PremultipliedImage::copy(pattern->image, paddedImage, {0, 0}, {padding, padding}, pattern->image.size);
const uint32_t x = padding;
const uint32_t y = padding;
const uint32_t w = pattern->image.size.width;
const uint32_t h = pattern->image.size.height;
// Add 1 pixel wrapped padding on each side of the image.
PremultipliedImage::copy(pattern->image, paddedImage, {0, h - 1}, {x, y - 1}, {w, 1}); // T
PremultipliedImage::copy(pattern->image, paddedImage, {0, 0}, {x, y + h}, {w, 1}); // B
PremultipliedImage::copy(pattern->image, paddedImage, {w - 1, 0}, {x - 1, y}, {1, h}); // L
PremultipliedImage::copy(pattern->image, paddedImage, {0, 0}, {x + w, y}, {1, h}); // R
imageAtlas.dynamicTexture->uploadImage(paddedImage.data.get(), texHandle);
}
imageAtlas.textureHandles.emplace_back(texHandle);
const auto it = versionMap.find(pattern->id);
const auto version = it != versionMap.end() ? it->second : 0;
imageAtlas.patternPositions.emplace(pattern->id,
ImagePosition{rectWithoutExtraPadding(rect), *pattern, version});
}
return imageAtlas;
}
void DynamicTextureAtlas::removeTextures(const std::vector<TextureHandle>& textureHandles,
const DynamicTexturePtr& dynamicTexture) {
std::lock_guard<std::mutex> lock(mutex);
if (!dynamicTexture) {
return;
}
for (const auto& texHandle : textureHandles) {
dynamicTexture->removeTexture(texHandle);
}
if (dynamicTexture->isEmpty()) {
auto iterator = std::find(dynamicTextures.begin(), dynamicTextures.end(), dynamicTexture);
if (iterator != dynamicTextures.end()) {
dynamicTextures.erase(iterator);
}
}
}
} // namespace gfx
} // namespace mbgl

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/containers.hpp>
#include <memory>

View File

@@ -1,7 +1,6 @@
#pragma once
#include <mbgl/text/quads.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/util/bitmask_operations.hpp>

View File

@@ -5,7 +5,6 @@
#include <mbgl/math/angles.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/text/get_anchors.hpp>
#include <mbgl/text/shaping.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>

View File

@@ -1,5 +1,4 @@
#include <mbgl/programs/background_program.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/map/transform_state.hpp>

View File

@@ -1,5 +1,4 @@
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/map/transform_state.hpp>

View File

@@ -1,5 +1,4 @@
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/map/transform_state.hpp>

View File

@@ -1,7 +1,6 @@
#include <mbgl/programs/line_program.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/util/mat2.hpp>
#include <mbgl/geometry/line_atlas.hpp>

View File

@@ -1,7 +1,6 @@
#pragma once
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>

View File

@@ -4,7 +4,6 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/text/cross_tile_symbol_index.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/placement.hpp>
#include <utility>

View File

@@ -1,114 +0,0 @@
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mapbox/shelf-pack.hpp>
namespace mbgl {
static constexpr uint32_t padding = 1;
ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image, uint32_t version_)
: pixelRatio(image.pixelRatio),
paddedRect(bin.x, bin.y, bin.w, bin.h),
version(version_),
stretchX(image.stretchX),
stretchY(image.stretchY),
content(image.content),
textFitWidth(image.textFitWidth),
textFitHeight(image.textFitHeight) {}
namespace {
const mapbox::Bin& _packImage(mapbox::ShelfPack& pack,
const style::Image::Impl& image,
ImageAtlas& resultImage,
ImageType imageType) {
const mapbox::Bin& bin = *pack.packOne(
-1, image.image.size.width + 2 * padding, image.image.size.height + 2 * padding);
resultImage.image.resize({static_cast<uint32_t>(pack.width()), static_cast<uint32_t>(pack.height())});
PremultipliedImage::copy(
image.image, resultImage.image, {0, 0}, {bin.x + padding, bin.y + padding}, image.image.size);
if (imageType == ImageType::Pattern) {
const uint32_t x = bin.x + padding;
const uint32_t y = bin.y + padding;
const uint32_t w = image.image.size.width;
const uint32_t h = image.image.size.height;
// Add 1 pixel wrapped padding on each side of the image.
PremultipliedImage::copy(image.image, resultImage.image, {0, h - 1}, {x, y - 1}, {w, 1}); // T
PremultipliedImage::copy(image.image, resultImage.image, {0, 0}, {x, y + h}, {w, 1}); // B
PremultipliedImage::copy(image.image, resultImage.image, {w - 1, 0}, {x - 1, y}, {1, h}); // L
PremultipliedImage::copy(image.image, resultImage.image, {0, 0}, {x + w, y}, {1, h}); // R
}
return bin;
}
void populateImagePatches(ImagePositions& imagePositions,
const ImageManager& imageManager,
std::vector<ImagePatch>& /*out*/ patches) {
if (imagePositions.empty()) {
imagePositions.reserve(imageManager.updatedImageVersions.size());
}
for (auto& updatedImageVersion : imageManager.updatedImageVersions) {
const std::string& name = updatedImageVersion.first;
const uint32_t version = updatedImageVersion.second;
const auto it = imagePositions.find(updatedImageVersion.first);
if (it != imagePositions.end()) {
auto& position = it->second;
if (position.version == version) continue;
const auto updatedImage = imageManager.getSharedImage(name);
if (updatedImage == nullptr) continue;
patches.emplace_back(*updatedImage, position.paddedRect);
position.version = version;
}
}
}
} // namespace
std::vector<ImagePatch> ImageAtlas::getImagePatchesAndUpdateVersions(const ImageManager& imageManager) {
std::vector<ImagePatch> imagePatches;
populateImagePatches(iconPositions, imageManager, imagePatches);
populateImagePatches(patternPositions, imageManager, imagePatches);
return imagePatches;
}
ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns, const ImageVersionMap& versionMap) {
ImageAtlas result;
mapbox::ShelfPack::ShelfPackOptions options;
options.autoResize = true;
mapbox::ShelfPack pack(0, 0, options);
result.iconPositions.reserve(icons.size());
for (const auto& entry : icons) {
const style::Image::Impl& image = *entry.second;
const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Icon);
const auto it = versionMap.find(entry.first);
const auto version = it != versionMap.end() ? it->second : 0;
result.iconPositions.emplace(image.id, ImagePosition{bin, image, version});
}
result.patternPositions.reserve(patterns.size());
for (const auto& entry : patterns) {
const style::Image::Impl& image = *entry.second;
const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Pattern);
const auto it = versionMap.find(entry.first);
const auto version = it != versionMap.end() ? it->second : 0;
result.patternPositions.emplace(image.id, ImagePosition{bin, image, version});
}
pack.shrink();
result.image.resize({static_cast<uint32_t>(pack.width()), static_cast<uint32_t>(pack.height())});
return result;
}
} // namespace mbgl

View File

@@ -1,80 +0,0 @@
#pragma once
#include <mbgl/style/image_impl.hpp>
#include <mbgl/util/rect.hpp>
#include <mapbox/shelf-pack.hpp>
#include <array>
#include <optional>
namespace mbgl {
namespace gfx {
class UploadPass;
class Texture;
} // namespace gfx
class ImageManager;
class ImagePosition {
public:
ImagePosition(const mapbox::Bin&, const style::Image::Impl&, uint32_t version = 0);
static constexpr const uint16_t padding = 1u;
float pixelRatio;
Rect<uint16_t> paddedRect;
uint32_t version;
style::ImageStretches stretchX;
style::ImageStretches stretchY;
std::optional<style::ImageContent> content;
std::optional<style::TextFit> textFitWidth;
std::optional<style::TextFit> textFitHeight;
std::array<uint16_t, 2> tl() const {
return {{static_cast<uint16_t>(paddedRect.x + padding), static_cast<uint16_t>(paddedRect.y + padding)}};
}
std::array<uint16_t, 2> br() const {
return {{static_cast<uint16_t>(paddedRect.x + paddedRect.w - padding),
static_cast<uint16_t>(paddedRect.y + paddedRect.h - padding)}};
}
std::array<uint16_t, 4> tlbr() const {
const auto _tl = tl();
const auto _br = br();
return {{_tl[0], _tl[1], _br[0], _br[1]}};
}
std::array<float, 2> displaySize() const {
return {{
static_cast<float>(paddedRect.w - padding * 2) / pixelRatio,
static_cast<float>(paddedRect.h - padding * 2) / pixelRatio,
}};
}
};
using ImagePositions = mbgl::unordered_map<std::string, ImagePosition>;
class ImagePatch {
public:
ImagePatch(Immutable<style::Image::Impl> image_, const Rect<uint16_t>& paddedRect_)
: image(std::move(image_)),
paddedRect(paddedRect_) {}
Immutable<style::Image::Impl> image;
Rect<uint16_t> paddedRect;
};
class ImageAtlas {
public:
PremultipliedImage image;
ImagePositions iconPositions;
ImagePositions patternPositions;
std::vector<ImagePatch> getImagePatchesAndUpdateVersions(const ImageManager&);
};
ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&, const ImageVersionMap& versionMap);
} // namespace mbgl

View File

@@ -5,7 +5,6 @@
#include <mbgl/gfx/line_drawable_data.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/programs/line_program.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_tile.hpp>

View File

@@ -498,11 +498,15 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
if (patternBuilder) {
patternBuilder->clearTweakers();
patternBuilder->addTweaker(getAtlasTweaker());
if (const auto& tweaker = getAtlasTweaker()) {
patternBuilder->addTweaker(tweaker);
}
}
if (doOutline && outlinePatternBuilder) {
outlinePatternBuilder->clearTweakers();
outlinePatternBuilder->addTweaker(getAtlasTweaker());
if (const auto& tweaker = getAtlasTweaker()) {
outlinePatternBuilder->addTweaker(tweaker);
}
}
if (patternBuilder && bucket.sharedTriangles->elements()) {

View File

@@ -14,7 +14,6 @@
#include <mbgl/renderer/tile_render_data.hpp>
#include <mbgl/renderer/upload_parameters.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/shaping.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>

View File

@@ -7,7 +7,6 @@
#include <mbgl/layout/pattern_layout.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/renderer/cross_faded_property_evaluator.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/paint_property_statistics.hpp>
#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
#include <mbgl/util/indexed_tuple.hpp>

View File

@@ -65,7 +65,9 @@ std::optional<ImagePosition> PatternAtlas::addPattern(const style::Image::Impl&
dirty = true;
return patterns.emplace(image.id, Pattern{.bin = bin, .position = {*bin, image}}).first->second.position;
return patterns
.emplace(image.id, Pattern{.bin = bin, .position = {Rect<uint16_t>(bin->x, bin->y, bin->w, bin->h), image}})
.first->second.position;
}
void PatternAtlas::removePattern(const std::string& id) {

View File

@@ -2,7 +2,6 @@
#include <mapbox/shelf-pack.hpp>
#include <mbgl/gfx/texture.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <unordered_map>

View File

@@ -153,7 +153,7 @@ void RenderOrchestrator::setObserver(RendererObserver* observer_) {
}
std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
const std::shared_ptr<UpdateParameters>& updateParameters) {
const std::shared_ptr<UpdateParameters>& updateParameters, gfx::DynamicTextureAtlasPtr dynamicTextureAtlas) {
MLN_TRACE_FUNC();
const auto startTime = util::MonotonicTimer::now().count();
@@ -194,7 +194,8 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
.imageManager = imageManager,
.glyphManager = glyphManager,
.prefetchZoomDelta = updateParameters->prefetchZoomDelta,
.threadPool = threadPool};
.threadPool = threadPool,
.dynamicTextureAtlas = dynamicTextureAtlas};
glyphManager->setURL(updateParameters->glyphURL);

View File

@@ -41,6 +41,8 @@ namespace gfx {
class ShaderRegistry;
class Drawable;
using DrawablePtr = std::shared_ptr<Drawable>;
class DynamicTextureAtlas;
using DynamicTextureAtlasPtr = std::shared_ptr<gfx::DynamicTextureAtlas>;
} // namespace gfx
namespace style {
@@ -64,7 +66,7 @@ public:
// TODO: Introduce RenderOrchestratorObserver.
void setObserver(RendererObserver*);
std::unique_ptr<RenderTree> createRenderTree(const std::shared_ptr<UpdateParameters>&);
std::unique_ptr<RenderTree> createRenderTree(const std::shared_ptr<UpdateParameters>&, gfx::DynamicTextureAtlasPtr);
std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const;
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;

View File

@@ -96,24 +96,6 @@ std::optional<ImagePosition> RenderTile::getPattern(const std::string& pattern)
return renderData->getPattern(pattern);
}
static const gfx::Texture2DPtr noTexture;
bool RenderTile::hasGlyphAtlasTexture() const {
return renderData && renderData->getGlyphAtlasTexture();
}
const gfx::Texture2DPtr& RenderTile::getGlyphAtlasTexture() const {
return renderData ? renderData->getGlyphAtlasTexture() : noTexture;
}
bool RenderTile::hasIconAtlasTexture() const {
return renderData && renderData->getIconAtlasTexture();
}
const gfx::Texture2DPtr& RenderTile::getIconAtlasTexture() const {
return renderData ? renderData->getIconAtlasTexture() : noTexture;
}
static const std::shared_ptr<TileAtlasTextures> noAtlas;
const std::shared_ptr<TileAtlasTextures>& RenderTile::getAtlasTextures() const {
return renderData ? renderData->getAtlasTextures() : noAtlas;

View File

@@ -4,7 +4,7 @@
#include <mbgl/gfx/texture.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/types.hpp>
@@ -60,12 +60,6 @@ public:
const LayerRenderData* getLayerRenderData(const style::Layer::Impl&) const;
std::optional<ImagePosition> getPattern(const std::string& pattern) const;
bool hasGlyphAtlasTexture() const;
const gfx::Texture2DPtr& getGlyphAtlasTexture() const;
bool hasIconAtlasTexture() const;
const gfx::Texture2DPtr& getIconAtlasTexture() const;
const std::shared_ptr<TileAtlasTextures>& getAtlasTextures() const;
bool getNeedsRendering() const { return needsRendering; };

View File

@@ -2,6 +2,7 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/gfx/backend_scope.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/layermanager/layer_manager.hpp>
#include <mbgl/renderer/renderer_impl.hpp>
@@ -32,7 +33,13 @@ void Renderer::setObserver(RendererObserver* observer) {
void Renderer::render(const std::shared_ptr<UpdateParameters>& updateParameters) {
MLN_TRACE_FUNC();
assert(updateParameters);
if (auto renderTree = impl->orchestrator.createRenderTree(updateParameters)) {
const bool styleChanged = impl->styleLoaded && !updateParameters->styleLoaded;
impl->styleLoaded = updateParameters->styleLoaded;
if (!impl->dynamicTextureAtlas || styleChanged) {
auto& context = impl->backend.getContext();
impl->dynamicTextureAtlas = std::make_unique<gfx::DynamicTextureAtlas>(context);
}
if (auto renderTree = impl->orchestrator.createRenderTree(updateParameters, impl->dynamicTextureAtlas)) {
renderTree->prepare();
impl->render(*renderTree, updateParameters);
}

View File

@@ -20,6 +20,8 @@ class RenderTree;
namespace gfx {
class RendererBackend;
class ShadeRegistry;
class DynamicTextureAtlas;
using DynamicTextureAtlasPtr = std::shared_ptr<gfx::DynamicTextureAtlas>;
} // namespace gfx
class Renderer::Impl : public gfx::ContextObserver {
@@ -50,6 +52,8 @@ private:
const float pixelRatio;
std::unique_ptr<RenderStaticData> staticData;
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
bool styleLoaded = false;
enum class RenderState {
Never,

View File

@@ -15,6 +15,11 @@ class AnnotationManager;
class ImageManager;
class GlyphManager;
namespace gfx {
class DynamicTextureAtlas;
using DynamicTextureAtlasPtr = std::shared_ptr<gfx::DynamicTextureAtlas>;
} // namespace gfx
class TileParameters {
public:
const float pixelRatio;
@@ -27,6 +32,7 @@ public:
std::shared_ptr<GlyphManager> glyphManager;
const uint8_t prefetchZoomDelta;
TaggedScheduler threadPool;
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
};
} // namespace mbgl

View File

@@ -9,16 +9,6 @@ TileRenderData::TileRenderData(std::shared_ptr<TileAtlasTextures> atlasTextures_
TileRenderData::~TileRenderData() = default;
static gfx::Texture2DPtr noTexture;
const gfx::Texture2DPtr& TileRenderData::getGlyphAtlasTexture() const {
return atlasTextures ? atlasTextures->glyph : noTexture;
}
const gfx::Texture2DPtr& TileRenderData::getIconAtlasTexture() const {
return atlasTextures ? atlasTextures->icon : noTexture;
}
std::optional<ImagePosition> TileRenderData::getPattern(const std::string&) const {
assert(false);
return std::nullopt;

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/gfx/texture.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <memory>
@@ -30,9 +30,6 @@ class TileRenderData {
public:
virtual ~TileRenderData();
const gfx::Texture2DPtr& getGlyphAtlasTexture() const;
const gfx::Texture2DPtr& getIconAtlasTexture() const;
const std::shared_ptr<TileAtlasTextures>& getAtlasTextures() const { return atlasTextures; }
// To be implemented for concrete tile types.
virtual std::optional<ImagePosition> getPattern(const std::string&) const;

View File

@@ -2,9 +2,11 @@
#include <mbgl/style/image.hpp>
#include <mbgl/util/containers.hpp>
#include <mbgl/util/rect.hpp>
#include <string>
#include <optional>
#include <array>
namespace mbgl {
namespace style {
@@ -61,4 +63,52 @@ inline bool operator<(const Immutable<mbgl::style::Image::Impl>& a, const Immuta
return a->id < b->id;
}
class ImagePosition {
public:
ImagePosition(const Rect<uint16_t>& rect, const style::Image::Impl& image, uint32_t version_ = 0)
: paddedRect(rect),
pixelRatio(image.pixelRatio),
stretchX(image.stretchX),
stretchY(image.stretchY),
content(image.content),
textFitWidth(image.textFitWidth),
textFitHeight(image.textFitHeight),
version(version_) {}
static constexpr const uint16_t padding = 1u;
Rect<uint16_t> paddedRect;
float pixelRatio;
style::ImageStretches stretchX;
style::ImageStretches stretchY;
std::optional<style::ImageContent> content;
std::optional<style::TextFit> textFitWidth;
std::optional<style::TextFit> textFitHeight;
uint32_t version;
std::array<uint16_t, 2> tl() const {
return {{static_cast<uint16_t>(paddedRect.x + padding), static_cast<uint16_t>(paddedRect.y + padding)}};
}
std::array<uint16_t, 2> br() const {
return {{static_cast<uint16_t>(paddedRect.x + paddedRect.w - padding),
static_cast<uint16_t>(paddedRect.y + paddedRect.h - padding)}};
}
std::array<uint16_t, 4> tlbr() const {
const auto _tl = tl();
const auto _br = br();
return {{_tl[0], _tl[1], _br[0], _br[1]}};
}
std::array<float, 2> displaySize() const {
return {{
static_cast<float>(paddedRect.w - padding * 2) / pixelRatio,
static_cast<float>(paddedRect.h - padding * 2) / pixelRatio,
}};
}
};
using ImagePositions = mbgl::unordered_map<std::string, ImagePosition>;
} // namespace mbgl

View File

@@ -1,48 +0,0 @@
#include <mbgl/text/glyph_atlas.hpp>
#include <mapbox/shelf-pack.hpp>
namespace mbgl {
static constexpr uint32_t padding = 1;
GlyphAtlas makeGlyphAtlas(const GlyphMap& glyphs) {
GlyphAtlas result;
mapbox::ShelfPack::ShelfPackOptions options;
options.autoResize = true;
mapbox::ShelfPack pack(0, 0, options);
for (const auto& glyphMapEntry : glyphs) {
FontStackHash fontStack = glyphMapEntry.first;
GlyphPositionMap& positions = result.positions[fontStack];
for (const auto& entry : glyphMapEntry.second) {
if (entry.second && (*entry.second)->bitmap.valid()) {
const Glyph& glyph = **entry.second;
const mapbox::Bin& bin = *pack.packOne(
-1, glyph.bitmap.size.width + 2 * padding, glyph.bitmap.size.height + 2 * padding);
result.image.resize({static_cast<uint32_t>(pack.width()), static_cast<uint32_t>(pack.height())});
AlphaImage::copy(
glyph.bitmap, result.image, {0, 0}, {bin.x + padding, bin.y + padding}, glyph.bitmap.size);
positions.emplace(glyph.id,
GlyphPosition{Rect<uint16_t>{static_cast<uint16_t>(bin.x),
static_cast<uint16_t>(bin.y),
static_cast<uint16_t>(bin.w),
static_cast<uint16_t>(bin.h)},
glyph.metrics});
}
}
}
pack.shrink();
result.image.resize({static_cast<uint32_t>(pack.width()), static_cast<uint32_t>(pack.height())});
return result;
}
} // namespace mbgl

View File

@@ -1,25 +0,0 @@
#pragma once
#include <mbgl/text/glyph.hpp>
#include <mapbox/shelf-pack.hpp>
namespace mbgl {
struct GlyphPosition {
Rect<uint16_t> rect;
GlyphMetrics metrics;
};
using GlyphPositionMap = std::map<GlyphID, GlyphPosition>;
using GlyphPositions = std::map<FontStackHash, GlyphPositionMap>;
class GlyphAtlas {
public:
AlphaImage image;
GlyphPositions positions;
};
GlyphAtlas makeGlyphAtlas(const GlyphMap&);
} // namespace mbgl

View File

@@ -3,7 +3,7 @@
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <vector>

View File

@@ -1,10 +1,9 @@
#pragma once
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/tagged_string.hpp>
#include <utility>

View File

@@ -6,7 +6,6 @@
#include <mbgl/renderer/layers/render_custom_layer.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/renderer/layers/render_background_layer.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/query.hpp>
@@ -15,15 +14,14 @@
#include <mbgl/renderer/tile_render_data.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/tile/geometry_tile_worker.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/util/instrumentation.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/thread_pool.hpp>
#include <mbgl/gfx/upload_pass.hpp>
#include <utility>
namespace mbgl {
@@ -44,6 +42,38 @@ LayerRenderData* GeometryTile::LayoutResult::getLayerRenderData(const style::Lay
return &result;
}
class ImagePatch {
public:
ImagePatch(Immutable<style::Image::Impl> image_, const Rect<uint16_t>& paddedRect_)
: image(std::move(image_)),
paddedRect(paddedRect_) {}
Immutable<style::Image::Impl> image;
Rect<uint16_t> paddedRect;
};
void populateImagePatches(ImagePositions& imagePositions,
const ImageManager& imageManager,
std::vector<ImagePatch>& /*out*/ patches) {
if (imagePositions.empty()) {
imagePositions.reserve(imageManager.updatedImageVersions.size());
}
for (auto& updatedImageVersion : imageManager.updatedImageVersions) {
const std::string& name = updatedImageVersion.first;
const uint32_t version = updatedImageVersion.second;
const auto it = imagePositions.find(updatedImageVersion.first);
if (it != imagePositions.end()) {
auto& position = it->second;
if (position.version == version) continue;
const auto updatedImage = imageManager.getSharedImage(name);
if (updatedImage == nullptr) continue;
patches.emplace_back(*updatedImage, position.paddedRect);
position.version = version;
}
}
}
class GeometryTileRenderData final : public TileRenderData {
public:
GeometryTileRenderData(std::shared_ptr<GeometryTile::LayoutResult> layoutResult_,
@@ -69,9 +99,9 @@ std::optional<ImagePosition> GeometryTileRenderData::getPattern(const std::strin
MLN_TRACE_FUNC();
if (layoutResult) {
const auto& iconAtlas = layoutResult->iconAtlas;
auto it = iconAtlas.patternPositions.find(pattern);
if (it != iconAtlas.patternPositions.end()) {
const auto& patternPositions = layoutResult->imageAtlas.patternPositions;
auto it = patternPositions.find(pattern);
if (it != patternPositions.end()) {
return it->second;
}
}
@@ -95,22 +125,16 @@ void GeometryTileRenderData::upload(gfx::UploadPass& uploadPass) {
assert(atlasTextures);
if (layoutResult->glyphAtlasImage && layoutResult->glyphAtlasImage->valid()) {
atlasTextures->glyph = uploadPass.getContext().createTexture2D();
atlasTextures->glyph->setSamplerConfiguration({.filter = gfx::TextureFilterType::Linear,
.wrapU = gfx::TextureWrapType::Clamp,
.wrapV = gfx::TextureWrapType::Clamp});
atlasTextures->glyph->upload(*layoutResult->glyphAtlasImage);
layoutResult->glyphAtlasImage = {};
if (const auto& glyphDynamicTexture = layoutResult->glyphAtlas.dynamicTexture) {
glyphDynamicTexture->uploadDeferredImages();
atlasTextures->glyph = glyphDynamicTexture->getTexture();
}
if (const auto& imageDynamicTexture = layoutResult->imageAtlas.dynamicTexture) {
imageDynamicTexture->uploadDeferredImages();
atlasTextures->icon = imageDynamicTexture->getTexture();
}
if (layoutResult->iconAtlas.image.valid()) {
atlasTextures->icon = uploadPass.getContext().createTexture2D();
atlasTextures->icon->upload(layoutResult->iconAtlas.image);
layoutResult->iconAtlas.image = {};
}
if (atlasTextures->icon && !imagePatches.empty()) {
if (!imagePatches.empty()) {
for (const auto& imagePatch : imagePatches) { // patch updated images.
atlasTextures->icon->uploadSubRegion(imagePatch.image->image,
imagePatch.paddedRect.x + ImagePosition::padding,
@@ -124,7 +148,9 @@ void GeometryTileRenderData::prepare(const SourcePrepareParameters& parameters)
MLN_TRACE_FUNC();
if (!layoutResult) return;
imagePatches = layoutResult->iconAtlas.getImagePatchesAndUpdateVersions(parameters.imageManager);
imagePatches.clear();
populateImagePatches(layoutResult->imageAtlas.iconPositions, parameters.imageManager, imagePatches);
populateImagePatches(layoutResult->imageAtlas.patternPositions, parameters.imageManager, imagePatches);
}
Bucket* GeometryTileRenderData::getBucket(const Layer::Impl& layer) const {
@@ -136,6 +162,13 @@ const LayerRenderData* GeometryTileRenderData::getLayerRenderData(const style::L
return layoutResult ? layoutResult->getLayerRenderData(layerImpl) : nullptr;
}
GeometryTile::LayoutResult::~LayoutResult() {
if (dynamicTextureAtlas) {
dynamicTextureAtlas->removeTextures(glyphAtlas.textureHandles, glyphAtlas.dynamicTexture);
dynamicTextureAtlas->removeTextures(imageAtlas.textureHandles, imageAtlas.dynamicTexture);
}
}
/*
Correlation between GeometryTile and GeometryTileWorker is safeguarded by two
correlation schemes:
@@ -168,7 +201,8 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_,
obsolete,
parameters.mode,
parameters.pixelRatio,
parameters.debugOptions & MapDebugOptions::Collision),
parameters.debugOptions & MapDebugOptions::Collision,
parameters.dynamicTextureAtlas),
fileSource(parameters.fileSource),
glyphManager(parameters.glyphManager),
imageManager(parameters.imageManager),
@@ -530,7 +564,7 @@ void GeometryTile::setFeatureState(const LayerFeatureStates& states) {
auto bucket = layer.second.bucket;
if (bucket && bucket->hasData()) {
bucket->update(featureStates, *sourceLayer, layerID, layoutResult->iconAtlas.patternPositions);
bucket->update(featureStates, *sourceLayer, layerID, layoutResult->imageAtlas.patternPositions);
}
}
}

View File

@@ -2,6 +2,7 @@
#include <mbgl/actor/actor.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <mbgl/gfx/texture.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
@@ -22,8 +23,6 @@ class GeometryTileData;
class RenderLayer;
class SourceQueryOptions;
class TileParameters;
class GlyphAtlas;
class ImageAtlas;
class TileAtlasTextures;
class GeometryTile : public Tile, public GlyphRequestor, public ImageRequestor {
@@ -73,19 +72,24 @@ public:
public:
mbgl::unordered_map<std::string, LayerRenderData> layerRenderData;
std::shared_ptr<FeatureIndex> featureIndex;
std::optional<AlphaImage> glyphAtlasImage;
ImageAtlas iconAtlas;
gfx::GlyphAtlas glyphAtlas;
gfx::ImageAtlas imageAtlas;
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
LayerRenderData* getLayerRenderData(const style::Layer::Impl&);
LayoutResult(mbgl::unordered_map<std::string, LayerRenderData> renderData_,
std::unique_ptr<FeatureIndex> featureIndex_,
std::optional<AlphaImage> glyphAtlasImage_,
ImageAtlas iconAtlas_)
gfx::GlyphAtlas glyphAtlas_,
gfx::ImageAtlas imageAtlas_,
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas_)
: layerRenderData(std::move(renderData_)),
featureIndex(std::move(featureIndex_)),
glyphAtlasImage(std::move(glyphAtlasImage_)),
iconAtlas(std::move(iconAtlas_)) {}
glyphAtlas(std::move(glyphAtlas_)),
imageAtlas(std::move(imageAtlas_)),
dynamicTextureAtlas(dynamicTextureAtlas_) {}
~LayoutResult();
};
void onLayout(std::shared_ptr<LayoutResult>, uint64_t correlationID);

View File

@@ -37,7 +37,8 @@ GeometryTileWorker::GeometryTileWorker(ActorRef<GeometryTileWorker> self_,
const std::atomic<bool>& obsolete_,
const MapMode mode_,
const float pixelRatio_,
const bool showCollisionBoxes_)
const bool showCollisionBoxes_,
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas_)
: self(std::move(self_)),
parent(std::move(parent_)),
scheduler(scheduler_),
@@ -46,7 +47,8 @@ GeometryTileWorker::GeometryTileWorker(ActorRef<GeometryTileWorker> self_,
obsolete(obsolete_),
mode(mode_),
pixelRatio(pixelRatio_),
showCollisionBoxes(showCollisionBoxes_) {}
showCollisionBoxes(showCollisionBoxes_),
dynamicTextureAtlas(dynamicTextureAtlas_) {}
GeometryTileWorker::~GeometryTileWorker() {
MLN_TRACE_FUNC();
@@ -332,7 +334,7 @@ void GeometryTileWorker::onImagesAvailable(ImageMap newIconMap,
if (imageCorrelationID != imageCorrelationID_) {
return; // Ignore outdated image request replies.
}
imageMap = std::move(newIconMap);
iconMap = std::move(newIconMap);
patternMap = std::move(newPatternMap);
versionMap = std::move(newVersionMap);
pendingImageDependencies.clear();
@@ -495,19 +497,25 @@ void GeometryTileWorker::finalizeLayout() {
return;
}
MBGL_TIMING_START(watch)
std::optional<AlphaImage> glyphAtlasImage;
ImageAtlas iconAtlas = makeImageAtlas(imageMap, patternMap, versionMap);
MBGL_TIMING_START(watch);
gfx::ImageAtlas imageAtlas;
gfx::GlyphAtlas glyphAtlas;
if (dynamicTextureAtlas) {
imageAtlas = dynamicTextureAtlas->uploadIconsAndPatterns(iconMap, patternMap, versionMap);
}
if (!layouts.empty()) {
GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap);
glyphAtlasImage = std::move(glyphAtlas.image);
if (dynamicTextureAtlas) {
glyphAtlas = dynamicTextureAtlas->uploadGlyphs(glyphMap);
}
for (auto& layout : layouts) {
if (obsolete) {
dynamicTextureAtlas->removeTextures(glyphAtlas.textureHandles, glyphAtlas.dynamicTexture);
dynamicTextureAtlas->removeTextures(imageAtlas.textureHandles, imageAtlas.dynamicTexture);
return;
}
layout->prepareSymbols(glyphMap, glyphAtlas.positions, imageMap, iconAtlas.iconPositions);
layout->prepareSymbols(glyphMap, glyphAtlas.glyphPositions, iconMap, imageAtlas.iconPositions);
if (!layout->hasSymbolInstances()) {
continue;
@@ -515,7 +523,7 @@ void GeometryTileWorker::finalizeLayout() {
// layout adds the bucket to buckets
layout->createBucket(
iconAtlas.patternPositions, featureIndex, renderData, firstLoad, showCollisionBoxes, id.canonical);
imageAtlas.patternPositions, featureIndex, renderData, firstLoad, showCollisionBoxes, id.canonical);
}
}
@@ -530,8 +538,11 @@ void GeometryTileWorker::finalizeLayout() {
<< id.canonical.y << " Time");
parent.invoke(&GeometryTile::onLayout,
std::make_shared<GeometryTile::LayoutResult>(
std::move(renderData), std::move(featureIndex), std::move(glyphAtlasImage), std::move(iconAtlas)),
std::make_shared<GeometryTile::LayoutResult>(std::move(renderData),
std::move(featureIndex),
std::move(glyphAtlas),
std::move(imageAtlas),
dynamicTextureAtlas),
correlationID);
}

View File

@@ -26,6 +26,11 @@ namespace style {
class Layer;
} // namespace style
namespace gfx {
class DynamicTextureAtlas;
using DynamicTextureAtlasPtr = std::shared_ptr<gfx::DynamicTextureAtlas>;
} // namespace gfx
class GeometryTileWorker {
public:
GeometryTileWorker(ActorRef<GeometryTileWorker> self,
@@ -36,7 +41,8 @@ public:
const std::atomic<bool>&,
MapMode,
float pixelRatio,
bool showCollisionBoxes_);
bool showCollisionBoxes_,
gfx::DynamicTextureAtlasPtr);
~GeometryTileWorker();
void setLayers(std::vector<Immutable<style::LayerProperties>>,
@@ -103,13 +109,15 @@ private:
GlyphDependencies pendingGlyphDependencies;
ImageDependencies pendingImageDependencies;
GlyphMap glyphMap;
ImageMap imageMap;
ImageMap iconMap;
ImageMap patternMap;
ImageVersionMap versionMap;
std::set<std::string> availableImages;
bool showCollisionBoxes;
bool firstLoad = true;
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
};
} // namespace mbgl

View File

@@ -5,6 +5,7 @@
#include <mbgl/test/fake_file_source.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <memory>
@@ -24,11 +25,10 @@ public:
const std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
const std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
TaggedScheduler threadPool;
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
TileParameters tileParameters;
style::Style style;
@@ -43,7 +43,8 @@ public:
imageManager,
glyphManager,
0,
threadPool},
threadPool,
dynamicTextureAtlas},
style{fileSource, 1, threadPool} {}
~VectorTileTest() {

View File

@@ -44,6 +44,7 @@
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/renderer/tile_render_data.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <cstdint>
#include <optional>
@@ -64,6 +65,7 @@ public:
AnnotationManager annotationManager{style};
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
TaggedScheduler threadPool;
Style style;
@@ -77,7 +79,8 @@ public:
imageManager,
glyphManager,
0,
threadPool};
threadPool,
dynamicTextureAtlas};
};
SourceTest()

View File

@@ -13,8 +13,7 @@ using namespace mbgl::style;
TEST(getIconQuads, normal) {
SymbolLayoutProperties::Evaluated layout;
Anchor anchor(2.0, 3.0, 0.0, 0);
ImagePosition image = {mapbox::Bin(-1, 15, 11, 0, 0, 0, 0),
style::Image::Impl("test", PremultipliedImage({1, 1}), 1.0f)};
ImagePosition image = {Rect<uint16_t>(0, 0, 15, 11), style::Image::Impl("test", PremultipliedImage({1, 1}), 1.0f)};
auto shapedIcon = PositionedIcon::shapeIcon(image, {{-6.5f, -4.5f}}, SymbolAnchorType::Center);
@@ -36,7 +35,7 @@ TEST(getIconQuads, normal) {
TEST(getIconQuads, style) {
Anchor anchor(0.0, 0.0, 0.0, 0);
const ImagePosition image = {mapbox::Bin(-1, 20, 20, 0, 0, 0, 0),
const ImagePosition image = {Rect<uint16_t>(0, 0, 20, 20),
style::Image::Impl("test", PremultipliedImage({1, 1}), 1.0f)};
GeometryCoordinates line;

View File

@@ -120,7 +120,7 @@ void setupShapedText(Shaping& shapedText, float textSize) {
shapedText.positionedLines.back().positionedGlyphs.emplace_back(glyph);
}
void testApplyTextFit(const mapbox::Bin& rectangle,
void testApplyTextFit(const Rect<uint16_t>& rectangle,
const style::ImageContent& content,
const std::optional<style::TextFit> textFitWidth,
const std::optional<style::TextFit> textFitHeight,
@@ -159,7 +159,7 @@ TEST(Shaping, applyTextFit) {
// applyTextFitHorizontal
// This set of tests against applyTextFit starts with a 100x20 image with a 5,5,95,15 content box
// that has been fitted to a 4*4 text with scale 4, resulting in a 16*16 image.
const auto horizontalRectangle = mapbox::Bin(-1, 100, 20, -1, -1, 0, 0);
const auto horizontalRectangle = Rect<uint16_t>(0, 0, 100, 20);
const style::ImageContent horizontalContent = {5, 5, 95, 15};
{
@@ -207,7 +207,7 @@ TEST(Shaping, applyTextFit) {
// applyTextFitVertical
// This set of tests against applyTextFit starts with a 20x100 image with a 5,5,15,95 content box
// that has been fitted to a 4*4 text with scale 4, resulting in a 16*16 image.
const auto verticalRectangle = mapbox::Bin(-1, 20, 100, -1, -1, 0, 0);
const auto verticalRectangle = Rect<uint16_t>(0, 0, 20, 100);
const style::ImageContent verticalContent = {5, 5, 15, 95};
{

View File

@@ -14,6 +14,7 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <memory>
@@ -29,6 +30,8 @@ public:
AnnotationManager annotationManager{style};
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
TileParameters tileParameters;
style::Style style;
@@ -42,7 +45,8 @@ public:
imageManager,
glyphManager,
0,
{Scheduler::GetBackground(), uniqueID}},
{Scheduler::GetBackground(), uniqueID},
dynamicTextureAtlas},
style{fileSource, 1, tileParameters.threadPool} {}
};

View File

@@ -14,6 +14,7 @@
#include <mbgl/style/style.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
#include <memory>
@@ -29,6 +30,8 @@ public:
AnnotationManager annotationManager{style};
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
TileParameters tileParameters;
style::Style style;
@@ -43,7 +46,8 @@ public:
imageManager,
glyphManager,
0,
{Scheduler::GetBackground(), uniqueID}},
{Scheduler::GetBackground(), uniqueID},
dynamicTextureAtlas},
style{fileSource, 1, tileParameters.threadPool} {}
};

View File

@@ -11,6 +11,7 @@
#include <mbgl/renderer/buckets/hillshade_bucket.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
using namespace mbgl;
@@ -23,6 +24,8 @@ public:
AnnotationManager annotationManager{style};
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
TileParameters tileParameters;
style::Style style;
@@ -37,7 +40,8 @@ public:
imageManager,
glyphManager,
0,
{Scheduler::GetBackground(), uniqueID}},
{Scheduler::GetBackground(), uniqueID},
dynamicTextureAtlas},
style{fileSource, 1, tileParameters.threadPool} {}
};

View File

@@ -11,6 +11,7 @@
#include <mbgl/renderer/buckets/raster_bucket.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/gfx/dynamic_texture_atlas.hpp>
using namespace mbgl;
@@ -23,6 +24,8 @@ public:
AnnotationManager annotationManager{style};
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
TileParameters tileParameters;
style::Style style;
@@ -37,7 +40,8 @@ public:
imageManager,
glyphManager,
0,
{Scheduler::GetBackground(), uniqueID}},
{Scheduler::GetBackground(), uniqueID},
dynamicTextureAtlas},
style{fileSource, 1, tileParameters.threadPool} {}
};