From 0fd752934304aa8ad4e56fe9d1ddfe8a6ba2af80 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Wed, 2 Nov 2016 20:05:20 -0700 Subject: [PATCH 01/20] derive data-driven attribute components from spec --- js/data/bucket/circle_bucket.js | 7 ------- js/data/bucket/fill_bucket.js | 3 --- js/data/bucket/fill_extrusion_bucket.js | 3 --- js/data/bucket/line_bucket.js | 1 - js/data/program_configuration.js | 28 +++++++++++++++---------- test/js/data/bucket.test.js | 8 +++---- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index beb31088d2d..a7339bdcefe 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -16,7 +16,6 @@ const circleInterface = { paintAttributes: [{ name: 'a_color', - components: 4, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { return layer.getPaintValue("circle-color", globalProperties, featureProperties); @@ -25,9 +24,7 @@ const circleInterface = { paintProperty: 'circle-color' }, { name: 'a_radius', - components: 1, type: 'Uint16', - isLayerConstant: false, getValue: (layer, globalProperties, featureProperties) => { return [layer.getPaintValue("circle-radius", globalProperties, featureProperties)]; }, @@ -35,9 +32,7 @@ const circleInterface = { paintProperty: 'circle-radius' }, { name: 'a_blur', - components: 1, type: 'Uint16', - isLayerConstant: false, getValue: (layer, globalProperties, featureProperties) => { return [layer.getPaintValue("circle-blur", globalProperties, featureProperties)]; }, @@ -45,9 +40,7 @@ const circleInterface = { paintProperty: 'circle-blur' }, { name: 'a_opacity', - components: 1, type: 'Uint16', - isLayerConstant: false, getValue: (layer, globalProperties, featureProperties) => { return [layer.getPaintValue("circle-opacity", globalProperties, featureProperties)]; }, diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index fd36b707fd1..539dcdc7727 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -20,7 +20,6 @@ const fillInterface = { paintAttributes: [{ name: 'a_color', - components: 4, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { return layer.getPaintValue("fill-color", globalProperties, featureProperties); @@ -29,7 +28,6 @@ const fillInterface = { paintProperty: 'fill-color' }, { name: 'a_outline_color', - components: 4, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { return layer.getPaintValue("fill-outline-color", globalProperties, featureProperties); @@ -38,7 +36,6 @@ const fillInterface = { paintProperty: 'fill-outline-color' }, { name: 'a_opacity', - components: 1, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { return [layer.getPaintValue("fill-opacity", globalProperties, featureProperties)]; diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index b467d1c1d82..76771cad94b 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -28,7 +28,6 @@ const fillExtrusionInterface = { paintAttributes: [{ name: 'a_base', - components: 1, type: 'Uint16', getValue: (layer, globalProperties, featureProperties) => { return [Math.max(layer.getPaintValue("fill-extrusion-base", globalProperties, featureProperties), 0)]; @@ -37,7 +36,6 @@ const fillExtrusionInterface = { paintProperty: 'fill-extrusion-base' }, { name: 'a_height', - components: 1, type: 'Uint16', getValue: (layer, globalProperties, featureProperties) => { return [Math.max(layer.getPaintValue("fill-extrusion-height", globalProperties, featureProperties), 0)]; @@ -46,7 +44,6 @@ const fillExtrusionInterface = { paintProperty: 'fill-extrusion-height' }, { name: 'a_color', - components: 4, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { const color = layer.getPaintValue("fill-extrusion-color", globalProperties, featureProperties); diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index 968f380b1f5..731c77b86b6 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -51,7 +51,6 @@ const lineInterface = { }]), paintAttributes: [{ name: 'a_color', - components: 4, type: 'Uint8', getValue: (layer, globalProperties, featureProperties) => { return layer.getPaintValue("line-color", globalProperties, featureProperties); diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 7e7b33a2be7..a7c093c9912 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -36,6 +36,8 @@ class ProgramConfiguration { const vertexDefine = self.vertexPragmas.define; for (const attribute of attributes) { + const specification = layer._paintSpecifications[attribute.paintProperty]; + const isColor = specification.type === 'color'; const inputName = attribute.name; assert(attribute.name.slice(0, 2) === 'a_'); const name = attribute.name.slice(2); @@ -44,13 +46,13 @@ class ProgramConfiguration { fragmentInit[name] = ''; if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { - self.uniforms.push(attribute); + self.uniforms.push(util.extend({}, attribute, {isColor})); fragmentDefine[name] = vertexDefine[name] = `uniform {precision} {type} ${inputName};\n`; fragmentInit[name] = vertexInit[name] = `{precision} {type} ${name} = ${inputName};\n`; } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { - self.attributes.push(util.extend({}, attribute, {name: inputName})); + self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1})); fragmentDefine[name] = `varying {precision} {type} ${name};\n`; vertexDefine[name] = `varying {precision} {type} ${name};\n attribute {precision} {type} ${inputName};\n`; @@ -74,17 +76,16 @@ class ProgramConfiguration { fragmentDefine[name] = `varying {precision} {type} ${name};\n`; vertexDefine[name] = `varying {precision} {type} ${name};\n uniform lowp float ${tName};\n`; - self.uniforms.push(util.extend({}, attribute, { + self.uniforms.push({ name: tName, getValue: createGetUniform(attribute, stopOffset), - components: 1 - })); + isColor: false + }); - if (attribute.components === 1) { + if (!isColor) { self.attributes.push(util.extend({}, attribute, { getValue: createFunctionGetValue(attribute, fourZoomLevels), - isFunction: true, - components: attribute.components * 4 + components: 4 })); vertexDefine[name] += `attribute {precision} vec4 ${inputName};\n`; @@ -96,8 +97,8 @@ class ProgramConfiguration { inputNames.push(inputName + k); self.attributes.push(util.extend({}, attribute, { getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]), - isFunction: true, - name: inputName + k + name: inputName + k, + components: 4 })); vertexDefine[name] += `attribute {precision} {type} ${inputName + k};\n`; } @@ -206,7 +207,12 @@ class ProgramConfiguration { setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { const uniformLocation = program[uniform.name]; - gl[`uniform${uniform.components}fv`](uniformLocation, uniform.getValue(layer, globalProperties)); + const value = uniform.getValue(layer, globalProperties); + if (uniform.isColor) { + gl.uniform4fv(uniformLocation, value); + } else { + gl.uniform1fv(uniformLocation, value); + } } } } diff --git a/test/js/data/bucket.test.js b/test/js/data/bucket.test.js index d33f8041f8c..75c691fb06d 100644 --- a/test/js/data/bucket.test.js +++ b/test/js/data/bucket.test.js @@ -22,8 +22,8 @@ test('Bucket', (t) => { } const dataDrivenPaint = { - 'circle-color': { - stops: [[0, 'red'], [100, 'violet']], + 'circle-opacity': { + stops: [[0, 0], [100, 1.0]], property: 'mapbox' } }; @@ -48,7 +48,7 @@ test('Bucket', (t) => { getValue: function(layer, globalProperties, featureProperties) { return [featureProperties.x]; }, - paintProperty: 'circle-color' + paintProperty: 'circle-opacity' }] }; @@ -142,7 +142,7 @@ test('Bucket', (t) => { name: 'a_map', type: 'Int16', getValue: function() { return [5]; }, - paintProperty: 'circle-color' + paintProperty: 'circle-opacity' }], layoutAttributes: [], layers: [ From b998d58a4f479fd5bb06f7a4b6d1da05f2d667b5 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Wed, 2 Nov 2016 20:33:33 -0700 Subject: [PATCH 02/20] enforce minimum value from spec --- js/style/style_declaration.js | 4 ++++ test/js/style/style_declaration.test.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/js/style/style_declaration.js b/js/style/style_declaration.js index 801c6bc5d52..65eb24b6adc 100644 --- a/js/style/style_declaration.js +++ b/js/style/style_declaration.js @@ -13,6 +13,7 @@ class StyleDeclaration { // immutable representation of value. used for comparison this.json = JSON.stringify(this.value); + this.minimum = reference.minimum; this.isColor = reference.type === 'color'; const parsedValue = this.isColor && this.value ? parseColor(this.value) : value; @@ -47,6 +48,9 @@ class StyleDeclaration { if (this.isColor && value) { return parseColor(value); } + if (this.minimum !== undefined && value < this.minimum) { + return this.minimum; + } return value; } diff --git a/test/js/style/style_declaration.test.js b/test/js/style/style_declaration.test.js index e6cb4548404..2734bfeb81e 100644 --- a/test/js/style/style_declaration.test.js +++ b/test/js/style/style_declaration.test.js @@ -12,6 +12,12 @@ test('StyleDeclaration', (t) => { t.end(); }); + t.test('with minimum value', (t) => { + t.equal((new StyleDeclaration({type: "number", minimum: -2}, -5)).calculate({zoom: 0}), -2); + t.equal((new StyleDeclaration({type: "number", minimum: -2}, 5)).calculate({zoom: 0}), 5); + t.end(); + }); + t.test('interpolated functions', (t) => { const reference = {type: "number", function: "interpolated"}; t.equal((new StyleDeclaration(reference, { stops: [[0, 1]] })).calculate({zoom: 0}), 1); From 47a0a145a4fed978cd7081bcec3a0ec8a9168670 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Wed, 2 Nov 2016 20:44:48 -0700 Subject: [PATCH 03/20] get rid of DDS attributes getValue --- js/data/bucket/circle_bucket.js | 12 ----------- js/data/bucket/fill_bucket.js | 9 -------- js/data/bucket/fill_extrusion_bucket.js | 11 ---------- js/data/bucket/line_bucket.js | 3 --- js/data/program_configuration.js | 28 ++++++++++++++++--------- 5 files changed, 18 insertions(+), 45 deletions(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index a7339bdcefe..35102ef4b4f 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -17,33 +17,21 @@ const circleInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("circle-color", globalProperties, featureProperties); - }, multiplier: 255, paintProperty: 'circle-color' }, { name: 'a_radius', type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-radius", globalProperties, featureProperties)]; - }, multiplier: 10, paintProperty: 'circle-radius' }, { name: 'a_blur', type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-blur", globalProperties, featureProperties)]; - }, multiplier: 10, paintProperty: 'circle-blur' }, { name: 'a_opacity', type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-opacity", globalProperties, featureProperties)]; - }, multiplier: 255, paintProperty: 'circle-opacity' }] diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index 539dcdc7727..e3efda7af22 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -21,25 +21,16 @@ const fillInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("fill-color", globalProperties, featureProperties); - }, multiplier: 255, paintProperty: 'fill-color' }, { name: 'a_outline_color', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("fill-outline-color", globalProperties, featureProperties); - }, multiplier: 255, paintProperty: 'fill-outline-color' }, { name: 'a_opacity', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("fill-opacity", globalProperties, featureProperties)]; - }, multiplier: 255, paintProperty: 'fill-opacity' }] diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index 76771cad94b..333095de589 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -29,27 +29,16 @@ const fillExtrusionInterface = { paintAttributes: [{ name: 'a_base', type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [Math.max(layer.getPaintValue("fill-extrusion-base", globalProperties, featureProperties), 0)]; - }, multiplier: 1, paintProperty: 'fill-extrusion-base' }, { name: 'a_height', type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [Math.max(layer.getPaintValue("fill-extrusion-height", globalProperties, featureProperties), 0)]; - }, multiplier: 1, paintProperty: 'fill-extrusion-height' }, { name: 'a_color', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - const color = layer.getPaintValue("fill-extrusion-color", globalProperties, featureProperties); - color[3] = 1.0; - return color; - }, multiplier: 255, paintProperty: 'fill-extrusion-color' }] diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index 731c77b86b6..c974cb982d6 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -52,9 +52,6 @@ const lineInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("line-color", globalProperties, featureProperties); - }, multiplier: 255, paintProperty: 'line-color' }], diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index a7c093c9912..60eb054a48e 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -140,15 +140,21 @@ class ProgramConfiguration { paintArray.resize(length); for (const attribute of this.attributes) { - const value = attribute.getValue(layer, globalProperties, featureProperties); + const value = attribute.getValue ? + attribute.getValue(layer, globalProperties, featureProperties) : + layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); + const multiplier = attribute.multiplier || 1; const components = attribute.components || 1; for (let i = start; i < length; i++) { const vertex = paintArray.get(i); - for (let c = 0; c < components; c++) { - const memberName = components > 1 ? (attribute.name + c) : attribute.name; - vertex[memberName] = value[c] * multiplier; + if (components > 1) { + for (let c = 0; c < components; c++) { + vertex[attribute.name + c] = value[c] * multiplier; + } + } else { + vertex[attribute.name] = value * multiplier; } } } @@ -206,12 +212,14 @@ class ProgramConfiguration { setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { - const uniformLocation = program[uniform.name]; - const value = uniform.getValue(layer, globalProperties); + const value = uniform.getValue ? + uniform.getValue(layer, globalProperties) : + layer.getPaintValue(uniform.paintProperty, globalProperties); + if (uniform.isColor) { - gl.uniform4fv(uniformLocation, value); + gl.uniform4fv(program[uniform.name], value); } else { - gl.uniform1fv(uniformLocation, value); + gl.uniform1f(program[uniform.name], value); } } } @@ -221,13 +229,13 @@ function createFunctionGetValue(attribute, stopZoomLevels) { return function(layer, globalProperties, featureProperties) { if (stopZoomLevels.length === 1) { // return one multi-component value like color0 - return attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevels[0] }), featureProperties); + return layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, { zoom: stopZoomLevels[0] }), featureProperties); } else { // pack multiple single-component values into a four component attribute const values = []; for (let z = 0; z < stopZoomLevels.length; z++) { const stopZoomLevel = stopZoomLevels[z]; - values.push(attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevel }), featureProperties)[0]); + values.push(layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, { zoom: stopZoomLevel }), featureProperties)); } return values; } From 16f87828cd7ae3f535b060e124a7a1a2d15005ab Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Wed, 2 Nov 2016 20:58:25 -0700 Subject: [PATCH 04/20] derive attribute multiplier where possible --- js/data/bucket/circle_bucket.js | 1 - js/data/bucket/fill_bucket.js | 2 -- js/data/bucket/fill_extrusion_bucket.js | 3 --- js/data/bucket/line_bucket.js | 1 - js/data/program_configuration.js | 18 ++++++++++-------- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index 35102ef4b4f..31f3dfb7900 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -17,7 +17,6 @@ const circleInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - multiplier: 255, paintProperty: 'circle-color' }, { name: 'a_radius', diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index e3efda7af22..3afbaf5ec5e 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -21,12 +21,10 @@ const fillInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - multiplier: 255, paintProperty: 'fill-color' }, { name: 'a_outline_color', type: 'Uint8', - multiplier: 255, paintProperty: 'fill-outline-color' }, { name: 'a_opacity', diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index 333095de589..7d8c68494d5 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -29,17 +29,14 @@ const fillExtrusionInterface = { paintAttributes: [{ name: 'a_base', type: 'Uint16', - multiplier: 1, paintProperty: 'fill-extrusion-base' }, { name: 'a_height', type: 'Uint16', - multiplier: 1, paintProperty: 'fill-extrusion-height' }, { name: 'a_color', type: 'Uint8', - multiplier: 255, paintProperty: 'fill-extrusion-color' }] }; diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index c974cb982d6..8cec99b82b8 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -52,7 +52,6 @@ const lineInterface = { paintAttributes: [{ name: 'a_color', type: 'Uint8', - multiplier: 255, paintProperty: 'line-color' }], elementArrayType: createElementArrayType() diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 60eb054a48e..8d969694e47 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -41,7 +41,7 @@ class ProgramConfiguration { const inputName = attribute.name; assert(attribute.name.slice(0, 2) === 'a_'); const name = attribute.name.slice(2); - const multiplier = (attribute.multiplier || 1).toFixed(1); + const multiplier = attribute.multiplier || (isColor ? 255 : 1); fragmentInit[name] = ''; @@ -52,11 +52,11 @@ class ProgramConfiguration { fragmentInit[name] = vertexInit[name] = `{precision} {type} ${name} = ${inputName};\n`; } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { - self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1})); + self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1, multiplier})); fragmentDefine[name] = `varying {precision} {type} ${name};\n`; vertexDefine[name] = `varying {precision} {type} ${name};\n attribute {precision} {type} ${inputName};\n`; - vertexInit[name] = `${name} = ${inputName} / ${multiplier};\n`; + vertexInit[name] = `${name} = ${inputName} / ${multiplier}.0;\n`; } else { // Pick the index of the first offset to add to the buffers. @@ -85,11 +85,12 @@ class ProgramConfiguration { if (!isColor) { self.attributes.push(util.extend({}, attribute, { getValue: createFunctionGetValue(attribute, fourZoomLevels), - components: 4 + components: 4, + multiplier })); vertexDefine[name] += `attribute {precision} vec4 ${inputName};\n`; - vertexInit[name] = `${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier};\n`; + vertexInit[name] = `${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;\n`; } else { const inputNames = []; @@ -98,11 +99,12 @@ class ProgramConfiguration { self.attributes.push(util.extend({}, attribute, { getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]), name: inputName + k, - components: 4 + components: 4, + multiplier })); vertexDefine[name] += `attribute {precision} {type} ${inputName + k};\n`; } - vertexInit[name] = `${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier};\n`; + vertexInit[name] = `${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier}.0;\n`; } } } @@ -144,7 +146,7 @@ class ProgramConfiguration { attribute.getValue(layer, globalProperties, featureProperties) : layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); - const multiplier = attribute.multiplier || 1; + const multiplier = attribute.multiplier; const components = attribute.components || 1; for (let i = start; i < length; i++) { From 5476198fb0965ec67b3803bccbd411519e31709c Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 14:26:45 -0700 Subject: [PATCH 05/20] nicer formatting for attribute configurations --- js/data/bucket/circle_bucket.js | 34 ++++++-------------- js/data/bucket/fill_bucket.js | 27 +++++----------- js/data/bucket/fill_extrusion_bucket.js | 36 ++++++---------------- js/data/bucket/line_bucket.js | 21 +++++-------- js/data/bucket/symbol_bucket.js | 41 +++++++------------------ 5 files changed, 45 insertions(+), 114 deletions(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index 31f3dfb7900..bf5f03311b3 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -7,33 +7,17 @@ const loadGeometry = require('../load_geometry'); const EXTENT = require('../extent'); const circleInterface = { - layoutVertexArrayType: createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }]), + layoutVertexArrayType: createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'} + ]), elementArrayType: createElementArrayType(), - paintAttributes: [{ - name: 'a_color', - type: 'Uint8', - paintProperty: 'circle-color' - }, { - name: 'a_radius', - type: 'Uint16', - multiplier: 10, - paintProperty: 'circle-radius' - }, { - name: 'a_blur', - type: 'Uint16', - multiplier: 10, - paintProperty: 'circle-blur' - }, { - name: 'a_opacity', - type: 'Uint16', - multiplier: 255, - paintProperty: 'circle-opacity' - }] + paintAttributes: [ + {name: 'a_color', paintProperty: 'circle-color', type: 'Uint8'}, + {name: 'a_radius', paintProperty: 'circle-radius', type: 'Uint16', multiplier: 10}, + {name: 'a_blur', paintProperty: 'circle-blur', type: 'Uint16', multiplier: 10}, + {name: 'a_opacity', paintProperty: 'circle-opacity', type: 'Uint16', multiplier: 255} + ] }; function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) { diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index 3afbaf5ec5e..40e6c59ed3a 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -10,28 +10,17 @@ const assert = require('assert'); const EARCUT_MAX_RINGS = 500; const fillInterface = { - layoutVertexArrayType: createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }]), + layoutVertexArrayType: createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'} + ]), elementArrayType: createElementArrayType(3), elementArrayType2: createElementArrayType(2), - paintAttributes: [{ - name: 'a_color', - type: 'Uint8', - paintProperty: 'fill-color' - }, { - name: 'a_outline_color', - type: 'Uint8', - paintProperty: 'fill-outline-color' - }, { - name: 'a_opacity', - type: 'Uint8', - multiplier: 255, - paintProperty: 'fill-opacity' - }] + paintAttributes: [ + {name: 'a_color', paintProperty: 'fill-color', type: 'Uint8'}, + {name: 'a_outline_color', paintProperty: 'fill-outline-color', type: 'Uint8'}, + {name: 'a_opacity', paintProperty: 'fill-opacity', type: 'Uint8', multiplier: 255} + ] }; class FillBucket extends Bucket { diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index 7d8c68494d5..c1935e17ee0 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -11,34 +11,18 @@ const assert = require('assert'); const EARCUT_MAX_RINGS = 500; const fillExtrusionInterface = { - layoutVertexArrayType: createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }, { - name: 'a_normal', - components: 3, - type: 'Int16' - }, { - name: 'a_edgedistance', - components: 1, - type: 'Int16' - }]), + layoutVertexArrayType: createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'}, + {name: 'a_normal', components: 3, type: 'Int16'}, + {name: 'a_edgedistance', components: 1, type: 'Int16'} + ]), elementArrayType: createElementArrayType(3), - paintAttributes: [{ - name: 'a_base', - type: 'Uint16', - paintProperty: 'fill-extrusion-base' - }, { - name: 'a_height', - type: 'Uint16', - paintProperty: 'fill-extrusion-height' - }, { - name: 'a_color', - type: 'Uint8', - paintProperty: 'fill-extrusion-color' - }] + paintAttributes: [ + {name: 'a_base', paintProperty: 'fill-extrusion-base', type: 'Uint16'}, + {name: 'a_height', paintProperty: 'fill-extrusion-height', type: 'Uint16'}, + {name: 'a_color', paintProperty: 'fill-extrusion-color', type: 'Uint8'} + ] }; const FACTOR = Math.pow(2, 13); diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index 8cec99b82b8..d7535e588f0 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -40,20 +40,13 @@ const LINE_DISTANCE_SCALE = 1 / 2; const MAX_LINE_DISTANCE = Math.pow(2, LINE_DISTANCE_BUFFER_BITS - 1) / LINE_DISTANCE_SCALE; const lineInterface = { - layoutVertexArrayType: createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }, { - name: 'a_data', - components: 4, - type: 'Uint8' - }]), - paintAttributes: [{ - name: 'a_color', - type: 'Uint8', - paintProperty: 'line-color' - }], + layoutVertexArrayType: createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'}, + {name: 'a_data', components: 4, type: 'Uint8'} + ]), + paintAttributes: [ + {name: 'a_color', paintProperty: 'line-color', type: 'Uint8'} + ], elementArrayType: createElementArrayType() }; diff --git a/js/data/bucket/symbol_bucket.js b/js/data/bucket/symbol_bucket.js index 3e9158b171a..7bfb02d754b 100644 --- a/js/data/bucket/symbol_bucket.js +++ b/js/data/bucket/symbol_bucket.js @@ -27,23 +27,12 @@ const getIconQuads = Quads.getIconQuads; const elementArrayType = createElementArrayType(); -const layoutVertexArrayType = createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' -}, { - name: 'a_offset', - components: 2, - type: 'Int16' -}, { - name: 'a_texture_pos', - components: 2, - type: 'Uint16' -}, { - name: 'a_data', - components: 4, - type: 'Uint8' -}]); +const layoutVertexArrayType = createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'}, + {name: 'a_offset', components: 2, type: 'Int16'}, + {name: 'a_texture_pos', components: 2, type: 'Uint16'}, + {name: 'a_data', components: 4, type: 'Uint8'} +]); const symbolInterfaces = { glyph: { @@ -55,19 +44,11 @@ const symbolInterfaces = { elementArrayType: elementArrayType }, collisionBox: { - layoutVertexArrayType: createVertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }, { - name: 'a_extrude', - components: 2, - type: 'Int16' - }, { - name: 'a_data', - components: 2, - type: 'Uint8' - }]), + layoutVertexArrayType: createVertexArrayType([ + {name: 'a_pos', components: 2, type: 'Int16'}, + {name: 'a_extrude', components: 2, type: 'Int16'}, + {name: 'a_data', components: 2, type: 'Uint8'} + ]), elementArrayType: createElementArrayType(2) } }; From 5af8a8f502cd401174aa41c72fa73ec44281b43f Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 14:27:25 -0700 Subject: [PATCH 06/20] fix circle-opacity attribute to use Uint8 rather than Uint16 --- js/data/bucket/circle_bucket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index bf5f03311b3..a790cc25df5 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -16,7 +16,7 @@ const circleInterface = { {name: 'a_color', paintProperty: 'circle-color', type: 'Uint8'}, {name: 'a_radius', paintProperty: 'circle-radius', type: 'Uint16', multiplier: 10}, {name: 'a_blur', paintProperty: 'circle-blur', type: 'Uint16', multiplier: 10}, - {name: 'a_opacity', paintProperty: 'circle-opacity', type: 'Uint16', multiplier: 255} + {name: 'a_opacity', paintProperty: 'circle-opacity', type: 'Uint8', multiplier: 255} ] }; From 312c395f4b6b31a6817df8abe38512e58d1f8e6f Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 14:59:06 -0700 Subject: [PATCH 07/20] start refactoring pragmas by inverting their structure --- js/data/program_configuration.js | 78 ++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 8d969694e47..9ea3da5b72c 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -22,18 +22,16 @@ const assert = require('assert'); * @private */ class ProgramConfiguration { - static createDynamic(attributes, layer, zoom) { - const self = new ProgramConfiguration(); - self.attributes = []; - self.uniforms = []; - self.vertexPragmas = { define: {}, initialize: {} }; - self.fragmentPragmas = { define: {}, initialize: {} }; + constructor() { + this.attributes = []; + this.uniforms = []; + this.vertexPragmas = {}; + this.fragmentPragmas = {}; + } - const fragmentInit = self.fragmentPragmas.initialize; - const fragmentDefine = self.fragmentPragmas.define; - const vertexInit = self.vertexPragmas.initialize; - const vertexDefine = self.vertexPragmas.define; + static createDynamic(attributes, layer, zoom) { + const self = new ProgramConfiguration(); for (const attribute of attributes) { const specification = layer._paintSpecifications[attribute.paintProperty]; @@ -43,20 +41,27 @@ class ProgramConfiguration { const name = attribute.name.slice(2); const multiplier = attribute.multiplier || (isColor ? 255 : 1); - fragmentInit[name] = ''; + const frag = self.fragmentPragmas[name] = {define: [], initialize: []}; + const vert = self.vertexPragmas[name] = {define: [], initialize: []}; if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { self.uniforms.push(util.extend({}, attribute, {isColor})); - fragmentDefine[name] = vertexDefine[name] = `uniform {precision} {type} ${inputName};\n`; - fragmentInit[name] = vertexInit[name] = `{precision} {type} ${name} = ${inputName};\n`; + frag.define.push(`uniform {precision} {type} ${inputName};`); + vert.define.push(`uniform {precision} {type} ${inputName};`); + + frag.initialize.push(`{precision} {type} ${name} = ${inputName};`); + vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1, multiplier})); - fragmentDefine[name] = `varying {precision} {type} ${name};\n`; - vertexDefine[name] = `varying {precision} {type} ${name};\n attribute {precision} {type} ${inputName};\n`; - vertexInit[name] = `${name} = ${inputName} / ${multiplier}.0;\n`; + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + + vert.define.push(`attribute {precision} {type} ${inputName};`); + + vert.initialize.push(`${name} = ${inputName} / ${multiplier}.0;`); } else { // Pick the index of the first offset to add to the buffers. @@ -73,8 +78,9 @@ class ProgramConfiguration { const tName = `u_${name}_t`; - fragmentDefine[name] = `varying {precision} {type} ${name};\n`; - vertexDefine[name] = `varying {precision} {type} ${name};\n uniform lowp float ${tName};\n`; + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`uniform lowp float ${tName};`); self.uniforms.push({ name: tName, @@ -89,8 +95,8 @@ class ProgramConfiguration { multiplier })); - vertexDefine[name] += `attribute {precision} vec4 ${inputName};\n`; - vertexInit[name] = `${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;\n`; + vert.define.push(`attribute {precision} vec4 ${inputName};`); + vert.initialize.push(`${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;`); } else { const inputNames = []; @@ -102,9 +108,9 @@ class ProgramConfiguration { components: 4, multiplier })); - vertexDefine[name] += `attribute {precision} {type} ${inputName + k};\n`; + vert.define.push(`attribute {precision} {type} ${inputName + k};`); } - vertexInit[name] = `${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier}.0;\n`; + vert.initialize.push(`${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier}.0;`); } } } @@ -117,22 +123,23 @@ class ProgramConfiguration { static createStatic(uniforms) { const self = new ProgramConfiguration(); - const pragmas = { define: {}, initialize: {} }; + for (const uniform of uniforms) { + assert(uniform.name.indexOf('u_') === 0); + const name = uniform.name.slice(2); - self.attributes = []; - self.uniforms = []; - self.vertexPragmas = pragmas; - self.fragmentPragmas = pragmas; + const frag = self.fragmentPragmas[name] = {define: [], initialize: []}; + const vert = self.vertexPragmas[name] = {define: [], initialize: []}; - for (const uniform of uniforms) { - assert(uniform.name.slice(0, 2) === 'u_'); + const type = `${uniform.components === 1 ? 'float' : `vec${uniform.components}`}`; + + frag.define.push(`uniform {precision} ${type} u_${name};`); + vert.define.push(`uniform {precision} ${type} u_${name};`); - const type = `{precision} ${uniform.components === 1 ? 'float' : `vec${uniform.components}`}`; - pragmas.define[uniform.name.slice(2)] = `uniform ${type} ${uniform.name};\n`; - pragmas.initialize[uniform.name.slice(2)] = `${type} ${uniform.name.slice(2)} = ${uniform.name};\n`; + frag.initialize.push(`{precision} ${type} ${name} = u_${name};`); + vert.initialize.push(`{precision} ${type} ${name} = u_${name};`); } - self.cacheKey = JSON.stringify(pragmas); + self.cacheKey = JSON.stringify(self.fragmentPragmas); return self; } @@ -257,7 +264,10 @@ function createGetUniform(attribute, stopOffset) { function applyPragmas(source, pragmas) { return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { - return pragmas[operation][name].replace(/{type}/g, type).replace(/{precision}/g, precision); + return pragmas[name][operation] + .join('\n') + .replace(/{type}/g, type) + .replace(/{precision}/g, precision); }); } From e1a6d5947abcb2d478c25d6b3b52a6e823d809d1 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 16:38:51 -0700 Subject: [PATCH 08/20] unify uniform pragmas configuration --- js/data/program_configuration.js | 48 +++++++++++++++++--------------- js/render/painter.js | 16 ++++------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 9ea3da5b72c..6da3434feba 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -41,17 +41,12 @@ class ProgramConfiguration { const name = attribute.name.slice(2); const multiplier = attribute.multiplier || (isColor ? 255 : 1); - const frag = self.fragmentPragmas[name] = {define: [], initialize: []}; - const vert = self.vertexPragmas[name] = {define: [], initialize: []}; + const frag = self.getFragmentPragmas(name); + const vert = self.getVertexPragmas(name); if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { self.uniforms.push(util.extend({}, attribute, {isColor})); - - frag.define.push(`uniform {precision} {type} ${inputName};`); - vert.define.push(`uniform {precision} {type} ${inputName};`); - - frag.initialize.push(`{precision} {type} ${name} = ${inputName};`); - vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); + self.addUniform(name, inputName); } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1, multiplier})); @@ -80,6 +75,7 @@ class ProgramConfiguration { frag.define.push(`varying {precision} {type} ${name};`); vert.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`uniform lowp float ${tName};`); self.uniforms.push({ @@ -120,28 +116,36 @@ class ProgramConfiguration { return self; } - static createStatic(uniforms) { + static createStatic(uniformNames) { const self = new ProgramConfiguration(); - for (const uniform of uniforms) { - assert(uniform.name.indexOf('u_') === 0); - const name = uniform.name.slice(2); + for (const name of uniformNames) { + self.addUniform(name, `u_${name}`); + } + self.cacheKey = JSON.stringify(self.fragmentPragmas); - const frag = self.fragmentPragmas[name] = {define: [], initialize: []}; - const vert = self.vertexPragmas[name] = {define: [], initialize: []}; + return self; + } - const type = `${uniform.components === 1 ? 'float' : `vec${uniform.components}`}`; + addUniform(name, inputName) { + const frag = this.getFragmentPragmas(name); + const vert = this.getVertexPragmas(name); - frag.define.push(`uniform {precision} ${type} u_${name};`); - vert.define.push(`uniform {precision} ${type} u_${name};`); + frag.define.push(`uniform {precision} {type} ${inputName};`); + vert.define.push(`uniform {precision} {type} ${inputName};`); - frag.initialize.push(`{precision} ${type} ${name} = u_${name};`); - vert.initialize.push(`{precision} ${type} ${name} = u_${name};`); - } + frag.initialize.push(`{precision} {type} ${name} = ${inputName};`); + vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); + } - self.cacheKey = JSON.stringify(self.fragmentPragmas); + getFragmentPragmas(name) { + this.fragmentPragmas[name] = this.fragmentPragmas[name] || {define: [], initialize: []}; + return this.fragmentPragmas[name]; + } - return self; + getVertexPragmas(name) { + this.vertexPragmas[name] = this.vertexPragmas[name] || {define: [], initialize: []}; + return this.vertexPragmas[name]; } populatePaintArray(layer, paintArray, length, globalProperties, featureProperties) { diff --git a/js/render/painter.js b/js/render/painter.js index b0c2305479b..9da74d40822 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -49,10 +49,7 @@ class Painter { this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); - this.basicFillProgramConfiguration = ProgramConfiguration.createStatic([ - {name: 'u_color', components: 4}, - {name: 'u_opacity', components: 1} - ]); + this.basicFillProgramConfiguration = ProgramConfiguration.createStatic(['color', 'opacity']); this.emptyProgramConfiguration = ProgramConfiguration.createStatic([]); } @@ -359,20 +356,19 @@ class Painter { } } - _createProgramCached(name, paintAttributeSet) { + _createProgramCached(name, programConfiguration) { this.cache = this.cache || {}; - const key = `${name}${paintAttributeSet.cacheKey}${!!this._showOverdrawInspector}`; + const key = `${name}${programConfiguration.cacheKey}${!!this._showOverdrawInspector}`; if (!this.cache[key]) { - this.cache[key] = paintAttributeSet.createProgram(name, this._showOverdrawInspector, this.gl); + this.cache[key] = programConfiguration.createProgram(name, this._showOverdrawInspector, this.gl); } return this.cache[key]; } - useProgram(name, paintAttributeSet) { + useProgram(name, programConfiguration) { const gl = this.gl; - const nextProgram = this._createProgramCached(name, - paintAttributeSet || this.emptyProgramConfiguration); + const nextProgram = this._createProgramCached(name, programConfiguration || this.emptyProgramConfiguration); const previousProgram = this.currentProgram; if (previousProgram !== nextProgram) { From 0712616ed1ac060b2ec1b991185be729ed5862f5 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 17:03:57 -0700 Subject: [PATCH 09/20] unify varying configuration --- js/data/program_configuration.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 6da3434feba..73207a21fc9 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -41,7 +41,6 @@ class ProgramConfiguration { const name = attribute.name.slice(2); const multiplier = attribute.multiplier || (isColor ? 255 : 1); - const frag = self.getFragmentPragmas(name); const vert = self.getVertexPragmas(name); if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { @@ -50,12 +49,9 @@ class ProgramConfiguration { } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1, multiplier})); - - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); + self.addVarying(name); vert.define.push(`attribute {precision} {type} ${inputName};`); - vert.initialize.push(`${name} = ${inputName} / ${multiplier}.0;`); } else { @@ -73,8 +69,7 @@ class ProgramConfiguration { const tName = `u_${name}_t`; - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); + self.addVarying(name); vert.define.push(`uniform lowp float ${tName};`); @@ -138,6 +133,14 @@ class ProgramConfiguration { vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); } + addVarying(name) { + const frag = this.getFragmentPragmas(name); + const vert = this.getVertexPragmas(name); + + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + } + getFragmentPragmas(name) { this.fragmentPragmas[name] = this.fragmentPragmas[name] || {define: [], initialize: []}; return this.fragmentPragmas[name]; From 16ead5281c63ad6257dd477ca359f92cb93d4040 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 17:56:44 -0700 Subject: [PATCH 10/20] clean up attribute normalization --- js/data/program_configuration.js | 63 +++++++++++++++++++------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 73207a21fc9..0638a36c887 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -33,22 +33,22 @@ class ProgramConfiguration { static createDynamic(attributes, layer, zoom) { const self = new ProgramConfiguration(); - for (const attribute of attributes) { - const specification = layer._paintSpecifications[attribute.paintProperty]; - const isColor = specification.type === 'color'; + for (const attributeConfig of attributes) { + + const attribute = normalizeAttribute(attributeConfig, layer); const inputName = attribute.name; - assert(attribute.name.slice(0, 2) === 'a_'); - const name = attribute.name.slice(2); - const multiplier = attribute.multiplier || (isColor ? 255 : 1); + assert(inputName.indexOf('a_') === 0); + const name = inputName.slice(2); + const multiplier = attribute.multiplier; const vert = self.getVertexPragmas(name); if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { - self.uniforms.push(util.extend({}, attribute, {isColor})); + self.uniforms.push(attribute); self.addUniform(name, inputName); } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { - self.attributes.push(util.extend({}, attribute, {components: isColor ? 4 : 1, multiplier})); + self.attributes.push(attribute); self.addVarying(name); vert.define.push(`attribute {precision} {type} ${inputName};`); @@ -76,15 +76,17 @@ class ProgramConfiguration { self.uniforms.push({ name: tName, getValue: createGetUniform(attribute, stopOffset), - isColor: false + components: 1 }); - if (!isColor) { - self.attributes.push(util.extend({}, attribute, { - getValue: createFunctionGetValue(attribute, fourZoomLevels), + if (attribute.components === 1) { + self.attributes.push({ + name: inputName, + type: attribute.type, components: 4, - multiplier - })); + multiplier, + getValue: createFunctionGetValue(attribute, fourZoomLevels) + }); vert.define.push(`attribute {precision} vec4 ${inputName};`); vert.initialize.push(`${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;`); @@ -93,12 +95,13 @@ class ProgramConfiguration { const inputNames = []; for (let k = 0; k < 4; k++) { inputNames.push(inputName + k); - self.attributes.push(util.extend({}, attribute, { - getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]), + self.attributes.push({ name: inputName + k, + type: attribute.type, components: 4, - multiplier - })); + multiplier, + getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]) + }); vert.define.push(`attribute {precision} {type} ${inputName + k};`); } vert.initialize.push(`${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier}.0;`); @@ -160,17 +163,14 @@ class ProgramConfiguration { attribute.getValue(layer, globalProperties, featureProperties) : layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); - const multiplier = attribute.multiplier; - const components = attribute.components || 1; - for (let i = start; i < length; i++) { const vertex = paintArray.get(i); - if (components > 1) { - for (let c = 0; c < components; c++) { - vertex[attribute.name + c] = value[c] * multiplier; + if (attribute.components === 4) { + for (let c = 0; c < 4; c++) { + vertex[attribute.name + c] = value[c] * attribute.multiplier; } } else { - vertex[attribute.name] = value * multiplier; + vertex[attribute.name] = value * attribute.multiplier; } } } @@ -232,7 +232,7 @@ class ProgramConfiguration { uniform.getValue(layer, globalProperties) : layer.getPaintValue(uniform.paintProperty, globalProperties); - if (uniform.isColor) { + if (uniform.components === 4) { gl.uniform4fv(program[uniform.name], value); } else { gl.uniform1f(program[uniform.name], value); @@ -241,6 +241,17 @@ class ProgramConfiguration { } } +function normalizeAttribute(attribute, layer) { + const specification = layer._paintSpecifications[attribute.paintProperty]; + const isColor = specification.type === 'color'; + + attribute = util.extend({}, attribute); + attribute.components = isColor ? 4 : 1; + attribute.multiplier = attribute.multiplier || (isColor ? 255 : 1); + + return attribute; +} + function createFunctionGetValue(attribute, stopZoomLevels) { return function(layer, globalProperties, featureProperties) { if (stopZoomLevels.length === 1) { From 73e00ffaabdb1be00fd4f4bbff93df8411fa028c Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 18:21:59 -0700 Subject: [PATCH 11/20] clean up interpolation uniforms --- js/data/program_configuration.js | 31 ++++++++++-------------- js/style/style_layer.js | 4 +-- js/style/style_layer/fill_style_layer.js | 6 ++--- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 0638a36c887..c47d3837d60 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -26,6 +26,7 @@ class ProgramConfiguration { constructor() { this.attributes = []; this.uniforms = []; + this.interpolationUniforms = []; this.vertexPragmas = {}; this.fragmentPragmas = {}; } @@ -73,10 +74,10 @@ class ProgramConfiguration { vert.define.push(`uniform lowp float ${tName};`); - self.uniforms.push({ + self.interpolationUniforms.push({ name: tName, - getValue: createGetUniform(attribute, stopOffset), - components: 1 + paintProperty: attribute.paintProperty, + stopOffset }); if (attribute.components === 1) { @@ -228,16 +229,21 @@ class ProgramConfiguration { setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { - const value = uniform.getValue ? - uniform.getValue(layer, globalProperties) : - layer.getPaintValue(uniform.paintProperty, globalProperties); - + const value = layer.getPaintValue(uniform.paintProperty, globalProperties); if (uniform.components === 4) { gl.uniform4fv(program[uniform.name], value); } else { gl.uniform1f(program[uniform.name], value); } } + for (const uniform of this.interpolationUniforms) { + // stopInterp indicates which stops need to be interpolated. + // If stopInterp is 3.5 then interpolate half way between stops 3 and 4. + const stopInterp = layer.getPaintInterpolationT(uniform.paintProperty, globalProperties); + // We can only store four stop values in the buffers. stopOffset is the number of stops that come + // before the stops that were added to the buffers. + gl.uniform1f(program[uniform.name], Math.max(0, Math.min(4, stopInterp - uniform.stopOffset))); + } } } @@ -269,17 +275,6 @@ function createFunctionGetValue(attribute, stopZoomLevels) { }; } -function createGetUniform(attribute, stopOffset) { - return function(layer, globalProperties) { - // stopInterp indicates which stops need to be interpolated. - // If stopInterp is 3.5 then interpolate half way between stops 3 and 4. - const stopInterp = layer.getPaintInterpolationT(attribute.paintProperty, globalProperties.zoom); - // We can only store four stop values in the buffers. stopOffset is the number of stops that come - // before the stops that were added to the buffers. - return [Math.max(0, Math.min(4, stopInterp - stopOffset))]; - }; -} - function applyPragmas(source, pragmas) { return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { return pragmas[name][operation] diff --git a/js/style/style_layer.js b/js/style/style_layer.js index 890ddfc99e2..d6181cfabe5 100644 --- a/js/style/style_layer.js +++ b/js/style/style_layer.js @@ -157,9 +157,9 @@ class StyleLayer extends Evented { } } - getPaintInterpolationT(name, zoom) { + getPaintInterpolationT(name, globalProperties) { const transition = this._paintTransitions[name]; - return transition.declaration.calculateInterpolationT({ zoom: zoom }); + return transition.declaration.calculateInterpolationT(globalProperties); } isPaintValueFeatureConstant(name) { diff --git a/js/style/style_layer/fill_style_layer.js b/js/style/style_layer/fill_style_layer.js index 63c1adcf162..0968caed446 100644 --- a/js/style/style_layer/fill_style_layer.js +++ b/js/style/style_layer/fill_style_layer.js @@ -21,11 +21,11 @@ class FillStyleLayer extends StyleLayer { } } - getPaintInterpolationT(name, zoom) { + getPaintInterpolationT(name, globalProperties) { if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { - return super.getPaintInterpolationT('fill-color', zoom); + return super.getPaintInterpolationT('fill-color', globalProperties); } else { - return super.getPaintInterpolationT(name, zoom); + return super.getPaintInterpolationT(name, globalProperties); } } From 7cf8037a6164ee8c147a883fd2df657cb17f70cd Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 18:32:42 -0700 Subject: [PATCH 12/20] clean up gl program creation --- js/data/program_configuration.js | 21 +++++++-------------- js/render/painter.js | 4 +--- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index c47d3837d60..8336642f789 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -205,26 +205,19 @@ class ProgramConfiguration { gl.linkProgram(program); assert(gl.getProgramParameter(program, gl.LINK_STATUS), gl.getProgramInfoLog(program)); - const attributes = {}; const numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); + const result = {program, numAttributes}; + for (let i = 0; i < numAttributes; i++) { const attribute = gl.getActiveAttrib(program, i); - attributes[attribute.name] = gl.getAttribLocation(program, attribute.name); + result[attribute.name] = gl.getAttribLocation(program, attribute.name); } - - const uniforms = {}; const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); - for (let ui = 0; ui < numUniforms; ui++) { - const uniform = gl.getActiveUniform(program, ui); - uniforms[uniform.name] = gl.getUniformLocation(program, uniform.name); + for (let i = 0; i < numUniforms; i++) { + const uniform = gl.getActiveUniform(program, i); + result[uniform.name] = gl.getUniformLocation(program, uniform.name); } - - return util.extend({ - program: program, - definition: definition, - attributes: attributes, - numAttributes: numAttributes - }, attributes, uniforms); + return result; } setUniforms(gl, program, layer, globalProperties) { diff --git a/js/render/painter.js b/js/render/painter.js index 9da74d40822..d35120a8ba1 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -367,11 +367,9 @@ class Painter { useProgram(name, programConfiguration) { const gl = this.gl; - const nextProgram = this._createProgramCached(name, programConfiguration || this.emptyProgramConfiguration); - const previousProgram = this.currentProgram; - if (previousProgram !== nextProgram) { + if (this.currentProgram !== nextProgram) { gl.useProgram(nextProgram.program); this.currentProgram = nextProgram; } From 058c230ca6b75bd8a77500dfe84d7488881d9f07 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 18:44:52 -0700 Subject: [PATCH 13/20] move useProgram back to Painter --- js/data/program_configuration.js | 49 ---------------------------- js/render/painter.js | 55 ++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 8336642f789..41a0e826f38 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -2,7 +2,6 @@ const createVertexArrayType = require('./vertex_array_type'); const util = require('../util/util'); -const shaders = require('mapbox-gl-shaders'); const assert = require('assert'); /** @@ -181,45 +180,6 @@ class ProgramConfiguration { return createVertexArrayType(this.attributes); } - createProgram(name, showOverdraw, gl) { - const program = gl.createProgram(); - const definition = shaders[name]; - - let definesSource = '#define MAPBOX_GL_JS;\n'; - if (showOverdraw) { - definesSource += '#define OVERDRAW_INSPECTOR;\n'; - } - - const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, applyPragmas(definesSource + definition.fragmentSource, this.fragmentPragmas)); - gl.compileShader(fragmentShader); - assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(fragmentShader)); - gl.attachShader(program, fragmentShader); - - const vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, applyPragmas(definesSource + shaders.util + definition.vertexSource, this.vertexPragmas)); - gl.compileShader(vertexShader); - assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(vertexShader)); - gl.attachShader(program, vertexShader); - - gl.linkProgram(program); - assert(gl.getProgramParameter(program, gl.LINK_STATUS), gl.getProgramInfoLog(program)); - - const numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); - const result = {program, numAttributes}; - - for (let i = 0; i < numAttributes; i++) { - const attribute = gl.getActiveAttrib(program, i); - result[attribute.name] = gl.getAttribLocation(program, attribute.name); - } - const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); - for (let i = 0; i < numUniforms; i++) { - const uniform = gl.getActiveUniform(program, i); - result[uniform.name] = gl.getUniformLocation(program, uniform.name); - } - return result; - } - setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { const value = layer.getPaintValue(uniform.paintProperty, globalProperties); @@ -268,13 +228,4 @@ function createFunctionGetValue(attribute, stopZoomLevels) { }; } -function applyPragmas(source, pragmas) { - return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { - return pragmas[name][operation] - .join('\n') - .replace(/{type}/g, type) - .replace(/{precision}/g, precision); - }); -} - module.exports = ProgramConfiguration; diff --git a/js/render/painter.js b/js/render/painter.js index d35120a8ba1..2436fd2ced8 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -12,6 +12,8 @@ const VertexArrayObject = require('./vertex_array_object'); const RasterBoundsArray = require('../data/raster_bounds_array'); const PosArray = require('../data/pos_array'); const ProgramConfiguration = require('../data/program_configuration'); +const shaders = require('mapbox-gl-shaders'); +const assert = require('assert'); const draw = { symbol: require('./draw_symbol'), @@ -50,7 +52,6 @@ class Painter { this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); this.basicFillProgramConfiguration = ProgramConfiguration.createStatic(['color', 'opacity']); - this.emptyProgramConfiguration = ProgramConfiguration.createStatic([]); } /* @@ -356,18 +357,57 @@ class Painter { } } + createProgram(name, showOverdraw, gl, configuration) { + const program = gl.createProgram(); + const definition = shaders[name]; + + let definesSource = '#define MAPBOX_GL_JS;\n'; + if (showOverdraw) { + definesSource += '#define OVERDRAW_INSPECTOR;\n'; + } + + const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, applyPragmas(definesSource + definition.fragmentSource, configuration.fragmentPragmas)); + gl.compileShader(fragmentShader); + assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(fragmentShader)); + gl.attachShader(program, fragmentShader); + + const vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, applyPragmas(definesSource + shaders.util + definition.vertexSource, configuration.vertexPragmas)); + gl.compileShader(vertexShader); + assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(vertexShader)); + gl.attachShader(program, vertexShader); + + gl.linkProgram(program); + assert(gl.getProgramParameter(program, gl.LINK_STATUS), gl.getProgramInfoLog(program)); + + const numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); + const result = {program, numAttributes}; + + for (let i = 0; i < numAttributes; i++) { + const attribute = gl.getActiveAttrib(program, i); + result[attribute.name] = gl.getAttribLocation(program, attribute.name); + } + const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + for (let i = 0; i < numUniforms; i++) { + const uniform = gl.getActiveUniform(program, i); + result[uniform.name] = gl.getUniformLocation(program, uniform.name); + } + return result; + } + _createProgramCached(name, programConfiguration) { this.cache = this.cache || {}; const key = `${name}${programConfiguration.cacheKey}${!!this._showOverdrawInspector}`; if (!this.cache[key]) { - this.cache[key] = programConfiguration.createProgram(name, this._showOverdrawInspector, this.gl); + this.cache[key] = this.createProgram(name, this._showOverdrawInspector, this.gl, programConfiguration); } return this.cache[key]; } useProgram(name, programConfiguration) { const gl = this.gl; - const nextProgram = this._createProgramCached(name, programConfiguration || this.emptyProgramConfiguration); + const nextProgram = this._createProgramCached(name, programConfiguration || {}); if (this.currentProgram !== nextProgram) { gl.useProgram(nextProgram.program); @@ -378,4 +418,13 @@ class Painter { } } +function applyPragmas(source, pragmas) { + return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { + return pragmas[name][operation] + .join('\n') + .replace(/{type}/g, type) + .replace(/{precision}/g, precision); + }); +} + module.exports = Painter; From 0b56bb3af6f0f395db79a4a6ed10d765bec0cb05 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 19:35:44 -0700 Subject: [PATCH 14/20] clean up interpolation attributes --- js/data/program_configuration.js | 89 ++++++++++++-------------------- test/js/data/bucket.test.js | 13 +---- 2 files changed, 36 insertions(+), 66 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 41a0e826f38..791df91556c 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -42,6 +42,7 @@ class ProgramConfiguration { const multiplier = attribute.multiplier; const vert = self.getVertexPragmas(name); + const frag = self.getFragmentPragmas(name); if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { self.uniforms.push(attribute); @@ -49,62 +50,60 @@ class ProgramConfiguration { } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { self.attributes.push(attribute); - self.addVarying(name); + + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); vert.define.push(`attribute {precision} {type} ${inputName};`); vert.initialize.push(`${name} = ${inputName} / ${multiplier}.0;`); } else { + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + // Pick the index of the first offset to add to the buffers. - // Find the four closest stops, ideally with two on each side of the zoom level. let numStops = 0; const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); while (numStops < zoomLevels.length && zoomLevels[numStops] < zoom) numStops++; const stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); - const fourZoomLevels = []; - for (let s = 0; s < 4; s++) { - fourZoomLevels.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]); - } - const tName = `u_${name}_t`; - self.addVarying(name); - vert.define.push(`uniform lowp float ${tName};`); - self.interpolationUniforms.push({ name: tName, paintProperty: attribute.paintProperty, stopOffset }); + // Find the four closest stops, ideally with two on each side of the zoom level. + const zoomStops = []; + for (let s = 0; s < 4; s++) { + zoomStops.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]); + } + if (attribute.components === 1) { - self.attributes.push({ - name: inputName, - type: attribute.type, + self.attributes.push(util.extend({}, attribute, { components: 4, - multiplier, - getValue: createFunctionGetValue(attribute, fourZoomLevels) - }); - + zoomStops + })); vert.define.push(`attribute {precision} vec4 ${inputName};`); vert.initialize.push(`${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;`); } else { - const inputNames = []; + const componentNames = []; for (let k = 0; k < 4; k++) { - inputNames.push(inputName + k); - self.attributes.push({ - name: inputName + k, - type: attribute.type, + const componentName = inputName + k; + + self.attributes.push(util.extend({}, attribute, { + name: componentName, components: 4, - multiplier, - getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]) - }); - vert.define.push(`attribute {precision} {type} ${inputName + k};`); + zoomStops: [zoomStops[k]] + })); + componentNames.push(componentName); + vert.define.push(`attribute {precision} {type} ${componentName};`); } - vert.initialize.push(`${name} = evaluate_zoom_function_4(${inputNames.join(', ')}, ${tName}) / ${multiplier}.0;`); + vert.initialize.push(`${name} = evaluate_zoom_function_4(${componentNames.join(', ')}, ${tName}) / ${multiplier}.0;`); } } } @@ -136,14 +135,6 @@ class ProgramConfiguration { vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); } - addVarying(name) { - const frag = this.getFragmentPragmas(name); - const vert = this.getVertexPragmas(name); - - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); - } - getFragmentPragmas(name) { this.fragmentPragmas[name] = this.fragmentPragmas[name] || {define: [], initialize: []}; return this.fragmentPragmas[name]; @@ -159,9 +150,14 @@ class ProgramConfiguration { paintArray.resize(length); for (const attribute of this.attributes) { - const value = attribute.getValue ? - attribute.getValue(layer, globalProperties, featureProperties) : - layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); + let value; + if (attribute.zoomStops) { + // add one multi-component value like color0, or pack multiple single-component values into a four component attribute + const values = attribute.zoomStops.map((zoom) => layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, {zoom}), featureProperties)); + value = values.length === 1 ? values[0] : values; + } else { + value = layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); + } for (let i = start; i < length; i++) { const vertex = paintArray.get(i); @@ -211,21 +207,4 @@ function normalizeAttribute(attribute, layer) { return attribute; } -function createFunctionGetValue(attribute, stopZoomLevels) { - return function(layer, globalProperties, featureProperties) { - if (stopZoomLevels.length === 1) { - // return one multi-component value like color0 - return layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, { zoom: stopZoomLevels[0] }), featureProperties); - } else { - // pack multiple single-component values into a four component attribute - const values = []; - for (let z = 0; z < stopZoomLevels.length; z++) { - const stopZoomLevel = stopZoomLevels[z]; - values.push(layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, { zoom: stopZoomLevel }), featureProperties)); - } - return values; - } - }; -} - module.exports = ProgramConfiguration; diff --git a/test/js/data/bucket.test.js b/test/js/data/bucket.test.js index 75c691fb06d..c81f5343bae 100644 --- a/test/js/data/bucket.test.js +++ b/test/js/data/bucket.test.js @@ -23,8 +23,8 @@ test('Bucket', (t) => { const dataDrivenPaint = { 'circle-opacity': { - stops: [[0, 0], [100, 1.0]], - property: 'mapbox' + stops: [[0, 0], [100, 100]], + property: 'x' } }; @@ -45,9 +45,6 @@ test('Bucket', (t) => { paintAttributes: options.paintAttributes || [{ name: 'a_map', type: 'Int16', - getValue: function(layer, globalProperties, featureProperties) { - return [featureProperties.x]; - }, paintProperty: 'circle-opacity' }] }; @@ -141,7 +138,6 @@ test('Bucket', (t) => { paintAttributes: [{ name: 'a_map', type: 'Int16', - getValue: function() { return [5]; }, paintProperty: 'circle-opacity' }], layoutAttributes: [], @@ -153,11 +149,6 @@ test('Bucket', (t) => { bucket.populate([createFeature(17, 42)], createOptions()); t.equal(bucket.arrays.layoutVertexArray.bytesPerElement, 0); - t.deepEqual( - bucket.arrays.layerData.one.programConfiguration.uniforms[0].getValue.call(bucket), - [5] - ); - t.end(); }); From 434c3e8f682b99f2945f167fe234f3ea85b6f421 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 20:07:39 -0700 Subject: [PATCH 15/20] extract dds attribute processing into separate methods --- js/data/program_configuration.js | 156 ++++++++++++++++--------------- 1 file changed, 83 insertions(+), 73 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 791df91556c..fb7af7ceb63 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -36,75 +36,15 @@ class ProgramConfiguration { for (const attributeConfig of attributes) { const attribute = normalizeAttribute(attributeConfig, layer); - const inputName = attribute.name; - assert(inputName.indexOf('a_') === 0); - const name = inputName.slice(2); - const multiplier = attribute.multiplier; - - const vert = self.getVertexPragmas(name); - const frag = self.getFragmentPragmas(name); + assert(attribute.name.indexOf('a_') === 0); + const name = attribute.name.slice(2); if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { - self.uniforms.push(attribute); - self.addUniform(name, inputName); - + self.addZoomDrivenAttribute(name, attribute); } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { - self.attributes.push(attribute); - - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); - - vert.define.push(`attribute {precision} {type} ${inputName};`); - vert.initialize.push(`${name} = ${inputName} / ${multiplier}.0;`); - + self.addDataDrivenAttribute(name, attribute); } else { - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); - - // Pick the index of the first offset to add to the buffers. - let numStops = 0; - const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); - while (numStops < zoomLevels.length && zoomLevels[numStops] < zoom) numStops++; - const stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); - - const tName = `u_${name}_t`; - - vert.define.push(`uniform lowp float ${tName};`); - self.interpolationUniforms.push({ - name: tName, - paintProperty: attribute.paintProperty, - stopOffset - }); - - // Find the four closest stops, ideally with two on each side of the zoom level. - const zoomStops = []; - for (let s = 0; s < 4; s++) { - zoomStops.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]); - } - - if (attribute.components === 1) { - self.attributes.push(util.extend({}, attribute, { - components: 4, - zoomStops - })); - vert.define.push(`attribute {precision} vec4 ${inputName};`); - vert.initialize.push(`${name} = evaluate_zoom_function_1(${inputName}, ${tName}) / ${multiplier}.0;`); - - } else { - const componentNames = []; - for (let k = 0; k < 4; k++) { - const componentName = inputName + k; - - self.attributes.push(util.extend({}, attribute, { - name: componentName, - components: 4, - zoomStops: [zoomStops[k]] - })); - componentNames.push(componentName); - vert.define.push(`attribute {precision} {type} ${componentName};`); - } - vert.initialize.push(`${name} = evaluate_zoom_function_4(${componentNames.join(', ')}, ${tName}) / ${multiplier}.0;`); - } + self.addDataAndZoomDrivenAttribute(name, attribute, layer, zoom); } } @@ -135,6 +75,79 @@ class ProgramConfiguration { vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); } + addZoomDrivenAttribute(name, attribute) { + this.uniforms.push(attribute); + this.addUniform(name, attribute.name); + } + + addDataDrivenAttribute(name, attribute) { + const vert = this.getVertexPragmas(name); + const frag = this.getFragmentPragmas(name); + + this.attributes.push(attribute); + + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + + vert.define.push(`attribute {precision} {type} ${attribute.name};`); + vert.initialize.push(`${name} = ${attribute.name} / ${attribute.multiplier}.0;`); + } + + addDataAndZoomDrivenAttribute(name, attribute, layer, zoom) { + const vert = this.getVertexPragmas(name); + const frag = this.getFragmentPragmas(name); + + frag.define.push(`varying {precision} {type} ${name};`); + vert.define.push(`varying {precision} {type} ${name};`); + + // Pick the index of the first offset to add to the buffers. + let numStops = 0; + const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); + while (numStops < zoomLevels.length && zoomLevels[numStops] < zoom) numStops++; + const stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); + + const tName = `u_${name}_t`; + + vert.define.push(`uniform lowp float ${tName};`); + this.interpolationUniforms.push({ + name: tName, + paintProperty: attribute.paintProperty, + stopOffset + }); + + // Find the four closest stops, ideally with two on each side of the zoom level. + const zoomStops = []; + for (let s = 0; s < 4; s++) { + zoomStops.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]); + } + + const componentNames = []; + + if (attribute.components === 1) { + this.attributes.push(util.extend({}, attribute, { + components: 4, + zoomStops + })); + vert.define.push(`attribute {precision} vec4 ${attribute.name};`); + componentNames.push(attribute.name); + + } else { + for (let k = 0; k < 4; k++) { + const componentName = attribute.name + k; + componentNames.push(componentName); + + this.attributes.push(util.extend({}, attribute, { + name: componentName, + components: 4, + zoomStops: [zoomStops[k]] + })); + vert.define.push(`attribute {precision} {type} ${componentName};`); + } + } + vert.initialize.push(`${name} = evaluate_zoom_function_${attribute.components}(\ + ${componentNames.join(', ')}, ${tName}) / ${attribute.multiplier}.0;`); + } + getFragmentPragmas(name) { this.fragmentPragmas[name] = this.fragmentPragmas[name] || {define: [], initialize: []}; return this.fragmentPragmas[name]; @@ -197,14 +210,11 @@ class ProgramConfiguration { } function normalizeAttribute(attribute, layer) { - const specification = layer._paintSpecifications[attribute.paintProperty]; - const isColor = specification.type === 'color'; - - attribute = util.extend({}, attribute); - attribute.components = isColor ? 4 : 1; - attribute.multiplier = attribute.multiplier || (isColor ? 255 : 1); - - return attribute; + const isColor = layer._paintSpecifications[attribute.paintProperty].type === 'color'; + return util.extend({ + components: isColor ? 4 : 1, + multiplier: isColor ? 255 : 1 + }, attribute); } module.exports = ProgramConfiguration; From be2a76bd113b67fa3b5bd0d48b33ab508cdb9e4a Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 23:04:43 -0700 Subject: [PATCH 16/20] derive paint attribute names from properties --- js/data/bucket/circle_bucket.js | 8 +++---- js/data/bucket/fill_bucket.js | 6 +++--- js/data/bucket/fill_extrusion_bucket.js | 6 +++--- js/data/bucket/line_bucket.js | 2 +- js/data/program_configuration.js | 28 ++++++++++++------------- test/js/data/bucket.test.js | 16 +++++++------- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index a790cc25df5..f71404a4870 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -13,10 +13,10 @@ const circleInterface = { elementArrayType: createElementArrayType(), paintAttributes: [ - {name: 'a_color', paintProperty: 'circle-color', type: 'Uint8'}, - {name: 'a_radius', paintProperty: 'circle-radius', type: 'Uint16', multiplier: 10}, - {name: 'a_blur', paintProperty: 'circle-blur', type: 'Uint16', multiplier: 10}, - {name: 'a_opacity', paintProperty: 'circle-opacity', type: 'Uint8', multiplier: 255} + {property: 'circle-color', type: 'Uint8'}, + {property: 'circle-radius', type: 'Uint16', multiplier: 10}, + {property: 'circle-blur', type: 'Uint16', multiplier: 10}, + {property: 'circle-opacity', type: 'Uint8', multiplier: 255} ] }; diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index 40e6c59ed3a..2ed7c7630c0 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -17,9 +17,9 @@ const fillInterface = { elementArrayType2: createElementArrayType(2), paintAttributes: [ - {name: 'a_color', paintProperty: 'fill-color', type: 'Uint8'}, - {name: 'a_outline_color', paintProperty: 'fill-outline-color', type: 'Uint8'}, - {name: 'a_opacity', paintProperty: 'fill-opacity', type: 'Uint8', multiplier: 255} + {property: 'fill-color', type: 'Uint8'}, + {property: 'fill-outline-color', type: 'Uint8'}, + {property: 'fill-opacity', type: 'Uint8', multiplier: 255} ] }; diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index c1935e17ee0..9366e8f3f23 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -19,9 +19,9 @@ const fillExtrusionInterface = { elementArrayType: createElementArrayType(3), paintAttributes: [ - {name: 'a_base', paintProperty: 'fill-extrusion-base', type: 'Uint16'}, - {name: 'a_height', paintProperty: 'fill-extrusion-height', type: 'Uint16'}, - {name: 'a_color', paintProperty: 'fill-extrusion-color', type: 'Uint8'} + {property: 'fill-extrusion-base', type: 'Uint16'}, + {property: 'fill-extrusion-height', type: 'Uint16'}, + {property: 'fill-extrusion-color', type: 'Uint8'} ] }; diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index d7535e588f0..5d4d6887255 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -45,7 +45,7 @@ const lineInterface = { {name: 'a_data', components: 4, type: 'Uint8'} ]), paintAttributes: [ - {name: 'a_color', paintProperty: 'line-color', type: 'Uint8'} + {property: 'line-color', type: 'Uint8'} ], elementArrayType: createElementArrayType() }; diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index fb7af7ceb63..36f8ad25e53 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -2,7 +2,6 @@ const createVertexArrayType = require('./vertex_array_type'); const util = require('../util/util'); -const assert = require('assert'); /** * ProgramConfiguration contains the logic for binding style layer properties and tile @@ -34,14 +33,12 @@ class ProgramConfiguration { const self = new ProgramConfiguration(); for (const attributeConfig of attributes) { - - const attribute = normalizeAttribute(attributeConfig, layer); - assert(attribute.name.indexOf('a_') === 0); + const attribute = normalizePaintAttribute(attributeConfig, layer); const name = attribute.name.slice(2); - if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { + if (layer.isPaintValueFeatureConstant(attribute.property)) { self.addZoomDrivenAttribute(name, attribute); - } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { + } else if (layer.isPaintValueZoomConstant(attribute.property)) { self.addDataDrivenAttribute(name, attribute); } else { self.addDataAndZoomDrivenAttribute(name, attribute, layer, zoom); @@ -102,7 +99,7 @@ class ProgramConfiguration { // Pick the index of the first offset to add to the buffers. let numStops = 0; - const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); + const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.property); while (numStops < zoomLevels.length && zoomLevels[numStops] < zoom) numStops++; const stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); @@ -111,7 +108,7 @@ class ProgramConfiguration { vert.define.push(`uniform lowp float ${tName};`); this.interpolationUniforms.push({ name: tName, - paintProperty: attribute.paintProperty, + property: attribute.property, stopOffset }); @@ -166,10 +163,10 @@ class ProgramConfiguration { let value; if (attribute.zoomStops) { // add one multi-component value like color0, or pack multiple single-component values into a four component attribute - const values = attribute.zoomStops.map((zoom) => layer.getPaintValue(attribute.paintProperty, util.extend({}, globalProperties, {zoom}), featureProperties)); + const values = attribute.zoomStops.map((zoom) => layer.getPaintValue(attribute.property, util.extend({}, globalProperties, {zoom}), featureProperties)); value = values.length === 1 ? values[0] : values; } else { - value = layer.getPaintValue(attribute.paintProperty, globalProperties, featureProperties); + value = layer.getPaintValue(attribute.property, globalProperties, featureProperties); } for (let i = start; i < length; i++) { @@ -191,7 +188,7 @@ class ProgramConfiguration { setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { - const value = layer.getPaintValue(uniform.paintProperty, globalProperties); + const value = layer.getPaintValue(uniform.property, globalProperties); if (uniform.components === 4) { gl.uniform4fv(program[uniform.name], value); } else { @@ -201,7 +198,7 @@ class ProgramConfiguration { for (const uniform of this.interpolationUniforms) { // stopInterp indicates which stops need to be interpolated. // If stopInterp is 3.5 then interpolate half way between stops 3 and 4. - const stopInterp = layer.getPaintInterpolationT(uniform.paintProperty, globalProperties); + const stopInterp = layer.getPaintInterpolationT(uniform.property, globalProperties); // We can only store four stop values in the buffers. stopOffset is the number of stops that come // before the stops that were added to the buffers. gl.uniform1f(program[uniform.name], Math.max(0, Math.min(4, stopInterp - uniform.stopOffset))); @@ -209,9 +206,12 @@ class ProgramConfiguration { } } -function normalizeAttribute(attribute, layer) { - const isColor = layer._paintSpecifications[attribute.paintProperty].type === 'color'; +function normalizePaintAttribute(attribute, layer) { + const name = attribute.property.replace(`${layer.type}-`, '').replace(/-/g, '_'); + const isColor = layer._paintSpecifications[attribute.property].type === 'color'; + return util.extend({ + name: `a_${name}`, components: isColor ? 4 : 1, multiplier: isColor ? 255 : 1 }, attribute); diff --git a/test/js/data/bucket.test.js b/test/js/data/bucket.test.js index c81f5343bae..4c24ab42927 100644 --- a/test/js/data/bucket.test.js +++ b/test/js/data/bucket.test.js @@ -43,9 +43,8 @@ test('Bucket', (t) => { elementArrayType2: createElementArrayType(2), paintAttributes: options.paintAttributes || [{ - name: 'a_map', - type: 'Int16', - paintProperty: 'circle-opacity' + property: 'circle-opacity', + type: 'Int16' }] }; @@ -96,7 +95,7 @@ test('Bucket', (t) => { const paintVertex = bucket.arrays.layerData.layerid.paintVertexArray; t.equal(paintVertex.length, 1); const p0 = paintVertex.get(0); - t.equal(p0.a_map, 17); + t.equal(p0.a_opacity, 17); const testElement = bucket.arrays.elementArray; t.equal(testElement.length, 1); @@ -125,8 +124,8 @@ test('Bucket', (t) => { const v0 = bucket.arrays.layoutVertexArray.get(0); const a0 = bucket.arrays.layerData.one.paintVertexArray.get(0); const b0 = bucket.arrays.layerData.two.paintVertexArray.get(0); - t.equal(a0.a_map, 17); - t.equal(b0.a_map, 17); + t.equal(a0.a_opacity, 17); + t.equal(b0.a_opacity, 17); t.equal(v0.a_box0, 34); t.equal(v0.a_box1, 84); @@ -136,9 +135,8 @@ test('Bucket', (t) => { t.test('add features, disabled attribute', (t) => { const bucket = create({ paintAttributes: [{ - name: 'a_map', - type: 'Int16', - paintProperty: 'circle-opacity' + property: 'circle-opacity', + type: 'Int16' }], layoutAttributes: [], layers: [ From 765e713849a00c9d25c6d8669384e3ea1cd2c674 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 4 Nov 2016 23:50:53 -0700 Subject: [PATCH 17/20] much faster program caching mechanism which generates 100x smaller cache keys, making program lookups much faster --- js/data/array_group.js | 3 +-- js/data/program_configuration.js | 16 ++++++++-------- js/render/painter.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/js/data/array_group.js b/js/data/array_group.js index f8faeb86293..a98a3930aca 100644 --- a/js/data/array_group.js +++ b/js/data/array_group.js @@ -48,11 +48,10 @@ class ArrayGroup { for (const layer of layers) { const programConfiguration = ProgramConfiguration.createDynamic( programInterface.paintAttributes || [], layer, zoom); - const PaintVertexArrayType = programConfiguration.paintVertexArrayType(); this.layerData[layer.id] = { layer: layer, programConfiguration: programConfiguration, - paintVertexArray: new PaintVertexArrayType() + paintVertexArray: new programConfiguration.PaintVertexArray() }; } diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 36f8ad25e53..3e02e506ddc 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -27,6 +27,7 @@ class ProgramConfiguration { this.interpolationUniforms = []; this.vertexPragmas = {}; this.fragmentPragmas = {}; + this.cacheKey = ''; } static createDynamic(attributes, layer, zoom) { @@ -44,8 +45,7 @@ class ProgramConfiguration { self.addDataAndZoomDrivenAttribute(name, attribute, layer, zoom); } } - - self.cacheKey = JSON.stringify([self.vertexPragmas, self.fragmentPragmas]); + self.PaintVertexArray = createVertexArrayType(self.attributes); return self; } @@ -56,8 +56,6 @@ class ProgramConfiguration { for (const name of uniformNames) { self.addUniform(name, `u_${name}`); } - self.cacheKey = JSON.stringify(self.fragmentPragmas); - return self; } @@ -70,6 +68,8 @@ class ProgramConfiguration { frag.initialize.push(`{precision} {type} ${name} = ${inputName};`); vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); + + this.cacheKey += `/u_${name}`; } addZoomDrivenAttribute(name, attribute) { @@ -88,6 +88,8 @@ class ProgramConfiguration { vert.define.push(`attribute {precision} {type} ${attribute.name};`); vert.initialize.push(`${name} = ${attribute.name} / ${attribute.multiplier}.0;`); + + this.cacheKey += `/a_${name}`; } addDataAndZoomDrivenAttribute(name, attribute, layer, zoom) { @@ -143,6 +145,8 @@ class ProgramConfiguration { } vert.initialize.push(`${name} = evaluate_zoom_function_${attribute.components}(\ ${componentNames.join(', ')}, ${tName}) / ${attribute.multiplier}.0;`); + + this.cacheKey += `/z_${name}`; } getFragmentPragmas(name) { @@ -182,10 +186,6 @@ class ProgramConfiguration { } } - paintVertexArrayType() { - return createVertexArrayType(this.attributes); - } - setUniforms(gl, program, layer, globalProperties) { for (const uniform of this.uniforms) { const value = layer.getPaintValue(uniform.property, globalProperties); diff --git a/js/render/painter.js b/js/render/painter.js index 2436fd2ced8..ea734dbeb83 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -398,7 +398,7 @@ class Painter { _createProgramCached(name, programConfiguration) { this.cache = this.cache || {}; - const key = `${name}${programConfiguration.cacheKey}${!!this._showOverdrawInspector}`; + const key = `${name}${programConfiguration.cacheKey || ''}/${!!this._showOverdrawInspector}`; if (!this.cache[key]) { this.cache[key] = this.createProgram(name, this._showOverdrawInspector, this.gl, programConfiguration); } From f4cca390afc7db388772c64498a607687a02d4a8 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Sat, 5 Nov 2016 11:39:51 -0700 Subject: [PATCH 18/20] minor painter & program config cleanup --- js/data/program_configuration.js | 21 ++++++++++++--------- js/render/painter.js | 9 +++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 3e02e506ddc..72184412f47 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -137,7 +137,6 @@ class ProgramConfiguration { this.attributes.push(util.extend({}, attribute, { name: componentName, - components: 4, zoomStops: [zoomStops[k]] })); vert.define.push(`attribute {precision} {type} ${componentName};`); @@ -164,14 +163,7 @@ class ProgramConfiguration { paintArray.resize(length); for (const attribute of this.attributes) { - let value; - if (attribute.zoomStops) { - // add one multi-component value like color0, or pack multiple single-component values into a four component attribute - const values = attribute.zoomStops.map((zoom) => layer.getPaintValue(attribute.property, util.extend({}, globalProperties, {zoom}), featureProperties)); - value = values.length === 1 ? values[0] : values; - } else { - value = layer.getPaintValue(attribute.property, globalProperties, featureProperties); - } + const value = getPaintAttributeValue(attribute, layer, globalProperties, featureProperties); for (let i = start; i < length; i++) { const vertex = paintArray.get(i); @@ -206,6 +198,17 @@ class ProgramConfiguration { } } +function getPaintAttributeValue(attribute, layer, globalProperties, featureProperties) { + if (!attribute.zoomStops) { + return layer.getPaintValue(attribute.property, globalProperties, featureProperties); + } + // add one multi-component value like color0, or pack multiple single-component values into a four component attribute + const values = attribute.zoomStops.map((zoom) => layer.getPaintValue( + attribute.property, util.extend({}, globalProperties, {zoom}), featureProperties)); + + return values.length === 1 ? values[0] : values; +} + function normalizePaintAttribute(attribute, layer) { const name = attribute.property.replace(`${layer.type}-`, '').replace(/-/g, '_'); const isColor = layer._paintSpecifications[attribute.property].type === 'color'; diff --git a/js/render/painter.js b/js/render/painter.js index ea734dbeb83..54167315711 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -357,12 +357,13 @@ class Painter { } } - createProgram(name, showOverdraw, gl, configuration) { + createProgram(name, configuration) { + const gl = this.gl; const program = gl.createProgram(); const definition = shaders[name]; let definesSource = '#define MAPBOX_GL_JS;\n'; - if (showOverdraw) { + if (this._showOverdrawInspector) { definesSource += '#define OVERDRAW_INSPECTOR;\n'; } @@ -398,9 +399,9 @@ class Painter { _createProgramCached(name, programConfiguration) { this.cache = this.cache || {}; - const key = `${name}${programConfiguration.cacheKey || ''}/${!!this._showOverdrawInspector}`; + const key = `${name}${programConfiguration.cacheKey || ''}${this._showOverdrawInspector ? '/overdraw' : ''}`; if (!this.cache[key]) { - this.cache[key] = this.createProgram(name, this._showOverdrawInspector, this.gl, programConfiguration); + this.cache[key] = this.createProgram(name, programConfiguration); } return this.cache[key]; } From 36d780b2c76085b67d3b7c2564928e6ddccc67da Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Sat, 5 Nov 2016 12:20:49 -0700 Subject: [PATCH 19/20] move back applyPragmas to program configuration --- js/data/program_configuration.js | 58 ++++++++++++++++---------------- js/render/painter.js | 16 +++------ 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 72184412f47..723c1f151d9 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -25,8 +25,7 @@ class ProgramConfiguration { this.attributes = []; this.uniforms = []; this.interpolationUniforms = []; - this.vertexPragmas = {}; - this.fragmentPragmas = {}; + this.pragmas = {vertex: {}, fragment: {}}; this.cacheKey = ''; } @@ -60,14 +59,10 @@ class ProgramConfiguration { } addUniform(name, inputName) { - const frag = this.getFragmentPragmas(name); - const vert = this.getVertexPragmas(name); + const pragmas = this.getPragmas(name); - frag.define.push(`uniform {precision} {type} ${inputName};`); - vert.define.push(`uniform {precision} {type} ${inputName};`); - - frag.initialize.push(`{precision} {type} ${name} = ${inputName};`); - vert.initialize.push(`{precision} {type} ${name} = ${inputName};`); + pragmas.define.push(`uniform {precision} {type} ${inputName};`); + pragmas.initialize.push(`{precision} {type} ${name} = ${inputName};`); this.cacheKey += `/u_${name}`; } @@ -78,26 +73,22 @@ class ProgramConfiguration { } addDataDrivenAttribute(name, attribute) { - const vert = this.getVertexPragmas(name); - const frag = this.getFragmentPragmas(name); + const pragmas = this.getPragmas(name); this.attributes.push(attribute); - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); + pragmas.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`attribute {precision} {type} ${attribute.name};`); - vert.initialize.push(`${name} = ${attribute.name} / ${attribute.multiplier}.0;`); + pragmas.vertex.define.push(`attribute {precision} {type} ${attribute.name};`); + pragmas.vertex.initialize.push(`${name} = ${attribute.name} / ${attribute.multiplier}.0;`); this.cacheKey += `/a_${name}`; } addDataAndZoomDrivenAttribute(name, attribute, layer, zoom) { - const vert = this.getVertexPragmas(name); - const frag = this.getFragmentPragmas(name); + const pragmas = this.getPragmas(name); - frag.define.push(`varying {precision} {type} ${name};`); - vert.define.push(`varying {precision} {type} ${name};`); + pragmas.define.push(`varying {precision} {type} ${name};`); // Pick the index of the first offset to add to the buffers. let numStops = 0; @@ -107,7 +98,8 @@ class ProgramConfiguration { const tName = `u_${name}_t`; - vert.define.push(`uniform lowp float ${tName};`); + pragmas.vertex.define.push(`uniform lowp float ${tName};`); + this.interpolationUniforms.push({ name: tName, property: attribute.property, @@ -127,7 +119,7 @@ class ProgramConfiguration { components: 4, zoomStops })); - vert.define.push(`attribute {precision} vec4 ${attribute.name};`); + pragmas.vertex.define.push(`attribute {precision} vec4 ${attribute.name};`); componentNames.push(attribute.name); } else { @@ -139,23 +131,31 @@ class ProgramConfiguration { name: componentName, zoomStops: [zoomStops[k]] })); - vert.define.push(`attribute {precision} {type} ${componentName};`); + pragmas.vertex.define.push(`attribute {precision} {type} ${componentName};`); } } - vert.initialize.push(`${name} = evaluate_zoom_function_${attribute.components}(\ + pragmas.vertex.initialize.push(`${name} = evaluate_zoom_function_${attribute.components}(\ ${componentNames.join(', ')}, ${tName}) / ${attribute.multiplier}.0;`); this.cacheKey += `/z_${name}`; } - getFragmentPragmas(name) { - this.fragmentPragmas[name] = this.fragmentPragmas[name] || {define: [], initialize: []}; - return this.fragmentPragmas[name]; + getPragmas(name) { + if (!this.pragmas[name]) { + this.pragmas[name] = {define: [], initialize: []}; + this.pragmas[name].fragment = {define: [], initialize: []}; + this.pragmas[name].vertex = {define: [], initialize: []}; + } + return this.pragmas[name]; } - getVertexPragmas(name) { - this.vertexPragmas[name] = this.vertexPragmas[name] || {define: [], initialize: []}; - return this.vertexPragmas[name]; + applyPragmas(source, shaderType) { + return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { + return this.pragmas[name][operation].concat(this.pragmas[name][shaderType][operation]) + .join('\n') + .replace(/{type}/g, type) + .replace(/{precision}/g, precision); + }); } populatePaintArray(layer, paintArray, length, globalProperties, featureProperties) { diff --git a/js/render/painter.js b/js/render/painter.js index 54167315711..95945ae1d86 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -52,6 +52,7 @@ class Painter { this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); this.basicFillProgramConfiguration = ProgramConfiguration.createStatic(['color', 'opacity']); + this.emptyProgramConfiguration = new ProgramConfiguration(); } /* @@ -368,13 +369,13 @@ class Painter { } const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, applyPragmas(definesSource + definition.fragmentSource, configuration.fragmentPragmas)); + gl.shaderSource(fragmentShader, configuration.applyPragmas(definesSource + definition.fragmentSource, 'fragment')); gl.compileShader(fragmentShader); assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(fragmentShader)); gl.attachShader(program, fragmentShader); const vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, applyPragmas(definesSource + shaders.util + definition.vertexSource, configuration.vertexPragmas)); + gl.shaderSource(vertexShader, configuration.applyPragmas(definesSource + shaders.util + definition.vertexSource, 'vertex')); gl.compileShader(vertexShader); assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(vertexShader)); gl.attachShader(program, vertexShader); @@ -408,7 +409,7 @@ class Painter { useProgram(name, programConfiguration) { const gl = this.gl; - const nextProgram = this._createProgramCached(name, programConfiguration || {}); + const nextProgram = this._createProgramCached(name, programConfiguration || this.emptyProgramConfiguration); if (this.currentProgram !== nextProgram) { gl.useProgram(nextProgram.program); @@ -419,13 +420,4 @@ class Painter { } } -function applyPragmas(source, pragmas) { - return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { - return pragmas[name][operation] - .join('\n') - .replace(/{type}/g, type) - .replace(/{precision}/g, precision); - }); -} - module.exports = Painter; From 0d16d211b4200eb3507ab41c6df777c6656a314a Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Mon, 7 Nov 2016 15:49:06 -0800 Subject: [PATCH 20/20] rename program configuration methods --- js/data/program_configuration.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 723c1f151d9..518442cb485 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -37,11 +37,11 @@ class ProgramConfiguration { const name = attribute.name.slice(2); if (layer.isPaintValueFeatureConstant(attribute.property)) { - self.addZoomDrivenAttribute(name, attribute); + self.addZoomAttribute(name, attribute); } else if (layer.isPaintValueZoomConstant(attribute.property)) { - self.addDataDrivenAttribute(name, attribute); + self.addPropertyAttribute(name, attribute); } else { - self.addDataAndZoomDrivenAttribute(name, attribute, layer, zoom); + self.addZoomAndPropertyAttribute(name, attribute, layer, zoom); } } self.PaintVertexArray = createVertexArrayType(self.attributes); @@ -67,12 +67,12 @@ class ProgramConfiguration { this.cacheKey += `/u_${name}`; } - addZoomDrivenAttribute(name, attribute) { + addZoomAttribute(name, attribute) { this.uniforms.push(attribute); this.addUniform(name, attribute.name); } - addDataDrivenAttribute(name, attribute) { + addPropertyAttribute(name, attribute) { const pragmas = this.getPragmas(name); this.attributes.push(attribute); @@ -85,7 +85,7 @@ class ProgramConfiguration { this.cacheKey += `/a_${name}`; } - addDataAndZoomDrivenAttribute(name, attribute, layer, zoom) { + addZoomAndPropertyAttribute(name, attribute, layer, zoom) { const pragmas = this.getPragmas(name); pragmas.define.push(`varying {precision} {type} ${name};`);