Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
## main
### ✨ Features and improvements
- _...Add new stuff here..._
<<<<<<< HEAD
- GPU performance optimization: Render halo and glyph in a single pass (-40% Time Reduction) ([#7436](https://github.com/maplibre/maplibre-gl-js/pull/7436)) (by [@xavierjs](https://github.com/xavierjs))
=======
- Optimize matrix inversions and reduce GPU stalls ([#7367](https://github.com/maplibre/maplibre-gl-js/pull/7367)) (by [@xavierjs](https://github.com/xavierjs))
- Add example showing how to measure map performance using built-in events (`load`, `idle`, `render`) ([#7077](https://github.com/maplibre/maplibre-gl-js/pull/7077)) (by [@CommanderStorm](https://github.com/CommanderStorm))
- Add `touchZoomRotate.setZoomRate()` and `touchZoomRotate.setZoomThreshold()` to customize touch zoom speed and pinch sensitivity ([#7271](https://github.com/maplibre/maplibre-gl-js/issues/7271))
>>>>>>> main

### 🐞 Bug fixes
- Fix `Popup` not updating its position when switching between terrain/globe projections ([#7468](https://github.com/maplibre/maplibre-gl-js/pull/7468)) (by [@CommanderStorm](https://github.com/CommanderStorm))
Expand Down
36 changes: 25 additions & 11 deletions src/shaders/glsl/symbol_sdf.fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define SDF_PX 8.0

uniform bool u_is_halo;
uniform bool u_is_plain;
uniform sampler2D u_texture;
uniform highp float u_gamma_scale;
uniform lowp float u_device_pixel_ratio;
Expand Down Expand Up @@ -29,26 +30,39 @@ void main() {

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 inner_edge = (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);
inner_edge = inner_edge + gamma * gamma_scale;
}

lowp float dist = texture(u_texture, tex).a;
highp float gamma_scaled = gamma * gamma_scale;
highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist);

lowp vec4 color_alpha_out_text, color_alpha_out_halo;

if (u_is_plain){
highp float gamma_scaled = gamma * gamma_scale;
highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist);
color_alpha_out_text = total_opacity * alpha * fill_color;
}
if (u_is_halo) {
float gamma_halo = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
float inner_edge_halo = inner_edge + gamma_halo * gamma_scale;
highp float gamma_scaled_halo = gamma_halo * gamma_scale;
highp float alpha_halo = smoothstep(inner_edge_halo - gamma_scaled_halo, inner_edge_halo + gamma_scaled_halo, dist);

// When drawing halos, we want the inside of the halo to be transparent as well
// in case the text fill is transparent.
lowp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX;
alpha = min(smoothstep(halo_edge - gamma_scaled, halo_edge + gamma_scaled, dist), 1.0 - alpha);
highp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX;
alpha_halo = min(smoothstep(halo_edge - gamma_scaled_halo, halo_edge + gamma_scaled_halo, dist), 1.0 - alpha_halo);

color_alpha_out_halo = total_opacity * alpha_halo * halo_color;
}
if (u_is_plain && u_is_halo) {
fragColor = color_alpha_out_text + (1. - color_alpha_out_text.a) * color_alpha_out_halo;
} else if (u_is_halo){
fragColor = color_alpha_out_halo;
} else {
fragColor = color_alpha_out_text;
}

fragColor = color * (alpha * total_opacity);

#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
Expand Down
32 changes: 23 additions & 9 deletions src/shaders/glsl/symbol_text_and_icon.fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define ICON 0.0

uniform bool u_is_halo;
uniform bool u_is_text;
uniform sampler2D u_texture;
uniform sampler2D u_texture_icon;
uniform highp float u_gamma_scale;
Expand Down Expand Up @@ -44,20 +45,33 @@ void main() {

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;

lowp vec4 color_alpha_out, color_alpha_out_halo;
if (u_is_text) {
highp float gamma_scaled = gamma * gamma_scale;
highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist);
color_alpha_out = fill_color * (alpha * total_opacity);
}
if (u_is_halo) {
highp float gamma_halo = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
lowp float buff_halo = (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);
highp float gamma_scaled_halo = gamma_halo * gamma_scale;
highp float alpha_halo = smoothstep(buff_halo - gamma_scaled_halo, buff_halo + gamma_scaled_halo, dist);

color_alpha_out_halo = halo_color * (alpha_halo * total_opacity);
}

fragColor = color * (alpha * total_opacity);
if (u_is_text && u_is_halo) {
fragColor = color_alpha_out + (1. - color_alpha_out.a) * color_alpha_out_halo;
} else if (u_is_halo) {
fragColor = color_alpha_out_halo;
} else {
fragColor = color_alpha_out;
}

#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
Expand Down
24 changes: 19 additions & 5 deletions src/webgl/draw/draw_symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ function drawLayerSymbols(
if (!bucket.iconsInText) {
uniformValues = symbolSDFUniformValues(sizeData.kind,
size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter,
uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, true, pitchedTextRescaling);
uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, hasHalo, pitchedTextRescaling);
} else {
uniformValues = symbolTextAndIconUniformValues(sizeData.kind,
size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter,
Expand Down Expand Up @@ -460,6 +460,10 @@ function drawLayerSymbols(
tileRenderState.sort((a, b) => a.sortKey - b.sortKey);
}

const haloWidthProperty = layer.paint.get(isText ? 'text-halo-width' : 'icon-halo-width');
const haloWidth = haloWidthProperty.constantOr(null) ?? Infinity;
const isGlyphOverlap = layer.layout.get('text-letter-spacing').constantOr(0) * ONE_EM < 0 || haloWidth > 1;

for (const segmentState of tileRenderState) {
const state = segmentState.state;

Expand All @@ -472,15 +476,25 @@ function drawLayerSymbols(
}
}

if (state.isSDF) {
const isHalo = state.isSDF && state.hasHalo;
if (isHalo) {
const uniformValues = state.uniformValues;
if (state.hasHalo) {
uniformValues['u_is_halo'] = 1;
uniformValues['u_is_halo'] = 1;
if (isGlyphOverlap){
// render halo in 2 pass (1 for the halo only, 1 for the text only)
uniformValues['u_is_plain'] = 0;
drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, uniformValues, state.projectionData, segmentState.terrainData);
uniformValues['u_is_halo'] = 0;
uniformValues['u_is_plain'] = 1;
}
uniformValues['u_is_halo'] = 0;
}

drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, state.uniformValues, state.projectionData, segmentState.terrainData);

if (isHalo && !isGlyphOverlap) {
// for 1 pass halo rendering, restore the uniforms state
state.uniformValues['u_is_halo'] = 0;
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/webgl/program/symbol_program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type SymbolSDFUniformsType = {
'u_gamma_scale': Uniform1f;
'u_device_pixel_ratio': Uniform1f;
'u_is_halo': Uniform1i;
'u_is_plain': Uniform1i;
'u_translation': Uniform2f;
'u_pitched_scale': Uniform1f;
};
Expand Down Expand Up @@ -123,6 +124,7 @@ const symbolSDFUniforms = (context: Context, locations: UniformLocations): Symbo
'u_gamma_scale': new Uniform1f(context, locations.u_gamma_scale),
'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio),
'u_is_halo': new Uniform1i(context, locations.u_is_halo),
'u_is_plain': new Uniform1i(context, locations.u_is_plain),
'u_translation': new Uniform2f(context, locations.u_translation),
'u_pitched_scale': new Uniform1f(context, locations.u_pitched_scale),
});
Expand Down Expand Up @@ -223,7 +225,8 @@ const symbolSDFUniformValues = (
glCoordMatrix, translation, isText, texSize, pitchedScale), {
'u_gamma_scale': (pitchWithMap ? Math.cos(transform.pitch * Math.PI / 180.0) * transform.cameraToCenterDistance : 1),
'u_device_pixel_ratio': painter.pixelRatio,
'u_is_halo': +isHalo
'u_is_halo': + ((isHalo) ? 1 : 0 ),
'u_is_plain': 1
});
};

Expand Down
25 changes: 25 additions & 0 deletions test/bench/benchmarks/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,31 @@ export class LayerSymbol extends LayerBenchmark {
}
}

export class LayerSymbolWithHalo extends LayerBenchmark {
constructor() {
super();

this.layerStyle = Object.assign({}, style, {
layers: generateLayers({
'id': 'symbollayer',
'type': 'symbol',
'source': 'openmaptiles',
'source-layer': 'poi',
'layout': {
'icon-image': 'dot_11',
'text-field': '{name_en}'
},
'paint': {
'text-color': '#000000',
'text-halo-color': '#ff0000',
'text-halo-width': 2,
'text-halo-blur': 1
}
})
});
}
}

export class LayerSymbolWithIcons extends LayerBenchmark {
constructor() {
super();
Expand Down
3 changes: 2 additions & 1 deletion test/bench/versions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import WorkerTransfer from '../benchmarks/worker_transfer';
import Paint from '../benchmarks/paint';
import PaintStates from '../benchmarks/paint_states';
import {PropertyLevelRemove, FeatureLevelRemove, SourceLevelRemove} from '../benchmarks/remove_paint_state';
import {LayerBackground, LayerCircle, LayerFill, LayerFillExtrusion, LayerHeatmap, LayerHillshade, LayerColorRelief2Colors, LayerColorRelief256Colors, LayerLine, LayerRaster, LayerSymbol, LayerSymbolWithIcons, LayerTextWithVariableAnchor, LayerSymbolWithSortKey} from '../benchmarks/layers';
import {LayerBackground, LayerCircle, LayerFill, LayerFillExtrusion, LayerHeatmap, LayerHillshade, LayerColorRelief2Colors, LayerColorRelief256Colors, LayerLine, LayerRaster, LayerSymbol, LayerSymbolWithHalo, LayerSymbolWithIcons, LayerTextWithVariableAnchor, LayerSymbolWithSortKey} from '../benchmarks/layers';
import Load from '../benchmarks/map_load';
import HillshadeLoad from '../benchmarks/hillshade_load';
import ColorReliefLoad from '../benchmarks/color_relief_load';
Expand Down Expand Up @@ -76,6 +76,7 @@ register('LayerColorRelief256Colors', new LayerColorRelief256Colors());
register('LayerLine', new LayerLine());
register('LayerRaster', new LayerRaster());
register('LayerSymbol', new LayerSymbol());
register('LayerSymbolWithHalo', new LayerSymbolWithHalo());
register('LayerSymbolWithIcons', new LayerSymbolWithIcons());
register('LayerTextWithVariableAnchor', new LayerTextWithVariableAnchor());
register('LayerSymbolWithSortKey', new LayerSymbolWithSortKey());
Expand Down
2 changes: 1 addition & 1 deletion test/build/bundle_size.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1055000
1055874
Loading