From 642903fdb43934d925c3266aa63db84d43413f0f Mon Sep 17 00:00:00 2001 From: mwilsnd <53413200+mwilsnd@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:33:01 -0500 Subject: [PATCH] Merge branch 'topic/drawable-fixes' into topic/drawable (#1560) Co-authored-by: Stefan Karschti Co-authored-by: Alex Cristici Co-authored-by: Tim Sylvester Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CMakeLists.txt | 6 + bazel/core.bzl | 6 + include/mbgl/gfx/drawable.hpp | 9 +- include/mbgl/gfx/drawable_atlases_tweaker.hpp | 24 +- include/mbgl/gfx/drawable_builder.hpp | 5 + include/mbgl/gfx/texture2d.hpp | 5 - include/mbgl/gfx/vertex_attribute.hpp | 10 - include/mbgl/gl/texture2d.hpp | 5 - include/mbgl/shaders/gl/collision_circle.hpp | 4 +- .../shaders/gl/drawable_collision_box.hpp | 72 +++++ .../shaders/gl/drawable_collision_circle.hpp | 93 +++++++ include/mbgl/shaders/gl/drawable_debug.hpp | 51 ++++ include/mbgl/shaders/shader_manifest.hpp | 3 + include/mbgl/shaders/shader_source.hpp | 4 +- platform/BUILD.bazel | 17 ++ .../android/MapboxGLAndroidSDK/build.gradle | 8 - platform/ios/BUILD.bazel | 55 +++- platform/ios/benchmark/BUILD.bazel | 36 +++ platform/ios/benchmark/MBXBenchAppDelegate.m | 2 +- platform/ios/scripts/bazel-generate-plists.sh | 4 + platform/ios/scripts/bazel-xcodeproj.sh | 2 +- render-test/ios/tests/Tests.m | 4 +- shaders/collision_circle.fragment.glsl | 2 +- shaders/collision_circle.vertex.glsl | 2 +- shaders/drawable.collision_box.fragment.glsl | 27 ++ shaders/drawable.collision_box.vertex.glsl | 30 +++ .../drawable.collision_circle.fragment.glsl | 39 +++ shaders/drawable.collision_circle.vertex.glsl | 38 +++ shaders/drawable.debug.fragment.glsl | 17 ++ shaders/drawable.debug.vertex.glsl | 18 ++ shaders/manifest.json | 21 ++ src/mbgl/geometry/line_atlas.cpp | 11 +- src/mbgl/geometry/line_atlas.hpp | 3 +- src/mbgl/gfx/collision_drawable_data.hpp | 24 ++ src/mbgl/gfx/drawable_atlases_tweaker.cpp | 21 +- src/mbgl/gfx/drawable_builder.cpp | 1 + src/mbgl/gfx/index_vector.hpp | 56 +++- src/mbgl/gfx/upload_pass.hpp | 22 -- src/mbgl/gfx/vertex_vector.hpp | 1 + src/mbgl/gl/drawable_gl.cpp | 47 ++-- src/mbgl/gl/drawable_gl_impl.hpp | 1 - src/mbgl/gl/renderer_backend.cpp | 3 + src/mbgl/gl/texture2d.cpp | 6 +- src/mbgl/gl/upload_pass.cpp | 2 + src/mbgl/layout/symbol_layout.cpp | 18 +- src/mbgl/renderer/buckets/symbol_bucket.cpp | 12 +- src/mbgl/renderer/buckets/symbol_bucket.hpp | 28 +- .../layers/background_layer_tweaker.cpp | 14 +- .../renderer/layers/circle_layer_tweaker.cpp | 5 +- .../layers/collision_layer_tweaker.cpp | 94 +++++++ .../layers/collision_layer_tweaker.hpp | 26 ++ .../layers/fill_extrusion_layer_tweaker.cpp | 4 +- .../layers/render_fill_extrusion_layer.cpp | 6 +- .../renderer/layers/render_fill_layer.cpp | 10 +- .../renderer/layers/render_heatmap_layer.cpp | 8 +- .../layers/render_hillshade_layer.cpp | 6 +- .../renderer/layers/render_line_layer.cpp | 45 ++-- .../renderer/layers/render_line_layer.hpp | 2 + .../renderer/layers/render_raster_layer.cpp | 207 ++++---------- .../renderer/layers/render_raster_layer.hpp | 9 +- .../renderer/layers/render_symbol_layer.cpp | 253 +++++++++++++++++- .../renderer/layers/render_symbol_layer.hpp | 13 + .../renderer/layers/symbol_layer_tweaker.cpp | 10 +- src/mbgl/renderer/paint_parameters.cpp | 2 +- src/mbgl/renderer/pattern_atlas.cpp | 8 +- src/mbgl/renderer/pattern_atlas.hpp | 3 +- src/mbgl/renderer/render_orchestrator.cpp | 86 ++++-- src/mbgl/renderer/render_orchestrator.hpp | 13 +- src/mbgl/renderer/render_tile.cpp | 10 - src/mbgl/renderer/render_tile.hpp | 4 +- src/mbgl/renderer/render_tree.hpp | 14 + src/mbgl/renderer/renderer_impl.cpp | 103 ++++--- .../renderer/sources/render_image_source.hpp | 3 + .../renderer/sources/render_tile_source.cpp | 247 +++++++++++++++-- .../renderer/sources/render_tile_source.hpp | 25 ++ src/mbgl/text/placement.cpp | 20 +- 76 files changed, 1680 insertions(+), 445 deletions(-) create mode 100644 include/mbgl/shaders/gl/drawable_collision_box.hpp create mode 100644 include/mbgl/shaders/gl/drawable_collision_circle.hpp create mode 100644 include/mbgl/shaders/gl/drawable_debug.hpp create mode 100644 platform/ios/benchmark/BUILD.bazel mode change 100644 => 100755 platform/ios/scripts/bazel-generate-plists.sh mode change 100644 => 100755 platform/ios/scripts/bazel-xcodeproj.sh create mode 100644 shaders/drawable.collision_box.fragment.glsl create mode 100644 shaders/drawable.collision_box.vertex.glsl create mode 100644 shaders/drawable.collision_circle.fragment.glsl create mode 100644 shaders/drawable.collision_circle.vertex.glsl create mode 100644 shaders/drawable.debug.fragment.glsl create mode 100644 shaders/drawable.debug.vertex.glsl create mode 100644 src/mbgl/gfx/collision_drawable_data.hpp create mode 100644 src/mbgl/renderer/layers/collision_layer_tweaker.cpp create mode 100644 src/mbgl/renderer/layers/collision_layer_tweaker.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 63bea2250..49d46e99a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/line_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/symbol_drawable_data.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/collision_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_block.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_buffer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/vertex_attribute.cpp @@ -209,6 +210,8 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/collision_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/collision_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/shader_program_base.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program_mtl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/identity.cpp @@ -1003,6 +1006,9 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_circle.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_collision_box.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_collision_circle.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_debug.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index 9d61ef5ad..71c3f3687 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -62,6 +62,9 @@ MLN_GENERATED_SHADER_HEADERS = [ "include/mbgl/shaders/gl/drawable_background.hpp", "include/mbgl/shaders/gl/drawable_background_pattern.hpp", "include/mbgl/shaders/gl/drawable_circle.hpp", + "include/mbgl/shaders/gl/drawable_collision_box.hpp", + "include/mbgl/shaders/gl/drawable_collision_circle.hpp", + "include/mbgl/shaders/gl/drawable_debug.hpp", "include/mbgl/shaders/gl/drawable_fill.hpp", "include/mbgl/shaders/gl/drawable_fill_outline.hpp", "include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp", @@ -896,6 +899,7 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/gfx/image_drawable_data.hpp", "src/mbgl/gfx/line_drawable_data.hpp", "src/mbgl/gfx/symbol_drawable_data.hpp", + "src/mbgl/gfx/collision_drawable_data.hpp", "src/mbgl/gfx/uniform_block.cpp", "src/mbgl/gfx/uniform_buffer.cpp", "src/mbgl/gfx/vertex_attribute.cpp", @@ -926,6 +930,8 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/renderer/layers/raster_layer_tweaker.hpp", "src/mbgl/renderer/layers/symbol_layer_tweaker.cpp", "src/mbgl/renderer/layers/symbol_layer_tweaker.hpp", + "src/mbgl/renderer/layers/collision_layer_tweaker.cpp", + "src/mbgl/renderer/layers/collision_layer_tweaker.hpp", "src/mbgl/shaders/shader_program_base.cpp", "src/mbgl/shaders/mtl/shader_program_mtl.cpp", "src/mbgl/shaders/gl/shader_program_gl.cpp", diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 94607c859..1656ad594 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,6 @@ class VertexAttributeArray; using DrawPriority = int64_t; using DrawableTweakerPtr = std::shared_ptr; -using IndexVectorBasePtr = std::shared_ptr; using ShaderProgramBasePtr = std::shared_ptr; using Texture2DPtr = std::shared_ptr; @@ -136,7 +136,11 @@ public: DrawPriority getDrawPriority() const { return drawPriority; } void setDrawPriority(DrawPriority value) { drawPriority = value; } - /// Get sub-layer index. Determines depth range within the layer for 2D drawables + /// Whether to enable depth testing + bool getEnableDepth() { return enableDepth; } + void setEnableDepth(bool value) { enableDepth = value; } + + /// Determines depth range within the layer for 2D drawables int32_t getSubLayerIndex() const { return subLayerIndex; } /// Set sub-layer index @@ -227,6 +231,7 @@ protected: bool enabled = true; bool enableColor = true; bool enableStencil = false; + bool enableDepth = true; bool is3D = false; bool isCustom = false; std::string name; diff --git a/include/mbgl/gfx/drawable_atlases_tweaker.hpp b/include/mbgl/gfx/drawable_atlases_tweaker.hpp index c9e6a86c6..1f9f991aa 100644 --- a/include/mbgl/gfx/drawable_atlases_tweaker.hpp +++ b/include/mbgl/gfx/drawable_atlases_tweaker.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include @@ -19,11 +21,22 @@ class Drawable; */ class DrawableAtlasesTweaker : public gfx::DrawableTweaker { public: - DrawableAtlasesTweaker(TileAtlasTexturesPtr atlases_, std::string iconName_, std::string glyphName_, bool isText_) + DrawableAtlasesTweaker(TileAtlasTexturesPtr atlases_, + std::string iconName_, + std::string glyphName_, + bool isText_, + const bool sdfIcons_, + const style::AlignmentType rotationAlignment_, + const bool iconScaled_, + const bool textSizeIsZoomConstant_) : atlases(std::move(atlases_)), iconName(std::move(iconName_)), glyphName(std::move(glyphName_)), - isText(isText_) {} + isText(isText_), + sdfIcons(sdfIcons_), + rotationAlignment(rotationAlignment_), + iconScaled(iconScaled_), + textSizeIsZoomConstant(textSizeIsZoomConstant_) {} ~DrawableAtlasesTweaker() override = default; void init(Drawable&) override; @@ -31,12 +44,17 @@ public: void execute(Drawable&, const PaintParameters&) override; protected: - void setupTextures(Drawable&); + void setupTextures(Drawable&, const bool); TileAtlasTexturesPtr atlases; std::string iconName; std::string glyphName; bool isText; + + const bool sdfIcons; + const style::AlignmentType rotationAlignment; + const bool iconScaled; + const bool textSizeIsZoomConstant; }; } // namespace gfx diff --git a/include/mbgl/gfx/drawable_builder.hpp b/include/mbgl/gfx/drawable_builder.hpp index 7803c6596..51111a649 100644 --- a/include/mbgl/gfx/drawable_builder.hpp +++ b/include/mbgl/gfx/drawable_builder.hpp @@ -75,6 +75,10 @@ public: int32_t getSubLayerIndex() const { return subLayerIndex; } void setSubLayerIndex(int32_t value) { subLayerIndex = value; } + /// Whether to enable depth testing + bool getEnableDepth() { return enableDepth; } + void setEnableDepth(bool value) { enableDepth = value; } + /// Depth writability for 2D drawables DepthMaskType getDepthType() const { return depthType; } @@ -204,6 +208,7 @@ protected: bool enabled = true; bool enableColor = true; bool enableStencil = false; + bool enableDepth = true; bool is3D = false; float lineWidth = 1.0f; DrawPriority drawPriority = 0; diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index 4787e1410..341217910 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -113,11 +113,6 @@ public: /// @see needsUpload virtual void upload() noexcept = 0; - /// @brief Get the underlying GL texture resource - /// @note: Compat with legacy textures, to be refactored - /// @return gfx::TextureResource - virtual gfx::TextureResource& getResource() const = 0; - /// @brief Check whether the texture needs upload /// @return bool virtual bool needsUpload() const noexcept = 0; diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index e2e828618..1b0bd33fc 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -225,16 +225,6 @@ public: /// @brief Clears the shared data void resetSharedRawData() { sharedRawData.reset(); } - /// Convert from the odd partially-normalized color component array produced by `Color::toArray` into normalized - /// RGBA. - static float4 colorAttrRGBA(const Color& color) { - const auto components = color.toArray(); - return {static_cast(components[0] / 255.0), - static_cast(components[1] / 255.0), - static_cast(components[2] / 255.0), - static_cast(components[3])}; - } - protected: VertexAttribute& operator=(const VertexAttribute&) = default; VertexAttribute& operator=(VertexAttribute&& other) { diff --git a/include/mbgl/gl/texture2d.hpp b/include/mbgl/gl/texture2d.hpp index 18b30959c..01e02035c 100644 --- a/include/mbgl/gl/texture2d.hpp +++ b/include/mbgl/gl/texture2d.hpp @@ -40,11 +40,6 @@ public: // gfx::Texture2D void uploadSubRegion(const void* pixelData, const Size& size, uint16_t xOffset, uint16_t yOffset) noexcept override; void upload() noexcept override; - gfx::TextureResource& getResource() const override { - assert(textureResource); - return *textureResource; - } - bool needsUpload() const noexcept override { return !!image; }; public: diff --git a/include/mbgl/shaders/gl/collision_circle.hpp b/include/mbgl/shaders/gl/collision_circle.hpp index 15ea527ba..05a5217d9 100644 --- a/include/mbgl/shaders/gl/collision_circle.hpp +++ b/include/mbgl/shaders/gl/collision_circle.hpp @@ -20,7 +20,7 @@ uniform float u_camera_to_center_distance; out float v_placed; out float v_notUsed; out float v_radius; -out vec2 v_extrude; +out highp vec2 v_extrude; out vec2 v_extrude_scale; void main() { @@ -49,7 +49,7 @@ void main() { in float v_placed; in float v_notUsed; in float v_radius; -in vec2 v_extrude; +in highp vec2 v_extrude; in vec2 v_extrude_scale; void main() { diff --git a/include/mbgl/shaders/gl/drawable_collision_box.hpp b/include/mbgl/shaders/gl/drawable_collision_box.hpp new file mode 100644 index 000000000..83cbe7d62 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_collision_box.hpp @@ -0,0 +1,72 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "CollisionBoxShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos; +layout (location = 1) in vec2 a_anchor_pos; +layout (location = 2) in vec2 a_extrude; +layout (location = 3) in vec2 a_placed; +layout (location = 4) in vec2 a_shift; + +layout (std140) uniform CollisionBoxUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float pad1; +}; + +out float v_placed; +out float v_notUsed; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + gl_Position.xy += (a_extrude + a_shift) * u_extrude_scale * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform CollisionBoxUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float pad1; +}; + +in float v_placed; +in float v_notUsed; + +void main() { + + float alpha = 0.5; + + // Red = collision, hide label + fragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + fragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + fragColor *= .1; + } +})"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_collision_circle.hpp b/include/mbgl/shaders/gl/drawable_collision_circle.hpp new file mode 100644 index 000000000..d743ce43a --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_collision_circle.hpp @@ -0,0 +1,93 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "CollisionCircleShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos; +layout (location = 1) in vec2 a_anchor_pos; +layout (location = 2) in vec2 a_extrude; +layout (location = 3) in vec2 a_placed; + +layout (std140) uniform CollisionCircleUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float u_overscale_factor; +}; + +out float v_placed; +out float v_notUsed; +out float v_radius; +out highp vec2 v_extrude; +out vec2 v_extrude_scale; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + + highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur + gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; + v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius + + v_extrude = a_extrude * padding_factor; + v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio; +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform CollisionCircleUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float u_overscale_factor; +}; + +in float v_placed; +in float v_notUsed; +in float v_radius; +in highp vec2 v_extrude; +in vec2 v_extrude_scale; + +void main() { + float alpha = 0.5; + + // Red = collision, hide label + vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + color = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + color *= .2; + } + + float extrude_scale_length = length(v_extrude_scale); + float extrude_length = length(v_extrude) * extrude_scale_length; + float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor; + float radius = v_radius * extrude_scale_length; + + float distance_to_edge = abs(extrude_length - radius); + float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge); + + fragColor = opacity_t * color; +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_debug.hpp b/include/mbgl/shaders/gl/drawable_debug.hpp new file mode 100644 index 000000000..da5b0f042 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_debug.hpp @@ -0,0 +1,51 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "DebugShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos; +out vec2 v_uv; + +layout (std140) uniform DebugUBO { + highp mat4 u_matrix; + highp vec4 u_color; + highp float u_overlay_scale; + highp float pad1; + highp float pad2; + highp float pad3; +}; + +void main() { + // This vertex shader expects a EXTENT x EXTENT quad, + // The UV co-ordinates for the overlay texture can be calculated using that knowledge + v_uv = a_pos / 8192.0; + gl_Position = u_matrix * vec4(a_pos * u_overlay_scale, 0, 1); +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform DebugUBO { + highp mat4 u_matrix; + highp vec4 u_color; + highp float u_overlay_scale; + highp float pad1; + highp float pad2; + highp float pad3; +}; + +uniform sampler2D u_overlay; + +in vec2 v_uv; + +void main() { + vec4 overlay_color = texture(u_overlay, v_uv); + fragColor = mix(u_color, overlay_color, overlay_color.a); +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index fccdb72c2..26baa99fb 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index d09c188ae..4b4092246 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -12,6 +12,9 @@ enum class BuiltIn { BackgroundShader, BackgroundPatternShader, CircleShader, + CollisionBoxShader, + CollisionCircleShader, + DebugShader, FillShader, FillOutlineShader, LineGradientShader, @@ -31,7 +34,6 @@ enum class BuiltIn { SymbolSDFTextShader, SymbolSDFIconShader, SymbolTextAndIconShader, - Prelude, BackgroundProgram, BackgroundPatternProgram, diff --git a/platform/BUILD.bazel b/platform/BUILD.bazel index d1c837070..fe42bd3cd 100644 --- a/platform/BUILD.bazel +++ b/platform/BUILD.bazel @@ -176,6 +176,23 @@ objc_library( ], ) +objc_library( + name = "ios-benchapp", + copts = MAPLIBRE_FLAGS, + srcs = ["//platform/ios/benchmark:ios_benchmark_srcs"], + hdrs = ["//platform/ios/benchmark:ios_benchmark_hdrs"], + includes = [ + "darwin/app", + "darwin/src", + "ios/src", + ], + visibility = ["//platform/ios:__pkg__"], + deps = [ + ":objc-headers", + "//:mbgl-core", + ], +) + sh_binary( name = "check-public-symbols", srcs = ["//platform/darwin:scripts/check-public-symbols.sh"], diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 959dbc6aa..07dcb2bf6 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -84,14 +84,6 @@ android { } } } - create("split") { - dimension = "renderer" - externalNativeBuild { - cmake { - arguments "-DMLN_LEGACY_RENDERER=ON", "-DMLN_DRAWABLE_RENDERER=ON", "-DMLN_RENDERER_SPLIT_VIEW=ON" - } - } - } } // build native libraries diff --git a/platform/ios/BUILD.bazel b/platform/ios/BUILD.bazel index 4179969a8..66b0425de 100644 --- a/platform/ios/BUILD.bazel +++ b/platform/ios/BUILD.bazel @@ -431,6 +431,24 @@ ios_application( ], ) +ios_application( + name = "BenchmarkApp", + bundle_id = "{}.benchmark.app".format(BUNDLE_ID_PREFIX), + families = [ + "iphone", + "ipad", + ], + infoplists = ["build/Info-benchmark.plist"], + minimum_os_version = "12.0", + provisioning_profile = "xcode_profile", + resources = ["//platform/ios/benchmark:bundle_resources"], + visibility = ["//visibility:public"], + deps = [ + "//platform:ios-benchapp", + "//platform:ios-sdk", + ], +) + # Outputs a file with the size of MapLibre as a dynamic library in bytes genrule( name = "size", @@ -462,8 +480,39 @@ xcodeproj( }, top_level_targets = [ top_level_target( - ":App", - target_environments = ["device", "simulator"], + "App", + target_environments = [ + "simulator", + "device", + ], + ), + top_level_target( + "BenchmarkApp", + target_environments = [ + "simulator", + "device", + ], + ), + top_level_target( + "//render-test/ios:RenderTest", + target_environments = [ + "simulator", + "device", + ], + ), + top_level_target( + "//platform/ios/iosapp-UITests:uitest", + target_environments = [ + "simulator", + "device", + ], + ), + top_level_target( + "//platform/ios/test:ios_test", + target_environments = [ + "simulator", + "device", + ], ), ], xcode_configurations = { @@ -480,9 +529,9 @@ sh_binary( "Integration_Tests/Info.plist", "app/Info.plist", "bench_UITests/Info.plist", - "benchmark/Info.plist", "framework/Info.plist", "framework/Info-static.plist", + "//platform/ios/benchmark:Info.plist", "//platform/ios/iosapp-UITests:Info.plist", "//platform/ios/test:Info.plist", ], diff --git a/platform/ios/benchmark/BUILD.bazel b/platform/ios/benchmark/BUILD.bazel new file mode 100644 index 000000000..f6cb42192 --- /dev/null +++ b/platform/ios/benchmark/BUILD.bazel @@ -0,0 +1,36 @@ +filegroup( + name = "ios_benchmark_srcs", + srcs = [ + "main.m", + "MBXBenchAppDelegate.m", + "MBXBenchViewController.mm", + "locations.cpp", + ], + visibility = ["//platform:__pkg__"], +) + +filegroup( + name = "ios_benchmark_hdrs", + srcs = [ + "MBXBenchAppDelegate.h", + "MBXBenchViewController.h", + "locations.hpp", + ], + visibility = ["//platform:__pkg__"], +) + +filegroup( + name = "bundle_resources", + srcs = glob([ + "benchmark/*.lproj/**", + "benchmark/Assets.xcassets/**", + "benchmark/assets/**/*.pbf", + "benchmark/assets/**/*.json", + "benchmark/assets/**/*.png", + ]), + visibility = ["//platform/ios:__pkg__"], +) + +exports_files([ + "Info.plist", +]) \ No newline at end of file diff --git a/platform/ios/benchmark/MBXBenchAppDelegate.m b/platform/ios/benchmark/MBXBenchAppDelegate.m index 6aa801037..99f9c8c6d 100644 --- a/platform/ios/benchmark/MBXBenchAppDelegate.m +++ b/platform/ios/benchmark/MBXBenchAppDelegate.m @@ -1,4 +1,4 @@ -@import Mapbox; +#import "Mapbox.h" #import "MBXBenchAppDelegate.h" #import "MBXBenchViewController.h" diff --git a/platform/ios/scripts/bazel-generate-plists.sh b/platform/ios/scripts/bazel-generate-plists.sh old mode 100644 new mode 100755 index b25aef515..dd6740055 --- a/platform/ios/scripts/bazel-generate-plists.sh +++ b/platform/ios/scripts/bazel-generate-plists.sh @@ -48,6 +48,8 @@ temp_info_static_plist="platform/ios/build/Info-static.plist" temp_info_plist="platform/ios/build/Info.plist" # Move and configure the app plist temp_app_info_plist="platform/ios/build/Info-app.plist" +# Move and configure the BenchmarkApp plist +temp_benchmark_info_plist="platform/ios/build/Info-benchmark.plist" if [ ! -d platform/ios/build ]; then mkdir platform/ios/build @@ -56,6 +58,7 @@ fi cp platform/ios/framework/Info-static.plist "$temp_info_static_plist" cp platform/ios/framework/Info.plist "$temp_info_plist" cp platform/ios/app/Info.plist "$temp_app_info_plist" +cp platform/ios/benchmark/Info.plist "$temp_benchmark_info_plist" # Replace semver and hash plutil -replace MLNSemanticVersionString -string "$sem_version" "$temp_info_static_plist" @@ -67,6 +70,7 @@ plutil -replace MLNCommitHash -string "$hash" "$temp_info_plist" echo "Inserting MapLibre API key..." if [ "$token" ]; then plutil -replace MLNApiKey -string $token "$temp_app_info_plist" + plutil -replace MLNApiKey -string $token "$temp_benchmark_info_plist" echo "API key insertion successful" else echo "Warning: Missing API key." diff --git a/platform/ios/scripts/bazel-xcodeproj.sh b/platform/ios/scripts/bazel-xcodeproj.sh old mode 100644 new mode 100755 index e03a02566..bba214a85 --- a/platform/ios/scripts/bazel-xcodeproj.sh +++ b/platform/ios/scripts/bazel-xcodeproj.sh @@ -35,7 +35,7 @@ while [[ $# -gt 0 ]]; do ;; --apikey) shift - token="$1" + args+=("--token" "$1") shift ;; -*|--*) diff --git a/render-test/ios/tests/Tests.m b/render-test/ios/tests/Tests.m index 0b7f3c99d..9192ed4cd 100644 --- a/render-test/ios/tests/Tests.m +++ b/render-test/ios/tests/Tests.m @@ -25,7 +25,7 @@ NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL fileFound = [fileManager fileExistsAtPath: styleResult]; - XCTAssert(fileFound, @"Test result html '%@' doese not exit", styleResult); + XCTAssert(fileFound, @"Test result html '%@' does not exit", styleResult); NSURL *styleURL = [NSURL fileURLWithPath:styleResult]; XCTAttachment *attachment1URL = [XCTAttachment attachmentWithContentsOfFileAtURL: styleURL]; XCTAssert(attachment1URL, @"Failed to attach test result '%@'", styleResult); @@ -33,7 +33,7 @@ [self addAttachment:attachment1URL]; fileFound = [fileManager fileExistsAtPath: metricResult]; - XCTAssert(fileFound, @"Test result html '%@' doese not exit", metricResult); + XCTAssert(fileFound, @"Test result html '%@' does not exit", metricResult); NSURL *metricURL = [NSURL fileURLWithPath:metricResult]; XCTAttachment *attachment2URL = [XCTAttachment attachmentWithContentsOfFileAtURL: metricURL]; XCTAssert(attachment2URL, @"Failed to attach test result '%@'", metricResult); diff --git a/shaders/collision_circle.fragment.glsl b/shaders/collision_circle.fragment.glsl index 9b5db3f75..9623672ae 100644 --- a/shaders/collision_circle.fragment.glsl +++ b/shaders/collision_circle.fragment.glsl @@ -3,7 +3,7 @@ uniform float u_overscale_factor; in float v_placed; in float v_notUsed; in float v_radius; -in vec2 v_extrude; +in highp vec2 v_extrude; in vec2 v_extrude_scale; void main() { diff --git a/shaders/collision_circle.vertex.glsl b/shaders/collision_circle.vertex.glsl index 08950dae2..2d61e47c9 100644 --- a/shaders/collision_circle.vertex.glsl +++ b/shaders/collision_circle.vertex.glsl @@ -10,7 +10,7 @@ uniform float u_camera_to_center_distance; out float v_placed; out float v_notUsed; out float v_radius; -out vec2 v_extrude; +out highp vec2 v_extrude; out vec2 v_extrude_scale; void main() { diff --git a/shaders/drawable.collision_box.fragment.glsl b/shaders/drawable.collision_box.fragment.glsl new file mode 100644 index 000000000..6aad81ec5 --- /dev/null +++ b/shaders/drawable.collision_box.fragment.glsl @@ -0,0 +1,27 @@ +layout (std140) uniform CollisionBoxUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float pad1; +}; + +in float v_placed; +in float v_notUsed; + +void main() { + + float alpha = 0.5; + + // Red = collision, hide label + fragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + fragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + fragColor *= .1; + } +} \ No newline at end of file diff --git a/shaders/drawable.collision_box.vertex.glsl b/shaders/drawable.collision_box.vertex.glsl new file mode 100644 index 000000000..8c2b28ee3 --- /dev/null +++ b/shaders/drawable.collision_box.vertex.glsl @@ -0,0 +1,30 @@ +layout (location = 0) in vec2 a_pos; +layout (location = 1) in vec2 a_anchor_pos; +layout (location = 2) in vec2 a_extrude; +layout (location = 3) in vec2 a_placed; +layout (location = 4) in vec2 a_shift; + +layout (std140) uniform CollisionBoxUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float pad1; +}; + +out float v_placed; +out float v_notUsed; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + gl_Position.xy += (a_extrude + a_shift) * u_extrude_scale * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; +} diff --git a/shaders/drawable.collision_circle.fragment.glsl b/shaders/drawable.collision_circle.fragment.glsl new file mode 100644 index 000000000..370020015 --- /dev/null +++ b/shaders/drawable.collision_circle.fragment.glsl @@ -0,0 +1,39 @@ +layout (std140) uniform CollisionCircleUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float u_overscale_factor; +}; + +in float v_placed; +in float v_notUsed; +in float v_radius; +in highp vec2 v_extrude; +in vec2 v_extrude_scale; + +void main() { + float alpha = 0.5; + + // Red = collision, hide label + vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + color = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + color *= .2; + } + + float extrude_scale_length = length(v_extrude_scale); + float extrude_length = length(v_extrude) * extrude_scale_length; + float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor; + float radius = v_radius * extrude_scale_length; + + float distance_to_edge = abs(extrude_length - radius); + float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge); + + fragColor = opacity_t * color; +} diff --git a/shaders/drawable.collision_circle.vertex.glsl b/shaders/drawable.collision_circle.vertex.glsl new file mode 100644 index 000000000..1e19b93b5 --- /dev/null +++ b/shaders/drawable.collision_circle.vertex.glsl @@ -0,0 +1,38 @@ +layout (location = 0) in vec2 a_pos; +layout (location = 1) in vec2 a_anchor_pos; +layout (location = 2) in vec2 a_extrude; +layout (location = 3) in vec2 a_placed; + +layout (std140) uniform CollisionCircleUBO { + highp mat4 u_matrix; + highp vec2 u_extrude_scale; + highp float u_camera_to_center_distance; + highp float u_overscale_factor; +}; + +out float v_placed; +out float v_notUsed; +out float v_radius; +out highp vec2 v_extrude; +out vec2 v_extrude_scale; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + + highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur + gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; + v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius + + v_extrude = a_extrude * padding_factor; + v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio; +} diff --git a/shaders/drawable.debug.fragment.glsl b/shaders/drawable.debug.fragment.glsl new file mode 100644 index 000000000..4b197f541 --- /dev/null +++ b/shaders/drawable.debug.fragment.glsl @@ -0,0 +1,17 @@ +layout (std140) uniform DebugUBO { + highp mat4 u_matrix; + highp vec4 u_color; + highp float u_overlay_scale; + highp float pad1; + highp float pad2; + highp float pad3; +}; + +uniform sampler2D u_overlay; + +in vec2 v_uv; + +void main() { + vec4 overlay_color = texture(u_overlay, v_uv); + fragColor = mix(u_color, overlay_color, overlay_color.a); +} diff --git a/shaders/drawable.debug.vertex.glsl b/shaders/drawable.debug.vertex.glsl new file mode 100644 index 000000000..20b10f2db --- /dev/null +++ b/shaders/drawable.debug.vertex.glsl @@ -0,0 +1,18 @@ +layout (location = 0) in vec2 a_pos; +out vec2 v_uv; + +layout (std140) uniform DebugUBO { + highp mat4 u_matrix; + highp vec4 u_color; + highp float u_overlay_scale; + highp float pad1; + highp float pad2; + highp float pad3; +}; + +void main() { + // This vertex shader expects a EXTENT x EXTENT quad, + // The UV co-ordinates for the overlay texture can be calculated using that knowledge + v_uv = a_pos / 8192.0; + gl_Position = u_matrix * vec4(a_pos * u_overlay_scale, 0, 1); +} diff --git a/shaders/manifest.json b/shaders/manifest.json index 8e27a9b7e..d94879173 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -20,6 +20,27 @@ "glsl_frag": "drawable.circle.fragment.glsl", "uses_ubos": true }, + { + "name": "CollisionBoxShader", + "header": "drawable_collision_box", + "glsl_vert": "drawable.collision_box.vertex.glsl", + "glsl_frag": "drawable.collision_box.fragment.glsl", + "uses_ubos": true + }, + { + "name": "CollisionCircleShader", + "header": "drawable_collision_circle", + "glsl_vert": "drawable.collision_circle.vertex.glsl", + "glsl_frag": "drawable.collision_circle.fragment.glsl", + "uses_ubos": true + }, + { + "name": "DebugShader", + "header": "drawable_debug", + "glsl_vert": "drawable.debug.vertex.glsl", + "glsl_frag": "drawable.debug.fragment.glsl", + "uses_ubos": true + }, { "name": "FillShader", "header": "drawable_fill", diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index e92e5e7ca..a953be815 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -222,24 +222,17 @@ void DashPatternTexture::upload(gfx::UploadPass& uploadPass) { #endif } +#if MLN_LEGACY_RENDERER gfx::TextureBinding DashPatternTexture::textureBinding() const { // The texture needs to have been uploaded already. -#if MLN_DRAWABLE_RENDERER - assert(std::holds_alternative(texture)); - return {std::get(texture)->getResource(), - gfx::TextureFilterType::Linear, - gfx::TextureMipMapType::No, - gfx::TextureWrapType::Repeat, - gfx::TextureWrapType::Clamp}; -#else assert(texture.is()); return {texture.get().getResource(), gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No, gfx::TextureWrapType::Repeat, gfx::TextureWrapType::Clamp}; -#endif } +#endif #if MLN_DRAWABLE_RENDERER static const gfx::Texture2DPtr noTexture; diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index 7472a52b1..d39c802ec 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -51,9 +51,10 @@ public: void upload(gfx::UploadPass&); // Binds the atlas texture to the GPU, and uploads data if it is out of date. - gfx::TextureBinding textureBinding() const; #if MLN_DRAWABLE_RENDERER const std::shared_ptr& getTexture() const; +#else + gfx::TextureBinding textureBinding() const; #endif // Returns the size of the texture image. diff --git a/src/mbgl/gfx/collision_drawable_data.hpp b/src/mbgl/gfx/collision_drawable_data.hpp new file mode 100644 index 000000000..aeed40da1 --- /dev/null +++ b/src/mbgl/gfx/collision_drawable_data.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace gfx { + +struct CollisionDrawableData : public DrawableData { + CollisionDrawableData(const std::array translate_, const style::TranslateAnchorType translateAnchor_) + : translate(translate_), + translateAnchor(translateAnchor_) {} + ~CollisionDrawableData() override = default; + + std::array translate; + style::TranslateAnchorType translateAnchor; +}; + +using UniqueCollisionDrawableData = std::unique_ptr; + +} // namespace gfx +} // namespace mbgl diff --git a/src/mbgl/gfx/drawable_atlases_tweaker.cpp b/src/mbgl/gfx/drawable_atlases_tweaker.cpp index b3acb1fc5..ae300e039 100644 --- a/src/mbgl/gfx/drawable_atlases_tweaker.cpp +++ b/src/mbgl/gfx/drawable_atlases_tweaker.cpp @@ -3,13 +3,22 @@ #include #include #include +#include namespace mbgl { namespace gfx { -void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable) { +void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable, const bool linearFilterForIcons) { if (const auto& shader = drawable.getShader()) { if (const auto samplerLocation = shader->getSamplerLocation(glyphName)) { + if (atlases) { + atlases->glyph->setSamplerConfiguration( + {TextureFilterType::Linear, TextureWrapType::Clamp, TextureWrapType::Clamp}); + atlases->icon->setSamplerConfiguration( + {linearFilterForIcons ? TextureFilterType::Linear : TextureFilterType::Nearest, + TextureWrapType::Clamp, + TextureWrapType::Clamp}); + } if (const auto iconSamplerLocation = shader->getSamplerLocation(iconName)) { assert(*samplerLocation != *iconSamplerLocation); drawable.setTexture(atlases ? atlases->glyph : nullptr, *samplerLocation); @@ -22,11 +31,15 @@ void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable) { } void DrawableAtlasesTweaker::init(gfx::Drawable& drawable) { - setupTextures(drawable); + setupTextures(drawable, true); } -void DrawableAtlasesTweaker::execute(gfx::Drawable& drawable, const PaintParameters&) { - setupTextures(drawable); +void DrawableAtlasesTweaker::execute(gfx::Drawable& drawable, const PaintParameters& parameters) { + const bool transformed = rotationAlignment == style::AlignmentType::Map || parameters.state.getPitch() != 0; + const bool linearFilterForIcons = isText ? (parameters.state.isChanging() || transformed || !textSizeIsZoomConstant) + : (sdfIcons || parameters.state.isChanging() || iconScaled || transformed); + + setupTextures(drawable, linearFilterForIcons); } } // namespace gfx diff --git a/src/mbgl/gfx/drawable_builder.cpp b/src/mbgl/gfx/drawable_builder.cpp index d59ae2bb2..e462145ac 100644 --- a/src/mbgl/gfx/drawable_builder.cpp +++ b/src/mbgl/gfx/drawable_builder.cpp @@ -52,6 +52,7 @@ void DrawableBuilder::flush() { draw->setRenderPass(renderPass); draw->setDrawPriority(drawPriority); draw->setSubLayerIndex(subLayerIndex); + draw->setEnableDepth(enableDepth); draw->setDepthType(depthType); draw->setIs3D(is3D); draw->setColorMode(impl->colorMode); diff --git a/src/mbgl/gfx/index_vector.hpp b/src/mbgl/gfx/index_vector.hpp index 9d6cdbdc4..5062c75ff 100644 --- a/src/mbgl/gfx/index_vector.hpp +++ b/src/mbgl/gfx/index_vector.hpp @@ -4,10 +4,15 @@ #include #include +#include namespace mbgl { namespace gfx { +struct IndexBufferBase { + virtual ~IndexBufferBase() = default; +}; + class IndexVectorBase { protected: std::vector v; @@ -18,6 +23,35 @@ public: IndexVectorBase() = default; IndexVectorBase(std::vector&& indexes) : v(std::move(indexes)) {} + IndexVectorBase(const IndexVectorBase&) {} // buffer is not copied + IndexVectorBase(IndexVectorBase&& other) + : buffer(std::move(other.buffer)), + dirty(other.dirty), + released(other.released) {} + virtual ~IndexVectorBase() = default; + + IndexBufferBase* getBuffer() const { return buffer.get(); } + void setBuffer(std::unique_ptr&& value) { buffer = std::move(value); } + + bool getDirty() const { return dirty; } + void setDirty(bool value = true) { dirty = value; } + + bool isReleased() const { return released; } + + void extend(std::size_t n, const uint16_t val) { + v.resize(v.size() + n, val); + dirty = true; + } + + uint16_t& at(std::size_t n) { + assert(n < v.size()); + dirty = true; + return v.at(n); + } + const uint16_t& at(std::size_t n) const { + assert(n < v.size()); + return v.at(n); + } std::size_t elements() const { return v.size(); } @@ -25,15 +59,31 @@ public: bool empty() const { return v.empty(); } - void clear() { v.clear(); } + void clear() { + dirty = true; + v.clear(); + } + + void release() { + // If we've already created a buffer, we don't need the raw data any more. + if (buffer) { + clear(); + } + released = true; + } const uint16_t* data() const { return v.data(); } const std::vector& vector() const { return v; } + +protected: + std::unique_ptr buffer; + bool dirty = true; + bool released = false; }; template -class IndexVector : public IndexVectorBase { +class IndexVector final : public IndexVectorBase { public: static constexpr std::size_t groupSize = BufferGroupSizeOf::value; @@ -44,5 +94,7 @@ public: } }; +using IndexVectorBasePtr = std::shared_ptr; + } // namespace gfx } // namespace mbgl diff --git a/src/mbgl/gfx/upload_pass.hpp b/src/mbgl/gfx/upload_pass.hpp index a5ec411a6..51e3fe1ea 100644 --- a/src/mbgl/gfx/upload_pass.hpp +++ b/src/mbgl/gfx/upload_pass.hpp @@ -127,28 +127,6 @@ public: updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type); } -#if MLN_DRAWABLE_RENDERER - template - void updateTexture(Texture2D& texture, - const Image& image, - TextureChannelDataType type = TextureChannelDataType::UnsignedByte) { - const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha; - updateTexture2D(texture, image.size, image.data.get(), format, type); - } - - template - void updateTextureSub(Texture2D& texture, - const Image& image, - const uint16_t offsetX, - const uint16_t offsetY, - TextureChannelDataType type = TextureChannelDataType::UnsignedByte) { - assert(image.size.width + offsetX <= texture.getSize().width); - assert(image.size.height + offsetY <= texture.getSize().height); - const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha; - updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type); - } -#endif - public: virtual std::unique_ptr createTextureResource(Size, const void* data, diff --git a/src/mbgl/gfx/vertex_vector.hpp b/src/mbgl/gfx/vertex_vector.hpp index 1cb6b1a1f..f18c47e13 100644 --- a/src/mbgl/gfx/vertex_vector.hpp +++ b/src/mbgl/gfx/vertex_vector.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace mbgl { namespace gfx { diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index 85f8198c5..79a8cb5c0 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -17,7 +17,6 @@ DrawableGL::DrawableGL(std::string name_) impl(std::make_unique()) {} DrawableGL::~DrawableGL() { - impl->indexBuffer = {0, nullptr}; impl->attributeBuffers.clear(); } @@ -40,8 +39,12 @@ void DrawableGL::draw(PaintParameters& parameters) const { return; } - context.setDepthMode(getIs3D() ? parameters.depthModeFor3D() - : parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType())); + if (enableDepth) { + context.setDepthMode(getIs3D() ? parameters.depthModeFor3D() + : parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType())); + } else { + context.setDepthMode(gfx::DepthMode::disabled()); + } // force disable depth test for debugging // context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}}); @@ -136,6 +139,14 @@ void DrawableGL::unbindUniformBuffers() const { } } +struct IndexBufferGL : public gfx::IndexBufferBase { + IndexBufferGL(std::unique_ptr&& buffer_) + : buffer(std::move(buffer_)) {} + ~IndexBufferGL() override = default; + + std::unique_ptr buffer; +}; + void DrawableGL::upload(gfx::UploadPass& uploadPass) { if (!shader) { return; @@ -151,10 +162,6 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) { auto& glContext = static_cast(context); constexpr auto usage = gfx::BufferUsageType::StaticDraw; - const auto indexBytes = impl->indexes->elements() * sizeof(gfx::IndexVectorBase::value_type); - auto indexBufferResource = uploadPass.createIndexBufferResource(impl->indexes->data(), indexBytes, usage); - auto indexBuffer = gfx::IndexBuffer{impl->indexes->elements(), std::move(indexBufferResource)}; - // Apply drawable values to shader defaults const auto& defaults = shader->getVertexAttributes(); const auto& overrides = impl->vertexAttributes; @@ -173,7 +180,17 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) { vertexBuffers); impl->attributeBuffers = std::move(vertexBuffers); - impl->indexBuffer = std::move(indexBuffer); + + if (impl->indexes->getDirty()) { + auto indexBufferResource{ + uploadPass.createIndexBufferResource(impl->indexes->data(), impl->indexes->bytes(), usage)}; + auto indexBuffer = std::make_unique(impl->indexes->elements(), + std::move(indexBufferResource)); + auto buffer = std::make_unique(std::move(indexBuffer)); + + impl->indexes->setBuffer(std::move(buffer)); + impl->indexes->setDirty(false); + } // Create a VAO for each group of vertexes described by a segment for (const auto& seg : impl->segments) { @@ -190,13 +207,13 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) { } } - auto vertexArray = glContext.createVertexArray(); - - vertexArray.bind(glContext, impl->indexBuffer, bindings); - - assert(vertexArray.isValid()); - - glSeg.setVertexArray(std::move(vertexArray)); + if (!glSeg.getVertexArray().isValid()) { + auto vertexArray = glContext.createVertexArray(); + IndexBufferGL& indexBuffer = *static_cast(impl->indexes->getBuffer()); + vertexArray.bind(glContext, *indexBuffer.buffer, bindings); + assert(vertexArray.isValid()); + glSeg.setVertexArray(std::move(vertexArray)); + } }; } diff --git a/src/mbgl/gl/drawable_gl_impl.hpp b/src/mbgl/gl/drawable_gl_impl.hpp index 2caa19d35..d2288b4ef 100644 --- a/src/mbgl/gl/drawable_gl_impl.hpp +++ b/src/mbgl/gl/drawable_gl_impl.hpp @@ -40,7 +40,6 @@ public: VertexAttributeArrayGL vertexAttributes; - gfx::IndexBuffer indexBuffer = {0, nullptr}; std::vector attributeBuffers; UniformBufferArrayGL uniformBuffers; diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 1d1a39c71..ab4a43444 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -96,6 +96,9 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar registerTypesgetDirty()) { updateVertexBufferResource(resource, rawBufPtr, rawBufSize); + vec->setDirty(false); } return rawData->resource; } @@ -162,6 +163,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe auto buffer = std::make_unique(); buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage); vec->setBuffer(std::move(buffer)); + vec->setDirty(false); return static_cast(vec->getBuffer())->resource; } } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 8ebb96e01..cfb3927b8 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -1124,7 +1124,7 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) { if (collisionBuffer.segments.empty() || collisionBuffer.segments.back().vertexLength + vertexLength > std::numeric_limits::max()) { collisionBuffer.segments.emplace_back( - collisionBuffer.vertices.elements(), + collisionBuffer.vertices().elements(), feature.alongLine ? (isText ? bucket.textCollisionCircle->triangles.elements() : bucket.iconCollisionCircle->triangles.elements()) : (isText ? bucket.textCollisionBox->lines.elements() @@ -1134,23 +1134,23 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) { auto& segment = collisionBuffer.segments.back(); auto index = static_cast(segment.vertexLength); - collisionBuffer.vertices.emplace_back( + collisionBuffer.vertices().emplace_back( CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tl)); - collisionBuffer.vertices.emplace_back( + collisionBuffer.vertices().emplace_back( CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tr)); - collisionBuffer.vertices.emplace_back( + collisionBuffer.vertices().emplace_back( CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, br)); - collisionBuffer.vertices.emplace_back( + collisionBuffer.vertices().emplace_back( CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, bl)); // Dynamic vertices are initialized so that the vertex count // always agrees with the layout vertex buffer, but they will // always be updated before rendering happens auto dynamicVertex = CollisionBoxProgram::dynamicVertex(false, false, {}); - collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); - collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); - collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); - collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); + collisionBuffer.dynamicVertices().emplace_back(dynamicVertex); + collisionBuffer.dynamicVertices().emplace_back(dynamicVertex); + collisionBuffer.dynamicVertices().emplace_back(dynamicVertex); + collisionBuffer.dynamicVertices().emplace_back(dynamicVertex); if (feature.alongLine) { auto& collisionCircle = (isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle); diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 811f86d83..872e9ed93 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -134,15 +134,15 @@ void SymbolBucket::upload([[maybe_unused]] gfx::UploadPass& uploadPass) { const auto updateCollisionBox = [&](CollisionBoxBuffer& collisionBox) { if (!staticUploaded) { collisionBox.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionBox.lines)); - collisionBox.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.vertices)); + collisionBox.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.vertices())); } if (!placementChangesUploaded) { if (!collisionBox.dynamicVertexBuffer) { collisionBox.dynamicVertexBuffer = uploadPass.createVertexBuffer( - std::move(collisionBox.dynamicVertices), gfx::BufferUsageType::StreamDraw); + std::move(collisionBox.dynamicVertices()), gfx::BufferUsageType::StreamDraw); } else { uploadPass.updateVertexBuffer(*collisionBox.dynamicVertexBuffer, - std::move(collisionBox.dynamicVertices)); + std::move(collisionBox.dynamicVertices())); } } }; @@ -157,15 +157,15 @@ void SymbolBucket::upload([[maybe_unused]] gfx::UploadPass& uploadPass) { const auto updateCollisionCircle = [&](CollisionCircleBuffer& collisionCircle) { if (!staticUploaded) { collisionCircle.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionCircle.triangles)); - collisionCircle.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.vertices)); + collisionCircle.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.vertices())); } if (!placementChangesUploaded) { if (!collisionCircle.dynamicVertexBuffer) { collisionCircle.dynamicVertexBuffer = uploadPass.createVertexBuffer( - std::move(collisionCircle.dynamicVertices), gfx::BufferUsageType::StreamDraw); + std::move(collisionCircle.dynamicVertices()), gfx::BufferUsageType::StreamDraw); } else { uploadPass.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer, - std::move(collisionCircle.dynamicVertices)); + std::move(collisionCircle.dynamicVertices())); } } }; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index f0d80da20..878b008e0 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -178,18 +178,34 @@ public: Buffer icon; Buffer sdfIcon; + using CollisionVertexVector = gfx::VertexVector>; + using CollisionDynamicVertexVector = gfx::VertexVector>; + struct CollisionBuffer { - gfx::VertexVector> vertices; - gfx::VertexVector> dynamicVertices; + std::shared_ptr sharedVertices = std::make_shared(); + CollisionVertexVector& vertices() { return *sharedVertices; } + const CollisionVertexVector& vertices() const { return *sharedVertices; } + + std::shared_ptr sharedDynamicVertices = + std::make_shared(); + CollisionDynamicVertexVector& dynamicVertices() { return *sharedDynamicVertices; } + const CollisionDynamicVertexVector& dynamicVertices() const { return *sharedDynamicVertices; } + SegmentVector segments; +#if MLN_LEGACY_RENDERER std::optional>> vertexBuffer; std::optional>> dynamicVertexBuffer; +#endif // MLN_LEGACY_RENDERER }; struct CollisionBoxBuffer : public CollisionBuffer { - gfx::IndexVector lines; + using LineIndexVector = gfx::IndexVector; + const std::shared_ptr sharedLines = std::make_shared(); + LineIndexVector& lines = *sharedLines; +#if MLN_LEGACY_RENDERER std::optional indexBuffer; +#endif // MLN_LEGACY_RENDERER }; std::unique_ptr iconCollisionBox; std::unique_ptr textCollisionBox; @@ -205,8 +221,12 @@ public: } struct CollisionCircleBuffer : public CollisionBuffer { - gfx::IndexVector triangles; + using TriangleIndexVector = gfx::IndexVector; + const std::shared_ptr sharedTriangles = std::make_shared(); + TriangleIndexVector& triangles = *sharedTriangles; +#if MLN_LEGACY_RENDERER std::optional indexBuffer; +#endif // MLN_LEGACY_RENDERER }; std::unique_ptr iconCollisionCircle; std::unique_ptr textCollisionCircle; diff --git a/src/mbgl/renderer/layers/background_layer_tweaker.cpp b/src/mbgl/renderer/layers/background_layer_tweaker.cpp index 2e05debbc..4ae21fb9e 100644 --- a/src/mbgl/renderer/layers/background_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/background_layer_tweaker.cpp @@ -81,7 +81,7 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre } layerGroup.setEnabled(true); - int32_t samplerLocation = -1; + std::optional samplerLocation{}; layerGroup.visitDrawables([&](gfx::Drawable& drawable) { assert(drawable.getTileID()); @@ -99,14 +99,16 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre uniforms.createOrUpdate(BackgroundDrawableUBOName, &drawableUBO, context); if (hasPattern) { - if (samplerLocation < 0) { - if (const auto index = shader->getSamplerLocation(texUniformName)) { - samplerLocation = *index; + if (!samplerLocation.has_value()) { + samplerLocation = shader->getSamplerLocation(texUniformName); + if (const auto& tex = parameters.patternAtlas.texture()) { + tex->setSamplerConfiguration( + {gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); } } - if (0 <= samplerLocation) { + if (samplerLocation.has_value()) { if (const auto& tex = parameters.patternAtlas.texture()) { - drawable.setTexture(tex, samplerLocation); + drawable.setTexture(tex, samplerLocation.value()); } } diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp index 039b0bf7c..239756693 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp @@ -71,6 +71,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, paintParamsUniformBuffer->update(&paintParamsUBO, sizeof(CirclePaintParamsUBO)); } + const bool scaleWithMap = evaluated.get() == CirclePitchScaleType::Map; const bool pitchWithMap = evaluated.get() == AlignmentType::Map; // Updated only with evaluated properties @@ -84,7 +85,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, /* .stroke_width = */ evaluated.get().constantOr(CircleStrokeWidth::defaultValue()), /* .stroke_opacity = */ evaluated.get().constantOr(CircleStrokeOpacity::defaultValue()), - /* .scale_with_map = */ evaluated.get() == CirclePitchScaleType::Map, + /* .scale_with_map = */ scaleWithMap, /* .pitch_with_map = */ pitchWithMap, /* .padding = */ 0}; evaluatedPropsUniformBuffer = context.createUniformBuffer(&evaluatedPropsUBO, sizeof(evaluatedPropsUBO)); @@ -113,7 +114,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const CircleDrawableUBO drawableUBO = { /* .matrix = */ util::cast(matrix), /* .extrude_scale = */ - pitchWithMap ? std::array{{pixelsToTileUnits}} : parameters.pixelsToGLUnits, + pitchWithMap ? std::array{{pixelsToTileUnits, pixelsToTileUnits}} : parameters.pixelsToGLUnits, /* .padding = */ {0}}; uniforms.createOrUpdate(CircleDrawableUBOName, &drawableUBO, context); diff --git a/src/mbgl/renderer/layers/collision_layer_tweaker.cpp b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp new file mode 100644 index 000000000..2e0facf30 --- /dev/null +++ b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp @@ -0,0 +1,94 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +using namespace style; + +namespace { + +struct alignas(16) CollisionUBO { + std::array matrix; + std::array extrude_scale; + float camera_to_center_distance; + float overscale_factor; +}; +static_assert(sizeof(CollisionUBO) == 20 * 4); + +} // namespace + +void CollisionLayerTweaker::execute(LayerGroupBase& layerGroup, + const RenderTree& renderTree, + const PaintParameters& parameters) { + if (layerGroup.empty()) { + return; + } + + auto& context = parameters.context; + const auto& state = parameters.state; + +#if !defined(NDEBUG) + const auto label = layerGroup.getName() + "-update-uniforms"; + const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); +#endif + + layerGroup.visitDrawables([&](gfx::Drawable& drawable) { + if (!drawable.getTileID() || !drawable.getData()) { + return; + } + + const auto tileID = drawable.getTileID()->toUnwrapped(); + const auto& data = static_cast(*drawable.getData()); + + // matrix + const auto translate = data.translate; + const auto anchor = data.translateAnchor; + constexpr bool nearClipped = false; + constexpr bool inViewportPixelUnits = false; + const auto matrix = getTileMatrix( + tileID, renderTree, state, translate, anchor, nearClipped, inViewportPixelUnits); + + // extrude scale + const auto pixelRatio = tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())); + const auto scale = static_cast( + std::pow(2, parameters.state.getZoom() - drawable.getTileID()->overscaledZ)); + const std::array extrudeScale = {{parameters.pixelsToGLUnits[0] / (pixelRatio * scale), + parameters.pixelsToGLUnits[1] / (pixelRatio * scale)}}; + + const CollisionUBO drawableUBO = { + /*.matrix=*/util::cast(matrix), + /*.extrude_scale*/ extrudeScale, + /*.camera_to_center_distance*/ parameters.state.getCameraToCenterDistance(), + /*.overscale_factor*/ static_cast(drawable.getTileID()->overscaleFactor())}; + + const auto shader = drawable.getShader(); + const auto& shaderUniforms = shader->getUniformBlocks(); + auto& uniforms = drawable.mutableUniformBuffers(); + + if (shaderUniforms.get(std::string(CollisionBoxUBOName))) { + // collision box + uniforms.createOrUpdate(CollisionBoxUBOName, &drawableUBO, context); + } else if (shaderUniforms.get(std::string(CollisionCircleUBOName))) { + // collision circle + uniforms.createOrUpdate(CollisionCircleUBOName, &drawableUBO, context); + } else { + Log::Error(Event::General, "Collision shader uniform name unknown."); + } + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/collision_layer_tweaker.hpp b/src/mbgl/renderer/layers/collision_layer_tweaker.hpp new file mode 100644 index 000000000..e9d854fff --- /dev/null +++ b/src/mbgl/renderer/layers/collision_layer_tweaker.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +namespace mbgl { + +/** + Collision drawables' layer tweaker + */ +class CollisionLayerTweaker : public LayerTweaker { +public: + CollisionLayerTweaker(Immutable properties) + : LayerTweaker(properties){}; + +public: + ~CollisionLayerTweaker() override = default; + + void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override; + + static constexpr std::string_view CollisionCircleUBOName = "CollisionCircleUBO"; + static constexpr std::string_view CollisionBoxUBOName = "CollisionBoxUBO"; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp index e387cb995..ea5045472 100644 --- a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp @@ -34,7 +34,7 @@ static_assert(sizeof(FillExtrusionDrawableUBO) == 7 * 16); /// Evaluated properties that do not depend on the tile struct alignas(16) FillExtrusionDrawablePropsUBO { - /* 0 */ std::array color; + /* 0 */ Color color; /* 16 */ std::array light_color; /* 28 */ float pad1; /* 32 */ std::array light_position; @@ -82,7 +82,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, // UBO depends on more than just evaluated properties, so we need to update every time, // but the resulting buffer can be shared across all the drawables from the layer. const FillExtrusionDrawablePropsUBO paramsUBO = { - /* .color = */ gfx::VertexAttribute::colorAttrRGBA(constOrDefault(evaluated)), + /* .color = */ constOrDefault(evaluated), /* .light_color = */ FillExtrusionProgram::lightColor(parameters.evaluatedLight), /* .pad = */ 0, /* .light_position = */ FillExtrusionProgram::lightPosition(parameters.evaluatedLight, state), diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 5f655554e..0399a9cae 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -448,7 +448,11 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, tweaker = std::make_shared(atlases, std::string(), std::string(IconTextureName), - /*isText=*/false); + /*isText=*/false, + false, + style::AlignmentType::Auto, + false, + false); if (depthBuilder) { depthBuilder->addTweaker(tweaker); } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 5089f0619..400d342c9 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -339,7 +339,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, std::unique_ptr outlinePatternBuilder; const auto layerPrefix = getID() + "/"; - const auto renderPass = static_cast(evaluatedProperties->renderPasses); + const auto renderPass = RenderPass::Translucent; const auto finish = [&](gfx::DrawableBuilder& builder, const OverscaledTileID& tileID, @@ -462,7 +462,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, : gfx::DepthMaskType::ReadOnly); builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended() : gfx::ColorMode::unblended()); - builder->setSubLayerIndex(0); + builder->setSubLayerIndex(1); builder->setRenderPass(renderPass); fillBuilder = std::move(builder); } @@ -549,7 +549,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, auto tweaker = std::make_shared(atlases, /*glyphName=*/std::string(), std::string(IconTextureName), - /*isText=*/false); + /*isText=*/false, + false, + style::AlignmentType::Auto, + false, + false); if (patternBuilder) { patternBuilder->addTweaker(tweaker); } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index ec8facf72..d611c6e94 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -390,10 +390,10 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, heatmapBuilder = context.createDrawableBuilder("heatmap"); heatmapBuilder->setShader(std::static_pointer_cast(heatmapShader)); - heatmapBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite - : gfx::DepthMaskType::ReadOnly); + heatmapBuilder->setEnableDepth(false); heatmapBuilder->setColorMode(gfx::ColorMode::additive()); heatmapBuilder->setCullFaceMode(gfx::CullFaceMode::disabled()); + heatmapBuilder->setEnableStencil(false); heatmapBuilder->setRenderPass(renderPass); heatmapBuilder->setVertexAttributes(std::move(heatmapVertexAttrs)); heatmapBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2); @@ -450,10 +450,10 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, heatmapTextureBuilder = context.createDrawableBuilder("heatmapTexture"); heatmapTextureBuilder->setShader(heatmapTextureShader); - heatmapTextureBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite - : gfx::DepthMaskType::ReadOnly); + heatmapTextureBuilder->setEnableDepth(false); heatmapTextureBuilder->setColorMode(gfx::ColorMode::alphaBlended()); heatmapTextureBuilder->setCullFaceMode(gfx::CullFaceMode::disabled()); + heatmapTextureBuilder->setEnableStencil(false); heatmapTextureBuilder->setRenderPass(renderPass); heatmapTextureBuilder->setVertexAttributes(std::move(textureVertexAttrs)); heatmapTextureBuilder->setRawVertices({}, textureVertexCount, gfx::AttributeDataType::Short2); diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index cd5e44d67..48069aefb 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -387,13 +387,13 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, offsetof(HillshadeLayoutVertex, a2), 0, sizeof(HillshadeLayoutVertex), - gfx::AttributeDataType::Short4); + gfx::AttributeDataType::Short2); } hillshadePrepareBuilder = context.createDrawableBuilder("hillshadePrepare"); hillshadePrepareBuilder->setShader(hillshadePrepareShader); hillshadePrepareBuilder->setDepthType(gfx::DepthMaskType::ReadOnly); - hillshadePrepareBuilder->setColorMode(gfx::ColorMode::alphaBlended()); + hillshadePrepareBuilder->setColorMode(gfx::ColorMode::unblended()); hillshadePrepareBuilder->setCullFaceMode(gfx::CullFaceMode::disabled()); hillshadePrepareBuilder->setRenderPass(renderPass); @@ -448,7 +448,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, offsetof(HillshadeLayoutVertex, a2), 0, sizeof(HillshadeLayoutVertex), - gfx::AttributeDataType::Short4); + gfx::AttributeDataType::Short2); } hillshadeBuilder = context.createDrawableBuilder("hillshade"); diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 7c4757deb..ee1949b1d 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -21,6 +21,7 @@ #if MLN_DRAWABLE_RENDERER #include +#include #include #include #include @@ -406,6 +407,8 @@ struct alignas(16) LinePatternTilePropertiesUBO { static_assert(sizeof(LinePatternTilePropertiesUBO) % 16 == 0); static constexpr std::string_view LinePatternTilePropertiesUBOName = "LinePatternTilePropertiesUBO"; +static constexpr auto LineImageUniformName = "u_image"; + void RenderLineLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, @@ -643,24 +646,34 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, // texture if (const auto& atlases = tile.getAtlasTextures(); atlases && atlases->icon) { - if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) { - builder->setTexture(atlases->icon, samplerLocation.value()); + if (!iconTweaker) { + iconTweaker = std::make_shared( + atlases, + "", + LineImageUniformName, + /*isText*/ false, + /*sdfIcons*/ true, // to force linear filter + /*rotationAlignment_*/ AlignmentType::Auto, + /*iconScaled*/ false, + /*textSizeIsZoomConstant_*/ false); + } - // segments - setSegments(builder, bucket); + builder->addTweaker(iconTweaker); - // finish - builder->flush(); - for (auto& drawable : builder->clearDrawables()) { - drawable->setTileID(tileID); - drawable->mutableUniformBuffers().createOrUpdate( - LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context); - drawable->mutableUniformBuffers().createOrUpdate( - LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context); + // segments + setSegments(builder, bucket); - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; - } + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->mutableUniformBuffers().createOrUpdate( + LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context); + drawable->mutableUniformBuffers().createOrUpdate( + LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; } } @@ -678,7 +691,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, addAttributes(*builder, bucket, std::move(vertexAttrs)); // texture - if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) { + if (const auto samplerLocation = builder->getShader()->getSamplerLocation(LineImageUniformName)) { if (!colorRampTexture2D && colorRamp->valid()) { // create texture. to be reused for all the tiles of the layer colorRampTexture2D = context.createTexture2D(); diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 863d72b05..91e86fe13 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -88,6 +88,8 @@ private: gfx::ShaderGroupPtr lineGradientShaderGroup; gfx::ShaderGroupPtr lineSDFShaderGroup; gfx::ShaderGroupPtr linePatternShaderGroup; + + gfx::DrawableTweakerPtr iconTweaker; #endif }; diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index b6c8fe7b7..daa5ffbbc 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -256,11 +256,11 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, rasterShader = context.getGenericShader(shaders, "RasterShader"); } - if (!staticDataSharedVertices) { - staticDataSharedVertices = std::make_shared(RenderStaticData::rasterVertices()); + if (!staticDataVertices) { + staticDataVertices = std::make_shared(RenderStaticData::rasterVertices()); } if (!staticDataIndices) { - staticDataIndices = std::make_shared(RenderStaticData::quadTriangleIndices()); + staticDataIndices = std::make_shared(RenderStaticData::quadTriangleIndices()); } if (!staticDataSegments) { staticDataSegments = std::make_shared(RenderStaticData::rasterSegments()); @@ -306,99 +306,9 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, } }; - auto buildTileDrawables = [&setTextures](std::unique_ptr& builder, - const RasterBucket& bucket) { - auto buildRenderData = [](const TileMask& mask, - std::vector>& vertices, - std::vector>& attributes, - std::vector& indices, - std::vector& segments) { - constexpr const uint16_t vertexLength = 4; - - if (vertices.empty()) { - vertices.reserve(mask.size() * vertexLength); - attributes.reserve(mask.size() * vertexLength); - indices.reserve(mask.size() * 6); - segments.reserve(mask.size()); - } - // Create the vertex buffer for the specified tile mask. - for (const auto& id : mask) { - // Create a quad for every masked tile. - const int32_t vertexExtent = util::EXTENT >> id.z; - - const Point tlVertex = {static_cast(id.x * vertexExtent), - static_cast(id.y * vertexExtent)}; - const Point brVertex = {static_cast(tlVertex.x + vertexExtent), - static_cast(tlVertex.y + vertexExtent)}; - - if (segments.empty() || - (segments.back().vertexLength + vertexLength > std::numeric_limits::max())) { - // Move to a new segments because the old one can't hold the geometry. - segments.emplace_back(vertices.size(), indices.size()); - } - - vertices.emplace_back(std::array{{tlVertex.x, tlVertex.y}}); - attributes.emplace_back(std::array{{tlVertex.x, tlVertex.y}}); - - vertices.emplace_back(std::array{{brVertex.x, tlVertex.y}}); - attributes.emplace_back(std::array{{brVertex.x, tlVertex.y}}); - - vertices.emplace_back(std::array{{tlVertex.x, brVertex.y}}); - attributes.emplace_back(std::array{{tlVertex.x, brVertex.y}}); - - vertices.emplace_back(std::array{{brVertex.x, brVertex.y}}); - attributes.emplace_back(std::array{{brVertex.x, brVertex.y}}); - - auto& segment = segments.back(); - assert(segment.vertexLength <= std::numeric_limits::max()); - const auto offset = static_cast(segment.vertexLength); - - // 0, 1, 2 - // 1, 2, 3 - indices.insert(indices.end(), - {offset, - static_cast(offset + 1u), - static_cast(offset + 2u), - static_cast(offset + 1u), - static_cast(offset + 2u), - static_cast(offset + 3u)}); - - segment.vertexLength += vertexLength; - segment.indexLength += 6; - } - }; - - std::vector> vertices, attributes; - std::vector indices; - std::vector segments; - buildRenderData(bucket.mask, vertices, attributes, indices, segments); - builder->addVertices(vertices, 0, vertices.size()); - builder->setSegments(gfx::Triangles(), indices, segments.data(), segments.size()); - - // attributes - { - gfx::VertexAttributeArray vertexAttrs; - if (const auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) { - attr->reserve(attributes.size()); - std::size_t index{0}; - for (const auto& a : attributes) { - attr->set(index++, {a[0], a[1]}); - } - } - builder->setVertexAttributes(std::move(vertexAttrs)); - } - - // textures - setTextures(builder, bucket); - }; - - auto updateTileDrawables = [&](std::unique_ptr& builder, - auto* tileLayerGroup, - const auto& tileID, - const RasterBucket& bucket) { - // Set up tile drawable - auto vertices = staticDataSharedVertices; - auto indices = staticDataIndices; + auto buildVertexData = [this](std::unique_ptr& builder, const RasterBucket& bucket) { + RasterVertexVectorPtr vertices = staticDataVertices; + TriangleIndexVectorPtr indices = staticDataIndices; const RasterSegmentVector* segments = staticDataSegments.get(); if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) { @@ -407,75 +317,52 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, segments = &bucket.segments; } - // attributes - gfx::VertexAttributeArray vertexAttrs; - - if (const auto& attr = vertexAttrs.add(PosAttribName)) { - attr->setSharedRawData(vertices, - offsetof(RasterLayoutVertex, a1), - 0, - sizeof(RasterLayoutVertex), - gfx::AttributeDataType::Short2); - } - if (const auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) { - attr->setSharedRawData(vertices, - offsetof(RasterLayoutVertex, a2), - 0, - sizeof(RasterLayoutVertex), - gfx::AttributeDataType::Short4); - } - - tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { - drawable.setVertexAttributes(std::move(vertexAttrs)); - drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); - - std::vector> drawSegments; - for (std::size_t i = 0; i < segments->size(); ++i) { - const auto& seg = segments->data()[i]; - auto segCopy = SegmentBase{ - // no copy constructor - seg.vertexOffset, - seg.indexOffset, - seg.vertexLength, - seg.indexLength, - seg.sortKey, - }; - drawSegments.emplace_back(builder->createSegment(gfx::Triangles(), std::move(segCopy))); - } - drawable.setIndexData(indices->vector(), std::move(drawSegments)); - }); - }; - - auto buildImageDrawables = [&setTextures](std::unique_ptr& builder, - const RasterBucket& bucket) { // attributes { gfx::VertexAttributeArray vertexAttrs; if (auto& attr = vertexAttrs.add(PosAttribName)) { - attr->setSharedRawData(bucket.sharedVertices, + attr->setSharedRawData(vertices, offsetof(RasterLayoutVertex, a1), /*vertexOffset=*/0, sizeof(RasterLayoutVertex), gfx::AttributeDataType::Short2); } - if (auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) { - std::size_t index{0}; - for (auto& v : bucket.vertices.vector()) { - attr->set(index++, {v.a2[0], v.a2[1]}); - } + if (auto& attr = vertexAttrs.add(TexturePosAttribName)) { + attr->setSharedRawData(vertices, + offsetof(RasterLayoutVertex, a2), + /*vertexOffset=*/0, + sizeof(RasterLayoutVertex), + gfx::AttributeDataType::Short2); } builder->setVertexAttributes(std::move(vertexAttrs)); } - builder->setRawVertices({}, bucket.vertices.elements(), gfx::AttributeDataType::Short2); - builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size()); + builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); + builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size()); + }; - // textures + auto buildDrawables = [&setTextures, &buildVertexData](std::unique_ptr& builder, + const RasterBucket& bucket) { + buildVertexData(builder, bucket); setTextures(builder, bucket); }; + auto updateTileDrawables = [&](std::unique_ptr& builder, + auto* tileLayerGroup, + const auto& tileID, + const RasterBucket& bucket) { + // TODO: check for oportunity to skip + + buildVertexData(builder, bucket); + tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + for (auto& tex : drawable.getTextures()) { + builder->setTexture(tex.second, tex.first); + } + }); + }; + if (imageData) { RasterBucket& bucket = *imageData->bucket; if (!bucket.vertices.empty()) { @@ -490,7 +377,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, auto builder = createBuilder(); for (const auto& matrix_ : imageData->matrices) { - buildImageDrawables(builder, bucket); + buildDrawables(builder, bucket); // finish builder->flush(); @@ -538,21 +425,23 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, setRenderTileBucketID(tileID, bucket.getID()); if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { + // re-create drawable geometry and pass texture updateTileDrawables(builder, tileLayerGroup, tileID, bucket); - continue; - } - if (bucket.image) { - buildTileDrawables(builder, bucket); - - // finish - builder->flush(); - for (auto& drawable : builder->clearDrawables()) { - drawable->setTileID(tileID); - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; - } + // erase current drawable + removeTile(renderPass, tileID); + } else if (bucket.image) { + // build new drawable for this tile + buildDrawables(builder, bucket); }; + + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } } } } diff --git a/src/mbgl/renderer/layers/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index 4e2d6ac23..c45b3210a 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.hpp +++ b/src/mbgl/renderer/layers/render_raster_layer.hpp @@ -55,12 +55,15 @@ private: LayerGroupPtr imageLayerGroup; using RasterVertexVector = gfx::VertexVector; - std::shared_ptr staticDataSharedVertices; + using RasterVertexVectorPtr = std::shared_ptr; + RasterVertexVectorPtr staticDataVertices; - using RasterIndexVector = gfx::IndexVector; - std::shared_ptr staticDataIndices; + using TriangleIndexVector = gfx::IndexVector; + using TriangleIndexVectorPtr = std::shared_ptr; + TriangleIndexVectorPtr staticDataIndices; using RasterSegmentVector = SegmentVector; + using RasterSegmentVectorPtr = std::shared_ptr; std::shared_ptr staticDataSegments; #endif }; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index e167bbba8..b1156932f 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -26,9 +26,12 @@ #include #include #include +#include #include #include #include +#include +#include #endif // MLN_DRAWABLE_RENDERER #include @@ -45,6 +48,8 @@ constexpr std::string_view SymbolIconShaderName = "SymbolIconShader"; constexpr std::string_view SymbolSDFIconShaderName = "SymbolSDFTextShader"; constexpr std::string_view SymbolSDFTextShaderName = "SymbolSDFIconShader"; constexpr std::string_view SymbolTextAndIconShaderName = "SymbolTextAndIconShader"; +constexpr std::string_view CollisionBoxShaderName = "CollisionBoxShader"; +constexpr std::string_view CollisionCircleShaderName = "CollisionCircleShader"; #endif // MLN_DRAWABLE_RENDERER @@ -839,8 +844,113 @@ void updateTileDrawable(gfx::Drawable& drawable, drawable.setVertexAttributes(std::move(attribs)); } +constexpr auto CollisionPosAttribName = "a_pos"; +constexpr auto CollisionAnchorPosAttribName = "a_anchor_pos"; +constexpr auto CollisionExtrudeAttribName = "a_extrude"; +constexpr auto CollisionPlacedAttribName = "a_placed"; +constexpr auto CollisionShiftAttribName = "a_shift"; + +gfx::VertexAttributeArray getCollisionVertexAttributes(const SymbolBucket::CollisionBuffer& buffer, bool staticCopy) { + gfx::VertexAttributeArray vertexAttrs; + + if (staticCopy) { + if (auto& attr = vertexAttrs.getOrAdd(CollisionPosAttribName)) { + std::size_t index{0}; + for (auto& v : buffer.vertices().vector()) { + attr->set(index++, {v.a1[0], v.a1[1]}); + } + } + if (auto& attr = vertexAttrs.getOrAdd(CollisionAnchorPosAttribName)) { + std::size_t index{0}; + for (auto& v : buffer.vertices().vector()) { + attr->set(index++, {v.a2[0], v.a2[1]}); + } + } + if (auto& attr = vertexAttrs.getOrAdd(CollisionExtrudeAttribName)) { + std::size_t index{0}; + for (auto& v : buffer.vertices().vector()) { + attr->set(index++, {v.a3[0], v.a3[1]}); + } + } + + if (auto& attr = vertexAttrs.getOrAdd(CollisionPlacedAttribName)) { + std::size_t index{0}; + for (auto& v : buffer.dynamicVertices().vector()) { + attr->set(index++, {v.a1[0], v.a1[1]}); + } + } + if (auto& attr = vertexAttrs.getOrAdd(CollisionShiftAttribName)) { + std::size_t index{0}; + for (auto& v : buffer.dynamicVertices().vector()) { + attr->set(index++, {v.a2[0], v.a2[1]}); + } + } + } else { + if (const auto& attr = vertexAttrs.getOrAdd(CollisionPosAttribName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(CollisionBoxVertex, a1), + /*vertexOffset=*/0, + sizeof(CollisionBoxVertex), + gfx::AttributeDataType::Short2); + } + if (const auto& attr = vertexAttrs.getOrAdd(CollisionAnchorPosAttribName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(CollisionBoxVertex, a2), + /*vertexOffset=*/0, + sizeof(CollisionBoxVertex), + gfx::AttributeDataType::Short2); + } + if (const auto& attr = vertexAttrs.getOrAdd(CollisionExtrudeAttribName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(CollisionBoxVertex, a3), + /*vertexOffset=*/0, + sizeof(CollisionBoxVertex), + gfx::AttributeDataType::Short2); + } + + using DynamicVertex = gfx::Vertex; + + if (const auto& attr = vertexAttrs.getOrAdd(CollisionPlacedAttribName)) { + attr->setSharedRawData(buffer.sharedDynamicVertices, + offsetof(DynamicVertex, a1), + /*vertexOffset=*/0, + sizeof(DynamicVertex), + gfx::AttributeDataType::UByte2); + } + if (const auto& attr = vertexAttrs.getOrAdd(CollisionShiftAttribName)) { + attr->setSharedRawData(buffer.sharedDynamicVertices, + offsetof(DynamicVertex, a2), + /*vertexOffset=*/0, + sizeof(DynamicVertex), + gfx::AttributeDataType::Float2); + } + } + + return vertexAttrs; +} + } // namespace +void RenderSymbolLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { + if (const auto tileGroup = static_cast(layerGroup.get())) { + stats.drawablesRemoved += tileGroup->removeDrawables(renderPass, tileID).size(); + } + if (collisionTileLayerGroup) { + stats.drawablesRemoved += collisionTileLayerGroup->removeDrawables(renderPass, tileID).size(); + } +} + +void RenderSymbolLayer::removeAllDrawables() { + if (layerGroup) { + stats.drawablesRemoved += layerGroup->getDrawableCount(); + layerGroup->clearDrawables(); + } + if (collisionTileLayerGroup) { + stats.drawablesRemoved += collisionTileLayerGroup->getDrawableCount(); + collisionTileLayerGroup->clearDrawables(); + } +} + void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, @@ -859,6 +969,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } } + if (!collisionTileLayerGroup) { + if ((collisionTileLayerGroup = context.createTileLayerGroup( + layerIndex, /*initialCapacity=*/64, getID() + "-collision"))) { + collisionTileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + activateLayerGroup(collisionTileLayerGroup, true, changes); + } + } + if (!symbolIconGroup) { symbolIconGroup = shaders.getShaderGroup(std::string(SymbolIconShaderName)); } @@ -871,7 +989,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, if (!symbolTextAndIconGroup) { symbolTextAndIconGroup = shaders.getShaderGroup(std::string(SymbolTextAndIconShaderName)); } + if (!collisionBoxGroup) { + collisionBoxGroup = shaders.getShaderGroup(std::string(CollisionBoxShaderName)); + } + if (!collisionCircleGroup) { + collisionCircleGroup = shaders.getShaderGroup(std::string(CollisionCircleShaderName)); + } + // remove drawables that are dropped out of scope auto* tileLayerGroup = static_cast(layerGroup.get()); stats.drawablesRemoved += tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. @@ -881,6 +1006,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } return false; }); + stats.drawablesRemoved += collisionTileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) { + // If the render pass has changed or the tile has dropped out of the cover set, remove it. + const auto& tileID = drawable.getTileID(); + if (drawable.getRenderPass() != passes || (tileID && !hasRenderTile(*tileID))) { + return true; + } + return false; + }); const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get().isUndefined(); std::multiset renderableSegments; @@ -888,6 +1021,16 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto currentZoom = static_cast(state.getZoom()); const auto layerPrefix = getID() + "/"; + const auto layerCollisionPrefix = getID() + "-collision/"; + + std::unique_ptr collisionBuilder = context.createDrawableBuilder(layerCollisionPrefix); + collisionBuilder->setSubLayerIndex(0); + collisionBuilder->setEnableStencil(false); + collisionBuilder->setEnableDepth(false); + collisionBuilder->setRenderPass(passes); + collisionBuilder->setCullFaceMode(gfx::CullFaceMode::disabled()); + collisionBuilder->setColorMode(gfx::ColorMode::alphaBlended()); + collisionBuilder->setVertexAttrName(CollisionPosAttribName); for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -911,6 +1054,77 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); + auto addCollisionDrawables = + [&collisionBuilder, this, &bucket, &renderData, &context, &layerCollisionPrefix, &tileID]( + const bool isText, const bool hasCollisionBox, const bool hasCollisionCircle) { + if (!hasCollisionBox && !hasCollisionCircle) return; + + const auto& layout = *bucket.layout; + const auto& evaluated = getEvaluated(renderData.layerProperties); + const auto values = isText ? textPropertyValues(evaluated, layout) + : iconPropertyValues(evaluated, layout); + const std::string suffix = isText ? "text/" : "icon/"; + + auto addVertices = [&collisionBuilder](const auto& vertices, bool staticCopy) { + if (staticCopy) { + std::vector> verts(vertices.size()); + std::transform(vertices.begin(), + vertices.end(), + verts.begin(), + [](const auto& v) -> std::array { return v.a1; }); + collisionBuilder->addVertices(verts, 0, verts.size()); + } else { + collisionBuilder->setRawVertices({}, vertices.size(), gfx::AttributeDataType::Short2); + } + }; + + constexpr bool staticVertexAndAttributes = true; + + if (hasCollisionBox) { + const auto& collisionBox = isText ? bucket.textCollisionBox : bucket.iconCollisionBox; + if (const auto shader = std::static_pointer_cast( + collisionBoxGroup->getOrCreateShader(context, {}, CollisionPosAttribName))) { + collisionBuilder->setDrawableName(layerCollisionPrefix + suffix + "box"); + collisionBuilder->setShader(shader); + addVertices(collisionBox->vertices().vector(), staticVertexAndAttributes); + collisionBuilder->setVertexAttributes( + getCollisionVertexAttributes(*collisionBox, staticVertexAndAttributes)); + collisionBuilder->setSegments(gfx::Lines(1.0f), + collisionBox->sharedLines, + collisionBox->segments.data(), + collisionBox->segments.size()); + collisionBuilder->flush(); + } + } + + if (hasCollisionCircle) { + const auto& collisionCircle = isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle; + if (const auto shader = std::static_pointer_cast( + collisionCircleGroup->getOrCreateShader(context, {}, CollisionPosAttribName))) { + collisionBuilder->setDrawableName(layerCollisionPrefix + suffix + "circle"); + collisionBuilder->setShader(shader); + addVertices(collisionCircle->vertices().vector(), staticVertexAndAttributes); + collisionBuilder->setVertexAttributes( + getCollisionVertexAttributes(*collisionCircle, staticVertexAndAttributes)); + collisionBuilder->setSegments(gfx::Triangles(), + collisionCircle->sharedTriangles, + collisionCircle->segments.data(), + collisionCircle->segments.size()); + collisionBuilder->flush(); + } + } + + // add drawables to layer group + for (auto& drawable : collisionBuilder->clearDrawables()) { + drawable->setTileID(tileID); + auto drawData = std::make_unique(values.translate, + values.translateAnchor); + drawable->setData(std::move(drawData)); + collisionTileLayerGroup->addDrawable(passes, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + }; + // If we already have drawables for this tile, update them. if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) { // Just update the drawables we already created @@ -918,6 +1132,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& evaluated = getEvaluated(renderData.layerProperties); updateTileDrawable(drawable, context, bucket, bucketPaintProperties, evaluated, state); }); + + // re-create collision drawables + collisionTileLayerGroup->removeDrawables(passes, tileID); + addCollisionDrawables( + false /*isText*/, bucket.hasIconCollisionBoxData(), bucket.hasIconCollisionCircleData()); + addCollisionDrawables( + true /*isText*/, bucket.hasTextCollisionBoxData(), bucket.hasTextCollisionCircleData()); + continue; } @@ -946,6 +1168,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, if (bucket.hasTextData() && atlases->glyph) { addRenderables(bucket.text, SymbolType::Text); } + + addCollisionDrawables(false /*isText*/, bucket.hasIconCollisionBoxData(), bucket.hasIconCollisionCircleData()); + addCollisionDrawables(true /*isText*/, bucket.hasTextCollisionBoxData(), bucket.hasTextCollisionCircleData()); } // We'll be processing renderables across tiles, potentially out-of-order, so keep @@ -1008,12 +1233,27 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, // We can use the same tweakers for all the segments in a tile if (isText && !tileInfo.textTweaker) { - tileInfo.textTweaker = std::make_shared( - atlases, iconTexUniformName, texUniformName, isText); + const bool textSizeIsZoomConstant = + bucket.textSizeBinder->evaluateForZoom(static_cast(state.getZoom())).isZoomConstant; + tileInfo.textTweaker = std::make_shared(atlases, + iconTexUniformName, + texUniformName, + isText, + false, + values.rotationAlignment, + false, + textSizeIsZoomConstant); } if (!isText && !tileInfo.iconTweaker) { - tileInfo.iconTweaker = std::make_shared( - atlases, iconTexUniformName, texUniformName, isText); + const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; + tileInfo.iconTweaker = std::make_shared(atlases, + iconTexUniformName, + texUniformName, + isText, + sdfIcons, + values.rotationAlignment, + iconScaled, + false); } if (!builder) { @@ -1043,11 +1283,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, builder->setDrawableName(layerPrefix + std::string(suffix)); builder->setVertexAttributes(attribs); - // TODO: texture filtering - // const bool linear = parameters.state.isChanging() || transformed || - // !partiallyEvaluatedTextSize.isZoomConstant; const auto filterType = linear ? - // gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest; - builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1); builder->flush(); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index fa50c8532..7150c931f 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -94,6 +94,15 @@ public: UniqueChangeRequestVec&) override; #endif // MLN_DRAWABLE_RENDERER +protected: +#if MLN_DRAWABLE_RENDERER + /// Remove all drawables for the tile from the layer group + void removeTile(RenderPass, const OverscaledTileID&) override; + + /// Remove all the drawables for tiles + void removeAllDrawables() override; +#endif // MLN_DRAWABLE_RENDERER + private: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; @@ -125,6 +134,10 @@ private: gfx::ShaderGroupPtr symbolSDFIconGroup; gfx::ShaderGroupPtr symbolSDFTextGroup; gfx::ShaderGroupPtr symbolTextAndIconGroup; + + gfx::ShaderGroupPtr collisionBoxGroup; + gfx::ShaderGroupPtr collisionCircleGroup; + std::shared_ptr collisionTileLayerGroup; #endif // MLN_DRAWABLE_RENDERER }; diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp index 2f1a54e94..3e613fa89 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -45,8 +45,8 @@ static_assert(sizeof(SymbolDrawableUBO) == 15 * 16); /// Evaluated properties that do not depend on the tile struct alignas(16) SymbolDrawablePaintUBO { - /* 0 */ std::array fill_color; - /* 16 */ std::array halo_color; + /* 0 */ Color fill_color; + /* 16 */ Color halo_color; /* 32 */ float opacity; /* 36 */ float halo_width; /* 40 */ float halo_blur; @@ -80,11 +80,9 @@ auto constOrDefault(const IndexedTuple, TypeList>& evalua SymbolDrawablePaintUBO buildPaintUBO(bool isText, const SymbolPaintProperties::PossiblyEvaluated& evaluated) { return { - /*.fill_color=*/gfx::VertexAttribute::colorAttrRGBA(isText ? constOrDefault(evaluated) - : constOrDefault(evaluated)), + /*.fill_color=*/isText ? constOrDefault(evaluated) : constOrDefault(evaluated), /*.halo_color=*/ - gfx::VertexAttribute::colorAttrRGBA(isText ? constOrDefault(evaluated) - : constOrDefault(evaluated)), + isText ? constOrDefault(evaluated) : constOrDefault(evaluated), /*.opacity=*/isText ? constOrDefault(evaluated) : constOrDefault(evaluated), /*.halo_width=*/ isText ? constOrDefault(evaluated) : constOrDefault(evaluated), diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index d3e4cf20f..6d0e786f6 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -150,7 +150,7 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun for (auto i = beg; i != end; ++i) { const auto& tileID = f(*i); - const int32_t stencilID = nextStencilID + 1; + const int32_t stencilID = nextStencilID; const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID)); if (result.second) { // inserted diff --git a/src/mbgl/renderer/pattern_atlas.cpp b/src/mbgl/renderer/pattern_atlas.cpp index 3e2e02919..62dd147f4 100644 --- a/src/mbgl/renderer/pattern_atlas.cpp +++ b/src/mbgl/renderer/pattern_atlas.cpp @@ -107,18 +107,14 @@ void PatternAtlas::upload([[maybe_unused]] gfx::UploadPass& uploadPass) { dirty = false; } +#if MLN_LEGACY_RENDERER // @note: Deprecated gfx::TextureBinding PatternAtlas::textureBinding() const { -#if MLN_DRAWABLE_RENDERER - assert(atlasTexture2D); - assert(!dirty); - return {atlasTexture2D->getResource(), gfx::TextureFilterType::Linear}; -#else assert(atlasTexture); assert(!dirty); return {atlasTexture->getResource(), gfx::TextureFilterType::Linear}; -#endif } +#endif #if MLN_DRAWABLE_RENDERER const std::shared_ptr& PatternAtlas::texture() const { diff --git a/src/mbgl/renderer/pattern_atlas.hpp b/src/mbgl/renderer/pattern_atlas.hpp index 3dd87e8d7..a782a7917 100644 --- a/src/mbgl/renderer/pattern_atlas.hpp +++ b/src/mbgl/renderer/pattern_atlas.hpp @@ -32,9 +32,10 @@ public: std::optional addPattern(const style::Image::Impl&); void removePattern(const std::string&); - gfx::TextureBinding textureBinding() const; // @TODO: Migrate #if MLN_DRAWABLE_RENDERER const std::shared_ptr& texture() const; +#else + gfx::TextureBinding textureBinding() const; // @TODO: Migrate #endif void upload(gfx::UploadPass&); diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index a60ff5d9e..d6c813b83 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -58,6 +58,9 @@ private: void upload(gfx::UploadPass& pass) const override { layer.get().upload(pass); } void render(PaintParameters& parameters) const override { layer.get().render(parameters); } const std::string& getName() const override { return layer.get().getID(); } +#if MLN_DRAWABLE_RENDERER + void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override{}; +#endif }; class RenderTreeImpl final : public RenderTree { @@ -772,6 +775,16 @@ void RenderOrchestrator::clearData() { if (!layerImpls->empty()) layerImpls = makeMutable>>(); if (!imageImpls->empty()) imageImpls = makeMutable>>(); +#if MLN_DRAWABLE_RENDERER + UniqueChangeRequestVec changes; + for (const auto& entry : renderLayers) { + entry.second->layerRemoved(changes); + } + addChanges(changes); + + debugLayerGroups.clear(); +#endif + renderSources.clear(); renderLayers.clear(); @@ -805,36 +818,42 @@ void RenderOrchestrator::updateLayerGroupOrder() { bool RenderOrchestrator::addLayerGroup(LayerGroupBasePtr layerGroup, const bool replace) { const auto index = layerGroup->getLayerIndex(); - const auto result = layerGroupsByLayerIndex.insert(std::make_pair(index, LayerGroupBasePtr{})); - if (result.second) { - // added - result.first->second = std::move(layerGroup); - return true; - } else { - // not added - if (replace) { - onRemoveLayerGroup(*result.first->second); - result.first->second = std::move(layerGroup); - return true; - } else { - return false; + auto range = layerGroupsByLayerIndex.equal_range(index); + bool found = false; + for (auto it = range.first; it != range.second; ++it) { + if (it->second == layerGroup) { + found = true; + if (replace) { + onRemoveLayerGroup(*it->second); + it->second = std::move(layerGroup); + } + break; } } + if (found) + return replace; + else { + layerGroupsByLayerIndex.insert(std::make_pair(index, std::move(layerGroup))); + } + return true; } bool RenderOrchestrator::removeLayerGroup(const int32_t layerIndex) { - const auto hit = layerGroupsByLayerIndex.find(layerIndex); - if (hit != layerGroupsByLayerIndex.end()) { + LayerGroupMap::const_iterator hit; + bool removed = false; + while ((hit = layerGroupsByLayerIndex.find(layerIndex)) != layerGroupsByLayerIndex.end()) { onRemoveLayerGroup(*hit->second); layerGroupsByLayerIndex.erase(hit); - return true; - } else { - return false; + removed = true; } + return removed; } -size_t RenderOrchestrator::numLayerGroups() const noexcept { - return layerGroupsByLayerIndex.size(); +int32_t RenderOrchestrator::maxLayerIndex() const { + if (!layerGroupsByLayerIndex.empty()) { + return layerGroupsByLayerIndex.crbegin()->second->getLayerIndex(); + } + return -1; } static const LayerGroupBasePtr no_group; @@ -918,17 +937,40 @@ bool RenderOrchestrator::removeRenderTarget(const RenderTargetPtr& renderTarget) } } -void RenderOrchestrator::observeRenderTargets(std::function f) { +void RenderOrchestrator::visitRenderTargets(std::function f) { for (auto& renderTarget : renderTargets) { f(*renderTarget); } } -void RenderOrchestrator::observeRenderTargets(std::function f) const { +void RenderOrchestrator::visitRenderTargets(std::function f) const { for (const auto& renderTarget : renderTargets) { f(*renderTarget); } } + +void RenderOrchestrator::updateDebugLayerGroups(const RenderTree& renderTree, PaintParameters& parameters) { + for (const RenderItem& item : renderTree.getSourceRenderItems()) { + item.updateDebugDrawables(debugLayerGroups, parameters); + } +} + +void RenderOrchestrator::visitDebugLayerGroups(std::function f) { + for (auto& pair : debugLayerGroups) { + if (pair.second) { + f(*pair.second); + } + } +} + +void RenderOrchestrator::visitDebugLayerGroups(std::function f) const { + for (const auto& pair : debugLayerGroups) { + if (pair.second) { + f(*pair.second); + } + } +} + #endif // MLN_DRAWABLE_RENDERER void RenderOrchestrator::onGlyphsError(const FontStack& fontStack, diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index 830db2fb9..ba751f2a9 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -100,7 +100,7 @@ public: #if MLN_DRAWABLE_RENDERER bool addLayerGroup(LayerGroupBasePtr, bool replace); bool removeLayerGroup(const int32_t layerIndex); - size_t numLayerGroups() const noexcept; + int32_t maxLayerIndex() const; const LayerGroupBasePtr& getLayerGroup(const int32_t layerIndex) const; void visitLayerGroups(std::function); void visitLayerGroups(std::function) const; @@ -117,8 +117,12 @@ public: bool addRenderTarget(RenderTargetPtr); bool removeRenderTarget(const RenderTargetPtr&); - void observeRenderTargets(std::function f); - void observeRenderTargets(std::function f) const; + void visitRenderTargets(std::function f); + void visitRenderTargets(std::function f) const; + + void updateDebugLayerGroups(const RenderTree& renderTree, PaintParameters& parameters); + void visitDebugLayerGroups(std::function); + void visitDebugLayerGroups(std::function) const; #endif const ZoomHistory& getZoomHistory() const { return zoomHistory; } @@ -195,11 +199,12 @@ private: #if MLN_DRAWABLE_RENDERER std::vector> pendingChanges; - using LayerGroupMap = std::map; + using LayerGroupMap = std::multimap; LayerGroupMap layerGroupsByLayerIndex; bool layerGroupOrderDirty = false; std::vector renderTargets; + RenderItem::DebugLayerGroupMap debugLayerGroups; #endif }; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 9bb5f79b7..f700d9ffe 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -107,11 +107,6 @@ const gfx::Texture2DPtr& RenderTile::getGlyphAtlasTexture() const { return renderData ? renderData->getGlyphAtlasTexture() : noTexture; } -gfx::TextureBinding RenderTile::getGlyphAtlasTextureBinding(gfx::TextureFilterType filter) const { - assert(renderData && renderData->getGlyphAtlasTexture()); - return {getGlyphAtlasTexture()->getResource(), filter}; -} - bool RenderTile::hasIconAtlasTexture() const { return renderData && renderData->getIconAtlasTexture(); } @@ -120,11 +115,6 @@ const gfx::Texture2DPtr& RenderTile::getIconAtlasTexture() const { return renderData ? renderData->getIconAtlasTexture() : noTexture; } -gfx::TextureBinding RenderTile::getIconAtlasTextureBinding(gfx::TextureFilterType filter) const { - assert(renderData && renderData->getIconAtlasTexture()); - return {getIconAtlasTexture()->getResource(), filter}; -} - 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 064765bae..b7daa2470 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -65,13 +65,13 @@ public: #if MLN_DRAWABLE_RENDERER bool hasGlyphAtlasTexture() const; const gfx::Texture2DPtr& getGlyphAtlasTexture() const; - gfx::TextureBinding getGlyphAtlasTextureBinding(gfx::TextureFilterType) const; bool hasIconAtlasTexture() const; const gfx::Texture2DPtr& getIconAtlasTexture() const; - gfx::TextureBinding getIconAtlasTextureBinding(gfx::TextureFilterType) const; const std::shared_ptr& getAtlasTextures() const; + + bool getNeedsRendering() const { return needsRendering; }; #else gfx::TextureBinding getGlyphAtlasTextureBinding(gfx::TextureFilterType) const; gfx::TextureBinding getIconAtlasTextureBinding(gfx::TextureFilterType) const; diff --git a/src/mbgl/renderer/render_tree.hpp b/src/mbgl/renderer/render_tree.hpp index e6a25d0c7..42383dec0 100644 --- a/src/mbgl/renderer/render_tree.hpp +++ b/src/mbgl/renderer/render_tree.hpp @@ -17,15 +17,29 @@ class PatternAtlas; namespace gfx { class UploadPass; +class Context; } // namespace gfx +class LayerGroupBase; +using LayerGroupBasePtr = std::shared_ptr; + class RenderItem { public: + enum class DebugType { + TextOutline, + Text, + Border + }; + using DebugLayerGroupMap = std::map; + virtual ~RenderItem() = default; virtual void upload(gfx::UploadPass&) const = 0; virtual void render(PaintParameters&) const = 0; virtual bool hasRenderPass(RenderPass) const = 0; virtual const std::string& getName() const = 0; +#if MLN_DRAWABLE_RENDERER + virtual void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const = 0; +#endif }; using RenderItems = std::vector>; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 5cf5aeacd..426609eaf 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -23,6 +23,8 @@ #include #include #include + +#include #endif #if (MLN_LEGACY_RENDERER && MLN_DRAWABLE_RENDERER) @@ -91,6 +93,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const auto& renderTreeParameters = renderTree.getParameters(); staticData->has3D = renderTreeParameters.has3D; + staticData->backendSize = backend.getDefaultRenderable().getSize(); if (renderState == RenderState::Never) { observer->onWillStartRenderingMap(); @@ -140,7 +143,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, *staticData->shaders, context, renderTreeParameters.transformParams.state, updateParameters, renderTree); } - // Run changes + // Process changes orchestrator.processChanges(); // Run layer tweakers to update any dynamic elements @@ -150,6 +153,9 @@ void Renderer::Impl::render(const RenderTree& renderTree, } }); + // Update the debug layer groups + orchestrator.updateDebugLayerGroups(renderTree, parameters); + // Give the layers a chance to do setup // orchestrator.visitLayerGroups([&](LayerGroup& layerGroup) { layerGroup.preRender(orchestrator, parameters); // }); @@ -162,7 +168,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); }); // Give the render targets a chance to upload - orchestrator.observeRenderTargets([&](RenderTarget& renderTarget) { renderTarget.upload(*uploadPass); }); + orchestrator.visitRenderTargets([&](RenderTarget& renderTarget) { renderTarget.upload(*uploadPass); }); + + // Upload the Debug layer group + orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); }); } #endif @@ -219,7 +228,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, #if MLN_DRAWABLE_RENDERER const auto drawableTargetsPass = [&] { // draw render targets - orchestrator.observeRenderTargets( + orchestrator.visitRenderTargets( [&](RenderTarget& renderTarget) { renderTarget.render(orchestrator, renderTree, parameters); }); }; #endif @@ -246,31 +255,28 @@ void Renderer::Impl::render(const RenderTree& renderTree, // Drawables const auto drawableOpaquePass = [&] { const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-opaque")); + const auto maxLayerIndex = orchestrator.maxLayerIndex(); parameters.pass = RenderPass::Opaque; parameters.currentLayer = 0; - parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers * - PaintParameters::depthEpsilon; + parameters.depthRangeSize = 1 - (maxLayerIndex + 3) * parameters.numSublayers * PaintParameters::depthEpsilon; // draw layer groups, opaque pass orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { + parameters.currentLayer = layerGroup.getLayerIndex(); layerGroup.render(orchestrator, parameters); - parameters.currentLayer++; }); }; const auto drawableTranslucentPass = [&] { const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-translucent")); + const auto maxLayerIndex = orchestrator.maxLayerIndex(); parameters.pass = RenderPass::Translucent; - parameters.currentLayer = static_cast(orchestrator.numLayerGroups()) - 1; - parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers * - PaintParameters::depthEpsilon; + parameters.depthRangeSize = 1 - (maxLayerIndex + 3) * parameters.numSublayers * PaintParameters::depthEpsilon; // draw layer groups, translucent pass orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { + parameters.currentLayer = maxLayerIndex - layerGroup.getLayerIndex(); layerGroup.render(orchestrator, parameters); - if (parameters.currentLayer != 0) { - parameters.currentLayer--; - } }); }; #endif @@ -313,6 +319,45 @@ void Renderer::Impl::render(const RenderTree& renderTree, }; #endif // MLN_LEGACY_RENDERER +#if MLN_DRAWABLE_RENDERER + const auto drawableDebugOverlays = [&] { + // Renders debug overlays. + { + const auto debugGroup(parameters.renderPass->createDebugGroup("debug")); + orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) { + layerGroup.visitDrawables([&](gfx::Drawable& drawable) { drawable.draw(parameters); }); + }); + } + }; +#endif // MLN_DRAWABLE_RENDERER + +#if MLN_LEGACY_RENDERER + const auto renderDebugOverlays = [&] { + // Renders debug overlays. + { + const auto debugGroup(parameters.renderPass->createDebugGroup("debug")); + + // Finalize the rendering, e.g. by calling debug render calls per tile. + // This guarantees that we have at least one function per tile called. + // When only rendering layers via the stylesheet, it's possible that we + // don't ever visit a tile during rendering. + for (const RenderItem& renderItem : sourceRenderItems) { + renderItem.render(parameters); + } + } + +#if !defined(NDEBUG) + if (parameters.debugOptions & MapDebugOptions::StencilClip) { + // Render tile clip boundaries, using stencil buffer to calculate fill color. + parameters.context.visualizeStencilBuffer(); + } else if (parameters.debugOptions & MapDebugOptions::DepthBuffer) { + // Render the depth buffer. + parameters.context.visualizeDepthBuffer(parameters.depthRangeSize); + } +#endif + }; +#endif // MLN_LEGACY_RENDERER + #if (MLN_DRAWABLE_RENDERER && !MLN_LEGACY_RENDERER) if (parameters.staticData.has3D) { common3DPass(); @@ -322,6 +367,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, commonClearPass(); drawableOpaquePass(); drawableTranslucentPass(); + drawableDebugOverlays(); #elif (MLN_LEGACY_RENDERER && !MLN_DRAWABLE_RENDERER) if (parameters.staticData.has3D) { common3DPass(); @@ -330,6 +376,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, commonClearPass(); renderLayerOpaquePass(); renderLayerTranslucentPass(); + renderDebugOverlays(); #elif (MLN_DRAWABLE_RENDERER && MLN_LEGACY_RENDERER) #if MLN_RENDERER_SPLIT_VIEW [[maybe_unused]] const auto W = backend.getDefaultRenderable().getSize().width; @@ -384,6 +431,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, parameters.clearTileClippingMasks(); drawableOpaquePass(); drawableTranslucentPass(); + drawableDebugOverlays(); // RenderLayers on the right platform::glScissor(halfW, 0, W, H); @@ -391,6 +439,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, parameters.clearTileClippingMasks(); renderLayerOpaquePass(); renderLayerTranslucentPass(); + renderDebugOverlays(); #endif // MLN_RENDERER_QUAD_SPLIT_VIEW // Reset viewport platform::glScissor(0, 0, W, H); @@ -409,38 +458,14 @@ void Renderer::Impl::render(const RenderTree& renderTree, drawableOpaquePass(); drawableTranslucentPass(); + + renderDebugOverlays(); + drawableDebugOverlays(); #endif // MLN_RENDERER_SPLIT_VIEW #else static_assert(0, "Must define one of (MLN_DRAWABLE_RENDERER, MLN_LEGACY_RENDERER)"); #endif -#if MLN_LEGACY_RENDERER - // - DEBUG PASS - // -------------------------------------------------------------------------------- - // Renders debug overlays. - { - const auto debugGroup(parameters.renderPass->createDebugGroup("debug")); - - // Finalize the rendering, e.g. by calling debug render calls per tile. - // This guarantees that we have at least one function per tile called. - // When only rendering layers via the stylesheet, it's possible that we - // don't ever visit a tile during rendering. - for (const RenderItem& renderItem : sourceRenderItems) { - renderItem.render(parameters); - } - } - -#if !defined(NDEBUG) - if (parameters.debugOptions & MapDebugOptions::StencilClip) { - // Render tile clip boundaries, using stencil buffer to calculate fill color. - parameters.context.visualizeStencilBuffer(); - } else if (parameters.debugOptions & MapDebugOptions::DepthBuffer) { - // Render the depth buffer. - parameters.context.visualizeDepthBuffer(parameters.depthRangeSize); - } -#endif -#endif // MLN_LEGACY_RENDERER - #if MLN_DRAWABLE_RENDERER // Give the layers a chance to do cleanup orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.postRender(orchestrator, parameters); }); diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 7e461eee1..ab74a9745 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -25,6 +25,9 @@ private: bool hasRenderPass(RenderPass) const override { return false; } const std::string& getName() const override { return name; } std::string name; +#if MLN_DRAWABLE_RENDERER + void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override{}; +#endif mutable std::optional debugTexture; }; diff --git a/src/mbgl/renderer/sources/render_tile_source.cpp b/src/mbgl/renderer/sources/render_tile_source.cpp index 45b6d87b1..b4f7b0521 100644 --- a/src/mbgl/renderer/sources/render_tile_source.cpp +++ b/src/mbgl/renderer/sources/render_tile_source.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -10,26 +9,21 @@ #include #include +#if MLN_DRAWABLE_RENDERER +#include +#include +#include +#include +#include +#include + +#include +#endif + namespace mbgl { using namespace style; -class TileSourceRenderItem : public RenderItem { -public: - TileSourceRenderItem(Immutable> renderTiles_, std::string name_) - : renderTiles(std::move(renderTiles_)), - name(std::move(name_)) {} - -private: - void upload(gfx::UploadPass&) const override; - void render(PaintParameters&) const override; - bool hasRenderPass(RenderPass) const override { return false; } - const std::string& getName() const override { return name; } - - Immutable> renderTiles; - std::string name; -}; - void TileSourceRenderItem::upload(gfx::UploadPass& parameters) const { for (auto& tile : *renderTiles) { tile.upload(parameters); @@ -42,6 +36,225 @@ void TileSourceRenderItem::render(PaintParameters& parameters) const { } } +#if MLN_DRAWABLE_RENDERER +void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGroups, + PaintParameters& parameters) const { + if (!(parameters.debugOptions & + (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus | MapDebugOptions::TileBorders))) { + debugLayerGroups.clear(); + return; + } + + // Debug UBO definition + struct alignas(16) DebugUBO { + std::array matrix; + Color color; + float overlay_scale; + float pad1, pad2, pad3; + }; + static_assert(sizeof(DebugUBO) % 16 == 0); + constexpr auto DebugUBOName = "DebugUBO"; + + // initialize + auto& context = parameters.context; + const auto renderPass = RenderPass::None; + auto& shaders = *parameters.staticData.shaders; + constexpr auto DebugShaderName = "DebugShader"; + gfx::ShaderProgramBasePtr debugShader = context.getGenericShader(shaders, std::string(DebugShaderName)); + + // create a builder + constexpr auto VertexAttribName = "a_pos"; + std::unique_ptr builder = context.createDrawableBuilder("debug-builder"); + builder->setShader(debugShader); + builder->setRenderPass(renderPass); + builder->setEnableDepth(false); + builder->setColorMode(gfx::ColorMode::unblended()); + builder->setCullFaceMode(gfx::CullFaceMode::disabled()); + builder->setEnableStencil(false); + builder->setVertexAttrName(VertexAttribName); + + // add or get the layer group for a debug type + const auto addOrGetLayerGroupForType = [&debugLayerGroups, &context]( + DebugType type, + const std::string&& layerName) -> DebugLayerGroupMap::const_iterator { + auto it = debugLayerGroups.find(type); + if (it == debugLayerGroups.end()) { + auto inserted = debugLayerGroups.insert(std::make_pair( + type, context.createTileLayerGroup(static_cast(type), /*initialCapacity=*/64, layerName))); + assert(inserted.second); + it = inserted.first; + } + return it; + }; + + // build a set of tiles to cover + std::unordered_set newTiles; + for (auto& tile : *renderTiles) { + if (tile.getNeedsRendering()) { + newTiles.insert(tile.getOverscaledTileID()); + } + } + + // create texture. to be reused for all the tiles of the debug layers + auto texture = context.createTexture2D(); + std::optional samplerLocation; + { + std::array data{{0, 0, 0, 0}}; + auto emptyImage = std::make_shared(Size(1, 1), data.data(), data.size()); + texture->setImage(emptyImage); + texture->setSamplerConfiguration( + {gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + constexpr auto DebugOverlayUniformName = "u_overlay"; + samplerLocation = debugShader->getSamplerLocation(DebugOverlayUniformName); + } + assert(samplerLocation.has_value()); + if (!samplerLocation.has_value()) return; + + // function to update existing tile drawables with UBO value. return number of updated drawables + const auto updateDrawables = + [&](TileLayerGroup* tileLayerGroup, const OverscaledTileID& tileID, const DebugUBO& debugUBO) -> size_t { + auto updatedCount = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + // update existing drawable + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.createOrUpdate(DebugUBOName, &debugUBO, context); + }); + return updatedCount; + }; + + // function to add drawable + const auto addDrawable = [&](TileLayerGroup* tileLayerGroup, + const OverscaledTileID& tileID, + const DebugUBO& debugUBO, + const gfx::DrawMode mode, + const auto& vertices, + const auto& indexes, + const auto& segments) { + // create new drawable + std::vector> verts(vertices.size()); + std::transform(vertices.begin(), vertices.end(), verts.begin(), [](const auto& v) -> std::array { + return v.a1; + }); + + builder->addVertices(verts, 0, verts.size()); + builder->setSegments(mode, indexes, segments.data(), segments.size()); + // texture + builder->setTexture(texture, samplerLocation.value()); + + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + auto& uniforms = drawable->mutableUniformBuffers(); + uniforms.createOrUpdate(DebugUBOName, &debugUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + } + }; + + // Timestamps or Parse Status + if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { + TileLayerGroup* outlineLayerGroup = static_cast( + addOrGetLayerGroupForType(DebugType::TextOutline, "debug-text-outline")->second.get()); + TileLayerGroup* textLayerGroup = static_cast( + addOrGetLayerGroupForType(DebugType::Text, "debug-text")->second.get()); + + // erase drawables that are not in the current tile set + for (auto& lg : {outlineLayerGroup, textLayerGroup}) { + lg->removeDrawablesIf([&](gfx::Drawable& drawable) { + return !(drawable.getTileID().has_value() && newTiles.count(*drawable.getTileID()) > 0); + }); + } + + // add new drawables and update existing ones + for (auto& tile : *renderTiles) { + if (tile.getNeedsRendering()) { + const auto tileID = tile.getOverscaledTileID(); + const auto& debugBucket = tile.debugBucket; + if (!debugBucket) continue; + + const DebugUBO outlineUBO{/*matrix = */ util::cast(tile.matrix), + /*color = */ Color::white(), + /*overlay_scale = */ 1.0f, + 0, + 0, + 0}; + if (0 == updateDrawables(outlineLayerGroup, tileID, outlineUBO)) { + addDrawable(outlineLayerGroup, + tileID, + outlineUBO, + gfx::Lines(4.0f * parameters.pixelRatio), + debugBucket->vertices.vector(), + debugBucket->indices.vector(), + debugBucket->segments); + } + + const DebugUBO textUBO{/*matrix = */ util::cast(tile.matrix), + /*color = */ Color::black(), + /*overlay_scale = */ 1.0f, + 0, + 0, + 0}; + if (0 == updateDrawables(textLayerGroup, tileID, textUBO)) { + addDrawable(textLayerGroup, + tileID, + textUBO, + gfx::Lines(2.0f * parameters.pixelRatio), + debugBucket->vertices.vector(), + debugBucket->indices.vector(), + debugBucket->segments); + } + } + } + } else { + // tile texts are not required, erase layer groups + debugLayerGroups.erase(DebugType::TextOutline); + debugLayerGroups.erase(DebugType::Text); + } + + // Tile Borders + if (parameters.debugOptions & (MapDebugOptions::TileBorders)) { + TileLayerGroup* tileLayerGroup = static_cast( + addOrGetLayerGroupForType(DebugType::Border, "debug-border")->second.get()); + + // erase drawables that are not in the current tile set + tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) { + return !(drawable.getTileID().has_value() && newTiles.count(*drawable.getTileID()) > 0); + }); + + // add new drawables and update existing ones + auto vertices = RenderStaticData::tileVertices().vector(); + auto indexes = RenderStaticData::tileLineStripIndices().vector(); + auto segments = RenderStaticData::tileBorderSegments(); + for (auto& tile : *renderTiles) { + if (tile.getNeedsRendering()) { + const auto tileID = tile.getOverscaledTileID(); + const auto& debugBucket = tile.debugBucket; + if (!debugBucket) continue; + + const DebugUBO debugUBO{/*matrix = */ util::cast(tile.matrix), + /*color = */ Color::red(), + /*overlay_scale = */ 1.0f, + 0, + 0, + 0}; + if (0 == updateDrawables(tileLayerGroup, tileID, debugUBO)) { + addDrawable(tileLayerGroup, + tileID, + debugUBO, + gfx::LineStrip(4.0f * parameters.pixelRatio), + vertices, + indexes, + segments); + } + } + } + } else { + // if tile borders are not required, erase layer group + debugLayerGroups.erase(DebugType::Border); + } +} +#endif + RenderTileSource::RenderTileSource(Immutable impl_) : RenderSource(std::move(impl_)), renderTiles(makeMutable>()) { diff --git a/src/mbgl/renderer/sources/render_tile_source.hpp b/src/mbgl/renderer/sources/render_tile_source.hpp index 6ca108e7a..dd10bd4ce 100644 --- a/src/mbgl/renderer/sources/render_tile_source.hpp +++ b/src/mbgl/renderer/sources/render_tile_source.hpp @@ -4,6 +4,11 @@ #include #include #include +#include + +#if MLN_DRAWABLE_RENDERER +#include +#endif namespace mbgl { @@ -84,4 +89,24 @@ private: std::optional cachedTileset; }; +class TileSourceRenderItem : public RenderItem { +public: + TileSourceRenderItem(Immutable> renderTiles_, std::string name_) + : renderTiles(std::move(renderTiles_)), + name(std::move(name_)) {} + +private: + void upload(gfx::UploadPass&) const override; + void render(PaintParameters&) const override; + bool hasRenderPass(RenderPass) const override { return false; } + const std::string& getName() const override { return name; } + +#if MLN_DRAWABLE_RENDERER + void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override; +#endif + + Immutable> renderTiles; + std::string name; +}; + } // namespace mbgl diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 022f90a7f..e42b817d5 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -952,10 +952,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, if (bucket.hasTextData()) bucket.text.sharedOpacityVertices->clear(); if (bucket.hasIconData()) bucket.icon.sharedOpacityVertices->clear(); if (bucket.hasSdfIconData()) bucket.sdfIcon.sharedOpacityVertices->clear(); - if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox->dynamicVertices.clear(); - if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle->dynamicVertices.clear(); - if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices.clear(); - if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices.clear(); + if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox->dynamicVertices().clear(); + if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle->dynamicVertices().clear(); + if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices().clear(); + if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices().clear(); const JointOpacityState duplicateOpacityState(false, false, true); @@ -1056,7 +1056,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, return; } const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, shift); - bucket.iconCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex); + bucket.iconCollisionBox->dynamicVertices().extend(feature.boxes.size() * 4, dynamicVertex); }; auto updateTextCollisionBox = @@ -1092,7 +1092,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, } } const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !used, shift); - bucket.textCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex); + bucket.textCollisionBox->dynamicVertices().extend(feature.boxes.size() * 4, dynamicVertex); return shift; }; @@ -1104,15 +1104,15 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, if (circles != collisionCircles.end()) { for (const auto& circle : circles->second) { const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !circle.isCircle(), {}); - isText ? bucket.textCollisionCircle->dynamicVertices.extend(4, dynamicVertex) - : bucket.iconCollisionCircle->dynamicVertices.extend(4, dynamicVertex); + isText ? bucket.textCollisionCircle->dynamicVertices().extend(4, dynamicVertex) + : bucket.iconCollisionCircle->dynamicVertices().extend(4, dynamicVertex); } } else { // This feature was not placed, because it was not loaded or // from a fading tile. Apply default values. static const auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false /*not used*/, {}); - isText ? bucket.textCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex) - : bucket.iconCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex); + isText ? bucket.textCollisionCircle->dynamicVertices().extend(4 * feature.boxes.size(), dynamicVertex) + : bucket.iconCollisionCircle->dynamicVertices().extend(4 * feature.boxes.size(), dynamicVertex); } }; Point textShift{0.0f, 0.0f};