From 7d2894851a3f490f09e94720e5bfec1ab01e74dd Mon Sep 17 00:00:00 2001 From: David Manthey Date: Tue, 8 May 2018 15:30:12 -0400 Subject: [PATCH 1/2] Modify the webgl line feature shaders. Chrome 65 and 66 when running in xvfb with openmesa do not compute atan(0, ) correctly. Also, there are occasional int() casts that round down even when they are small integers. These changes make image comparisons more robust by working around the atan issue (this may be the issue detailed in chromium.googlesource.com/angle/angle/commit/da9fb09). I have submitted a new issue to chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=841296 to track this problem. With this commit, the baselines were regenerated with Chrome 64, and the test strictness requirements changed in PR #792 have been reverted. There are subtly differences between Chrome 64 and 66 (font aliasing is slightly different, and I think the other changes are because the shader float precision is subtly different, though I'm not sure of that). --- src/gl/lineFeature.js | 41 +++++++++++++++++---------- testing/test-data/base-images.tgz.md5 | 2 +- testing/test-data/base-images.tgz.url | 2 +- tests/gl-cases/glLines.js | 4 +-- tests/gl-cases/glPolygons.js | 4 +-- tests/headed-cases/lines.js | 4 +-- 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/gl/lineFeature.js b/src/gl/lineFeature.js index d55bdaea1b..7a4e962eeb 100644 --- a/src/gl/lineFeature.js +++ b/src/gl/lineFeature.js @@ -109,17 +109,24 @@ var gl_lineFeature = function (arg) { 'const float PI = 3.14159265358979323846264;', 'vec4 viewCoord(vec3 c) {', - ' vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1);', + ' vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1.0);', ' if (result.w != 0.0) result = result / result.w;', ' return result;', '}', + 'float atan2(float y, float x) {', + ' if (x > 0.0) return atan(y / x);', + ' if (x < 0.0 && y >= 0.0) return atan(y / x) + PI;', + ' if (x < 0.0) return atan(y / x) - PI;', + ' return sign(y) * 0.5 * PI;', + '}', + 'void main(void)', '{', /* If any vertex has been deliberately set to a negative opacity, * skip doing computations on it. */ ' if (strokeOpacity < 0.0) {', - ' gl_Position = vec4(2, 2, 0, 1);', + ' gl_Position = vec4(2.0, 2.0, 0.0, 1.0);', ' return;', ' }', /* convert coordinates. We have four values, since we need to @@ -133,10 +140,10 @@ var gl_lineFeature = function (arg) { // calculate line segment vector and angle ' vec2 deltaCB = C.xy - B.xy;', ' if (deltaCB == vec2(0.0, 0.0)) {', - ' gl_Position = vec4(2, 2, 0, 1);', + ' gl_Position = vec4(2.0, 2.0, 0.0, 1.0);', ' return;', ' }', - ' float angleCB = atan(deltaCB.y / aspect, deltaCB.x);', + ' float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);', // values we need to pass along ' strokeColorVar = vec4(strokeColor, strokeOpacity);', // extract values from our flags field @@ -169,14 +176,14 @@ var gl_lineFeature = function (arg) { // offset, then the functional join angle is not simply half the // angle between the two lines, but rather half the angle of the // inside edge of the the two lines. - ' float cosABC, sinABC, cosBCD, sinBCD;', // of half angles + ' float cosABC = 1.0, sinABC = 0.0, cosBCD = 1.0, sinBCD = 0.0;', // of half angles // handle near end ' if (nearMode >= 4) {', - ' float angleBA = atan((B.y - A.y) / aspect, B.x - A.x);', + ' float angleBA = atan2(B.y - A.y, (B.x - A.x) * aspect);', ' if (A.xy == B.xy) angleBA = angleCB;', ' float angleABC = angleCB - angleBA;', // ensure angle is in the range [-PI, PI], then take the half angle - ' angleABC = (mod(angleABC + PI, 2.0 * PI) - PI) / 2.0;', + ' angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;', ' cosABC = cos(angleABC); sinABC = sin(angleABC);', // if this angle is close to flat, pass-through the join ' if (nearMode >= 4 && cosABC > 0.999999) {', @@ -184,7 +191,7 @@ var gl_lineFeature = function (arg) { ' }', // miter, miter-clip ' if (nearMode == 4 || nearMode == 7) {', - ' if (cosABC == 0.0 || 1.0 / cosABC > miterLimit) {', + ' if (cosABC < 0.000001 || 1.0 / cosABC > miterLimit) {', ' if (nearMode == 4) {', ' nearMode = 5;', ' } else {', @@ -205,11 +212,11 @@ var gl_lineFeature = function (arg) { // handle far end ' if (farMode >= 4) {', - ' float angleDC = atan((D.y - C.y) / aspect, D.x - C.x);', + ' float angleDC = atan2(D.y - C.y, (D.x - C.x) * aspect);', ' if (D.xy == C.xy) angleDC = angleCB;', ' float angleBCD = angleDC - angleCB;', // ensure angle is in the range [-PI, PI], then take the half angle - ' angleBCD = (mod(angleBCD + PI, 2.0 * PI) - PI) / 2.0;', + ' angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;', ' cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);', // if this angle is close to flat, pass-through the join ' if (farMode >= 4 && cosBCD > 0.999999) {', @@ -217,7 +224,7 @@ var gl_lineFeature = function (arg) { ' }', // miter, miter-clip ' if (farMode == 4 || farMode == 7) {', - ' if (cosBCD == 0.0 || 1.0 / cosBCD > miterLimit) {', + ' if (cosBCD < 0.000001 || 1.0 / cosBCD > miterLimit) {', ' if (farMode == 4) farMode = 5;', ' } else {', ' farMode = 4;', @@ -231,7 +238,7 @@ var gl_lineFeature = function (arg) { ' gl_Position = vec4(', ' B.x + (xOffset * cos(angleCB) - yOffset * sin(angleCB)) * pixelWidth,', ' B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,', - ' B.z, 1);', + ' B.z, 1.0);', // store other values needed to determine which pixels to plot. ' float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;', @@ -262,7 +269,11 @@ var gl_lineFeature = function (arg) { function createFragmentShader(allowDebug) { var fragmentShaderSource = [ '#ifdef GL_ES', - ' precision highp float;', + ' #ifdef GL_FRAGMENT_PRECISION_HIGH', + ' precision highp float;', + ' #else', + ' precision mediump float;', + ' #endif', '#endif', 'varying vec4 strokeColorVar;', 'varying vec4 subpos;', @@ -275,8 +286,8 @@ var gl_lineFeature = function (arg) { ' vec4 color = strokeColorVar;', allowDebug ? ' bool debug = bool(mod(fixedFlags, 2.0));' : '', ' float opacity = 1.0;', - ' int nearMode = int(info.x);', - ' int farMode = int(info.y);', + ' int nearMode = int(floor(info.x + 0.5));', + ' int farMode = int(floor(info.y + 0.5));', ' float cosABC = angles.x;', ' float sinABC = angles.y;', ' float cosBCD = angles.z;', diff --git a/testing/test-data/base-images.tgz.md5 b/testing/test-data/base-images.tgz.md5 index b0a4cb7bba..7735d4198f 100644 --- a/testing/test-data/base-images.tgz.md5 +++ b/testing/test-data/base-images.tgz.md5 @@ -1 +1 @@ -2333a69e96ce063d10862bd8d563eb3d \ No newline at end of file +24a2ffe0807138fe13c33ddeccb2b426 \ No newline at end of file diff --git a/testing/test-data/base-images.tgz.url b/testing/test-data/base-images.tgz.url index 0107cbdd36..d0c36ceb1a 100644 --- a/testing/test-data/base-images.tgz.url +++ b/testing/test-data/base-images.tgz.url @@ -1 +1 @@ -https://data.kitware.com/api/v1/file/5a9ed5838d777f0685786207/download \ No newline at end of file +https://data.kitware.com/api/v1/file/5af1fcff8d777f0685797d19/download \ No newline at end of file diff --git a/tests/gl-cases/glLines.js b/tests/gl-cases/glLines.js index 61d3d2da78..dd109d0429 100644 --- a/tests/gl-cases/glLines.js +++ b/tests/gl-cases/glLines.js @@ -140,9 +140,7 @@ describe('glLines', function () { myMap.draw(); - // maximum error is 0.0030 because of a change in Chrome 65. When new - // versions are released, see if this can be moved back to 0.0015 - imageTest.imageTest('glLinesOpts', null, 0.0030, done, myMap.onIdle, 0, 2); + imageTest.imageTest('glLinesOpts', null, 0.0015, done, myMap.onIdle, 0, 2); }, 10000); }); diff --git a/tests/gl-cases/glPolygons.js b/tests/gl-cases/glPolygons.js index 4f81639b20..a62e8868ec 100644 --- a/tests/gl-cases/glPolygons.js +++ b/tests/gl-cases/glPolygons.js @@ -2446,9 +2446,7 @@ describe('glPolygons', function () { layer: layer }).read(JSON.stringify(data), function () { myMap.draw(); - // maximum error is 0.0030 because of a change in Chrome 65. When new - // versions are released, see if this can be moved back to 0.0015 - imageTest.imageTest('glMultiPolygons', null, 0.0030, done, myMap.onIdle, 0, 2); + imageTest.imageTest('glMultiPolygons', null, 0.0015, done, myMap.onIdle, 0, 2); }); }); diff --git a/tests/headed-cases/lines.js b/tests/headed-cases/lines.js index 17063f262f..cd1094a945 100644 --- a/tests/headed-cases/lines.js +++ b/tests/headed-cases/lines.js @@ -16,9 +16,7 @@ describe('lines example', function () { it('more lines', function (done) { base$ = $('iframe#map')[0].contentWindow.jQuery; base$('#lines').val(100000).trigger('change'); - // maximum error is 0.0030 because of a change in Chrome 65. When new - // versions are released, see if this can be moved back to 0.0015 - imageTest.imageTest('exampleLines100k', '#map', 0.0030, done, null, 0, 2, '#map.ready[segments="100000"]'); + imageTest.imageTest('exampleLines100k', '#map', 0.0015, done, null, 0, 2, '#map.ready[segments="100000"]'); }, 10000); it('thin preset', function (done) { base$('button.preset').eq(1).trigger('click'); From 682fa56c2e75aaff034b6171aa00a281c873a177 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Wed, 9 May 2018 10:47:26 -0400 Subject: [PATCH 2/2] Node 6 is failing, so try node 8. --- .travis.yml | 5 +++-- docs/provisioning.rst | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80b4a7f170..1883efed70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ sudo: required dist: trusty node_js: - - 6 + - 8 addons: firefox: latest # version 55.0 - 57.x have an issue with screenshots. @@ -38,8 +38,9 @@ before_install: # Start xvfb with a specific resolution and pixel depth - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x24" - CACHE="${HOME}/cache" CMAKE_VERSION=3.5.0 CMAKE_SHORT_VERSION=3.5 source ./scripts/install_cmake.sh + - npm install -g npm@latest + - npm install -g node-pre-gyp - npm prune - - npm install -g npm before_script: - export DISPLAY=:99.0 diff --git a/docs/provisioning.rst b/docs/provisioning.rst index 11f510aee1..acbbb879af 100644 --- a/docs/provisioning.rst +++ b/docs/provisioning.rst @@ -15,7 +15,7 @@ onward. They assume a basic installation, as, for instance, from the Add nodejs to the sources so it can be installed :: - wget -qO- https://deb.nodesource.com/setup_6.x | sudo bash - + wget -qO- https://deb.nodesource.com/setup_8.x | sudo bash - Install required packages (you may want to also include cmake-curses-gui for convenience in configuring CMake options) ::