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>
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
81
include/mbgl/gfx/dynamic_texture.hpp
Normal 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
|
||||
49
include/mbgl/gfx/dynamic_texture_atlas.hpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -2,6 +2,7 @@
|
||||
"base_test_path": "integration",
|
||||
"cache_path": "cache-style.db",
|
||||
"expectation_paths": [
|
||||
"expectations/platform-linux"
|
||||
],
|
||||
"ignore_paths": [
|
||||
"ignores/platform-all.json",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"base_test_path": "integration",
|
||||
"cache_path": "cache-style.db",
|
||||
"expectation_paths": [
|
||||
"expectations/platform-linux"
|
||||
],
|
||||
"ignore_paths": [
|
||||
"ignores/platform-all.json",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"base_test_path": "integration",
|
||||
"cache_path": "cache-style.db",
|
||||
"expectation_paths": [
|
||||
"expectations/platform-windows"
|
||||
],
|
||||
"ignore_paths": [
|
||||
"ignores/platform-all.json",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"base_test_path": "integration",
|
||||
"cache_path": "cache-style.db",
|
||||
"expectation_paths": [
|
||||
"expectations/platform-windows"
|
||||
],
|
||||
"ignore_paths": [
|
||||
"ignores/platform-all.json",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"base_test_path": "integration",
|
||||
"cache_path": "cache-style.db",
|
||||
"expectation_paths": [
|
||||
"expectations/platform-windows"
|
||||
],
|
||||
"ignore_paths": [
|
||||
"ignores/platform-all.json",
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
|
||||
104
src/mbgl/gfx/dynamic_texture.cpp
Normal 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
|
||||
256
src/mbgl/gfx/dynamic_texture_atlas.cpp
Normal 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
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
{
|
||||
|
||||
@@ -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} {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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} {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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} {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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} {}
|
||||
};
|
||||
|
||||
|
||||