Skip to content

Commit

Permalink
Use separate shaders for drawing backgrounds and clipping masks
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauren Budorick committed Jan 9, 2018
1 parent 3963d94 commit 5e44e62
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 46 deletions.
26 changes: 0 additions & 26 deletions src/data/program_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,32 +316,6 @@ class ProgramConfiguration {
return self;
}

static forBackgroundColor(color: Color, opacity: number) {
const self = new ProgramConfiguration();

self.binders['background-color'] = new ConstantBinder(color, 'color', 'color');
self.cacheKey += `/u_color`;

self.binders['background-opacity'] = new ConstantBinder(opacity, 'opacity', 'number');
self.cacheKey += `/u_opacity`;

return self;
}

static forBackgroundPattern(opacity: number) {
const self = new ProgramConfiguration();

self.binders['background-opacity'] = new ConstantBinder(opacity, 'opacity', 'number');
self.cacheKey += `/u_opacity`;

return self;
}

static forTileClippingMask() {
// The color and opacity values don't matter.
return ProgramConfiguration.forBackgroundColor(Color.black, 1);
}

populatePaintArrays(length: number, feature: Feature) {
for (const property in this.binders) {
this.binders[property].populatePaintArray(length, feature);
Expand Down
21 changes: 4 additions & 17 deletions src/render/draw_background.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// @flow

const pattern = require('./pattern');
const {ProgramConfiguration} = require('../data/program_configuration');
const {PossiblyEvaluated, PossiblyEvaluatedPropertyValue} = require('../style/properties');
const fillLayerPaintProperties = require('../style/style_layer/fill_style_layer_properties').paint;
const StencilMode = require('../gl/stencil_mode');
const DepthMode = require('../gl/depth_mode');

Expand All @@ -24,7 +21,6 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Backg
const transform = painter.transform;
const tileSize = transform.tileSize;
const image = layer.paint.get('background-pattern');
const globals = {zoom: transform.zoom};

const pass = (!image && color.a === 1 && opacity === 1) ? 'opaque' : 'translucent';
if (painter.renderPass !== pass) return;
Expand All @@ -33,28 +29,19 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Backg
context.setDepthMode(painter.depthModeForSublayer(0, pass === 'opaque' ? DepthMode.ReadWrite : DepthMode.ReadOnly));
context.setColorMode(painter.colorModeForRenderPass());

const properties = new PossiblyEvaluated(fillLayerPaintProperties);

(properties._values: any)['background-color'] = new PossiblyEvaluatedPropertyValue(
fillLayerPaintProperties.properties['fill-color'], {kind: 'constant', value: color}, globals);
(properties._values: any)['background-opacity'] = new PossiblyEvaluatedPropertyValue(
fillLayerPaintProperties.properties['fill-opacity'], {kind: 'constant', value: opacity}, globals);

let program;
if (image) {
if (pattern.isPatternMissing(image, painter)) return;
const configuration = ProgramConfiguration.forBackgroundPattern(opacity);
program = painter.useProgram('fillPattern', configuration);
configuration.setUniforms(context, program, properties, globals);
program = painter.useProgram('backgroundPattern');
pattern.prepare(image, painter, program);
painter.tileExtentPatternVAO.bind(context, program, painter.tileExtentBuffer, []);
} else {
const configuration = ProgramConfiguration.forBackgroundColor(color, opacity);
program = painter.useProgram('fill', configuration);
configuration.setUniforms(context, program, properties, globals);
program = painter.useProgram('background');
gl.uniform4fv(program.uniforms.u_color, [color.r, color.g, color.b, color.a]);
painter.tileExtentVAO.bind(context, program, painter.tileExtentBuffer, []);
}

gl.uniform1f(program.uniforms.u_opacity, opacity);
const tileIDs = transform.coveringTiles({tileSize});

for (const tileID of tileIDs) {
Expand Down
5 changes: 2 additions & 3 deletions src/render/painter.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class Painter {
mat4.ortho(matrix, 0, this.width, this.height, 0, 0, 1);
mat4.scale(matrix, matrix, [gl.drawingBufferWidth, gl.drawingBufferHeight, 0]);

const program = this.useProgram('fill', ProgramConfiguration.forTileClippingMask());
const program = this.useProgram('clippingMask');
gl.uniformMatrix4fv(program.uniforms.u_matrix, false, matrix);

this.viewportVAO.bind(context, program, this.viewportBuffer, []);
Expand All @@ -214,15 +214,14 @@ class Painter {

let idNext = 1;
this._tileClippingMaskIDs = {};
const programConfiguration = ProgramConfiguration.forTileClippingMask();

for (const tileID of tileIDs) {
const id = this._tileClippingMaskIDs[tileID.key] = idNext++;

// Tests will always pass, and ref value will be written to stencil buffer.
context.setStencilMode(new StencilMode({ func: gl.ALWAYS, mask: 0 }, id, 0xFF, gl.KEEP, gl.KEEP, gl.REPLACE));

const program = this.useProgram('fill', programConfiguration);
const program = this.useProgram('clippingMask');
gl.uniformMatrix4fv(program.uniforms.u_matrix, false, tileID.posMatrix);

// Draw the clipping mask
Expand Down
10 changes: 10 additions & 0 deletions src/shaders/background.fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
uniform vec4 u_color;
uniform float u_opacity;

void main() {
gl_FragColor = u_color * u_opacity;

#ifdef OVERDRAW_INSPECTOR
gl_FragColor = vec4(1.0);
#endif
}
7 changes: 7 additions & 0 deletions src/shaders/background.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
attribute vec2 a_pos;

uniform mat4 u_matrix;

void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}
28 changes: 28 additions & 0 deletions src/shaders/background_pattern.fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
uniform vec2 u_pattern_tl_a;
uniform vec2 u_pattern_br_a;
uniform vec2 u_pattern_tl_b;
uniform vec2 u_pattern_br_b;
uniform vec2 u_texsize;
uniform float u_mix;
uniform float u_opacity;

uniform sampler2D u_image;

varying vec2 v_pos_a;
varying vec2 v_pos_b;

void main() {
vec2 imagecoord = mod(v_pos_a, 1.0);
vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord);
vec4 color1 = texture2D(u_image, pos);

vec2 imagecoord_b = mod(v_pos_b, 1.0);
vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b);
vec4 color2 = texture2D(u_image, pos2);

gl_FragColor = mix(color1, color2, u_mix) * u_opacity;

#ifdef OVERDRAW_INSPECTOR
gl_FragColor = vec4(1.0);
#endif
}
20 changes: 20 additions & 0 deletions src/shaders/background_pattern.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
uniform mat4 u_matrix;
uniform vec2 u_pattern_size_a;
uniform vec2 u_pattern_size_b;
uniform vec2 u_pixel_coord_upper;
uniform vec2 u_pixel_coord_lower;
uniform float u_scale_a;
uniform float u_scale_b;
uniform float u_tile_units_to_pixels;

attribute vec2 a_pos;

varying vec2 v_pos_a;
varying vec2 v_pos_b;

void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);

v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
}
3 changes: 3 additions & 0 deletions src/shaders/clipping_mask.fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void main() {
gl_FragColor = vec4(1.0);
}
7 changes: 7 additions & 0 deletions src/shaders/clipping_mask.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
attribute vec2 a_pos;

uniform mat4 u_matrix;

void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}
12 changes: 12 additions & 0 deletions src/shaders/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,22 @@ const shaders: {[string]: {fragmentSource: string, vertexSource: string}} = {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/_prelude.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/_prelude.vertex.glsl', 'utf8')
},
background: {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/background.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/background.vertex.glsl', 'utf8')
},
backgroundPattern: {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/background_pattern.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/background_pattern.vertex.glsl', 'utf8')
},
circle: {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/circle.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/circle.vertex.glsl', 'utf8')
},
clippingMask: {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/clipping_mask.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/clipping_mask.vertex.glsl', 'utf8')
},
heatmap: {
fragmentSource: fs.readFileSync(__dirname + '/../shaders/heatmap.fragment.glsl', 'utf8'),
vertexSource: fs.readFileSync(__dirname + '/../shaders/heatmap.vertex.glsl', 'utf8')
Expand Down

0 comments on commit 5e44e62

Please sign in to comment.