From ea83eeb690192ffd28969ed68d8a1262e50de883 Mon Sep 17 00:00:00 2001 From: Yousif Aldolaijan Date: Wed, 5 Nov 2025 16:03:14 +0300 Subject: [PATCH 1/5] disable perspective scaling for symbols when offset is configured --- include/mbgl/shaders/gl/symbol_icon.hpp | 5 ++- include/mbgl/shaders/gl/symbol_sdf.hpp | 5 ++- .../mbgl/shaders/gl/symbol_text_and_icon.hpp | 5 ++- include/mbgl/shaders/mtl/symbol.hpp | 31 ++++++++++++------- include/mbgl/shaders/symbol_layer_ubo.hpp | 5 +-- include/mbgl/shaders/vulkan/symbol.hpp | 15 +++++++-- include/mbgl/shaders/webgpu/symbol.hpp | 13 ++++++-- shaders/symbol_icon.vertex.glsl | 5 ++- shaders/symbol_sdf.vertex.glsl | 5 ++- shaders/symbol_text_and_icon.vertex.glsl | 5 ++- src/mbgl/gfx/symbol_drawable_data.hpp | 7 +++-- .../renderer/layers/render_symbol_layer.cpp | 21 ++++++++----- .../renderer/layers/symbol_layer_tweaker.cpp | 1 + 13 files changed, 87 insertions(+), 36 deletions(-) diff --git a/include/mbgl/shaders/gl/symbol_icon.hpp b/include/mbgl/shaders/gl/symbol_icon.hpp index 9ac73b34aa43..79590f9ff6ee 100644 --- a/include/mbgl/shaders/gl/symbol_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_icon.hpp @@ -39,6 +39,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -115,7 +116,9 @@ lowp float opacity = u_opacity; 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = u_is_text_prop ? size / 24.0 : size; diff --git a/include/mbgl/shaders/gl/symbol_sdf.hpp b/include/mbgl/shaders/gl/symbol_sdf.hpp index 23a039491c06..cf0b7039b3e5 100644 --- a/include/mbgl/shaders/gl/symbol_sdf.hpp +++ b/include/mbgl/shaders/gl/symbol_sdf.hpp @@ -47,6 +47,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -167,7 +168,9 @@ lowp float halo_blur = u_halo_blur; 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = u_is_text_prop ? size / 24.0 : size; diff --git a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp index 39fc1906b1f0..88b1142ceb45 100644 --- a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp @@ -46,6 +46,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -166,7 +167,9 @@ lowp float halo_blur = u_halo_blur; 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = size / 24.0; diff --git a/include/mbgl/shaders/mtl/symbol.hpp b/include/mbgl/shaders/mtl/symbol.hpp index c4f22e6677a7..d04194b5e9ed 100644 --- a/include/mbgl/shaders/mtl/symbol.hpp +++ b/include/mbgl/shaders/mtl/symbol.hpp @@ -29,19 +29,20 @@ struct alignas(16) SymbolDrawableUBO { /* 216 */ /*bool*/ int pitch_with_map; /* 220 */ /*bool*/ int is_size_zoom_constant; /* 224 */ /*bool*/ int is_size_feature_constant; + /* 228 */ /*bool*/ int is_offset; - /* 228 */ float size_t; - /* 232 */ float size; + /* 232 */ float size_t; + /* 236 */ float size; // Interpolations - /* 236 */ float fill_color_t; - /* 240 */ float halo_color_t; - /* 244 */ float opacity_t; - /* 248 */ float halo_width_t; - /* 252 */ float halo_blur_t; - /* 256 */ + /* 240 */ float fill_color_t; + /* 244 */ float halo_color_t; + /* 248 */ float opacity_t; + /* 252 */ float halo_width_t; + /* 256 */ float halo_blur_t; + /* 260 */ }; -static_assert(sizeof(SymbolDrawableUBO) == 16 * 16, "wrong size"); +static_assert(sizeof(SymbolDrawableUBO) == 17 * 16, "wrong size"); struct alignas(16) SymbolTilePropsUBO { /* 0 */ /*bool*/ int is_text; @@ -171,7 +172,9 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = drawable.is_text_prop ? size / 24.0 : size; @@ -348,7 +351,9 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = drawable.is_text_prop ? size / 24.0 : size; @@ -583,7 +588,9 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = size / 24.0; diff --git a/include/mbgl/shaders/symbol_layer_ubo.hpp b/include/mbgl/shaders/symbol_layer_ubo.hpp index 84f176d0dc63..97a05ab4b70a 100644 --- a/include/mbgl/shaders/symbol_layer_ubo.hpp +++ b/include/mbgl/shaders/symbol_layer_ubo.hpp @@ -28,9 +28,10 @@ struct alignas(16) SymbolDrawableUBO { /* 244 */ float opacity_t; /* 248 */ float halo_width_t; /* 252 */ float halo_blur_t; - /* 256 */ + /* 256 */ /*bool*/ int is_offset; + /* 260 */ }; -static_assert(sizeof(SymbolDrawableUBO) == 16 * 16); +static_assert(sizeof(SymbolDrawableUBO) == 17 * 16); struct alignas(16) SymbolTilePropsUBO { /* 0 */ /*bool*/ int is_text; diff --git a/include/mbgl/shaders/vulkan/symbol.hpp b/include/mbgl/shaders/vulkan/symbol.hpp index 96edd885d610..9a2c0dfad76b 100644 --- a/include/mbgl/shaders/vulkan/symbol.hpp +++ b/include/mbgl/shaders/vulkan/symbol.hpp @@ -52,6 +52,7 @@ struct SymbolDrawableUBO { bool pitch_with_map; bool is_size_zoom_constant; bool is_size_feature_constant; + bool is_offset; float size_t; float size; @@ -106,7 +107,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = drawable.is_text_prop ? size / 24.0 : size; @@ -256,6 +259,7 @@ struct SymbolDrawableUBO { bool pitch_with_map; bool is_size_zoom_constant; bool is_size_feature_constant; + bool is_offset; float size_t; float size; @@ -335,7 +339,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = drawable.is_text_prop ? size / 24.0 : size; @@ -563,6 +569,7 @@ struct SymbolDrawableUBO { bool pitch_with_map; bool is_size_zoom_constant; bool is_size_feature_constant; + bool is_offset; float size_t; float size; @@ -644,7 +651,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!drawable.is_offset) { + size *= perspective_ratio; + } const float fontScale = size / 24.0; diff --git a/include/mbgl/shaders/webgpu/symbol.hpp b/include/mbgl/shaders/webgpu/symbol.hpp index 557f22b6634f..fb0b3a9b0480 100644 --- a/include/mbgl/shaders/webgpu/symbol.hpp +++ b/include/mbgl/shaders/webgpu/symbol.hpp @@ -41,6 +41,7 @@ struct SymbolDrawableUBO { pitch_with_map: u32, is_size_zoom_constant: u32, is_size_feature_constant: u32, + is_offset: u32, size_t: f32, size: f32, @@ -175,7 +176,9 @@ fn main(in: VertexInput) -> VertexOutput { ); let perspective_ratio = clamp(0.5 + 0.5 * distance_ratio, 0.0, 4.0); - size *= perspective_ratio; + if (drawable.is_offset == 0u) { + size *= perspective_ratio; + } let is_text = drawable.is_text_prop != 0u; let fontScale = select(size, size / 24.0, is_text); @@ -348,7 +351,9 @@ fn main(in: VertexInput) -> VertexOutput { ); let perspective_ratio = clamp(0.5 + 0.5 * distance_ratio, 0.0, 4.0); - size *= perspective_ratio; + if (drawable.is_offset == 0u) { + size *= perspective_ratio; + } let is_text = drawable.is_text_prop != 0u; let fontScale = select(size, size / 24.0, is_text); @@ -597,7 +602,9 @@ fn main(in: VertexInput) -> VertexOutput { ); let perspective_ratio = clamp(0.5 + 0.5 * distance_ratio, 0.0, 4.0); - size *= perspective_ratio; + if (drawable.is_offset == 0u) { + size *= perspective_ratio; + } let fontScale = size / 24.0; diff --git a/shaders/symbol_icon.vertex.glsl b/shaders/symbol_icon.vertex.glsl index 678f3323b74f..a2c5dffd7328 100644 --- a/shaders/symbol_icon.vertex.glsl +++ b/shaders/symbol_icon.vertex.glsl @@ -29,6 +29,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -98,7 +99,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = u_is_text_prop ? size / 24.0 : size; diff --git a/shaders/symbol_sdf.vertex.glsl b/shaders/symbol_sdf.vertex.glsl index 6c94980d7afe..edf31d4ef31a 100644 --- a/shaders/symbol_sdf.vertex.glsl +++ b/shaders/symbol_sdf.vertex.glsl @@ -37,6 +37,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -122,7 +123,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = u_is_text_prop ? size / 24.0 : size; diff --git a/shaders/symbol_text_and_icon.vertex.glsl b/shaders/symbol_text_and_icon.vertex.glsl index 6035d4512770..3e0557d62065 100644 --- a/shaders/symbol_text_and_icon.vertex.glsl +++ b/shaders/symbol_text_and_icon.vertex.glsl @@ -36,6 +36,7 @@ layout (std140) uniform SymbolDrawableUBO { bool u_pitch_with_map; bool u_is_size_zoom_constant; bool u_is_size_feature_constant; + bool u_is_offset; 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 @@ -121,7 +122,9 @@ void main() { 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles 4.0); - size *= perspective_ratio; + if (!u_is_offset) { + size *= perspective_ratio; + } float fontScale = size / 24.0; diff --git a/src/mbgl/gfx/symbol_drawable_data.hpp b/src/mbgl/gfx/symbol_drawable_data.hpp index 6688b39ecaa1..fd7e3be04724 100644 --- a/src/mbgl/gfx/symbol_drawable_data.hpp +++ b/src/mbgl/gfx/symbol_drawable_data.hpp @@ -19,14 +19,16 @@ struct SymbolDrawableData : public DrawableData { const style::AlignmentType pitchAlignment_, const style::AlignmentType rotationAlignment_, const style::SymbolPlacementType placement_, - const style::IconTextFitType textFit_) + const style::IconTextFitType textFit_, + const bool isOffset_) : isHalo(isHalo_), bucketVariablePlacement(bucketVariablePlacement_), symbolType(symbolType_), pitchAlignment(pitchAlignment_), rotationAlignment(rotationAlignment_), placement(placement_), - textFit(textFit_) {} + textFit(textFit_), + isOffset(isOffset_) {} ~SymbolDrawableData() override = default; const bool isHalo; @@ -36,6 +38,7 @@ struct SymbolDrawableData : public DrawableData { const style::AlignmentType rotationAlignment; const style::SymbolPlacementType placement; const style::IconTextFitType textFit; + const bool isOffset; }; using UniqueSymbolDrawableData = std::unique_ptr; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 1c309f2bfcd2..4941699bb6ca 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -509,9 +509,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, }); } - const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get().isUndefined(); + const auto& layout = impl_cast(baseImpl).layout; + const bool sortFeaturesByKey = !layout.get().isUndefined(); std::multiset renderableSegments; std::unique_ptr builder; + const bool isOffset = !layout.get().isUndefined(); const auto currentZoom = static_cast(state.getZoom()); const auto layerPrefix = getID() + "/"; @@ -557,8 +559,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, return; } - const auto& layout = *bucket.layout; - const auto values = isText ? textPropertyValues(evaluated, layout) : iconPropertyValues(evaluated, layout); + const auto& bucketLayout = *bucket.layout; + const auto values = isText ? textPropertyValues(evaluated, bucketLayout) + : iconPropertyValues(evaluated, bucketLayout); const std::string suffix = isText ? "text/" : "icon/"; const auto addVertices = [&collisionBuilder](const auto& vertices) { @@ -705,8 +708,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& evaluated = getEvaluated(renderable.renderData.layerProperties); auto& bucketPaintProperties = bucket.paintProperties.at(getID()); - const auto& layout = *bucket.layout; - const auto values = isText ? textPropertyValues(evaluated, layout) : iconPropertyValues(evaluated, layout); + const auto& bucketLayout = *bucket.layout; + const auto values = isText ? textPropertyValues(evaluated, bucketLayout) + : iconPropertyValues(evaluated, bucketLayout); const auto& atlases = tile.getAtlasTextures(); if (!atlases) { @@ -756,7 +760,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, textSizeIsZoomConstant); } if (!isText && !tileInfo.iconTweaker) { - const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; + const bool iconScaled = bucketLayout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; tileInfo.iconTweaker = std::make_shared(atlases, idSymbolImageIconTexture, idSymbolImageTexture, @@ -816,8 +820,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, /*.symbolType=*/renderable.type, /*.pitchAlignment=*/values.pitchAlignment, /*.rotationAlignment=*/values.rotationAlignment, - /*.placement=*/layout.get(), - /*.textFit=*/layout.get())); + /*.placement=*/bucketLayout.get(), + /*.textFit=*/bucketLayout.get(), + /*.isOffset=*/isOffset)); tileLayerGroup->addDrawable(passes, tileID, std::move(drawable)); ++stats.drawablesAdded; diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp index 8e08a7679ced..94f16f76aeac 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -181,6 +181,7 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete .pitch_with_map = (symbolData.pitchAlignment == style::AlignmentType::Map), .is_size_zoom_constant = size.isZoomConstant, .is_size_feature_constant = size.isFeatureConstant, + .is_offset = symbolData.isOffset, .size_t = size.sizeT, .size = size.size, From e6a33e37c8ebf36f828b4ade0878ef7ed109c672 Mon Sep 17 00:00:00 2001 From: Yousif Aldolaijan Date: Wed, 5 Nov 2025 16:04:27 +0300 Subject: [PATCH 2/5] add test for disabling perspective scaling when offset is enabled --- .../icon-offset/pitched-offset/expected.png | Bin 0 -> 39802 bytes .../icon-offset/pitched-offset/style.json | 124 ++++++++++++++++++ metrics/integration/sprites/almccon.json | 23 ++++ metrics/integration/sprites/almccon.png | Bin 0 -> 4154 bytes 4 files changed, 147 insertions(+) create mode 100644 metrics/integration/render-tests/icon-offset/pitched-offset/expected.png create mode 100644 metrics/integration/render-tests/icon-offset/pitched-offset/style.json create mode 100644 metrics/integration/sprites/almccon.json create mode 100644 metrics/integration/sprites/almccon.png diff --git a/metrics/integration/render-tests/icon-offset/pitched-offset/expected.png b/metrics/integration/render-tests/icon-offset/pitched-offset/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..dc506cd9f7996fa0e42f2f778c301e6dadaec6f5 GIT binary patch literal 39802 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 literal 0 HcmV?d00001 diff --git a/metrics/integration/render-tests/icon-offset/pitched-offset/style.json b/metrics/integration/render-tests/icon-offset/pitched-offset/style.json new file mode 100644 index 000000000000..3841efc0151d --- /dev/null +++ b/metrics/integration/render-tests/icon-offset/pitched-offset/style.json @@ -0,0 +1,124 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 1048 + } + }, + "pitch": 60, + "center": [-118.78224, 39.32157], + "zoom": 14, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "LineString", + "coordinates": [ + [ + -118.78156097142148, + 39.47488496583114 + ], + [ + -118.7823961479745, + 39.28832054802072 + ] + ] + } + } +}, +"sprite": "local://sprites/almccon", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {"visibility": "visible"}, + "paint": {"background-color": "rgba(204, 204, 204, 1)"} + }, + { + "id": "streets", + "type": "line", + "source": "geojson", + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "rgba(32, 32, 32, 1)", + "line-width": 150 + } + }, + { + "id": "road-lane-dashes-right", + "type": "line", + "source": "geojson", + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [4, 12], + "line-offset": 7 + } + }, + { + "id": "road-lane-dashes-left", + "type": "line", + "source": "geojson", + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [4, 12], + "line-offset": -7 + } + }, + { + "id": "road-arrows-center", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-allow-overlap": true, + "icon-image": "through", + "icon-rotate": 90, + "icon-rotation-alignment": "map", + "icon-pitch-alignment": "map", + "icon-size": 1, + "symbol-placement": "line", + "symbol-spacing": 300 + }, + "paint": {"icon-opacity": 0.8} + }, + { + "id": "road-arrows-right", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-allow-overlap": true, + "icon-image": "through", + "icon-offset": [50.339999999999996, 0], + "icon-rotate": 90, + "icon-rotation-alignment": "map", + "icon-pitch-alignment": "map", + "icon-size": 1, + "symbol-placement": "line", + "symbol-spacing": 300 + }, + "paint": {"icon-opacity": 0.8} + }, + { + "id": "road-arrows-left", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-allow-overlap": true, + "icon-image": "through", + "icon-offset": [-53.339999999999996, 0], + "icon-rotate": 90, + "icon-rotation-alignment": "map", + "icon-pitch-alignment": "map", + "icon-size": 1, + "symbol-placement": "line", + "symbol-spacing": 300 + }, + "paint": {"icon-opacity": 0.8} + } + ] +} diff --git a/metrics/integration/sprites/almccon.json b/metrics/integration/sprites/almccon.json new file mode 100644 index 000000000000..07d6b51b1b97 --- /dev/null +++ b/metrics/integration/sprites/almccon.json @@ -0,0 +1,23 @@ +{ + "through": { + "width": 48, + "height": 64, + "x": 531, + "y": 64, + "pixelRatio": 1 + }, + "through;right": { + "width": 48, + "height": 64, + "x": 579, + "y": 64, + "pixelRatio": 1 + }, + "through;slight_right": { + "width": 48, + "height": 64, + "x": 627, + "y": 64, + "pixelRatio": 1 + } +} diff --git a/metrics/integration/sprites/almccon.png b/metrics/integration/sprites/almccon.png new file mode 100644 index 0000000000000000000000000000000000000000..d4555fe1ae02c6962b28962e7624f26e100b3a45 GIT binary patch literal 4154 zcmeHKeNaSZ+kgs`BDNBe7l@F&kOUK=K&-Q1 z7Z-O!TLe+MvZFN+L^Mze0$Z)fVnEl5fGeo6U;zmql7N8jy)S`jciP=Lcvcn~qd<`7mcqYz zNMX@(1bNyjj(kt~9`7AgfJ>-+As&xW)e;#%BZ%JywTv%F!jzTsnVvMd2aWDcVK7iH zCQA1rIbLMoP%adqTZ7(mxC2ida-vcxLuoXXN<~$9P;q$zjlp8EXmlox$)o@TMUf^| z^3@cn;+0v3AWR{Ui)BhNE+s)memtJ4ay)lTM-gqI9|)%EN_XQQD6|nGDq9hfq*B zLcWs!Kfyu)D#GOwKFC=t;U{1;nKXe+no|-D#FKG3a15gJAfn*$P_9&=kgi?`fiM`p*iGJKVT>9gH;eH~xk z`i=58Es?<<_k>Gf-RE3@>4qs2sBW+0}_pr?>* zPtV-w>nXa1yfR(U*>?X2xc-(2LeDPj;llFQrYp)&gw8&kSlcnJ`S@O?K6kB4-|LEE ze7|cuQPvgDf$~38qT;${j!dQKdXBHaN+n}6{-#$|?dM$x$U;!}+L)7iAMOXqH4l&J zTbN!~qi)VZ5C{CuDcqWUbn z*ti6O=r6KC68pZaQPk-_Sj%cKo5Nz0mf4Pc=MA;Uu9(vc=DP0@GZ*jPI}@!dVf#xz z;nc6(Jv8Ptvbp^>dp#tpz;mM(A#1lpg>YZ4*?rd3dnU(p<}H}0`pqO65FBDuU~bSq z0lFR>E;5_WT=WLp_xVn64=H&bdMO2phE;Fhwl?j^y`3$_uY0?y%;&;O`)@ErZ!a`e zcgQ7wnQ!t5T9QQAEYDMck(F(A-_c|V)>Rvf!Me!nVqK5)Uy816wH@0t3sNUIH7RXS z_Vlb$eN3Crg~09mEPsR6jrE-@pk$ZZj_JD4(K@4b8trnvx~(?RzzHAqYo1(|-&&pV z*(s1fV$yIcF(l(Gt~?Hc44Mc!sS>MVD3unTM2>*cTbU%W;L%f4{x_@%iMwB{+_#-%?>0TE5 zB({cuPu~jtws)`NQRC|Vn5@tBW>X!m@6Xq3wnl|Sv=Q}HkrNUD4t#k2BX+Y`m#0T1 zhV&x!QA?U`yza>feYvhoxBd4q$r+Eo*%rGxkqSf8{(TTq*PSsHH*sH%O0}BU37;9Q zA-ZMU$2BS60T%aDdD}&+FFi5nGfVs1^qT0XhIg-fuuVjVorIYzs_I-{KXLa|cjWaR zg}*3$>80?|R8mjxtHmXgQ+slIGbOb(`k@UZ=&w<=A6Q)Tt%dzos@J4VY{?QED6vUR zlN#$^yEDx-sy)Pw)F=Zb)cADOplf(LyS%Nmzq-Ie&OAKMzLY&kZm3E&yuZg>XdtdE zyPnrrQx|)RMKjdVb=fO1pTk#X;Ha7%}5O6kqC^rCUbKtlEkfRHt`yfB=w z+lA0B?$3mFS4uz!kGJ;cl?B?au67$guFv3(9y3<8FnUW$^(F3Yy1G`)`+-NoIc&(Q z1uaTHrq>kQljs;dD;|3e2-@4EX}GOBdDlk`m(V}D-MaIFrRgyIw+Oi{1vjuZWmWX` z;!a7(I5k&pyVa+v>^%J#wZ&dLX0(bw-V1TaPyjfS=3EUV!hI92KY z+RUV=D#txPb|^M1<#&G2w9$JPD6s>U2;B{X@oUx4?p-ZLOcy=>DC4-Tr=~u1bj?7? zKcjuhB{{YP+tFvBNt`=W@e69Dv$=Ght$y{L6;oCJKntIMUh2A|XekpA&ENP2JYsW< zDDInbeg5R5`=e31Gwog3SJ%}Z#&mgWLcXkS|1@g++Z`0=@mwY3)vkfUj1&!4+??ty z9|_i7Te0BV@J2kK>7g68 z;Nil*v8;qQ9|Gwwf=lAI)|)Y{zRQq~-6?lVHl%;i)(0B^u{MLz zihNO3Ij|Bw-v0y?M5A%Gi#wJ9Q*Ba?qp2N_E#H5HR>;r!@ukg<_ZmlfP8VvlFO(g3 zCG6sM5M!$G<$Uf@cUISQ{ie~BV=+}Vm+Sgg-eoSyv=7{UMtz}%s6b%U@p_Y Date: Thu, 6 Nov 2025 16:27:23 +0300 Subject: [PATCH 3/5] correctly order the symbol ubo is_offset property --- include/mbgl/shaders/symbol_layer_ubo.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mbgl/shaders/symbol_layer_ubo.hpp b/include/mbgl/shaders/symbol_layer_ubo.hpp index 97a05ab4b70a..63c4cb84ee4e 100644 --- a/include/mbgl/shaders/symbol_layer_ubo.hpp +++ b/include/mbgl/shaders/symbol_layer_ubo.hpp @@ -18,17 +18,17 @@ struct alignas(16) SymbolDrawableUBO { /* 216 */ /*bool*/ int pitch_with_map; /* 220 */ /*bool*/ int is_size_zoom_constant; /* 224 */ /*bool*/ int is_size_feature_constant; + /* 228 */ /*bool*/ int is_offset; - /* 228 */ float size_t; - /* 232 */ float size; + /* 232 */ float size_t; + /* 236 */ float size; // Interpolations - /* 236 */ float fill_color_t; - /* 240 */ float halo_color_t; - /* 244 */ float opacity_t; - /* 248 */ float halo_width_t; - /* 252 */ float halo_blur_t; - /* 256 */ /*bool*/ int is_offset; + /* 240 */ float fill_color_t; + /* 244 */ float halo_color_t; + /* 248 */ float opacity_t; + /* 252 */ float halo_width_t; + /* 256 */ float halo_blur_t; /* 260 */ }; static_assert(sizeof(SymbolDrawableUBO) == 17 * 16); From 2aa10f30c9a9984fab965b38888874f6ba1ad529 Mon Sep 17 00:00:00 2001 From: Yousif Aldolaijan Date: Sun, 9 Nov 2025 12:50:14 +0300 Subject: [PATCH 4/5] add missing resources to check-style.db for testing --- metrics/cache-style.db | Bin 21344256 -> 21348352 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/metrics/cache-style.db b/metrics/cache-style.db index 11658f27560f283c5723c55201af38ba39eb9ca2..5ff6f77a24a2be5115f4fc793594482cba2a191a 100644 GIT binary patch delta 6108 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 delta 1527 zcmYM!WmJ;^6o>J>dk2#lfP#hS2wOpCi;9Bn6vghsLInf6FtORJ*_+*go1z%lirwAa z-TmB8e)v7-p7Z~H6BBKQ#C!7$7C$$qM&r}gY7FNHiAzg~85gDOaXyXm@294Dn4J3k zgA}K?V~2jcDI>|0p+E~2I=I0ddSrqJ49JWu$ck+6gcrP#9Xa3wU*tqC zH4uSF)I=@RMjg~eJ=8}7n9&f85QWBQf@m~FGc-pFv_vbkMjNz6JG4g!bVMg~Mi+EN z47#B^dY~tIAr`&S2YnHTc=SVm48TAnU=Rjl2!>)9hGPUqViZPW3=%OG<1ii*FcFiG zgvpqKshEc8n1Pu{h6Ps4!fedJT+D+F^RWO6u?UN?1WRFu1Iw@+E3gu)uo`Qy7VEGc z8?X_Zuo+vh6)D)3YRYh4II2eKVr_bhtF$t=kt$tuYv@sxN;yd~KsIV3(3UrA0$E=g`l9!Xw_pCq5e zUy@%^Kw^{xNCG86l3+ Date: Mon, 10 Nov 2025 16:31:21 +0300 Subject: [PATCH 5/5] add icon offset to test style to match expected image --- .../render-tests/icon-offset/pitched-offset/style.json | 1 + 1 file changed, 1 insertion(+) diff --git a/metrics/integration/render-tests/icon-offset/pitched-offset/style.json b/metrics/integration/render-tests/icon-offset/pitched-offset/style.json index 3841efc0151d..8aa7d6d18e8d 100644 --- a/metrics/integration/render-tests/icon-offset/pitched-offset/style.json +++ b/metrics/integration/render-tests/icon-offset/pitched-offset/style.json @@ -77,6 +77,7 @@ "layout": { "icon-allow-overlap": true, "icon-image": "through", + "icon-offset": [0, 0], "icon-rotate": 90, "icon-rotation-alignment": "map", "icon-pitch-alignment": "map",