diff --git a/CMakeLists.txt b/CMakeLists.txt index 946db2819..b47c67564 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/bazel/core.bzl b/bazel/core.bzl index d5ffae905..80ea58fee 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -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", diff --git a/include/mbgl/gfx/dynamic_texture.hpp b/include/mbgl/gfx/dynamic_texture.hpp new file mode 100644 index 000000000..6b436a981 --- /dev/null +++ b/include/mbgl/gfx/dynamic_texture.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include + +#include + +#include +#include + +namespace mbgl { + +namespace gfx { + +class Context; +class Texture2D; +using Texture2DPtr = std::shared_ptr; + +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& 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 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 reserveSize(const Size& size, int32_t uniqueId); + void uploadImage(const uint8_t* pixelData, TextureHandle& texHandle); + + template + std::optional addImage(const Image& image, int32_t uniqueId = -1) { + return addImage(image.data ? image.data.get() : nullptr, image.size, uniqueId); + } + std::optional 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::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 diff --git a/include/mbgl/gfx/dynamic_texture_atlas.hpp b/include/mbgl/gfx/dynamic_texture_atlas.hpp new file mode 100644 index 000000000..78c241539 --- /dev/null +++ b/include/mbgl/gfx/dynamic_texture_atlas.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include + +namespace mbgl { + +namespace gfx { + +using DynamicTexturePtr = std::shared_ptr; + +class GlyphAtlas { +public: + GlyphPositions glyphPositions; + std::vector textureHandles; + DynamicTexturePtr dynamicTexture; +}; + +class ImageAtlas { +public: + ImagePositions iconPositions; + ImagePositions patternPositions; + std::vector 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& textureHandles, const DynamicTexturePtr& dynamicTexture); + +private: + Context& context; + std::vector dynamicTextures; + std::unordered_map dummyDynamicTexture; + std::mutex mutex; +}; + +} // namespace gfx +} // namespace mbgl diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index aa7ece65d..2200e9a9b 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -53,6 +53,10 @@ public: /// @param image_ Image data to transfer virtual Texture2D& setImage(std::shared_ptr 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; diff --git a/include/mbgl/gl/texture2d.hpp b/include/mbgl/gl/texture2d.hpp index 97984dba1..37071a8d7 100644 --- a/include/mbgl/gl/texture2d.hpp +++ b/include/mbgl/gl/texture2d.hpp @@ -26,6 +26,8 @@ public: // gfx::Texture2D Texture2D& setImage(std::shared_ptr image_) noexcept override; + gfx::TexturePixelType getFormat() const noexcept override { return pixelFormat; } + Size getSize() const noexcept override { return size; } size_t getDataSize() const noexcept override; diff --git a/include/mbgl/mtl/texture2d.hpp b/include/mbgl/mtl/texture2d.hpp index 41b7e7667..0d8706a89 100644 --- a/include/mbgl/mtl/texture2d.hpp +++ b/include/mbgl/mtl/texture2d.hpp @@ -29,6 +29,8 @@ public: gfx::Texture2D& setImage(std::shared_ptr) noexcept override; + gfx::TexturePixelType getFormat() const noexcept override { return pixelFormat; } + Size getSize() const noexcept override { return size; } size_t getDataSize() const noexcept override; diff --git a/include/mbgl/text/glyph.hpp b/include/mbgl/text/glyph.hpp index 10cee1fba..c967363b3 100644 --- a/include/mbgl/text/glyph.hpp +++ b/include/mbgl/text/glyph.hpp @@ -131,4 +131,12 @@ enum class WritingModeType : uint8_t { using GlyphDependencies = std::map; using GlyphRangeDependencies = std::map>; +struct GlyphPosition { + Rect rect; + GlyphMetrics metrics; +}; + +using GlyphPositionMap = std::map; +using GlyphPositions = std::map; + } // end namespace mbgl diff --git a/include/mbgl/vulkan/texture2d.hpp b/include/mbgl/vulkan/texture2d.hpp index a67b40112..92c7a516a 100644 --- a/include/mbgl/vulkan/texture2d.hpp +++ b/include/mbgl/vulkan/texture2d.hpp @@ -54,6 +54,7 @@ public: gfx::Texture2D& setImage(std::shared_ptr) 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; diff --git a/metrics/BUILD.bazel b/metrics/BUILD.bazel index f6d01f6e2..658d6c1cd 100644 --- a/metrics/BUILD.bazel +++ b/metrics/BUILD.bazel @@ -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 diff --git a/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png index 5b2fabc6c..30b92f032 100644 Binary files a/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png and b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png differ diff --git a/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expectedPixel4a.png b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expectedPixel4a.png new file mode 100644 index 000000000..565232220 Binary files /dev/null and b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expectedPixel4a.png differ diff --git a/metrics/expectations/platform-linux/render-tests/icon-text-fit/textFit-grid-long/expected.png b/metrics/expectations/platform-linux/render-tests/icon-text-fit/textFit-grid-long/expected.png new file mode 100644 index 000000000..d47f7f2e1 Binary files /dev/null and b/metrics/expectations/platform-linux/render-tests/icon-text-fit/textFit-grid-long/expected.png differ diff --git a/metrics/expectations/platform-linux/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png b/metrics/expectations/platform-linux/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png new file mode 100644 index 000000000..07cf78edc Binary files /dev/null and b/metrics/expectations/platform-linux/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png differ diff --git a/metrics/expectations/platform-windows/render-tests/icon-text-fit/textFit-grid-long/expected.png b/metrics/expectations/platform-windows/render-tests/icon-text-fit/textFit-grid-long/expected.png new file mode 100644 index 000000000..d47f7f2e1 Binary files /dev/null and b/metrics/expectations/platform-windows/render-tests/icon-text-fit/textFit-grid-long/expected.png differ diff --git a/metrics/expectations/platform-windows/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png b/metrics/expectations/platform-windows/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png new file mode 100644 index 000000000..07cf78edc Binary files /dev/null and b/metrics/expectations/platform-windows/render-tests/text-variable-anchor/left-top-right-bottom-offset-tile-map-mode/expected.png differ diff --git a/metrics/integration/render-tests/line-pattern/mixed/expectedPixel4a.png b/metrics/integration/render-tests/line-pattern/mixed/expectedPixel4a.png new file mode 100644 index 000000000..1dfba9e04 Binary files /dev/null and b/metrics/integration/render-tests/line-pattern/mixed/expectedPixel4a.png differ diff --git a/metrics/integration/render-tests/regressions/mapbox-gl-js#5546/expectedPixel4a.png b/metrics/integration/render-tests/regressions/mapbox-gl-js#5546/expectedPixel4a.png new file mode 100644 index 000000000..25beba7fe Binary files /dev/null and b/metrics/integration/render-tests/regressions/mapbox-gl-js#5546/expectedPixel4a.png differ diff --git a/metrics/integration/render-tests/regressions/mapbox-gl-js#5776/expectedPixel4a.png b/metrics/integration/render-tests/regressions/mapbox-gl-js#5776/expectedPixel4a.png new file mode 100644 index 000000000..f56b07600 Binary files /dev/null and b/metrics/integration/render-tests/regressions/mapbox-gl-js#5776/expectedPixel4a.png differ diff --git a/metrics/integration/render-tests/text-arabic/multi-paragraph/expectedPixel4a.png b/metrics/integration/render-tests/text-arabic/multi-paragraph/expectedPixel4a.png new file mode 100644 index 000000000..7c9889502 Binary files /dev/null and b/metrics/integration/render-tests/text-arabic/multi-paragraph/expectedPixel4a.png differ diff --git a/metrics/integration/render-tests/text-font/chinese/expectedPixel4a.png b/metrics/integration/render-tests/text-font/chinese/expectedPixel4a.png new file mode 100644 index 000000000..358f76a8c Binary files /dev/null and b/metrics/integration/render-tests/text-font/chinese/expectedPixel4a.png differ diff --git a/metrics/integration/render-tests/text-max-width/ideographic-punctuation-breaking/expectedPixel4a.png b/metrics/integration/render-tests/text-max-width/ideographic-punctuation-breaking/expectedPixel4a.png new file mode 100644 index 000000000..109b4028e Binary files /dev/null and b/metrics/integration/render-tests/text-max-width/ideographic-punctuation-breaking/expectedPixel4a.png differ diff --git a/metrics/linux-drawable.json b/metrics/linux-drawable.json index 2eb85a802..c6d9222b7 100644 --- a/metrics/linux-drawable.json +++ b/metrics/linux-drawable.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", diff --git a/metrics/linux-vulkan.json b/metrics/linux-vulkan.json index fe72271f5..402e843f9 100644 --- a/metrics/linux-vulkan.json +++ b/metrics/linux-vulkan.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", diff --git a/metrics/windows-egl.json b/metrics/windows-egl.json index a759272ca..98f1409ef 100644 --- a/metrics/windows-egl.json +++ b/metrics/windows-egl.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", diff --git a/metrics/windows-opengl.json b/metrics/windows-opengl.json index bf693f931..e4c2d6176 100644 --- a/metrics/windows-opengl.json +++ b/metrics/windows-opengl.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", diff --git a/metrics/windows-vulkan.json b/metrics/windows-vulkan.json index bbcbe79ed..789484204 100644 --- a/metrics/windows-vulkan.json +++ b/metrics/windows-vulkan.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", diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index ba5fadb06..ea6c41685 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -202,6 +202,7 @@ int runRenderTests(int argc, char** argv, std::function 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 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 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 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 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()); diff --git a/src/mbgl/gfx/drawable_atlases_tweaker.cpp b/src/mbgl/gfx/drawable_atlases_tweaker.cpp index 96c9b7385..adf0c0fa3 100644 --- a/src/mbgl/gfx/drawable_atlases_tweaker.cpp +++ b/src/mbgl/gfx/drawable_atlases_tweaker.cpp @@ -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, diff --git a/src/mbgl/gfx/dynamic_texture.cpp b/src/mbgl/gfx/dynamic_texture.cpp new file mode 100644 index 000000000..f3bf5fa1e --- /dev/null +++ b/src/mbgl/gfx/dynamic_texture.cpp @@ -0,0 +1,104 @@ +#include +#include +#include + +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 DynamicTexture::reserveSize(const Size& size, int32_t uniqueId) { + std::lock_guard 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 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(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 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 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 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 diff --git a/src/mbgl/gfx/dynamic_texture_atlas.cpp b/src/mbgl/gfx/dynamic_texture_atlas.cpp new file mode 100644 index 000000000..645d6ad97 --- /dev/null +++ b/src/mbgl/gfx/dynamic_texture_atlas.cpp @@ -0,0 +1,256 @@ +#include +#include + +#include + +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 rectWithoutExtraPadding(const Rect& rect) { + return Rect( + rect.x + extraPadding, rect.y + extraPadding, rect.w - 2 * extraPadding, rect.h - 2 * extraPadding); +} + +GlyphAtlas DynamicTextureAtlas::uploadGlyphs(const GlyphMap& glyphs) { + using GlyphsToUpload = std::vector, FontStackHash>>; + std::lock_guard lock(mutex); + + GlyphAtlas glyphAtlas; + if (!glyphs.size()) { + glyphAtlas.dynamicTexture = dummyDynamicTexture[TexturePixelType::Alpha]; + if (!glyphAtlas.dynamicTexture) { + glyphAtlas.dynamicTexture = std::make_shared( + 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( + 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(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::lock_guard lock(mutex); + + ImageAtlas imageAtlas; + if (!icons.size() && !patterns.size()) { + imageAtlas.dynamicTexture = dummyDynamicTexture[TexturePixelType::RGBA]; + if (!imageAtlas.dynamicTexture) { + imageAtlas.dynamicTexture = std::make_shared( + 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( + 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(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(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& textureHandles, + const DynamicTexturePtr& dynamicTexture) { + std::lock_guard 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 diff --git a/src/mbgl/layout/layout.hpp b/src/mbgl/layout/layout.hpp index b826881b9..d0914e69b 100644 --- a/src/mbgl/layout/layout.hpp +++ b/src/mbgl/layout/layout.hpp @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include #include #include #include diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 1520ebff9..c03d23dc4 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 21a3d2d21..4b265a482 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mbgl/programs/background_program.cpp b/src/mbgl/programs/background_program.cpp index cb1d71df7..46fb13db3 100644 --- a/src/mbgl/programs/background_program.cpp +++ b/src/mbgl/programs/background_program.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/mbgl/programs/fill_extrusion_program.cpp b/src/mbgl/programs/fill_extrusion_program.cpp index e2b2ee849..0fc4b85b6 100644 --- a/src/mbgl/programs/fill_extrusion_program.cpp +++ b/src/mbgl/programs/fill_extrusion_program.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp index a6578e12a..eb687acbe 100644 --- a/src/mbgl/programs/fill_program.cpp +++ b/src/mbgl/programs/fill_program.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp index 17c746786..a14c4528a 100644 --- a/src/mbgl/programs/line_program.cpp +++ b/src/mbgl/programs/line_program.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 7826231bb..940ef2093 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index c64c7aa6a..adc616931 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp deleted file mode 100644 index e4586ce90..000000000 --- a/src/mbgl/renderer/image_atlas.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include - -#include - -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(pack.width()), static_cast(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& /*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 ImageAtlas::getImagePatchesAndUpdateVersions(const ImageManager& imageManager) { - std::vector 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(pack.width()), static_cast(pack.height())}); - - return result; -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/image_atlas.hpp b/src/mbgl/renderer/image_atlas.hpp deleted file mode 100644 index 055c81908..000000000 --- a/src/mbgl/renderer/image_atlas.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include -#include - -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 paddedRect; - uint32_t version; - style::ImageStretches stretchX; - style::ImageStretches stretchY; - std::optional content; - std::optional textFitWidth; - std::optional textFitHeight; - - std::array tl() const { - return {{static_cast(paddedRect.x + padding), static_cast(paddedRect.y + padding)}}; - } - - std::array br() const { - return {{static_cast(paddedRect.x + paddedRect.w - padding), - static_cast(paddedRect.y + paddedRect.h - padding)}}; - } - - std::array tlbr() const { - const auto _tl = tl(); - const auto _br = br(); - return {{_tl[0], _tl[1], _br[0], _br[1]}}; - } - - std::array displaySize() const { - return {{ - static_cast(paddedRect.w - padding * 2) / pixelRatio, - static_cast(paddedRect.h - padding * 2) / pixelRatio, - }}; - } -}; - -using ImagePositions = mbgl::unordered_map; - -class ImagePatch { -public: - ImagePatch(Immutable image_, const Rect& paddedRect_) - : image(std::move(image_)), - paddedRect(paddedRect_) {} - - Immutable image; - Rect paddedRect; -}; - -class ImageAtlas { -public: - PremultipliedImage image; - ImagePositions iconPositions; - ImagePositions patternPositions; - - std::vector getImagePatchesAndUpdateVersions(const ImageManager&); -}; - -ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&, const ImageVersionMap& versionMap); - -} // namespace mbgl diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.cpp b/src/mbgl/renderer/layers/line_layer_tweaker.cpp index 8b1fa69c6..dd9e0a0fb 100644 --- a/src/mbgl/renderer/layers/line_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/line_layer_tweaker.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 740961fd5..9346e1323 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -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()) { diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 250694f77..c7bd608c9 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index ab2bb50c5..55b1f5ed1 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mbgl/renderer/pattern_atlas.cpp b/src/mbgl/renderer/pattern_atlas.cpp index 5f10ff98a..8693db7f7 100644 --- a/src/mbgl/renderer/pattern_atlas.cpp +++ b/src/mbgl/renderer/pattern_atlas.cpp @@ -65,7 +65,9 @@ std::optional 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(bin->x, bin->y, bin->w, bin->h), image}}) + .first->second.position; } void PatternAtlas::removePattern(const std::string& id) { diff --git a/src/mbgl/renderer/pattern_atlas.hpp b/src/mbgl/renderer/pattern_atlas.hpp index 311be87d1..240c07f32 100644 --- a/src/mbgl/renderer/pattern_atlas.hpp +++ b/src/mbgl/renderer/pattern_atlas.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 2e6190877..339ad33c8 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -153,7 +153,7 @@ void RenderOrchestrator::setObserver(RendererObserver* observer_) { } std::unique_ptr RenderOrchestrator::createRenderTree( - const std::shared_ptr& updateParameters) { + const std::shared_ptr& updateParameters, gfx::DynamicTextureAtlasPtr dynamicTextureAtlas) { MLN_TRACE_FUNC(); const auto startTime = util::MonotonicTimer::now().count(); @@ -194,7 +194,8 @@ std::unique_ptr RenderOrchestrator::createRenderTree( .imageManager = imageManager, .glyphManager = glyphManager, .prefetchZoomDelta = updateParameters->prefetchZoomDelta, - .threadPool = threadPool}; + .threadPool = threadPool, + .dynamicTextureAtlas = dynamicTextureAtlas}; glyphManager->setURL(updateParameters->glyphURL); diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index 9e7738305..05b67f3e6 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -41,6 +41,8 @@ namespace gfx { class ShaderRegistry; class Drawable; using DrawablePtr = std::shared_ptr; +class DynamicTextureAtlas; +using DynamicTextureAtlasPtr = std::shared_ptr; } // namespace gfx namespace style { @@ -64,7 +66,7 @@ public: // TODO: Introduce RenderOrchestratorObserver. void setObserver(RendererObserver*); - std::unique_ptr createRenderTree(const std::shared_ptr&); + std::unique_ptr createRenderTree(const std::shared_ptr&, gfx::DynamicTextureAtlasPtr); std::vector queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const; std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index dc26fef75..2797431be 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -96,24 +96,6 @@ std::optional 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 noAtlas; const std::shared_ptr& RenderTile::getAtlasTextures() const { return renderData ? renderData->getAtlasTextures() : noAtlas; diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 53d88ea4f..778eba384 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -60,12 +60,6 @@ public: const LayerRenderData* getLayerRenderData(const style::Layer::Impl&) const; std::optional 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& getAtlasTextures() const; bool getNeedsRendering() const { return needsRendering; }; diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp index 611144d2a..ba3b0bc57 100644 --- a/src/mbgl/renderer/renderer.cpp +++ b/src/mbgl/renderer/renderer.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,13 @@ void Renderer::setObserver(RendererObserver* observer) { void Renderer::render(const std::shared_ptr& 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(context); + } + if (auto renderTree = impl->orchestrator.createRenderTree(updateParameters, impl->dynamicTextureAtlas)) { renderTree->prepare(); impl->render(*renderTree, updateParameters); } diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp index c34de65c3..b1137d267 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -20,6 +20,8 @@ class RenderTree; namespace gfx { class RendererBackend; class ShadeRegistry; +class DynamicTextureAtlas; +using DynamicTextureAtlasPtr = std::shared_ptr; } // namespace gfx class Renderer::Impl : public gfx::ContextObserver { @@ -50,6 +52,8 @@ private: const float pixelRatio; std::unique_ptr staticData; + gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; + bool styleLoaded = false; enum class RenderState { Never, diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp index 75c1c152f..0596fcce8 100644 --- a/src/mbgl/renderer/tile_parameters.hpp +++ b/src/mbgl/renderer/tile_parameters.hpp @@ -15,6 +15,11 @@ class AnnotationManager; class ImageManager; class GlyphManager; +namespace gfx { +class DynamicTextureAtlas; +using DynamicTextureAtlasPtr = std::shared_ptr; +} // namespace gfx + class TileParameters { public: const float pixelRatio; @@ -27,6 +32,7 @@ public: std::shared_ptr glyphManager; const uint8_t prefetchZoomDelta; TaggedScheduler threadPool; + gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; }; } // namespace mbgl diff --git a/src/mbgl/renderer/tile_render_data.cpp b/src/mbgl/renderer/tile_render_data.cpp index 0f28afd66..49ba69736 100644 --- a/src/mbgl/renderer/tile_render_data.cpp +++ b/src/mbgl/renderer/tile_render_data.cpp @@ -9,16 +9,6 @@ TileRenderData::TileRenderData(std::shared_ptr 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 TileRenderData::getPattern(const std::string&) const { assert(false); return std::nullopt; diff --git a/src/mbgl/renderer/tile_render_data.hpp b/src/mbgl/renderer/tile_render_data.hpp index 0f19d7823..cd5cae4ec 100644 --- a/src/mbgl/renderer/tile_render_data.hpp +++ b/src/mbgl/renderer/tile_render_data.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -30,9 +30,6 @@ class TileRenderData { public: virtual ~TileRenderData(); - const gfx::Texture2DPtr& getGlyphAtlasTexture() const; - const gfx::Texture2DPtr& getIconAtlasTexture() const; - const std::shared_ptr& getAtlasTextures() const { return atlasTextures; } // To be implemented for concrete tile types. virtual std::optional getPattern(const std::string&) const; diff --git a/src/mbgl/style/image_impl.hpp b/src/mbgl/style/image_impl.hpp index 2865972c9..a1fa558f4 100644 --- a/src/mbgl/style/image_impl.hpp +++ b/src/mbgl/style/image_impl.hpp @@ -2,9 +2,11 @@ #include #include +#include #include #include +#include namespace mbgl { namespace style { @@ -61,4 +63,52 @@ inline bool operator<(const Immutable& a, const Immuta return a->id < b->id; } +class ImagePosition { +public: + ImagePosition(const Rect& 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 paddedRect; + float pixelRatio; + style::ImageStretches stretchX; + style::ImageStretches stretchY; + std::optional content; + std::optional textFitWidth; + std::optional textFitHeight; + uint32_t version; + + std::array tl() const { + return {{static_cast(paddedRect.x + padding), static_cast(paddedRect.y + padding)}}; + } + + std::array br() const { + return {{static_cast(paddedRect.x + paddedRect.w - padding), + static_cast(paddedRect.y + paddedRect.h - padding)}}; + } + + std::array tlbr() const { + const auto _tl = tl(); + const auto _br = br(); + return {{_tl[0], _tl[1], _br[0], _br[1]}}; + } + + std::array displaySize() const { + return {{ + static_cast(paddedRect.w - padding * 2) / pixelRatio, + static_cast(paddedRect.h - padding * 2) / pixelRatio, + }}; + } +}; + +using ImagePositions = mbgl::unordered_map; + } // namespace mbgl diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp deleted file mode 100644 index d2a048d65..000000000 --- a/src/mbgl/text/glyph_atlas.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include - -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(pack.width()), static_cast(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{static_cast(bin.x), - static_cast(bin.y), - static_cast(bin.w), - static_cast(bin.h)}, - glyph.metrics}); - } - } - } - - pack.shrink(); - result.image.resize({static_cast(pack.width()), static_cast(pack.height())}); - - return result; -} - -} // namespace mbgl diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp deleted file mode 100644 index 9dd063ef6..000000000 --- a/src/mbgl/text/glyph_atlas.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { - -struct GlyphPosition { - Rect rect; - GlyphMetrics metrics; -}; - -using GlyphPositionMap = std::map; -using GlyphPositions = std::map; - -class GlyphAtlas { -public: - AlphaImage image; - GlyphPositions positions; -}; - -GlyphAtlas makeGlyphAtlas(const GlyphMap&); - -} // namespace mbgl diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index 74c5d346c..4f90d54c4 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 83a33c894..4fae4dc2a 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -1,10 +1,9 @@ #pragma once -#include +#include #include #include #include -#include #include #include diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index e898ae169..535b958ab 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -15,15 +14,14 @@ #include #include #include -#include #include #include #include #include #include #include - #include + #include namespace mbgl { @@ -44,6 +42,38 @@ LayerRenderData* GeometryTile::LayoutResult::getLayerRenderData(const style::Lay return &result; } +class ImagePatch { +public: + ImagePatch(Immutable image_, const Rect& paddedRect_) + : image(std::move(image_)), + paddedRect(paddedRect_) {} + Immutable image; + Rect paddedRect; +}; + +void populateImagePatches(ImagePositions& imagePositions, + const ImageManager& imageManager, + std::vector& /*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 layoutResult_, @@ -69,9 +99,9 @@ std::optional 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); } } } diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 549854d46..138ecc27b 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -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 layerRenderData; std::shared_ptr featureIndex; - std::optional glyphAtlasImage; - ImageAtlas iconAtlas; + gfx::GlyphAtlas glyphAtlas; + gfx::ImageAtlas imageAtlas; + gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; LayerRenderData* getLayerRenderData(const style::Layer::Impl&); LayoutResult(mbgl::unordered_map renderData_, std::unique_ptr featureIndex_, - std::optional 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, uint64_t correlationID); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 24a81c4ca..4935bc5f3 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -37,7 +37,8 @@ GeometryTileWorker::GeometryTileWorker(ActorRef self_, const std::atomic& 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 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 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( - std::move(renderData), std::move(featureIndex), std::move(glyphAtlasImage), std::move(iconAtlas)), + std::make_shared(std::move(renderData), + std::move(featureIndex), + std::move(glyphAtlas), + std::move(imageAtlas), + dynamicTextureAtlas), correlationID); } diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index ccd546520..eea005dfd 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -26,6 +26,11 @@ namespace style { class Layer; } // namespace style +namespace gfx { +class DynamicTextureAtlas; +using DynamicTextureAtlasPtr = std::shared_ptr; +} // namespace gfx + class GeometryTileWorker { public: GeometryTileWorker(ActorRef self, @@ -36,7 +41,8 @@ public: const std::atomic&, MapMode, float pixelRatio, - bool showCollisionBoxes_); + bool showCollisionBoxes_, + gfx::DynamicTextureAtlasPtr); ~GeometryTileWorker(); void setLayers(std::vector>, @@ -103,13 +109,15 @@ private: GlyphDependencies pendingGlyphDependencies; ImageDependencies pendingImageDependencies; GlyphMap glyphMap; - ImageMap imageMap; + ImageMap iconMap; ImageMap patternMap; ImageVersionMap versionMap; std::set availableImages; bool showCollisionBoxes; bool firstLoad = true; + + gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; }; } // namespace mbgl diff --git a/test/include/mbgl/test/vector_tile_test.hpp b/test/include/mbgl/test/vector_tile_test.hpp index f17a626db..3e2b41d73 100644 --- a/test/include/mbgl/test/vector_tile_test.hpp +++ b/test/include/mbgl/test/vector_tile_test.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -24,11 +25,10 @@ public: const std::shared_ptr imageManager = std::make_shared(); const std::shared_ptr glyphManager = std::make_shared(); - - 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() { diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp index 7e1b61832..8aad9033e 100644 --- a/test/style/source.test.cpp +++ b/test/style/source.test.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ public: AnnotationManager annotationManager{style}; std::shared_ptr imageManager = std::make_shared(); std::shared_ptr glyphManager = std::make_shared(); + gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; TaggedScheduler threadPool; Style style; @@ -77,7 +79,8 @@ public: imageManager, glyphManager, 0, - threadPool}; + threadPool, + dynamicTextureAtlas}; }; SourceTest() diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp index 3a2b9ba19..af88238b0 100644 --- a/test/text/quads.test.cpp +++ b/test/text/quads.test.cpp @@ -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(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(0, 0, 20, 20), style::Image::Impl("test", PremultipliedImage({1, 1}), 1.0f)}; GeometryCoordinates line; diff --git a/test/text/shaping.test.cpp b/test/text/shaping.test.cpp index bd502611f..0535cef50 100644 --- a/test/text/shaping.test.cpp +++ b/test/text/shaping.test.cpp @@ -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& rectangle, const style::ImageContent& content, const std::optional textFitWidth, const std::optional 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(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(0, 0, 20, 100); const style::ImageContent verticalContent = {5, 5, 15, 95}; { diff --git a/test/tile/custom_geometry_tile.test.cpp b/test/tile/custom_geometry_tile.test.cpp index 57fae1b8b..c630ae271 100644 --- a/test/tile/custom_geometry_tile.test.cpp +++ b/test/tile/custom_geometry_tile.test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -29,6 +30,8 @@ public: AnnotationManager annotationManager{style}; std::shared_ptr imageManager = std::make_shared(); std::shared_ptr glyphManager = std::make_shared(); + 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} {} }; diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp index 4889192fe..f1fb4dbf7 100644 --- a/test/tile/geojson_tile.test.cpp +++ b/test/tile/geojson_tile.test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -29,6 +30,8 @@ public: AnnotationManager annotationManager{style}; std::shared_ptr imageManager = std::make_shared(); std::shared_ptr glyphManager = std::make_shared(); + 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} {} }; diff --git a/test/tile/raster_dem_tile.test.cpp b/test/tile/raster_dem_tile.test.cpp index 23d67190b..ea7eeec94 100644 --- a/test/tile/raster_dem_tile.test.cpp +++ b/test/tile/raster_dem_tile.test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include using namespace mbgl; @@ -23,6 +24,8 @@ public: AnnotationManager annotationManager{style}; std::shared_ptr imageManager = std::make_shared(); std::shared_ptr glyphManager = std::make_shared(); + 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} {} }; diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp index 5f0922266..a305c3bd2 100644 --- a/test/tile/raster_tile.test.cpp +++ b/test/tile/raster_tile.test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include using namespace mbgl; @@ -23,6 +24,8 @@ public: AnnotationManager annotationManager{style}; std::shared_ptr imageManager = std::make_shared(); std::shared_ptr glyphManager = std::make_shared(); + 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} {} };