From 9ba646e9626a6f3cff911577687f827aa3758940 Mon Sep 17 00:00:00 2001 From: Tim Sylvester Date: Tue, 27 Jun 2023 12:26:54 -0700 Subject: [PATCH] Topic/drawable symbol (#1249) --- CMakeLists.txt | 11 +- bazel/core.bzl | 29 +- include/mbgl/gfx/drawable.hpp | 4 +- include/mbgl/renderer/change_request.hpp | 4 +- include/mbgl/renderer/layer_group.hpp | 12 +- .../mbgl/shaders/gl/drawable_symbol_icon.hpp | 183 ++++++ .../shaders/gl/drawable_symbol_sdf_icon.hpp | 313 ++++++++++ .../shaders/gl/drawable_symbol_sdf_text.hpp | 313 ++++++++++ .../gl/drawable_symbol_text_and_icon.hpp | 330 +++++++++++ include/mbgl/shaders/gl/prelude.hpp | 2 + include/mbgl/shaders/gl/symbol_icon.hpp | 4 +- include/mbgl/shaders/gl/symbol_sdf_icon.hpp | 4 +- include/mbgl/shaders/gl/symbol_sdf_text.hpp | 4 +- .../mbgl/shaders/gl/symbol_text_and_icon.hpp | 4 +- include/mbgl/shaders/shader_manifest.hpp | 4 + include/mbgl/shaders/shader_source.hpp | 4 + platform/ios/BUILD.bazel | 1 + shaders/_prelude.vertex.glsl | 2 + shaders/drawable.symbol_icon.fragment.glsl | 35 ++ shaders/drawable.symbol_icon.vertex.glsl | 121 ++++ shaders/drawable.symbol_sdf.fragment.glsl | 96 +++ shaders/drawable.symbol_sdf.vertex.glsl | 146 +++++ ...rawable.symbol_text_and_icon.fragment.glsl | 113 ++++ .../drawable.symbol_text_and_icon.vertex.glsl | 146 +++++ shaders/manifest.json | 28 + shaders/symbol_icon.vertex.glsl | 2 - shaders/symbol_sdf.vertex.glsl | 2 - shaders/symbol_text_and_icon.vertex.glsl | 2 - src/mbgl/gfx/symbol_drawable_data.hpp | 43 ++ src/mbgl/gl/drawable_gl.cpp | 8 +- src/mbgl/gl/renderer_backend.cpp | 6 +- src/mbgl/renderer/change_request.cpp | 11 +- src/mbgl/renderer/layer_group.cpp | 6 +- .../renderer/layers/raster_layer_tweaker.cpp | 2 +- .../layers/render_background_layer.cpp | 24 +- .../renderer/layers/render_circle_layer.cpp | 24 +- .../renderer/layers/render_fill_layer.cpp | 24 +- .../renderer/layers/render_raster_layer.cpp | 40 +- .../renderer/layers/render_raster_layer.hpp | 5 + .../renderer/layers/render_symbol_layer.cpp | 549 +++++++++++++++++- .../renderer/layers/render_symbol_layer.hpp | 30 + .../renderer/layers/symbol_layer_tweaker.cpp | 173 ++++++ .../renderer/layers/symbol_layer_tweaker.hpp | 56 ++ src/mbgl/renderer/render_layer.cpp | 73 ++- src/mbgl/renderer/render_layer.hpp | 25 +- src/mbgl/renderer/render_orchestrator.cpp | 10 +- src/mbgl/renderer/tile_layer_group.cpp | 6 +- 47 files changed, 2860 insertions(+), 174 deletions(-) create mode 100644 include/mbgl/shaders/gl/drawable_symbol_icon.hpp create mode 100644 include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp create mode 100644 include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp create mode 100644 include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp create mode 100644 shaders/drawable.symbol_icon.fragment.glsl create mode 100644 shaders/drawable.symbol_icon.vertex.glsl create mode 100644 shaders/drawable.symbol_sdf.fragment.glsl create mode 100644 shaders/drawable.symbol_sdf.vertex.glsl create mode 100644 shaders/drawable.symbol_text_and_icon.fragment.glsl create mode 100644 shaders/drawable.symbol_text_and_icon.vertex.glsl create mode 100644 src/mbgl/gfx/symbol_drawable_data.hpp create mode 100644 src/mbgl/renderer/layers/symbol_layer_tweaker.cpp create mode 100644 src/mbgl/renderer/layers/symbol_layer_tweaker.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d039cc9c8..872e9b4be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,6 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_impl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_builder.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_tweaker.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_block.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_buffer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/vertex_attribute.hpp @@ -170,7 +169,8 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_tweaker.cpp - + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_group.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/symbol_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 @@ -186,6 +186,8 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/fill_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.cpp ${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/shaders/shader_program_base.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program_mtl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/identity.cpp @@ -450,7 +452,6 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/renderer_backend.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/rendering_stats.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_registry.cpp - ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/stencil_mode.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/texture.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform.hpp @@ -987,6 +988,10 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_raster.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_icon.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/background_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/circle.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/clipping_mask.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index 3c9b16003..d2d153976 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -45,7 +45,6 @@ MLN_CORE_SOURCE = [ "src/mbgl/gfx/depth_mode.hpp", "src/mbgl/gfx/draw_mode.hpp", "src/mbgl/gfx/draw_scope.hpp", - "src/mbgl/gfx/image_drawable_data.hpp", "src/mbgl/gfx/index_buffer.hpp", "src/mbgl/gfx/index_vector.hpp", "src/mbgl/gfx/offscreen_texture.hpp", @@ -831,9 +830,13 @@ MLN_OPENGL_HEADERS = [ "include/mbgl/style/layers/location_indicator_layer.hpp", "include/mbgl/shaders/shader_source.hpp", "include/mbgl/shaders/shader_manifest.hpp", - "include/mbgl/shaders/gl/shader_group_gl.hpp", - "include/mbgl/shaders/gl/prelude.hpp", "include/mbgl/shaders/gl/background.hpp", + "include/mbgl/shaders/gl/background_pattern.hpp", + "include/mbgl/shaders/gl/circle.hpp", + "include/mbgl/shaders/gl/clipping_mask.hpp", + "include/mbgl/shaders/gl/collision_box.hpp", + "include/mbgl/shaders/gl/collision_circle.hpp", + "include/mbgl/shaders/gl/debug.hpp", "include/mbgl/shaders/gl/drawable_background.hpp", "include/mbgl/shaders/gl/drawable_background_pattern.hpp", "include/mbgl/shaders/gl/drawable_circle.hpp", @@ -842,12 +845,10 @@ MLN_OPENGL_HEADERS = [ "include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp", "include/mbgl/shaders/gl/drawable_fill_pattern.hpp", "include/mbgl/shaders/gl/drawable_raster.hpp", - "include/mbgl/shaders/gl/background_pattern.hpp", - "include/mbgl/shaders/gl/circle.hpp", - "include/mbgl/shaders/gl/clipping_mask.hpp", - "include/mbgl/shaders/gl/collision_box.hpp", - "include/mbgl/shaders/gl/collision_circle.hpp", - "include/mbgl/shaders/gl/debug.hpp", + "include/mbgl/shaders/gl/drawable_symbol_icon.hpp", + "include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp", + "include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp", + "include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp", "include/mbgl/shaders/gl/fill_extrusion_pattern.hpp", "include/mbgl/shaders/gl/fill_extrusion.hpp", "include/mbgl/shaders/gl/fill_outline_pattern.hpp", @@ -862,7 +863,9 @@ MLN_OPENGL_HEADERS = [ "include/mbgl/shaders/gl/line_pattern.hpp", "include/mbgl/shaders/gl/line_sdf.hpp", "include/mbgl/shaders/gl/line.hpp", + "include/mbgl/shaders/gl/prelude.hpp", "include/mbgl/shaders/gl/raster.hpp", + "include/mbgl/shaders/gl/shader_group_gl.hpp", "include/mbgl/shaders/gl/symbol_icon.hpp", "include/mbgl/shaders/gl/symbol_sdf_text.hpp", "include/mbgl/shaders/gl/symbol_sdf_icon.hpp", @@ -874,6 +877,8 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/gfx/drawable_builder.cpp", "src/mbgl/gfx/drawable_builder_impl.hpp", "src/mbgl/gfx/drawable_tweaker.cpp", + "src/mbgl/gfx/image_drawable_data.hpp", + "src/mbgl/gfx/symbol_drawable_data.hpp", "src/mbgl/gfx/uniform_block.cpp", "src/mbgl/gfx/uniform_buffer.cpp", "src/mbgl/gfx/vertex_attribute.cpp", @@ -889,10 +894,12 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/renderer/layers/fill_layer_tweaker.hpp", "src/mbgl/renderer/layers/raster_layer_tweaker.cpp", "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/shaders/shader_program_base.cpp", "src/mbgl/shaders/mtl/shader_program_mtl.cpp", - "src/mbgl/util/identity.cpp", "src/mbgl/shaders/gl/shader_program_gl.cpp", + "src/mbgl/util/identity.cpp", "src/mbgl/gl/drawable_gl.cpp", "src/mbgl/gl/drawable_gl_builder.cpp", "src/mbgl/gl/drawable_gl_impl.hpp", @@ -930,4 +937,4 @@ MLN_DRAWABLES_HEADERS = [ "include/mbgl/gl/uniform_buffer_gl.hpp", "include/mbgl/gl/vertex_attribute_gl.hpp", "include/mbgl/gl/texture2d.hpp" -] \ No newline at end of file +] diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index e4cd6c2c7..fb58f562c 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -159,7 +159,7 @@ public: static_cast(components[3])}; } - virtual const std::optional& getData() const { return drawableData; } + virtual const UniqueDrawableData& getData() const { return drawableData; } virtual void setData(UniqueDrawableData&& value) { drawableData = std::move(value); } protected: @@ -174,7 +174,7 @@ protected: int32_t lineWidth = 1; int32_t subLayerIndex = 0; DepthMaskType depthType; // = DepthMaskType::ReadOnly; - std::optional drawableData{}; + UniqueDrawableData drawableData{}; struct Impl; std::unique_ptr impl; diff --git a/include/mbgl/renderer/change_request.hpp b/include/mbgl/renderer/change_request.hpp index 5d3ddf4a5..064287cbc 100644 --- a/include/mbgl/renderer/change_request.hpp +++ b/include/mbgl/renderer/change_request.hpp @@ -79,13 +79,13 @@ protected: class UpdateLayerGroupIndexRequest : public ChangeRequest { public: - UpdateLayerGroupIndexRequest(std::shared_ptr tileLayerGroup_, int32_t newLayerIndex_); + UpdateLayerGroupIndexRequest(LayerGroupBasePtr, int32_t newLayerIndex_); UpdateLayerGroupIndexRequest(const UpdateLayerGroupIndexRequest &) = delete; void execute(RenderOrchestrator &) override; protected: - std::shared_ptr tileLayerGroup; + LayerGroupBasePtr layerGroup; int32_t newLayerIndex; }; diff --git a/include/mbgl/renderer/layer_group.hpp b/include/mbgl/renderer/layer_group.hpp index 38e72124b..d29b5bdf2 100644 --- a/include/mbgl/renderer/layer_group.hpp +++ b/include/mbgl/renderer/layer_group.hpp @@ -50,9 +50,13 @@ public: int32_t getLayerIndex() const { return layerIndex; } + void updateLayerIndex(int32_t value) { layerIndex = value; } + virtual std::size_t getDrawableCount() const = 0; bool empty() const { return getDrawableCount() == 0; } + virtual std::size_t clearDrawables() = 0; + /// Called before starting each frame virtual void preRender(RenderOrchestrator&, PaintParameters&) {} /// Called during the upload pass @@ -90,8 +94,6 @@ public: TileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name); ~TileLayerGroup() override; - void updateLayerIndex(int32_t newLayerIndex); - std::size_t getDrawableCount() const override; std::size_t getDrawableCount(mbgl::RenderPass, const OverscaledTileID&) const; @@ -106,7 +108,7 @@ public: void observeDrawables(mbgl::RenderPass, const OverscaledTileID&, std::function&&); void observeDrawables(mbgl::RenderPass, const OverscaledTileID&, std::function&&) const; - std::size_t clearDrawables(); + std::size_t clearDrawables() override; protected: struct Impl; @@ -121,8 +123,6 @@ public: LayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name); ~LayerGroup() override; - void updateLayerIndex(int32_t newLayerIndex); - std::size_t getDrawableCount() const override; std::size_t getDrawableCount(mbgl::RenderPass) const; @@ -133,7 +133,7 @@ public: void observeDrawables(std::function) const override; void observeDrawables(std::function) override; - std::size_t clearDrawables(); + std::size_t clearDrawables() override; protected: struct Impl; diff --git a/include/mbgl/shaders/gl/drawable_symbol_icon.hpp b/include/mbgl/shaders/gl/drawable_symbol_icon.hpp new file mode 100644 index 000000000..3ed326a2b --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_symbol_icon.hpp @@ -0,0 +1,183 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "SymbolIconShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec4 a_pixeloffset; +layout (location = 3) in vec3 a_projected_pos; +layout (location = 4) in float a_fade_opacity; + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec2 v_tex; +out float v_fade_opacity; + +#ifndef HAS_UNIFORM_u_opacity +layout (location = 5) in lowp vec2 a_opacity; +out lowp float opacity; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + vec2 a_pxoffset = a_pixeloffset.xy; + vec2 a_minFontScale = a_pixeloffset.zw / 256.0; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // See comments in symbol_sdf.vertex + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // See comments in symbol_sdf.vertex + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * max(a_minFontScale, fontScale) + a_pxoffset / 16.0), 0.0, 1.0); + + v_tex = a_tex / u_texsize; + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + v_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); +} +)"; + static constexpr const char* fragment = R"(uniform sampler2D u_texture; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +in vec2 v_tex; +in float v_fade_opacity; + +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + + lowp float alpha = opacity * v_fade_opacity; + fragColor = texture(u_texture, v_tex) * alpha; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp b/include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp new file mode 100644 index 000000000..132b2894c --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp @@ -0,0 +1,313 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "SymbolSDFIconShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec4 a_pixeloffset; +layout (location = 3) in vec3 a_projected_pos; +layout (location = 4) in float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec2 v_data0; +out vec3 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +layout (location = 5) in highp vec4 a_fill_color; +out highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +layout (location = 6) in highp vec4 a_halo_color; +out highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 7) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +layout (location = 8) in lowp vec2 a_halo_width; +out lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +layout (location = 9) in lowp vec2 a_halo_blur; +out lowp float halo_blur; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_fill_color +fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); +#else +highp vec4 fill_color = u_fill_color; +#endif + #ifndef HAS_UNIFORM_u_halo_color +halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); +#else +highp vec4 halo_color = u_halo_color; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_halo_width +halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); +#else +lowp float halo_width = u_halo_width; +#endif + #ifndef HAS_UNIFORM_u_halo_blur +halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); +#else +lowp float halo_blur = u_halo_blur; +#endif + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + vec2 a_pxoffset = a_pixeloffset.xy; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale + a_pxoffset), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0 = a_tex / u_texsize; + v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); +} +)"; + static constexpr const char* fragment = R"(#define SDF_PX 8.0 + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +uniform sampler2D u_texture; + +in vec2 v_data0; +in vec3 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +in highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +in highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +in lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +in lowp float halo_blur; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_fill_color +highp vec4 fill_color = u_fill_color; +#endif + #ifdef HAS_UNIFORM_u_halo_color +highp vec4 halo_color = u_halo_color; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + #ifdef HAS_UNIFORM_u_halo_width +lowp float halo_width = u_halo_width; +#endif + #ifdef HAS_UNIFORM_u_halo_blur +lowp float halo_blur = u_halo_blur; +#endif + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + vec2 tex = v_data0.xy; + float gamma_scale = v_data1.x; + float size = v_data1.y; + float fade_opacity = v_data1[2]; + + float fontScale = u_is_text ? size / 24.0 : size; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + fragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp b/include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp new file mode 100644 index 000000000..527c4fad5 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp @@ -0,0 +1,313 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "SymbolSDFTextShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec4 a_pixeloffset; +layout (location = 3) in vec3 a_projected_pos; +layout (location = 4) in float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec2 v_data0; +out vec3 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +layout (location = 5) in highp vec4 a_fill_color; +out highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +layout (location = 6) in highp vec4 a_halo_color; +out highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 7) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +layout (location = 8) in lowp vec2 a_halo_width; +out lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +layout (location = 9) in lowp vec2 a_halo_blur; +out lowp float halo_blur; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_fill_color +fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); +#else +highp vec4 fill_color = u_fill_color; +#endif + #ifndef HAS_UNIFORM_u_halo_color +halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); +#else +highp vec4 halo_color = u_halo_color; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_halo_width +halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); +#else +lowp float halo_width = u_halo_width; +#endif + #ifndef HAS_UNIFORM_u_halo_blur +halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); +#else +lowp float halo_blur = u_halo_blur; +#endif + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + vec2 a_pxoffset = a_pixeloffset.xy; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale + a_pxoffset), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0 = a_tex / u_texsize; + v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); +} +)"; + static constexpr const char* fragment = R"(#define SDF_PX 8.0 + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +uniform sampler2D u_texture; + +in vec2 v_data0; +in vec3 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +in highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +in highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +in lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +in lowp float halo_blur; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_fill_color +highp vec4 fill_color = u_fill_color; +#endif + #ifdef HAS_UNIFORM_u_halo_color +highp vec4 halo_color = u_halo_color; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + #ifdef HAS_UNIFORM_u_halo_width +lowp float halo_width = u_halo_width; +#endif + #ifdef HAS_UNIFORM_u_halo_blur +lowp float halo_blur = u_halo_blur; +#endif + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + vec2 tex = v_data0.xy; + float gamma_scale = v_data1.x; + float size = v_data1.y; + float fade_opacity = v_data1[2]; + + float fontScale = u_is_text ? size / 24.0 : size; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + fragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp b/include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp new file mode 100644 index 000000000..764dc6282 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp @@ -0,0 +1,330 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "SymbolTextAndIconShader"; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec3 a_projected_pos; +layout (location = 3) in float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec4 v_data0; +out vec4 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +layout (location = 4) in highp vec4 a_fill_color; +out highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +layout (location = 5) in highp vec4 a_halo_color; +out highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 6) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +layout (location = 7) in lowp vec2 a_halo_width; +out lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +layout (location = 8) in lowp vec2 a_halo_blur; +out lowp float halo_blur; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_fill_color +fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); +#else +highp vec4 fill_color = u_fill_color; +#endif + #ifndef HAS_UNIFORM_u_halo_color +halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); +#else +highp vec4 halo_color = u_halo_color; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_halo_width +halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); +#else +lowp float halo_width = u_halo_width; +#endif + #ifndef HAS_UNIFORM_u_halo_blur +halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); +#else +lowp float halo_blur = u_halo_blur; +#endif + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + float is_sdf = a_size[0] - 2.0 * a_size_min; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = size / 24.0; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0.xy = a_tex / u_texsize; + v_data0.zw = a_tex / u_texsize_icon; + v_data1 = vec4(gamma_scale, size, interpolated_fade_opacity, is_sdf); +} +)"; + static constexpr const char* fragment = R"(#define SDF_PX 8.0 + +#define SDF 1.0 +#define ICON 0.0 + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +uniform sampler2D u_texture; +uniform sampler2D u_texture_icon; + +in vec4 v_data0; +in vec4 v_data1; + +#ifndef HAS_UNIFORM_u_fill_color +in highp vec4 fill_color; +#endif +#ifndef HAS_UNIFORM_u_halo_color +in highp vec4 halo_color; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_halo_width +in lowp float halo_width; +#endif +#ifndef HAS_UNIFORM_u_halo_blur +in lowp float halo_blur; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_fill_color +highp vec4 fill_color = u_fill_color; +#endif + #ifdef HAS_UNIFORM_u_halo_color +highp vec4 halo_color = u_halo_color; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + #ifdef HAS_UNIFORM_u_halo_width +lowp float halo_width = u_halo_width; +#endif + #ifdef HAS_UNIFORM_u_halo_blur +lowp float halo_blur = u_halo_blur; +#endif + + float fade_opacity = v_data1[2]; + + if (v_data1.w == ICON) { + vec2 tex_icon = v_data0.zw; + lowp float alpha = opacity * fade_opacity; + fragColor = texture(u_texture_icon, tex_icon) * alpha; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif + return; + } + + vec2 tex = v_data0.xy; + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + float gamma_scale = v_data1.x; + float size = v_data1.y; + + float fontScale = size / 24.0; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + fragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/prelude.hpp b/include/mbgl/shaders/gl/prelude.hpp index 167d045f5..7e82ed6c2 100644 --- a/include/mbgl/shaders/gl/prelude.hpp +++ b/include/mbgl/shaders/gl/prelude.hpp @@ -26,6 +26,8 @@ precision highp float; #endif +const float PI = 3.141592653589793; + // Unpack a pair of values that have been packed into a single float. // The packed values are assumed to be 8-bit unsigned integers, and are // packed like so: diff --git a/include/mbgl/shaders/gl/symbol_icon.hpp b/include/mbgl/shaders/gl/symbol_icon.hpp index cfd59942a..bf96c3952 100644 --- a/include/mbgl/shaders/gl/symbol_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_icon.hpp @@ -8,9 +8,7 @@ namespace shaders { template <> struct ShaderSource { static constexpr const char* name = "SymbolIconProgram"; - static constexpr const char* vertex = R"(const float PI = 3.141592653589793; - -layout (location = 0) in vec4 a_pos_offset; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec4 a_pixeloffset; layout (location = 3) in vec3 a_projected_pos; diff --git a/include/mbgl/shaders/gl/symbol_sdf_icon.hpp b/include/mbgl/shaders/gl/symbol_sdf_icon.hpp index 17f6327de..6094108c8 100644 --- a/include/mbgl/shaders/gl/symbol_sdf_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_sdf_icon.hpp @@ -8,9 +8,7 @@ namespace shaders { template <> struct ShaderSource { static constexpr const char* name = "SymbolSDFIconProgram"; - static constexpr const char* vertex = R"(const float PI = 3.141592653589793; - -layout (location = 0) in vec4 a_pos_offset; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec4 a_pixeloffset; layout (location = 3) in vec3 a_projected_pos; diff --git a/include/mbgl/shaders/gl/symbol_sdf_text.hpp b/include/mbgl/shaders/gl/symbol_sdf_text.hpp index 66da9b9a2..eecf6ff6b 100644 --- a/include/mbgl/shaders/gl/symbol_sdf_text.hpp +++ b/include/mbgl/shaders/gl/symbol_sdf_text.hpp @@ -8,9 +8,7 @@ namespace shaders { template <> struct ShaderSource { static constexpr const char* name = "SymbolSDFTextProgram"; - static constexpr const char* vertex = R"(const float PI = 3.141592653589793; - -layout (location = 0) in vec4 a_pos_offset; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec4 a_pixeloffset; layout (location = 3) in vec3 a_projected_pos; diff --git a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp index 68332a8b3..6cb8f109f 100644 --- a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp @@ -8,9 +8,7 @@ namespace shaders { template <> struct ShaderSource { static constexpr const char* name = "SymbolTextAndIconProgram"; - static constexpr const char* vertex = R"(const float PI = 3.141592653589793; - -layout (location = 0) in vec4 a_pos_offset; + static constexpr const char* vertex = R"(layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec3 a_projected_pos; layout (location = 3) in float a_fade_opacity; diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index 963c68931..3a8185a72 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -11,6 +11,10 @@ #include #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 25738b8ef..e96be4572 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -17,6 +17,10 @@ enum class BuiltIn { FillPatternShader, FillOutlinePatternShader, RasterShader, + SymbolIconShader, + SymbolSDFTextShader, + SymbolSDFIconShader, + SymbolTextAndIconShader, Prelude, BackgroundProgram, BackgroundPatternProgram, diff --git a/platform/ios/BUILD.bazel b/platform/ios/BUILD.bazel index 3624c0fbb..55a0d9500 100644 --- a/platform/ios/BUILD.bazel +++ b/platform/ios/BUILD.bazel @@ -324,6 +324,7 @@ objc_library( objc_library( name = "iosapp", + defines = ["GLES_SILENCE_DEPRECATION"], srcs = [ "platform/darwin/app/LimeGreenStyleLayer.h", "platform/darwin/app/LimeGreenStyleLayer.m", diff --git a/shaders/_prelude.vertex.glsl b/shaders/_prelude.vertex.glsl index 9cd030e4e..6af721248 100644 --- a/shaders/_prelude.vertex.glsl +++ b/shaders/_prelude.vertex.glsl @@ -16,6 +16,8 @@ precision highp float; #endif +const float PI = 3.141592653589793; + // Unpack a pair of values that have been packed into a single float. // The packed values are assumed to be 8-bit unsigned integers, and are // packed like so: diff --git a/shaders/drawable.symbol_icon.fragment.glsl b/shaders/drawable.symbol_icon.fragment.glsl new file mode 100644 index 000000000..235217be1 --- /dev/null +++ b/shaders/drawable.symbol_icon.fragment.glsl @@ -0,0 +1,35 @@ +uniform sampler2D u_texture; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +in vec2 v_tex; +in float v_fade_opacity; + +#pragma mapbox: define lowp float opacity + +void main() { + #pragma mapbox: initialize lowp float opacity + + lowp float alpha = opacity * v_fade_opacity; + fragColor = texture(u_texture, v_tex) * alpha; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.symbol_icon.vertex.glsl b/shaders/drawable.symbol_icon.vertex.glsl new file mode 100644 index 000000000..f2f7ced56 --- /dev/null +++ b/shaders/drawable.symbol_icon.vertex.glsl @@ -0,0 +1,121 @@ +layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec4 a_pixeloffset; +layout (location = 3) in vec3 a_projected_pos; +layout (location = 4) in float a_fade_opacity; + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec2 v_tex; +out float v_fade_opacity; + +#pragma mapbox: define lowp float opacity + +void main() { + #pragma mapbox: initialize lowp float opacity + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + vec2 a_pxoffset = a_pixeloffset.xy; + vec2 a_minFontScale = a_pixeloffset.zw / 256.0; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // See comments in symbol_sdf.vertex + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // See comments in symbol_sdf.vertex + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * max(a_minFontScale, fontScale) + a_pxoffset / 16.0), 0.0, 1.0); + + v_tex = a_tex / u_texsize; + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + v_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); +} diff --git a/shaders/drawable.symbol_sdf.fragment.glsl b/shaders/drawable.symbol_sdf.fragment.glsl new file mode 100644 index 000000000..5dc8a369d --- /dev/null +++ b/shaders/drawable.symbol_sdf.fragment.glsl @@ -0,0 +1,96 @@ +#define SDF_PX 8.0 + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +uniform sampler2D u_texture; + +in vec2 v_data0; +in vec3 v_data1; + +#pragma mapbox: define highp vec4 fill_color +#pragma mapbox: define highp vec4 halo_color +#pragma mapbox: define lowp float opacity +#pragma mapbox: define lowp float halo_width +#pragma mapbox: define lowp float halo_blur + +void main() { + #pragma mapbox: initialize highp vec4 fill_color + #pragma mapbox: initialize highp vec4 halo_color + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize lowp float halo_width + #pragma mapbox: initialize lowp float halo_blur + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + vec2 tex = v_data0.xy; + float gamma_scale = v_data1.x; + float size = v_data1.y; + float fade_opacity = v_data1[2]; + + float fontScale = u_is_text ? size / 24.0 : size; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + fragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.symbol_sdf.vertex.glsl b/shaders/drawable.symbol_sdf.vertex.glsl new file mode 100644 index 000000000..0402e61f6 --- /dev/null +++ b/shaders/drawable.symbol_sdf.vertex.glsl @@ -0,0 +1,146 @@ +layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec4 a_pixeloffset; +layout (location = 3) in vec3 a_projected_pos; +layout (location = 4) in float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec2 v_data0; +out vec3 v_data1; + +#pragma mapbox: define highp vec4 fill_color +#pragma mapbox: define highp vec4 halo_color +#pragma mapbox: define lowp float opacity +#pragma mapbox: define lowp float halo_width +#pragma mapbox: define lowp float halo_blur + +void main() { + #pragma mapbox: initialize highp vec4 fill_color + #pragma mapbox: initialize highp vec4 halo_color + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize lowp float halo_width + #pragma mapbox: initialize lowp float halo_blur + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + vec2 a_pxoffset = a_pixeloffset.xy; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale + a_pxoffset), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0 = a_tex / u_texsize; + v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); +} diff --git a/shaders/drawable.symbol_text_and_icon.fragment.glsl b/shaders/drawable.symbol_text_and_icon.fragment.glsl new file mode 100644 index 000000000..ed6cfccdb --- /dev/null +++ b/shaders/drawable.symbol_text_and_icon.fragment.glsl @@ -0,0 +1,113 @@ +#define SDF_PX 8.0 + +#define SDF 1.0 +#define ICON 0.0 + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +uniform sampler2D u_texture; +uniform sampler2D u_texture_icon; + +in vec4 v_data0; +in vec4 v_data1; + +#pragma mapbox: define highp vec4 fill_color +#pragma mapbox: define highp vec4 halo_color +#pragma mapbox: define lowp float opacity +#pragma mapbox: define lowp float halo_width +#pragma mapbox: define lowp float halo_blur + +void main() { + #pragma mapbox: initialize highp vec4 fill_color + #pragma mapbox: initialize highp vec4 halo_color + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize lowp float halo_width + #pragma mapbox: initialize lowp float halo_blur + + float fade_opacity = v_data1[2]; + + if (v_data1.w == ICON) { + vec2 tex_icon = v_data0.zw; + lowp float alpha = opacity * fade_opacity; + fragColor = texture(u_texture_icon, tex_icon) * alpha; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif + return; + } + + vec2 tex = v_data0.xy; + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + float gamma_scale = v_data1.x; + float size = v_data1.y; + + float fontScale = size / 24.0; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + fragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.symbol_text_and_icon.vertex.glsl b/shaders/drawable.symbol_text_and_icon.vertex.glsl new file mode 100644 index 000000000..c0262eda8 --- /dev/null +++ b/shaders/drawable.symbol_text_and_icon.vertex.glsl @@ -0,0 +1,146 @@ +layout (location = 0) in vec4 a_pos_offset; +layout (location = 1) in vec4 a_data; +layout (location = 2) in vec3 a_projected_pos; +layout (location = 3) in float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] + +layout (std140) uniform SymbolDrawableUBO { + highp mat4 u_matrix; + highp mat4 u_label_plane_matrix; + highp mat4 u_coord_matrix; + + highp vec2 u_texsize; + highp vec2 u_texsize_icon; + + highp float u_gamma_scale; + highp float u_device_pixel_ratio; + + highp float u_camera_to_center_distance; + highp float u_pitch; + bool u_rotate_symbol; + highp float u_aspect_ratio; + highp float u_fade_change; + highp float u_pad2; +}; + +layout (std140) uniform SymbolDrawablePaintUBO { + highp vec4 u_fill_color; + highp vec4 u_halo_color; + highp float u_opacity; + highp float u_halo_width; + highp float u_halo_blur; + highp float u_padding; +}; + +layout (std140) uniform SymbolDrawableTilePropsUBO { + bool u_is_text; + bool u_is_halo; + bool u_pitch_with_map; + bool u_is_size_zoom_constant; + bool u_is_size_feature_constant; + highp float u_size_t; // used to interpolate between zoom stops when size is a composite function + highp float u_size; // used when size is both zoom and feature constant + bool u_pad3; +}; + +layout (std140) uniform SymbolDrawableInterpolateUBO { + highp float u_fill_color_t; + highp float u_halo_color_t; + highp float u_opacity_t; + highp float u_halo_width_t; + highp float u_halo_blur_t; + highp float u_pad4,u_pad5,u_pad6; +}; + +out vec4 v_data0; +out vec4 v_data1; + +#pragma mapbox: define highp vec4 fill_color +#pragma mapbox: define highp vec4 halo_color +#pragma mapbox: define lowp float opacity +#pragma mapbox: define lowp float halo_width +#pragma mapbox: define lowp float halo_blur + +void main() { + #pragma mapbox: initialize highp vec4 fill_color + #pragma mapbox: initialize highp vec4 halo_color + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize lowp float halo_width + #pragma mapbox: initialize lowp float halo_blur + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + float a_size_min = floor(a_size[0] * 0.5); + float is_sdf = a_size[0] - 2.0 * a_size_min; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size_min, a_size[1], u_size_t) / 128.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size_min / 128.0; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = size / 24.0; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0.xy = a_tex / u_texsize; + v_data0.zw = a_tex / u_texsize_icon; + v_data1 = vec4(gamma_scale, size, interpolated_fade_opacity, is_sdf); +} diff --git a/shaders/manifest.json b/shaders/manifest.json index 8f885b2bb..0f7312381 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -55,6 +55,34 @@ "glsl_frag": "drawable.raster.fragment.glsl", "uses_ubos": true }, + { + "name": "SymbolIconShader", + "header": "drawable_symbol_icon", + "glsl_vert": "drawable.symbol_icon.vertex.glsl", + "glsl_frag": "drawable.symbol_icon.fragment.glsl", + "uses_ubos": true + }, + { + "name": "SymbolSDFTextShader", + "header": "drawable_symbol_sdf_text", + "glsl_vert": "drawable.symbol_sdf.vertex.glsl", + "glsl_frag": "drawable.symbol_sdf.fragment.glsl", + "uses_ubos": true + }, + { + "name": "SymbolSDFIconShader", + "header": "drawable_symbol_sdf_icon", + "glsl_vert": "drawable.symbol_sdf.vertex.glsl", + "glsl_frag": "drawable.symbol_sdf.fragment.glsl", + "uses_ubos": true + }, + { + "name": "SymbolTextAndIconShader", + "header": "drawable_symbol_text_and_icon", + "glsl_vert": "drawable.symbol_text_and_icon.vertex.glsl", + "glsl_frag": "drawable.symbol_text_and_icon.fragment.glsl", + "uses_ubos": true + }, { "name": "Prelude", diff --git a/shaders/symbol_icon.vertex.glsl b/shaders/symbol_icon.vertex.glsl index 1df0fccdc..221423195 100644 --- a/shaders/symbol_icon.vertex.glsl +++ b/shaders/symbol_icon.vertex.glsl @@ -1,5 +1,3 @@ -const float PI = 3.141592653589793; - layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec4 a_pixeloffset; diff --git a/shaders/symbol_sdf.vertex.glsl b/shaders/symbol_sdf.vertex.glsl index 603bb59d6..2141399de 100644 --- a/shaders/symbol_sdf.vertex.glsl +++ b/shaders/symbol_sdf.vertex.glsl @@ -1,5 +1,3 @@ -const float PI = 3.141592653589793; - layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec4 a_pixeloffset; diff --git a/shaders/symbol_text_and_icon.vertex.glsl b/shaders/symbol_text_and_icon.vertex.glsl index 533ad147d..f4812aacc 100644 --- a/shaders/symbol_text_and_icon.vertex.glsl +++ b/shaders/symbol_text_and_icon.vertex.glsl @@ -1,5 +1,3 @@ -const float PI = 3.141592653589793; - layout (location = 0) in vec4 a_pos_offset; layout (location = 1) in vec4 a_data; layout (location = 2) in vec3 a_projected_pos; diff --git a/src/mbgl/gfx/symbol_drawable_data.hpp b/src/mbgl/gfx/symbol_drawable_data.hpp new file mode 100644 index 000000000..883e81e0b --- /dev/null +++ b/src/mbgl/gfx/symbol_drawable_data.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace style { +enum class SymbolType : uint8_t; +} // namespace style +namespace gfx { + +struct SymbolDrawableData : public DrawableData { + SymbolDrawableData(const bool isHalo_, + const bool bucketVariablePlacement_, + const style::SymbolType symbolType_, + const style::AlignmentType pitchAlignment_, + const style::AlignmentType rotationAlignment_, + const style::SymbolPlacementType placement_, + const style::IconTextFitType textFit_) + : isHalo(isHalo_), + bucketVariablePlacement(bucketVariablePlacement_), + symbolType(symbolType_), + pitchAlignment(pitchAlignment_), + rotationAlignment(rotationAlignment_), + placement(placement_), + textFit(textFit_) {} + ~SymbolDrawableData() = default; + + const bool isHalo; + bool bucketVariablePlacement; + const style::SymbolType symbolType; + const style::AlignmentType pitchAlignment; + const style::AlignmentType rotationAlignment; + const style::SymbolPlacementType placement; + const style::IconTextFitType textFit; +}; + +using UniqueSymbolDrawableData = std::unique_ptr; + +} // namespace gfx +} // namespace mbgl diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index fe924c68d..fbbcd687d 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -53,18 +53,16 @@ void DrawableGL::draw(const PaintParameters& parameters) const { bindUniformBuffers(); bindTextures(); - auto& glContext = static_cast(parameters.context); - for (const auto& seg : impl->segments) { const auto& glSeg = static_cast(*seg); const auto& mlSeg = glSeg.getSegment(); if (mlSeg.indexLength > 0 && glSeg.getVertexArray().isValid()) { - glContext.bindVertexArray = glSeg.getVertexArray().getID(); - glContext.draw(glSeg.getMode(), mlSeg.indexOffset, mlSeg.indexLength); + context.bindVertexArray = glSeg.getVertexArray().getID(); + context.draw(glSeg.getMode(), mlSeg.indexOffset, mlSeg.indexLength); } } - glContext.bindVertexArray = value::BindVertexArray::Default; + context.bindVertexArray = value::BindVertexArray::Default; unbindTextures(); unbindUniformBuffers(); diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 558c7da5b..54c89edb7 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -100,7 +100,11 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::FillOutlineShader, shaders::BuiltIn::FillOutlinePatternShader, shaders::BuiltIn::FillPatternShader, - shaders::BuiltIn::RasterShader>(shaders, programParameters); + shaders::BuiltIn::RasterShader, + shaders::BuiltIn::SymbolIconShader, + shaders::BuiltIn::SymbolSDFTextShader, + shaders::BuiltIn::SymbolSDFIconShader, + shaders::BuiltIn::SymbolTextAndIconShader>(shaders, programParameters); } #endif diff --git a/src/mbgl/renderer/change_request.cpp b/src/mbgl/renderer/change_request.cpp index 79636b217..cb7afb872 100644 --- a/src/mbgl/renderer/change_request.cpp +++ b/src/mbgl/renderer/change_request.cpp @@ -18,15 +18,14 @@ void RemoveLayerGroupRequest::execute(RenderOrchestrator &orchestrator) { orchestrator.removeLayerGroup(layerIndex); } -UpdateLayerGroupIndexRequest::UpdateLayerGroupIndexRequest(std::shared_ptr tileLayerGroup_, - int32_t newLayerIndex_) - : tileLayerGroup(std::move(tileLayerGroup_)), +UpdateLayerGroupIndexRequest::UpdateLayerGroupIndexRequest(LayerGroupBasePtr tileLayerGroup_, int32_t newLayerIndex_) + : layerGroup(std::move(tileLayerGroup_)), newLayerIndex(newLayerIndex_) {} void UpdateLayerGroupIndexRequest::execute(RenderOrchestrator &orchestrator) { - // Update the index of a tile layer group and indicate to the orchestator that it must rebuild the map of ordered - // layer groups - tileLayerGroup->updateLayerIndex(newLayerIndex); + // Update the index of a tile layer group and indicate to the + // orchestrator that it must rebuild the map of ordered layer groups + layerGroup->updateLayerIndex(newLayerIndex); orchestrator.markLayerGroupOrderDirty(); } diff --git a/src/mbgl/renderer/layer_group.cpp b/src/mbgl/renderer/layer_group.cpp index be40972bb..08bd2e242 100644 --- a/src/mbgl/renderer/layer_group.cpp +++ b/src/mbgl/renderer/layer_group.cpp @@ -19,11 +19,7 @@ LayerGroup::LayerGroup(int32_t layerIndex_, std::size_t initialCapacity, std::st : LayerGroupBase(layerIndex_, std::move(name_)), impl(std::make_unique(initialCapacity)) {} -LayerGroup::~LayerGroup() {} - -void LayerGroup::updateLayerIndex(int32_t newLayerIndex) { - layerIndex = newLayerIndex; -} +LayerGroup::~LayerGroup() = default; std::size_t LayerGroup::getDrawableCount() const { return impl->drawables.size(); diff --git a/src/mbgl/renderer/layers/raster_layer_tweaker.cpp b/src/mbgl/renderer/layers/raster_layer_tweaker.cpp index 4c7495cca..d8db43542 100644 --- a/src/mbgl/renderer/layers/raster_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/raster_layer_tweaker.cpp @@ -65,7 +65,7 @@ void RasterLayerTweaker::execute([[maybe_unused]] LayerGroupBase& layerGroup, if (!drawable.getTileID()) { // this is an image drawable if (const auto& data = drawable.getData()) { - const gfx::ImageDrawableData& imageData = static_cast(*data.value()); + const gfx::ImageDrawableData& imageData = static_cast(*data); matrix = imageData.matrix; } else { diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 10de049d5..96532327b 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -66,8 +66,8 @@ void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters& paramet evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (tileLayerGroup) { - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + if (layerGroup) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } #endif } @@ -221,7 +221,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, // renderTiles is always empty, we use tileCover instead if (tileCover.empty()) { - removeAllTiles(); + removeAllDrawables(); return; } @@ -239,17 +239,17 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, // If the result is transparent or missing, just remove any existing drawables and stop if (drawPasses == RenderPass::None) { - removeAllTiles(); + removeAllDrawables(); return; } - if (!tileLayerGroup) { - tileLayerGroup = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); - if (!tileLayerGroup) { - return; + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); } - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } + auto* tileLayerGroup = static_cast(layerGroup.get()); if (!hasPattern && !plainShader) { plainShader = context.getGenericShader(shaders, std::string(BackgroundPlainShaderName)); @@ -260,7 +260,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, const auto& curShader = hasPattern ? patternShader : plainShader; if (!curShader) { - removeAllTiles(); + removeAllDrawables(); return; } @@ -287,7 +287,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, const auto tileID = drawable->getTileID(); if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) { drawable.reset(); - ++stats.tileDrawablesRemoved; + ++stats.drawablesRemoved; return; } }); @@ -316,7 +316,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setTileID(tileID); tileLayerGroup->addDrawable(drawPasses, tileID, std::move(drawable)); - ++stats.tileDrawablesAdded; + ++stats.drawablesAdded; } } } diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 110e2fd51..4fefa6aa7 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -81,8 +81,8 @@ void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (tileLayerGroup) { - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + if (layerGroup) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } #endif } @@ -275,28 +275,28 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, [[maybe_unused]] const RenderTree& renderTree, - UniqueChangeRequestVec& /*changes*/) { + UniqueChangeRequestVec& changes) { std::unique_lock guard(mutex); if (!renderTiles || renderTiles->empty()) { - removeAllTiles(); + removeAllDrawables(); return; } // Set up a layer group - if (!tileLayerGroup) { - tileLayerGroup = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); - if (!tileLayerGroup) { - return; + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); } - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } + auto* tileLayerGroup = static_cast(layerGroup.get()); if (!circleShaderGroup) { circleShaderGroup = shaders.getShaderGroup(CircleShaderGroupName); } if (!circleShaderGroup) { - removeAllTiles(); + removeAllDrawables(); return; } @@ -320,7 +320,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) { // remove it drawable.reset(); - ++stats.tileDrawablesRemoved; + ++stats.drawablesRemoved; } }); @@ -408,7 +408,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, drawable->mutableUniformBuffers().createOrUpdate(CircleInterpolateUBOName, &interpolateUBO, context); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.tileDrawablesAdded; + ++stats.drawablesAdded; } } } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 632b04cea..71c5b56c5 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -35,10 +35,12 @@ using namespace style; namespace { +#if MLN_DRAWABLE_RENDERER constexpr std::string_view FillShaderName = "FillShader"; constexpr std::string_view FillOutlineShaderName = "FillOutlineShader"; constexpr std::string_view FillPatternShaderName = "FillPatternShader"; constexpr std::string_view FillOutlinePatternShaderName = "FillOutlinePatternShader"; +#endif // MLN_DRAWABLE_RENDERER inline const FillLayer::Impl& impl_cast(const Immutable& impl) { assert(impl->getTypeInfo() == FillLayer::Impl::staticTypeInfo()); @@ -79,8 +81,8 @@ void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (tileLayerGroup) { - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + if (layerGroup) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } #endif } @@ -290,18 +292,18 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, std::unique_lock guard(mutex); if (!renderTiles || renderTiles->empty()) { - removeAllTiles(); + removeAllDrawables(); return; } // Set up a layer group - if (!tileLayerGroup) { - tileLayerGroup = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); - if (!tileLayerGroup) { - return; + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); } - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } + auto* tileLayerGroup = static_cast(layerGroup.get()); if (!fillShaderGroup) { fillShaderGroup = shaders.getShaderGroup(std::string(FillShaderName)); @@ -316,7 +318,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, outlinePatternShaderGroup = shaders.getShaderGroup(std::string(FillOutlinePatternShaderName)); } if (!fillShaderGroup || !outlineShaderGroup || !patternShaderGroup || !outlinePatternShaderGroup) { - removeAllTiles(); + removeAllDrawables(); return; } @@ -350,7 +352,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, uniforms.createOrUpdate(FillLayerTweaker::FillInterpolateUBOName, &interpUBO, context); uniforms.createOrUpdate(FillLayerTweaker::FillTilePropsUBOName, &tileUBO, context); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.tileDrawablesAdded; + ++stats.drawablesAdded; } }; @@ -364,7 +366,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, const auto tileID = drawable->getTileID(); if (drawable->getRenderPass() != renderPass || (tileID && newTileIDs.find(*tileID) == newTileIDs.end())) { drawable.reset(); - ++stats.tileDrawablesRemoved; + ++stats.drawablesRemoved; } }); diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index f0fe76748..c526ca071 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -51,8 +51,8 @@ void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (tileLayerGroup && tileLayerGroup->getLayerTweaker()) { - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + if (layerGroup && layerGroup->getLayerTweaker()) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); } #endif } @@ -214,9 +214,15 @@ void RenderRasterLayer::render(PaintParameters& parameters) { } } } + #endif // MLN_LEGACY_RENDERER #if MLN_DRAWABLE_RENDERER +void RenderRasterLayer::markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) { + RenderLayer::markLayerRenderable(willRender, changes); + activateLayerGroup(imageLayerGroup, willRender, changes); +} + void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& /*state*/, @@ -225,13 +231,11 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, std::unique_lock guard(mutex); if ((!renderTiles || renderTiles->empty()) && !imageData) { - if (tileLayerGroup) { - stats.tileDrawablesRemoved += tileLayerGroup->getDrawableCount(); - tileLayerGroup->clearDrawables(); + if (layerGroup) { + stats.drawablesRemoved += layerGroup->clearDrawables(); } if (imageLayerGroup) { - // stats.tileDrawablesRemoved += layerScene->getDrawableCount(); - imageLayerGroup->clearDrawables(); + stats.drawablesRemoved += imageLayerGroup->clearDrawables(); } return; } @@ -387,11 +391,12 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, RasterBucket& bucket = *imageData->bucket; if (!bucket.vertices.empty()) { if (imageLayerGroup) { - imageLayerGroup->clearDrawables(); + stats.drawablesRemoved += imageLayerGroup->clearDrawables(); } else { // Set up a layer group imageLayerGroup = context.createLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); imageLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + activateLayerGroup(imageLayerGroup, isRenderable, changes); } auto builder = createBuilder(); @@ -400,16 +405,17 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, // finish builder->flush(); + for (auto& drawable : builder->clearDrawables()) { drawable->setData(std::make_unique(matrix_)); imageLayerGroup->addDrawable(std::move(drawable)); - ++stats.tileDrawablesAdded; + ++stats.drawablesAdded; } } } } else if (renderTiles) { - if (tileLayerGroup) { - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + if (layerGroup) { + layerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { // Has this tile dropped out of the cover set? if (const auto it = std::find_if(renderTiles->begin(), renderTiles->end(), @@ -420,15 +426,19 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, it == renderTiles->end()) { // remove it drawable.reset(); - ++stats.tileDrawablesRemoved; + ++stats.drawablesRemoved; } }); } else { // Set up a tile layer group - tileLayerGroup = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); - tileLayerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); + } } + auto* tileLayerGroup = static_cast(layerGroup.get()); + auto builder = createBuilder(); for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -449,7 +459,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setTileID(tileID); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.tileDrawablesAdded; + ++stats.drawablesAdded; } }; } diff --git a/src/mbgl/renderer/layers/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index 9bbf9e103..8c2297af2 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.hpp +++ b/src/mbgl/renderer/layers/render_raster_layer.hpp @@ -24,6 +24,11 @@ public: UniqueChangeRequestVec&) override; #endif +protected: +#if MLN_DRAWABLE_RENDERER + void markLayerRenderable(bool willRender, UniqueChangeRequestVec&) override; +#endif // MLN_DRAWABLE_RENDERER + private: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index d9e5775b1..156103fb8 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -1,24 +1,35 @@ #include -#include + +#include +#include +#include +#include +#include #include +#include +#include #include #include #include +#include #include -#include +#include #include #include -#include -#include -#include -#include #include #include -#include -#include -#include +#include +#include #include +#if MLN_DRAWABLE_RENDERER +#include +#include +#include +#include +#include +#endif // MLN_DRAWABLE_RENDERER + #include #include @@ -27,6 +38,15 @@ namespace mbgl { using namespace style; namespace { +#if MLN_DRAWABLE_RENDERER + +constexpr std::string_view SymbolIconShaderName = "SymbolIconShader"; +constexpr std::string_view SymbolSDFIconShaderName = "SymbolSDFTextShader"; +constexpr std::string_view SymbolSDFTextShaderName = "SymbolSDFIconShader"; +constexpr std::string_view SymbolTextAndIconShaderName = "SymbolTextAndIconShader"; + +#endif // MLN_DRAWABLE_RENDERER + style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { return style::SymbolPropertyValues{layout_.get(), @@ -35,7 +55,7 @@ style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintPropertie evaluated_.get(), evaluated_.get(), evaluated_.get().constantOr(Color::black()).a > 0 && - evaluated_.get().constantOr(1), + evaluated_.get().constantOr(1) != 0, evaluated_.get().constantOr(Color::black()).a > 0}; } @@ -47,12 +67,12 @@ style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintPropertie evaluated_.get(), evaluated_.get(), evaluated_.get().constantOr(Color::black()).a > 0 && - evaluated_.get().constantOr(1), + evaluated_.get().constantOr(1) != 0, evaluated_.get().constantOr(Color::black()).a > 0}; } -using SegmentWrapper = std::reference_wrapper>; -using SegmentVectorWrapper = std::reference_wrapper>; +using SegmentWrapper = std::reference_wrapper>; +using SegmentVectorWrapper = std::reference_wrapper>; using SegmentsWrapper = variant; struct RenderableSegment { @@ -61,13 +81,15 @@ struct RenderableSegment { const LayerRenderData& renderData_, const SymbolBucket::PaintProperties& bucketPaintProperties_, float sortKey_, - const SymbolType type_) + const SymbolType type_, + const uint8_t overscaledZ_ = 0) : segment(segment_), tile(tile_), renderData(renderData_), bucketPaintProperties(bucketPaintProperties_), sortKey(sortKey_), - type(type_) {} + type(type_), + overscaledZ(overscaledZ_) {} SegmentWrapper segment; const RenderTile& tile; @@ -75,6 +97,7 @@ struct RenderableSegment { const SymbolBucket::PaintProperties& bucketPaintProperties; float sortKey; SymbolType type; + uint8_t overscaledZ; friend bool operator<(const RenderableSegment& lhs, const RenderableSegment& rhs) { // Sort renderable segments by a sort key. @@ -99,6 +122,8 @@ struct RenderableSegment { } }; +#if MLN_LEGACY_RENDERER + template void drawIcon(const RenderSymbolLayer::Programs& programs, const DrawFn& draw, @@ -130,7 +155,7 @@ void drawIcon(const RenderSymbolLayer::Programs& programs, if (sdfIcons) { if (values.hasHalo) { draw(*programs.symbolSDFIconProgram, - SymbolSDFIconProgram::layoutUniformValues(false, + SymbolSDFIconProgram::layoutUniformValues(/* isText = */ false, variablePlacedIcon, values, iconSize, @@ -152,7 +177,7 @@ void drawIcon(const RenderSymbolLayer::Programs& programs, if (values.hasFill) { draw(*programs.symbolSDFIconProgram, - SymbolSDFIconProgram::layoutUniformValues(false, + SymbolSDFIconProgram::layoutUniformValues(/* isText = */ false, variablePlacedIcon, values, iconSize, @@ -173,7 +198,7 @@ void drawIcon(const RenderSymbolLayer::Programs& programs, } } else { draw(*programs.symbolIconProgram, - SymbolIconProgram::layoutUniformValues(false, + SymbolIconProgram::layoutUniformValues(/* isText = */ false, variablePlacedIcon, values, iconSize, @@ -200,15 +225,15 @@ void drawText(const RenderSymbolLayer::Programs& programs, SegmentsWrapper textSegments, const SymbolBucket::PaintProperties& bucketPaintProperties, const PaintParameters& parameters) { - auto& bucket = static_cast(*renderData.bucket); + const auto& bucket = static_cast(*renderData.bucket); const auto& evaluated = getEvaluated(renderData.layerProperties); const auto& layout = *bucket.layout; - auto values = textPropertyValues(evaluated, layout); + const auto values = textPropertyValues(evaluated, layout); const auto& paintPropertyValues = RenderSymbolLayer::textPaintProperties(evaluated); const bool alongLine = layout.get() != SymbolPlacementType::Point && - layout.get() == AlignmentType::Map; + values.rotationAlignment == AlignmentType::Map; const Size& glyphTexSize = tile.getGlyphAtlasTexture()->getSize(); const gfx::TextureBinding glyphTextureBinding = tile.getGlyphAtlasTextureBinding(gfx::TextureFilterType::Linear); @@ -269,7 +294,7 @@ void drawText(const RenderSymbolLayer::Programs& programs, } else { if (values.hasHalo) { drawGlyphs(*programs.symbolSDFTextProgram, - SymbolSDFTextProgram::layoutUniformValues(true, + SymbolSDFTextProgram::layoutUniformValues(/* isText = */ true, bucket.hasVariablePlacement, values, glyphTexSize, @@ -286,7 +311,7 @@ void drawText(const RenderSymbolLayer::Programs& programs, if (values.hasFill) { drawGlyphs(*programs.symbolSDFTextProgram, - SymbolSDFTextProgram::layoutUniformValues(true, + SymbolSDFTextProgram::layoutUniformValues(/* isText = */ true, bucket.hasVariablePlacement, values, glyphTexSize, @@ -303,6 +328,8 @@ void drawText(const RenderSymbolLayer::Programs& programs, } } +#endif // MLN_LEGACY_RENDERER + inline const SymbolLayer::Impl& impl_cast(const Immutable& impl) { assert(impl->getTypeInfo() == SymbolLayer::Impl::staticTypeInfo()); return static_cast(*impl); @@ -326,7 +353,7 @@ void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) auto properties = makeMutable(staticImmutableCast(baseImpl), unevaluated.evaluate(parameters)); auto& evaluated = properties->evaluated; - auto& layout = impl_cast(baseImpl).layout; + const auto& layout = impl_cast(baseImpl).layout; if (hasFormatSectionOverrides) { SymbolLayerPaintPropertyOverrides::setOverrides(layout, evaluated); @@ -343,6 +370,12 @@ void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) : RenderPass::None; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); + +#if MLN_DRAWABLE_RENDERER + if (layerGroup) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + } +#endif // MLN_DRAWABLE_RENDERER } bool RenderSymbolLayer::hasTransition() const { @@ -353,6 +386,8 @@ bool RenderSymbolLayer::hasCrossfade() const { return false; } +#if MLN_LEGACY_RENDERER + void RenderSymbolLayer::render(PaintParameters& parameters) { assert(renderTiles); if (parameters.pass == RenderPass::Opaque) { @@ -390,7 +425,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { this->checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); segments.match( - [&](const std::reference_wrapper>& segment) { + [&](const SegmentWrapper& segment) { programInstance.draw(parameters.context, *parameters.renderPass, gfx::Triangles(), @@ -405,7 +440,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { textureBindings, this->getID() + "/" + suffix); }, - [&](const std::reference_wrapper>& segmentVector) { + [&](const SegmentVectorWrapper& segmentVector) { programInstance.draw(parameters.context, *parameters.renderPass, gfx::Triangles(), @@ -597,6 +632,8 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { } } +#endif // MLN_LEGACY_RENDERER + // static style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties( const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_) { @@ -623,6 +660,16 @@ style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProper void RenderSymbolLayer::prepare(const LayerPrepareParameters& params) { renderTiles = params.source->getRenderTilesSortedByYPosition(); + +#if MLN_DRAWABLE_RENDERER + renderTileIDs.clear(); + renderTileIDs.reserve(renderTiles->size()); + std::transform(renderTiles->begin(), + renderTiles->end(), + std::inserter(renderTileIDs, renderTileIDs.end()), + [](const auto& tile) { return tile.get().getOverscaledTileID(); }); +#endif // MLN_DRAWABLE_RENDERER + addRenderPassesFromTiles(); placementData.clear(); @@ -654,4 +701,454 @@ void RenderSymbolLayer::prepare(const LayerPrepareParameters& params) { } } +#if MLN_DRAWABLE_RENDERER + +namespace { + +template +const auto& getProperty(const SymbolBucket::PaintProperties& paintProps, bool isText) { + return isText ? paintProps.textBinders.get() : paintProps.iconBinders.get(); +} + +template +auto getInterpFactor(const SymbolBucket::PaintProperties& paintProps, bool isText, float currentZoom) { + return std::get(getProperty(paintProps, isText)->interpolationFactor(currentZoom)); +} + +SymbolDrawableInterpolateUBO buildInterpUBO(const SymbolBucket::PaintProperties& paint, const bool t, const float z) { + return {/* .fill_color_t = */ getInterpFactor(paint, t, z), + /* .halo_color_t = */ getInterpFactor(paint, t, z), + /* .opacity_t = */ getInterpFactor(paint, t, z), + /* .halo_width_t = */ getInterpFactor(paint, t, z), + /* .halo_blur_t = */ getInterpFactor(paint, t, z), + /* .padding = */ 0, + 0, + 0}; +} + +SymbolDrawableTilePropsUBO buildTileUBO(const SymbolBucket& bucket, + const gfx::SymbolDrawableData& drawData, + const float currentZoom) { + const bool isText = (drawData.symbolType == SymbolType::Text); + const ZoomEvaluatedSize size = isText ? bucket.textSizeBinder->evaluateForZoom(currentZoom) + : bucket.iconSizeBinder->evaluateForZoom(currentZoom); + return { + /* .is_text = */ isText, + /* .is_halo = */ drawData.isHalo, + /* .pitch_with_map = */ (drawData.pitchAlignment == style::AlignmentType::Map), + /* .is_size_zoom_constant = */ size.isZoomConstant, + /* .is_size_feature_constant = */ size.isFeatureConstant, + /* .size_t = */ size.sizeT, + /* .size = */ size.size, + /* .padding = */ 0, + }; +} + +constexpr auto dataAttibName = "a_data"; +constexpr auto posOffsetAttribName = "a_pos_offset"; +constexpr auto pixOffsetAttribName = "a_pixeloffset"; +constexpr auto projPosAttribName = "a_projected_pos"; +constexpr auto fadeOpacityAttribName = "a_fade_opacity"; +constexpr auto texUniformName = "u_texture"; +constexpr auto iconTexUniformName = "u_texture_icon"; + +void updateTileDrawable(gfx::Drawable& drawable, + gfx::Context& context, + const SymbolBucket& bucket, + const SymbolBucket::PaintProperties& paintProps, + const TransformState& state) { + if (!drawable.getData()) { + return; + } + + auto& drawData = static_cast(*drawable.getData()); + const auto isText = (drawData.symbolType == SymbolType::Text); + const auto currentZoom = static_cast(state.getZoom()); + + // This property can be set after the initial appearance of the tile, as part of the layout process. + drawData.bucketVariablePlacement = bucket.hasVariablePlacement; + + const auto tileUBO = buildTileUBO(bucket, drawData, currentZoom); + const auto interpolateUBO = buildInterpUBO(paintProps, isText, currentZoom); + + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableTilePropsUBOName, &tileUBO, context); + uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableInterpolateUBOName, &interpolateUBO, context); + + // TODO: detect whether anything has actually changed + // See `Placement::updateBucketDynamicVertices` + if (const auto newAttribs = drawable.getVertexAttributes().clone()) { + const auto sdfIcons = (drawData.symbolType == SymbolType::IconSDF); + const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); + + if (auto& attr = newAttribs->getOrAdd(projPosAttribName)) { + const auto count = buffer.dynamicVertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, util::cast(buffer.dynamicVertices.at(i).a1)); + } + } + + if (auto& attr = newAttribs->getOrAdd(fadeOpacityAttribName)) { + const auto count = buffer.opacityVertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, buffer.opacityVertices.at(i).a1[0]); + } + } + + drawable.setVertexAttributes(std::move(*newAttribs)); + } +} + +} // namespace + +void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, + gfx::Context& context, + const TransformState& state, + const RenderTree& /*renderTree*/, + UniqueChangeRequestVec& changes) { + if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { + removeAllDrawables(); + return; + } + + // Set up a layer group + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); + } + } + + if (!symbolIconGroup) { + symbolIconGroup = shaders.getShaderGroup(std::string(SymbolIconShaderName)); + } + if (!symbolSDFIconGroup) { + symbolSDFIconGroup = shaders.getShaderGroup(std::string(SymbolSDFIconShaderName)); + } + if (!symbolSDFTextGroup) { + symbolSDFTextGroup = shaders.getShaderGroup(std::string(SymbolSDFTextShaderName)); + } + if (!symbolTextAndIconGroup) { + symbolTextAndIconGroup = shaders.getShaderGroup(std::string(SymbolTextAndIconShaderName)); + } + + auto* tileLayerGroup = static_cast(layerGroup.get()); + tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& 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 && renderTileIDs.find(*tileID) == renderTileIDs.end())) { + drawable.reset(); + tileBucketInstances.erase(*tileID); + ++stats.drawablesRemoved; + } + }); + + const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get().isUndefined(); + std::multiset renderableSegments; + std::unique_ptr builder; + + const auto currentZoom = static_cast(state.getZoom()); + const auto layerPrefix = getID() + "/"; + + for (const RenderTile& tile : *renderTiles) { + const auto& tileID = tile.getOverscaledTileID(); + + const auto* optRenderData = getRenderDataForPass(tile, passes); + if (!optRenderData || !optRenderData->bucket) { + removeTile(passes, tileID); + continue; + } + + const auto& renderData = *optRenderData; + const auto& bucket = static_cast(*renderData.bucket); + + assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); + const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); + + // If we already have drawables for this tile, update them. + if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) { + const auto hit = tileBucketInstances.insert(std::make_pair(tileID, bucket.bucketInstanceId)); + if (!hit.second && hit.first->second != bucket.bucketInstanceId) { + // The bucket has changed, reset the drawables for this tile. + tileLayerGroup->removeDrawables(passes, tileID); + hit.first->second = bucket.bucketInstanceId; + } else { + // Just update the drawables we already created + tileLayerGroup->observeDrawables(passes, tileID, [&](gfx::Drawable& drawable) { + updateTileDrawable(drawable, context, bucket, bucketPaintProperties, state); + }); + continue; + } + } + + float serialKey = 1.0f; + auto addRenderables = [&, it = renderableSegments.begin()](const SymbolBucket::Buffer& buffer, + const SymbolType type) mutable { + for (const auto& segment : buffer.segments) { + const auto key = sortFeaturesByKey ? segment.sortKey : (serialKey += 1.0); + assert(segment.vertexOffset + segment.vertexLength <= buffer.vertices.elements()); + it = renderableSegments.emplace_hint( + it, std::ref(segment), tile, renderData, bucketPaintProperties, key, type, tileID.overscaledZ); + } + }; + + addRenderables(bucket.icon, SymbolType::IconRGBA); + addRenderables(bucket.sdfIcon, SymbolType::IconSDF); + addRenderables(bucket.text, SymbolType::Text); + } + + using RawVertexVec = std::vector; // + struct RawVertices { + RawVertexVec text, icon; + }; + std::unordered_map rawVertices; + + for (auto& renderable : renderableSegments) { + const auto isText = (renderable.type == SymbolType::Text); + const auto sdfIcons = (renderable.type == SymbolType::IconSDF); + + const auto& tile = renderable.tile; + const auto tileID = tile.id.overscaleTo(renderable.overscaledZ); + const auto& bucket = static_cast(*renderable.renderData.bucket); + const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); + + const auto& evaluated = getEvaluated(renderable.renderData.layerProperties); + const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); + + const auto& layout = *bucket.layout; + const auto values = isText ? textPropertyValues(evaluated, layout) : iconPropertyValues(evaluated, layout); + + const auto buildVertices = [&](const SymbolBucket::Buffer& buffer_, RawVertexVec& dest) -> auto& { + const std::vector& src = buffer_.vertices.vector(); + const auto vertSize = sizeof(SymbolLayoutVertex::a1); + if (dest.size() != vertSize * src.size()) { + dest.resize(vertSize * src.size()); + for (std::size_t i = 0; i < src.size(); ++i) { + std::memcpy(&dest[vertSize * i], &src[i].a1, vertSize); + } + } + return dest; + }; + + gfx::VertexAttributeArray attrs; + if (const auto& attr = attrs.getOrAdd(dataAttibName)) { + const auto count = buffer.vertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, util::cast(buffer.vertices.at(i).a2)); + } + } + if (const auto& attr = attrs.getOrAdd(pixOffsetAttribName)) { + const auto count = buffer.vertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, util::cast(buffer.vertices.at(i).a3)); + } + } + if (const auto& attr = attrs.getOrAdd(projPosAttribName)) { + const auto count = buffer.dynamicVertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, util::cast(buffer.dynamicVertices.at(i).a1)); + } + } + if (const auto& attr = attrs.getOrAdd(fadeOpacityAttribName)) { + const auto count = buffer.opacityVertices.elements(); + attr->reserve(count); + for (auto i = 0ULL; i < count; ++i) { + attr->set(i, buffer.opacityVertices.at(i).a1[0]); + } + } + + const auto uniformProps = isText ? attrs.readDataDrivenPaintProperties( + bucketPaintProperties.textBinders, evaluated) + : attrs.readDataDrivenPaintProperties( + bucketPaintProperties.iconBinders, evaluated); + + const auto textHalo = evaluated.get().constantOr(Color::black()).a > 0.0f && + evaluated.get().constantOr(1); + const auto textFill = evaluated.get().constantOr(Color::black()).a > 0.0f; + + const auto iconHalo = evaluated.get().constantOr(Color::black()).a > 0.0f && + evaluated.get().constantOr(1); + const auto iconFill = evaluated.get().constantOr(Color::black()).a > 0.0f; + + const auto interpolateUBO = buildInterpUBO(bucketPaintProperties, isText, currentZoom); + + const auto draw = [&](const gfx::ShaderGroupPtr& shaderGroup, + const Segment& segment, + const gfx::IndexVector& indices, + const RawVertexVec& vertices, + const std::size_t vertexCount, + const bool isHalo, + const std::string_view suffix) { + if (!shaderGroup) { + return; + } + + if (!builder) { + builder = context.createDrawableBuilder(layerPrefix); + builder->setSubLayerIndex(0); + builder->setNeedsStencil(false); + builder->setRenderPass(passes); + builder->setCullFaceMode(gfx::CullFaceMode::disabled()); + builder->setDepthType(gfx::DepthMaskType::ReadOnly); + builder->setCullFaceMode(gfx::CullFaceMode::disabled()); + builder->setVertexAttrName(posOffsetAttribName); + } + + builder->setDrawableName(layerPrefix + std::string(suffix)); + builder->setVertexAttributes(std::move(attrs)); + + const auto shader = std::static_pointer_cast( + shaderGroup->getOrCreateShader(context, uniformProps, posOffsetAttribName)); + if (!shader) { + return; + } + builder->setShader(shader); + + // TODO: texture filtering + // const bool linear = parameters.state.isChanging() || transformed || + // !partiallyEvaluatedTextSize.isZoomConstant; const auto filterType = linear ? + // gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest; + + if (const auto& atlases = tile.getAtlasTextures()) { + if (const auto texSamplerLocation = shader->getSamplerLocation(texUniformName)) { + if (const auto iconSamplerLocation = shader->getSamplerLocation(iconTexUniformName)) { + assert(*texSamplerLocation != *iconSamplerLocation); + builder->setTextureSource([=]() -> gfx::Drawable::Textures { + return {{*texSamplerLocation, atlases->glyph}, {*iconSamplerLocation, atlases->icon}}; + }); + } else { + builder->setTextureSource([=]() -> gfx::Drawable::Textures { + return {{*texSamplerLocation, isText ? atlases->glyph : atlases->icon}}; + }); + } + } + } + + auto raw = vertices; + builder->setRawVertices(std::move(raw), vertexCount, gfx::AttributeDataType::Short4); + builder->setSegments(gfx::Triangles(), indices.vector(), &segment, 1); + + builder->flush(); + + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + + auto drawData = std::make_unique( + /*.isHalo=*/isHalo, + /*.bucketVaraiblePlacement=*/bucket.hasVariablePlacement, + /*.symbolType=*/renderable.type, + /*.pitchAlignment=*/values.pitchAlignment, + /*.rotationAlignment=*/values.rotationAlignment, + /*.placement=*/layout.get(), + /*.textFit=*/layout.get()); + + const auto tileUBO = buildTileUBO(bucket, *drawData, currentZoom); + drawable->setData(std::move(drawData)); + + auto& uniforms = drawable->mutableUniformBuffers(); + uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableTilePropsUBOName, &tileUBO, context); + uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableInterpolateUBOName, &interpolateUBO, context); + + tileLayerGroup->addDrawable(passes, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + }; + + if (isText) { + const auto& vertices = buildVertices(buffer, rawVertices[tile.id].text); + const auto vertexCount = buffer.vertices.elements(); + const auto& indices = buffer.triangles; + if (bucket.iconsInText) { + if (textHalo) { + draw(symbolTextAndIconGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ true, + "halo"); + } + + if (textFill) { + draw(symbolTextAndIconGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ false, + "fill"); + } + } else { + if (textHalo) { + draw(symbolSDFTextGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ true, + "halo"); + } + + if (textFill) { + draw(symbolSDFTextGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ false, + "fill"); + } + } + } else { // icons + const auto& vertices = buildVertices(buffer, rawVertices[tile.id].icon); + const auto vertexCount = buffer.vertices.elements(); + const auto& indices = buffer.triangles; + if (sdfIcons) { + if (iconHalo) { + draw(symbolSDFIconGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ true, + "halo"); + } + + if (iconFill) { + draw(symbolSDFIconGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ false, + "fill"); + } + } else { + draw(symbolIconGroup, + renderable.segment, + indices, + vertices, + vertexCount, + /* isHalo = */ false, + "icon"); + } + } + } +} + +#endif // MLN_DRAWABLE_RENDERER + } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index ea1cf5a2f..2d8921647 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -6,6 +6,10 @@ #include #include +#if MLN_DRAWABLE_RENDERER +#include +#endif // MLN_DRAWABLE_RENDERER + namespace mbgl { namespace style { @@ -81,14 +85,28 @@ public: static style::TextPaintProperties::PossiblyEvaluated textPaintProperties( const style::SymbolPaintProperties::PossiblyEvaluated&); +#if MLN_DRAWABLE_RENDERER + /// Generate any changes needed by the layer + void update(gfx::ShaderRegistry&, + gfx::Context&, + const TransformState&, + const RenderTree&, + UniqueChangeRequestVec&) override; +#endif // MLN_DRAWABLE_RENDERER + private: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; bool hasCrossfade() const override; + +#if MLN_LEGACY_RENDERER void render(PaintParameters&) override; +#endif // MLN_LEGACY_RENDERER + void prepare(const LayerPrepareParameters&) override; +private: // Paint properties style::SymbolPaintProperties::Unevaluated unevaluated; @@ -97,8 +115,20 @@ private: bool hasFormatSectionOverrides = false; +#if MLN_LEGACY_RENDERER // Programs Programs programs; +#endif // MLN_LEGACY_RENDERER + +#if MLN_DRAWABLE_RENDERER + gfx::ShaderGroupPtr symbolIconGroup; + gfx::ShaderGroupPtr symbolSDFIconGroup; + gfx::ShaderGroupPtr symbolSDFTextGroup; + gfx::ShaderGroupPtr symbolTextAndIconGroup; + + std::unordered_set renderTileIDs; + std::unordered_map tileBucketInstances; +#endif // MLN_DRAWABLE_RENDERER }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp new file mode 100644 index 000000000..8325313ca --- /dev/null +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -0,0 +1,173 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +using namespace style; + +struct alignas(16) SymbolDrawableUBO { + /* 0 */ std::array matrix; + /* 64 */ std::array label_plane_matrix; + /* 128 */ std::array coord_matrix; + + /* 192 */ std::array texsize; + /* 200 */ std::array texsize_icon; + + /* 208 */ float gamma_scale; + /* 212 */ float device_pixel_ratio; + + /* 216 */ float camera_to_center_distance; + /* 220 */ float pitch; + /* 224 */ /*bool*/ int rotate_symbol; + /* 228 */ float aspect_ratio; + /* 232 */ float fade_change; + /* 236 */ float pad; + /* 240 */ +}; +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; + /* 32 */ float opacity; + /* 36 */ float halo_width; + /* 40 */ float halo_blur; + /* 44 */ float padding; + /* 48 */ +}; +static_assert(sizeof(SymbolDrawablePaintUBO) == 3 * 16); + +static Size getTexSize(const gfx::Drawable& drawable, const std::string_view name) { + if (const auto shader = drawable.getShader()) { + if (const auto index = shader->getSamplerLocation(name)) { + if (const auto& tex = drawable.getTexture(*index)) { + return tex->getSize(); + } + } + } + return {0, 0}; +} + +static std::array toArray(const Size& s) { + return util::cast(std::array{s.width, s.height}); +} + +constexpr auto texUniformName = "u_texture"; +constexpr auto texIconUniformName = "u_texture_icon"; + +template +static auto constOrDefault(const IndexedTuple, TypeList>& evaluated) { + return evaluated.template get().constantOr(T::defaultValue()); +} + +void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, + const RenderTree& renderTree, + const PaintParameters& parameters) { + auto& context = parameters.context; + const auto& state = parameters.state; + const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + + if (layerGroup.empty()) { + return; + } + +#if !defined(NDEBUG) + const auto label = layerGroup.getName() + "-update-uniforms"; + const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); +#endif + + layerGroup.observeDrawables([&](gfx::Drawable& drawable) { + if (!drawable.getTileID() || !drawable.getData()) { + return; + } + + const auto tileID = drawable.getTileID()->toUnwrapped(); + const auto& symbolData = static_cast(*drawable.getData()); + const auto isText = (symbolData.symbolType == SymbolType::Text); + const SymbolDrawablePaintUBO paintUBO = { + /*.fill_color=*/gfx::Drawable::colorAttrRGBA(isText ? constOrDefault(evaluated) + : constOrDefault(evaluated)), + /*.halo_color=*/ + gfx::Drawable::colorAttrRGBA(isText ? constOrDefault(evaluated) + : constOrDefault(evaluated)), + /*.opacity=*/isText ? constOrDefault(evaluated) : constOrDefault(evaluated), + /*.halo_width=*/ + isText ? constOrDefault(evaluated) : constOrDefault(evaluated), + /*.halo_blur=*/isText ? constOrDefault(evaluated) : constOrDefault(evaluated), + /*.padding=*/0, + }; + + // from RenderTile::translatedMatrix + const auto translate = isText ? evaluated.get() : evaluated.get(); + const auto anchor = isText ? evaluated.get() + : evaluated.get(); + constexpr bool inViewportPixelUnits = false; + const auto matrix = getTileMatrix(tileID, renderTree, state, translate, anchor, inViewportPixelUnits); + + // from symbol_program, makeValues + const auto currentZoom = static_cast(state.getZoom()); + const float pixelsToTileUnits = tileID.pixelsToTileUnits(1.f, currentZoom); + const bool pitchWithMap = symbolData.pitchAlignment == style::AlignmentType::Map; + const bool rotateWithMap = symbolData.rotationAlignment == style::AlignmentType::Map; + const bool alongLine = symbolData.placement != SymbolPlacementType::Point && + symbolData.rotationAlignment == AlignmentType::Map; + const bool hasVariablePlacement = symbolData.bucketVariablePlacement && + (isText || symbolData.textFit != IconTextFitType::None); + const mat4 labelPlaneMatrix = (alongLine || hasVariablePlacement) + ? matrix::identity4() + : getLabelPlaneMatrix( + matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); + const mat4 glCoordMatrix = getGlCoordMatrix(matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); + + const auto camDist = state.getCameraToCenterDistance(); + const float gammaScale = (symbolData.pitchAlignment == AlignmentType::Map + ? static_cast(std::cos(state.getPitch())) * camDist + : 1.0f); + + // Line label rotation happens in `updateLineLabels`/`reprojectLineLabels`` + // Pitched point labels are automatically rotated by the labelPlaneMatrix projection + // Unpitched point labels need to have their rotation applied after projection + const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine; + + const SymbolDrawableUBO drawableUBO = { + /*.matrix=*/util::cast(matrix), + /*.label_plane_matrix=*/util::cast(labelPlaneMatrix), + /*.coord_matrix=*/util::cast(glCoordMatrix), + + /*.texsize=*/toArray(getTexSize(drawable, texUniformName)), + /*.texsize_icon=*/toArray(getTexSize(drawable, texIconUniformName)), + + /*.gamma_scale=*/gammaScale, + /*.device_pixel_ratio=*/parameters.pixelRatio, + + /*.camera_to_center_distance=*/camDist, + /*.pitch=*/static_cast(state.getPitch()), + /*.rotate_symbol=*/rotateInShader, + /*.aspect_ratio=*/state.getSize().aspectRatio(), + /*.fade_change=*/parameters.symbolFadeChange, + /*.pad=*/0, + }; + + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.createOrUpdate(SymbolDrawablePaintUBOName, &paintUBO, context); + uniforms.createOrUpdate(SymbolDrawableUBOName, &drawableUBO, context); + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp new file mode 100644 index 000000000..440c5fa9d --- /dev/null +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include + +namespace mbgl { + +/** + Symbol layer specific tweaker + */ +class SymbolLayerTweaker : public LayerTweaker { +public: + SymbolLayerTweaker(Immutable properties) + : LayerTweaker(properties){}; + +public: + ~SymbolLayerTweaker() override = default; + + void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override; + + static constexpr std::string_view SymbolDrawableUBOName = "SymbolDrawableUBO"; + static constexpr std::string_view SymbolDrawablePaintUBOName = "SymbolDrawablePaintUBO"; + static constexpr std::string_view SymbolDrawableTilePropsUBOName = "SymbolDrawableTilePropsUBO"; + static constexpr std::string_view SymbolDrawableInterpolateUBOName = "SymbolDrawableInterpolateUBO"; + +private: +}; + +/// Evaluated properties that depend on the tile +struct alignas(16) SymbolDrawableTilePropsUBO { + /* 0 */ /*bool*/ int is_text; + /* 4 */ /*bool*/ int is_halo; + /* 8 */ /*bool*/ int pitch_with_map; + /* 12 */ /*bool*/ int is_size_zoom_constant; + /* 16 */ /*bool*/ int is_size_feature_constant; + /* 20 */ float size_t; + /* 24 */ float size; + /* 28 */ float padding; + /* 32 */ +}; +static_assert(sizeof(SymbolDrawableTilePropsUBO) == 2 * 16); + +/// Attribute interpolations +struct alignas(16) SymbolDrawableInterpolateUBO { + /* 0 */ float fill_color_t; + /* 4 */ float halo_color_t; + /* 8 */ float opacity_t; + /* 12 */ float halo_width_t; + /* 16 */ float halo_blur_t; + /* 20 */ float pad1, pad2, pad3; + /* 32 */ +}; +static_assert(sizeof(SymbolDrawableInterpolateUBO) == 32); + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index d1dfbdf8f..dc244558c 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -1,9 +1,11 @@ #include + #include #include #include #include #include +#include #include #include #include @@ -63,12 +65,16 @@ std::optional RenderLayer::getSolidBackground() const { } #if MLN_DRAWABLE_RENDERER -void RenderLayer::layerRemoved(UniqueChangeRequestVec& changes) { - // Remove everything - if (tileLayerGroup) { - changes.emplace_back(std::make_unique(tileLayerGroup->getLayerIndex())); - tileLayerGroup.reset(); - } +void RenderLayer::layerChanged(const TransitionParameters&, + const Immutable&, + UniqueChangeRequestVec& changes) { + // Treat a layer change the same as a remove. + // It will be set up again when `update()` is called. + layerRemoved(changes); +} + +void RenderLayer::layerRemoved(UniqueChangeRequestVec&) { + removeAllDrawables(); } #endif @@ -126,13 +132,15 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile, #if MLN_DRAWABLE_RENDERER void RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { - stats.tileDrawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size(); + if (const auto tileGroup = static_cast(layerGroup.get())) { + stats.drawablesRemoved += tileGroup->removeDrawables(renderPass, tileID).size(); + } } -void RenderLayer::removeAllTiles() { - if (tileLayerGroup) { - stats.tileDrawablesRemoved += tileLayerGroup->getDrawableCount(); - tileLayerGroup->clearDrawables(); +void RenderLayer::removeAllDrawables() { + if (layerGroup) { + stats.drawablesRemoved += layerGroup->getDrawableCount(); + layerGroup->clearDrawables(); } } @@ -140,27 +148,40 @@ void RenderLayer::layerIndexChanged(int32_t newLayerIndex, UniqueChangeRequestVe layerIndex = newLayerIndex; // Submit a change request to update the layer index of our tile layer group - if (tileLayerGroup) { - changes.emplace_back(std::make_unique(tileLayerGroup, newLayerIndex)); + if (layerGroup) { + changes.emplace_back(std::make_unique(layerGroup, newLayerIndex)); } } void RenderLayer::markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) { - if (!tileLayerGroup) { - return; - } - if (isRenderable == willRender) { - return; - } + isRenderable = willRender; // This layer is either being freshly included in the renderable set or excluded - isRenderable = willRender; - if (willRender) { - // The RenderTree has determined this layer should be included in the renderable set for a frame - changes.emplace_back(std::make_unique(tileLayerGroup, /*canReplace=*/true)); - } else { - // The RenderTree is informing us we should not render anything - changes.emplace_back(std::make_unique(tileLayerGroup->getLayerIndex())); + activateLayerGroup(layerGroup, willRender, changes); +} + +void RenderLayer::setLayerGroup(LayerGroupBasePtr layerGroup_, UniqueChangeRequestVec& changes) { + // Remove the active layer group, if any, before replacing it. + activateLayerGroup(layerGroup, false, changes); + + layerGroup = std::move(layerGroup_); + + // Add the new layer group, if we're currently renderable. + activateLayerGroup(layerGroup, isRenderable, changes); +} + +/// (Un-)Register the layer group with the orchestrator +void RenderLayer::activateLayerGroup(const LayerGroupBasePtr& layerGroup_, + bool activate, + UniqueChangeRequestVec& changes) { + if (layerGroup_) { + if (activate) { + // The RenderTree has determined this layer should be included in the renderable set for a frame + changes.emplace_back(std::make_unique(layerGroup_, /*canReplace=*/true)); + } else { + // The RenderTree is informing us we should not render anything + changes.emplace_back(std::make_unique(layerGroup_->getLayerIndex())); + } } } #endif diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index a9ce01284..1c80c2816 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -17,6 +17,7 @@ namespace mbgl { class Bucket; class DynamicFeatureIndex; +class LayerGroupBase; class LineAtlas; class PropertyEvaluationParameters; class PaintParameters; @@ -30,8 +31,7 @@ class UploadParameters; #if MLN_DRAWABLE_RENDERER class ChangeRequest; -class TileLayerGroup; -using TileLayerGroupPtr = std::shared_ptr; +using LayerGroupBasePtr = std::shared_ptr; using UniqueChangeRequest = std::unique_ptr; using UniqueChangeRequestVec = std::vector; #endif @@ -160,6 +160,12 @@ public: virtual void update( gfx::ShaderRegistry&, gfx::Context&, const TransformState&, const RenderTree&, UniqueChangeRequestVec&) {} + /// Called when the style layer is replaced (same ID and type), and the render layer is reused. + virtual void layerChanged(const TransitionParameters&, + const Immutable& newLayer, + UniqueChangeRequestVec&); + + /// Called when the style layer is removed virtual void layerRemoved(UniqueChangeRequestVec&); /// @brief Called by the RenderOrchestrator during RenderTree construction. @@ -185,11 +191,16 @@ protected: const LayerRenderData* getRenderDataForPass(const RenderTile&, RenderPass) const; #if MLN_DRAWABLE_RENDERER + void setLayerGroup(LayerGroupBasePtr, UniqueChangeRequestVec&); + + /// (Un-)Register the layer group with the orchestrator + void activateLayerGroup(const LayerGroupBasePtr&, bool activate, UniqueChangeRequestVec& changes); + /// Remove all drawables for the tile from the layer group void removeTile(RenderPass, const OverscaledTileID&); /// Remove all the drawables for tiles - void removeAllTiles(); + void removeAllDrawables(); #endif protected: @@ -203,10 +214,12 @@ protected: LayerPlacementData placementData; #if MLN_DRAWABLE_RENDERER - TileLayerGroupPtr tileLayerGroup; + // will need to be overriden to handle their activation. + LayerGroupBasePtr layerGroup; #endif // Current layer index as specified by the layerIndexChanged event int32_t layerIndex{0}; + // Current renderable status as specified by the markLayerRenderable event bool isRenderable{false}; @@ -214,8 +227,8 @@ protected: struct Stats { size_t propertyEvaluations = 0; - size_t tileDrawablesAdded = 0; - size_t tileDrawablesRemoved = 0; + size_t drawablesAdded = 0; + size_t drawablesRemoved = 0; } stats; private: diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 6565ac31c..995459261 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -248,7 +248,15 @@ std::unique_ptr RenderOrchestrator::createRenderTree( // Update render layers for changed layers. for (const auto& entry : layerDiff.changed) { - renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after); + if (const auto& renderLayer = renderLayers.at(entry.first)) { + const auto& newLayer = entry.second.after; + +#if MLN_DRAWABLE_RENDERER + renderLayer->layerChanged(transitionParameters, newLayer, changes); +#endif // MLN_DRAWABLE_RENDERER + + renderLayer->transition(transitionParameters, newLayer); + } } if (layersAddedOrRemoved) { diff --git a/src/mbgl/renderer/tile_layer_group.cpp b/src/mbgl/renderer/tile_layer_group.cpp index 4326fa4b9..01408c2e9 100644 --- a/src/mbgl/renderer/tile_layer_group.cpp +++ b/src/mbgl/renderer/tile_layer_group.cpp @@ -37,11 +37,7 @@ TileLayerGroup::TileLayerGroup(int32_t layerIndex_, std::size_t initialCapacity, : LayerGroupBase(layerIndex_, std::move(name_)), impl(std::make_unique(initialCapacity)) {} -TileLayerGroup::~TileLayerGroup() {} - -void TileLayerGroup::updateLayerIndex(int32_t newLayerIndex) { - layerIndex = newLayerIndex; -} +TileLayerGroup::~TileLayerGroup() = default; std::size_t TileLayerGroup::getDrawableCount() const { return impl->tileDrawables.size();