Skip to content

Commit

Permalink
Combine line shaders (#10894)
Browse files Browse the repository at this point in the history
* Move dash and gradient line rendering to line program

* Remove LineSDF and LineGradient sources

* Remove unused variables, fix linter errors

* Remove unused uniforms

* Fix type usage

* Check for computed dash array values in line program

* Add render test case for combined usage of line-gradient with line-dasharray

* Remove negated line-dasharray requirement from line-gradient

* Make gradient attributes packed
  • Loading branch information
endanke authored Jul 28, 2021
1 parent c3e9f7f commit 54615bd
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 426 deletions.
2 changes: 1 addition & 1 deletion src/data/array_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,7 @@ export {
StructArrayLayout4i8 as FillExtrusionLayoutArray,
StructArrayLayout2i4 as HeatmapLayoutArray,
StructArrayLayout2i4ub1f12 as LineLayoutArray,
StructArrayLayout2f8 as LineExtLayoutArray,
StructArrayLayout3f12 as LineExtLayoutArray,
StructArrayLayout10ui20 as PatternLayoutArray,
StructArrayLayout8ui16 as DashLayoutArray,
StructArrayLayout4i4ui4i24 as SymbolLayoutArray,
Expand Down
3 changes: 1 addition & 2 deletions src/data/bucket/line_attributes_ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import {createLayout} from '../../util/struct_array.js';

const lineLayoutAttributesExt = createLayout([
{name: 'a_uv_x', components: 1, type: 'Float32'},
{name: 'a_split_index', components: 1, type: 'Float32'},
{name: 'a_packed', components: 3, type: 'Float32'}
]);

export default lineLayoutAttributesExt;
Expand Down
2 changes: 1 addition & 1 deletion src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ class LineBucket implements Bucket {

// Constructs a second vertex buffer with higher precision line progress
if (this.lineClips) {
this.layoutVertexArray2.emplaceBack(this.scaledDistance, this.lineClipsArray.length);
this.layoutVertexArray2.emplaceBack(this.scaledDistance, this.lineClipsArray.length, this.lineSoFar);
}

const e = segment.vertexLength++;
Expand Down
41 changes: 20 additions & 21 deletions src/render/draw_line.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import Texture from './texture.js';
import {
lineUniformValues,
linePatternUniformValues,
lineSDFUniformValues,
lineGradientUniformValues
lineDefinesValues
} from './program/line_program.js';

import type Painter from './painter.js';
import type SourceCache from '../source/source_cache.js';
import type LineStyleLayer from '../style/style_layer/line_style_layer.js';
import type LineBucket from '../data/bucket/line_bucket.js';
import type {OverscaledTileID} from '../source/tile_id.js';
import type {DynamicDefinesType} from './program/program_uniforms.js';
import {clamp, nextPowerOfTwo} from '../util/util.js';
import {renderColorRamp} from '../util/color_ramp.js';
import EXTENT from '../data/extent.js';
Expand All @@ -38,10 +38,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
const gradient = layer.paint.get('line-gradient');
const crossfade = layer.getCrossfadeParameters();

const programId =
image ? 'linePattern' :
dasharray ? 'lineSDF' :
gradient ? 'lineGradient' : 'line';
const programId = image ? 'linePattern' : 'line';

const context = painter.context;
const gl = context.gl;
Expand All @@ -55,7 +52,8 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
painter.prepareDrawTile(coord);

const programConfiguration = bucket.programConfigurations.get(layer.id);
const program = painter.useProgram(programId, programConfiguration);
const definesValues = lineDefinesValues(layer);
const program = painter.useProgram(programId, programConfiguration, ((definesValues: any): DynamicDefinesType[]));

const constantPattern = patternProperty.constantOr(null);
if (constantPattern && tile.imageAtlas) {
Expand All @@ -76,20 +74,11 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
}

const matrix = painter.terrain ? coord.projMatrix : null;
const uniformValues = image ? linePatternUniformValues(painter, tile, layer, crossfade, matrix) :
dasharray ? lineSDFUniformValues(painter, tile, layer, crossfade, matrix) :
gradient ? lineGradientUniformValues(painter, tile, layer, matrix, bucket.lineClipsArray.length) :
lineUniformValues(painter, tile, layer, matrix);
const uniformValues = image ?
linePatternUniformValues(painter, tile, layer, crossfade, matrix) :
lineUniformValues(painter, tile, layer, crossfade, matrix, bucket.lineClipsArray.length);

if (image) {
context.activeTexture.set(gl.TEXTURE0);
tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
programConfiguration.updatePaintBuffers(crossfade);
} else if (dasharray) {
context.activeTexture.set(gl.TEXTURE0);
tile.lineAtlasTexture.bind(gl.LINEAR, gl.REPEAT);
programConfiguration.updatePaintBuffers(crossfade);
} else if (gradient) {
if (gradient) {
const layerGradient = bucket.gradients[layer.id];
let gradientTexture = layerGradient.texture;
if (layer.gradientVersion !== layerGradient.version) {
Expand Down Expand Up @@ -120,9 +109,19 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
layerGradient.version = layer.gradientVersion;
gradientTexture = layerGradient.texture;
}
context.activeTexture.set(gl.TEXTURE0);
context.activeTexture.set(gl.TEXTURE1);
gradientTexture.bind(layer.stepInterpolant ? gl.NEAREST : gl.LINEAR, gl.CLAMP_TO_EDGE);
}
if (dasharray) {
context.activeTexture.set(gl.TEXTURE0);
tile.lineAtlasTexture.bind(gl.LINEAR, gl.REPEAT);
programConfiguration.updatePaintBuffers(crossfade);
}
if (image) {
context.activeTexture.set(gl.TEXTURE0);
tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
programConfiguration.updatePaintBuffers(crossfade);
}

painter.prepareDrawProgram(context, program, coord.toUnwrapped());

Expand Down
117 changes: 42 additions & 75 deletions src/render/program/line_program.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
UniformMatrix4f
} from '../uniform_binding.js';
import pixelsToTileUnits from '../../source/pixels_to_tile_units.js';
import {extend} from '../../util/util.js';
import browser from '../../util/browser.js';

import type Context from '../../gl/context.js';
Expand All @@ -20,19 +19,16 @@ import type Painter from '../painter.js';
import type {CrossfadeParameters} from '../../style/evaluation_parameters.js';

export type LineUniformsType = {|
'u_matrix': UniformMatrix4f,
'u_ratio': Uniform1f,
'u_device_pixel_ratio': Uniform1f,
'u_units_to_pixels': Uniform2f
|};

export type LineGradientUniformsType = {|
'u_matrix': UniformMatrix4f,
'u_ratio': Uniform1f,
'u_device_pixel_ratio': Uniform1f,
'u_units_to_pixels': Uniform2f,
'u_image': Uniform1i,
'u_dash_image': Uniform1i,
'u_gradient_image': Uniform1i,
'u_image_height': Uniform1f,
'u_texsize': Uniform2f,
'u_scale': Uniform3f,
'u_mix': Uniform1f
|};

export type LinePatternUniformsType = {|
Expand All @@ -46,31 +42,19 @@ export type LinePatternUniformsType = {|
'u_fade': Uniform1f
|};

export type LineSDFUniformsType = {|
'u_matrix': UniformMatrix4f,
'u_texsize': Uniform2f,
'u_ratio': Uniform1f,
'u_device_pixel_ratio': Uniform1f,
'u_units_to_pixels': Uniform2f,
'u_scale': Uniform3f,
'u_image': Uniform1i,
'u_mix': Uniform1f
|};
export type LineDefinesType = 'RENDER_LINE_GRADIENT' | 'RENDER_LINE_DASH';

const lineUniforms = (context: Context, locations: UniformLocations): LineUniformsType => ({
'u_matrix': new UniformMatrix4f(context, locations.u_matrix),
'u_ratio': new Uniform1f(context, locations.u_ratio),
'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio),
'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels)
});

const lineGradientUniforms = (context: Context, locations: UniformLocations): LineGradientUniformsType => ({
'u_matrix': new UniformMatrix4f(context, locations.u_matrix),
'u_ratio': new Uniform1f(context, locations.u_ratio),
'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio),
'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels),
'u_image': new Uniform1i(context, locations.u_image),
'u_dash_image': new Uniform1i(context, locations.u_dash_image),
'u_gradient_image': new Uniform1i(context, locations.u_gradient_image),
'u_image_height': new Uniform1f(context, locations.u_image_height),
'u_texsize': new Uniform2f(context, locations.u_texsize),
'u_scale': new Uniform3f(context, locations.u_scale),
'u_mix': new Uniform1f(context, locations.u_mix)
});

const linePatternUniforms = (context: Context, locations: UniformLocations): LinePatternUniformsType => ({
Expand All @@ -84,47 +68,37 @@ const linePatternUniforms = (context: Context, locations: UniformLocations): Lin
'u_fade': new Uniform1f(context, locations.u_fade)
});

const lineSDFUniforms = (context: Context, locations: UniformLocations): LineSDFUniformsType => ({
'u_matrix': new UniformMatrix4f(context, locations.u_matrix),
'u_texsize': new Uniform2f(context, locations.u_texsize),
'u_ratio': new Uniform1f(context, locations.u_ratio),
'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio),
'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels),
'u_image': new Uniform1i(context, locations.u_image),
'u_scale': new Uniform3f(context, locations.u_scale),
'u_mix': new Uniform1f(context, locations.u_mix)
});

const lineUniformValues = (
painter: Painter,
tile: Tile,
layer: LineStyleLayer,
matrix: ?Float32Array
crossfade: CrossfadeParameters,
matrix: ?Float32Array,
imageHeight: number
): UniformValues<LineUniformsType> => {
const transform = painter.transform;

return {
const values = {
'u_matrix': calculateMatrix(painter, tile, layer, matrix),
'u_ratio': 1 / pixelsToTileUnits(tile, 1, transform.zoom),
'u_device_pixel_ratio': browser.devicePixelRatio,
'u_units_to_pixels': [
1 / transform.pixelsToGLUnits[0],
1 / transform.pixelsToGLUnits[1]
]
};
};

const lineGradientUniformValues = (
painter: Painter,
tile: Tile,
layer: LineStyleLayer,
matrix: ?Float32Array,
imageHeight: number
): UniformValues<LineGradientUniformsType> => {
return extend(lineUniformValues(painter, tile, layer, matrix), {
'u_image': 0,
],
'u_dash_image': 0,
'u_gradient_image': 1,
'u_image_height': imageHeight,
});
'u_texsize': [0, 0],
'u_scale': [0, 0, 0],
'u_mix': 0
};
if (hasDash(layer)) {
const tileZoomRatio = calculateTileRatio(tile, painter.transform);
values['u_texsize'] = tile.lineAtlasTexture.size;
values['u_scale'] = [tileZoomRatio, crossfade.fromScale, crossfade.toScale];
values['u_mix'] = crossfade.t;
}
return values;
};

const linePatternUniformValues = (
Expand Down Expand Up @@ -152,22 +126,6 @@ const linePatternUniformValues = (
};
};

const lineSDFUniformValues = (
painter: Painter,
tile: Tile,
layer: LineStyleLayer,
crossfade: CrossfadeParameters,
matrix: ?Float32Array
): UniformValues<LineSDFUniformsType> => {
const tileZoomRatio = calculateTileRatio(tile, painter.transform);
return extend(lineUniformValues(painter, tile, layer, matrix), {
'u_texsize': tile.lineAtlasTexture.size,
'u_scale': [tileZoomRatio, crossfade.fromScale, crossfade.toScale],
'u_image': 0,
'u_mix': crossfade.t
});
};

function calculateTileRatio(tile: Tile, transform: Transform) {
return 1 / pixelsToTileUnits(tile, 1, transform.tileZoom);
}
Expand All @@ -181,13 +139,22 @@ function calculateMatrix(painter, tile, layer, matrix) {
);
}

const lineDefinesValues = (layer: LineStyleLayer): LineDefinesType[] => {
const values = [];
if (hasDash(layer)) values.push('RENDER_LINE_DASH');
if (layer.paint.get('line-gradient')) values.push('RENDER_LINE_GRADIENT');
return values;
};

function hasDash(layer) {
const dashPropertyValue = layer.paint.get('line-dasharray').value;
return dashPropertyValue.value || dashPropertyValue.kind !== "constant";
}

export {
lineUniforms,
lineGradientUniforms,
linePatternUniforms,
lineSDFUniforms,
lineUniformValues,
lineGradientUniformValues,
linePatternUniformValues,
lineSDFUniformValues
lineDefinesValues
};
7 changes: 3 additions & 4 deletions src/render/program/program_uniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import type {CircleDefinesType} from './circle_program.js';
import type {SymbolDefinesType} from './symbol_program.js';
import type {LineDefinesType} from './line_program.js';
import {fillExtrusionUniforms, fillExtrusionPatternUniforms} from './fill_extrusion_program.js';
import {fillUniforms, fillPatternUniforms, fillOutlineUniforms, fillOutlinePatternUniforms} from './fill_program.js';
import {circleUniforms} from './circle_program.js';
Expand All @@ -10,15 +11,15 @@ import {debugUniforms} from './debug_program.js';
import {clippingMaskUniforms} from './clipping_mask_program.js';
import {heatmapUniforms, heatmapTextureUniforms} from './heatmap_program.js';
import {hillshadeUniforms, hillshadePrepareUniforms} from './hillshade_program.js';
import {lineUniforms, lineGradientUniforms, linePatternUniforms, lineSDFUniforms} from './line_program.js';
import {lineUniforms, linePatternUniforms} from './line_program.js';
import {rasterUniforms} from './raster_program.js';
import {symbolIconUniforms, symbolSDFUniforms, symbolTextAndIconUniforms} from './symbol_program.js';
import {backgroundUniforms, backgroundPatternUniforms} from './background_program.js';
import {terrainRasterUniforms} from '../../terrain/terrain_raster_program.js';
import {skyboxUniforms, skyboxGradientUniforms} from './skybox_program.js';
import {skyboxCaptureUniforms} from './skybox_capture_program.js';

export type DynamicDefinesType = CircleDefinesType | SymbolDefinesType;
export type DynamicDefinesType = CircleDefinesType | SymbolDefinesType | LineDefinesType;

export const programUniforms = {
fillExtrusion: fillExtrusionUniforms,
Expand All @@ -37,9 +38,7 @@ export const programUniforms = {
hillshade: hillshadeUniforms,
hillshadePrepare: hillshadePrepareUniforms,
line: lineUniforms,
lineGradient: lineGradientUniforms,
linePattern: linePatternUniforms,
lineSDF: lineSDFUniforms,
raster: rasterUniforms,
symbolIcon: symbolIconUniforms,
symbolSDF: symbolSDFUniforms,
Expand Down
34 changes: 34 additions & 0 deletions src/shaders/line.fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,31 @@ varying vec2 v_width2;
varying vec2 v_normal;
varying float v_gamma_scale;

#ifdef RENDER_LINE_DASH
uniform sampler2D u_dash_image;
uniform float u_mix;
uniform vec3 u_scale;
varying vec2 v_tex_a;
varying vec2 v_tex_b;
#endif

#ifdef RENDER_LINE_GRADIENT
uniform sampler2D u_gradient_image;
varying highp vec2 v_uv;
#endif

#pragma mapbox: define highp vec4 color
#pragma mapbox: define lowp float floorwidth
#pragma mapbox: define lowp vec4 dash_from
#pragma mapbox: define lowp vec4 dash_to
#pragma mapbox: define lowp float blur
#pragma mapbox: define lowp float opacity

void main() {
#pragma mapbox: initialize highp vec4 color
#pragma mapbox: initialize lowp float floorwidth
#pragma mapbox: initialize lowp vec4 dash_from
#pragma mapbox: initialize lowp vec4 dash_to
#pragma mapbox: initialize lowp float blur
#pragma mapbox: initialize lowp float opacity

Expand All @@ -22,7 +41,22 @@ void main() {
float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale;
float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);

#ifdef RENDER_LINE_DASH
float sdfdist_a = texture2D(u_dash_image, v_tex_a).a;
float sdfdist_b = texture2D(u_dash_image, v_tex_b).a;
float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);
float sdfwidth = min(dash_from.z * u_scale.y, dash_to.z * u_scale.z);
float sdfgamma = 1.0 / (2.0 * u_device_pixel_ratio) / sdfwidth;
alpha *= smoothstep(0.5 - sdfgamma / floorwidth, 0.5 + sdfgamma / floorwidth, sdfdist);
#endif

#ifdef RENDER_LINE_GRADIENT
// For gradient lines, v_lineprogress is the ratio along the
// entire line, the gradient ramp is stored in a texture.
vec4 out_color = texture2D(u_gradient_image, v_uv);
#else
vec4 out_color = color;
#endif

#ifdef FOG
out_color = fog_dither(fog_apply_premultiplied(out_color, v_fog_pos));
Expand Down
Loading

0 comments on commit 54615bd

Please sign in to comment.