Speed up webgl point updates.
MODIFY
CHANGELOG.md
CHANGELOG.md
### Improvements
- Points with small radii or thin strokes are rendered better (#1021)
+- When only updating point styles, don't recompute geometry transforms (#1022)
### Changes
- Switched the default tile server to Stamen Design's toner-lite. (#1020)

MODIFY
src/webgl/pointFeature.js
src/webgl/pointFeature.js
@@ -128,8 +128,11 @@ var webgl_pointFeature = function (arg) {
/**
* Create and style the data needed to render the points.
+ *
+ * @param {boolean} onlyStyle if true, use the existing geoemtry and just
+ * recalculate the style.
*/
- function createGLPoints() {
+ function createGLPoints(onlyStyle) {
// unit and associated data is not used when drawing sprite
var i, j, numPts = m_this.data().length,
unit = pointPolygon(0, 0, 1, 1),
@@ -158,6 +161,7 @@ var webgl_pointFeature = function (arg) {
fillOpacityFunc = m_this.style.get('fillOpacity');
fillColorFunc = m_this.style.get('fillColor');
+ if (!onlyStyle) {
/* It is more efficient to do a transform on a single array rather than on
* an array of arrays or an array of objects. */
for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
@@ -184,6 +188,12 @@ var webgl_pointFeature = function (arg) {
if (m_primitiveShape !== 'sprite') {
unitBuf = util.getGeomBuffer(geom, 'unit', vpf * numPts * 2);
}
+ indices = geom.primitive(0).indices();
+ if (!(indices instanceof Uint16Array) || indices.length !== vpf * numPts) {
+ indices = new Uint16Array(vpf * numPts);
+ geom.primitive(0).setIndices(indices);
+ }
+ }
radius = util.getGeomBuffer(geom, 'radius', vpf * numPts);
stroke = util.getGeomBuffer(geom, 'stroke', vpf * numPts);
@@ -193,19 +203,16 @@ var webgl_pointFeature = function (arg) {
fill = util.getGeomBuffer(geom, 'fill', vpf * numPts);
fillOpacity = util.getGeomBuffer(geom, 'fillOpacity', vpf * numPts);
fillColor = util.getGeomBuffer(geom, 'fillColor', vpf * numPts * 3);
- indices = geom.primitive(0).indices();
- if (!(indices instanceof Uint16Array) || indices.length !== vpf * numPts) {
- indices = new Uint16Array(vpf * numPts);
- geom.primitive(0).setIndices(indices);
- }
for (i = ivpf = ivpf3 = iunit = i3 = 0; i < numPts; i += 1, i3 += 3) {
item = data[i];
+ if (!onlyStyle) {
if (m_primitiveShape !== 'sprite') {
for (j = 0; j < unit.length; j += 1, iunit += 1) {
unitBuf[iunit] = unit[j];
}
}
+ }
/* We can ignore the indicies (they will all be zero) */
radiusVal = radFunc(item, i);
strokeVal = strokeFunc(item, i) ? 1.0 : 0.0;
@@ -216,9 +223,11 @@ var webgl_pointFeature = function (arg) {
fillOpacityVal = fillOpacityFunc(item, i);
fillColorVal = fillColorFunc(item, i);
for (j = 0; j < vpf; j += 1, ivpf += 1, ivpf3 += 3) {
+ if (!onlyStyle) {
posBuf[ivpf3] = position[i3];
posBuf[ivpf3 + 1] = position[i3 + 1];
posBuf[ivpf3 + 2] = position[i3 + 2];
+ }
radius[ivpf] = radiusVal;
stroke[ivpf] = strokeVal;
strokeWidth[ivpf] = strokeWidthVal;
@@ -234,9 +243,20 @@ var webgl_pointFeature = function (arg) {
}
}
+ if (!onlyStyle) {
geom.boundsDirty(true);
m_mapper.modified();
m_mapper.boundsDirtyTimestamp().modified();
+ } else {
+ m_mapper.updateSourceBuffer('radius');
+ m_mapper.updateSourceBuffer('stroke');
+ m_mapper.updateSourceBuffer('strokeWidth');
+ m_mapper.updateSourceBuffer('strokeColor');
+ m_mapper.updateSourceBuffer('strokeOpacity');
+ m_mapper.updateSourceBuffer('fill');
+ m_mapper.updateSourceBuffer('fillColor');
+ m_mapper.updateSourceBuffer('fillOpacity');
+ }
}
/**
@@ -468,7 +488,7 @@ var webgl_pointFeature = function (arg) {
* @returns {this}
*/
this._build = function () {
- createGLPoints();
+ createGLPoints(m_this.dataTime().timestamp() < m_this.buildTime().timestamp());
if (!m_this.renderer().contextRenderer().hasActor(m_actor)) {
m_this.renderer().contextRenderer().addActor(m_actor);
}

MODIFY
src/webgl/pointFeaturePoly.frag
src/webgl/pointFeaturePoly.frag
@@ -8,21 +8,19 @@ varying vec4 fillColorVar;
varying vec4 strokeColorVar;
varying float radiusVar;
varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
varying vec3 unitVar; // distinct for square/triangle
void main () {
vec4 strokeColor, fillColor;
float endStep;
// No stroke or fill implies nothing to draw
- if (fillVar == 0.0 && strokeVar == 0.0)
+ if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0)
discard;
float rad = length(unitVar.xy); // distinct for square/triangle
if (rad > 1.0)
discard;
// If there is no stroke, the fill region should transition to nothing
- if (strokeVar == 0.0) {
+ if (strokeColorVar.a == 0.0) {
strokeColor = vec4(fillColorVar.rgb, 0.0);
endStep = 1.0;
} else {
@@ -30,7 +28,7 @@ void main () {
endStep = radiusVar / (radiusVar + strokeWidthVar);
}
// Likewise, if there is no fill, the stroke should transition to nothing
- if (fillVar == 0.0)
+ if (fillColorVar.a == 0.0)
fillColor = vec4(strokeColor.rgb, 0.0);
else
fillColor = fillColorVar;

MODIFY
src/webgl/pointFeaturePoly.vert
src/webgl/pointFeaturePoly.vert
@@ -20,32 +20,26 @@ varying vec4 fillColorVar;
varying vec4 strokeColorVar;
varying float radiusVar;
varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
attribute vec2 unit; // for non-sprite
varying vec3 unitVar; // for non-sprite
void main(void)
{
strokeWidthVar = strokeWidth;
+ fillColorVar = vec4(fillColor, fillOpacity);
+ strokeColorVar = vec4(strokeColor, strokeOpacity);
// No stroke or fill implies nothing to draw
if (stroke < 1.0 || strokeWidth <= 0.0 || strokeOpacity <= 0.0) {
- strokeVar = 0.0;
+ strokeColorVar.a = 0.0;
strokeWidthVar = 0.0;
}
- else
- strokeVar = 1.0;
if (fill < 1.0 || radius <= 0.0 || fillOpacity <= 0.0)
- fillVar = 0.0;
- else
- fillVar = 1.0;
+ fillColorVar.a = 0.0;
/* If the point has no visible pixels, skip doing computations on it. */
- if (fillVar == 0.0 && strokeVar == 0.0) {
+ if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0) {
gl_Position = vec4(2, 2, 0, 1);
return;
}
- fillColorVar = vec4 (fillColor, fillOpacity);
- strokeColorVar = vec4 (strokeColor, strokeOpacity);
radiusVar = radius;
// for non-sprite
unitVar = vec3(unit, 1.0);

MODIFY
src/webgl/pointFeatureSprite.frag
src/webgl/pointFeatureSprite.frag
@@ -8,21 +8,19 @@ varying vec4 fillColorVar;
varying vec4 strokeColorVar;
varying float radiusVar;
varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
// the square/triangle shade defines unitVar
void main () {
vec4 strokeColor, fillColor;
float endStep;
// No stroke or fill implies nothing to draw
- if (fillVar == 0.0 && strokeVar == 0.0)
+ if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0)
discard;
float rad = 2.0 * length(gl_PointCoord - vec2(0.5)); // distinct for sprite
if (rad > 1.0)
discard;
// If there is no stroke, the fill region should transition to nothing
- if (strokeVar == 0.0) {
+ if (strokeColorVar.a == 0.0) {
strokeColor = vec4(fillColorVar.rgb, 0.0);
endStep = 1.0;
} else {
@@ -30,7 +28,7 @@ void main () {
endStep = radiusVar / (radiusVar + strokeWidthVar);
}
// Likewise, if there is no fill, the stroke should transition to nothing
- if (fillVar == 0.0)
+ if (fillColorVar.a == 0.0)
fillColor = vec4(strokeColor.rgb, 0.0);
else
fillColor = fillColorVar;

MODIFY
src/webgl/pointFeatureSprite.vert
src/webgl/pointFeatureSprite.vert
@@ -20,31 +20,25 @@ varying vec4 fillColorVar;
varying vec4 strokeColorVar;
varying float radiusVar;
varying float strokeWidthVar;
-varying float fillVar;
-varying float strokeVar;
// non-sprite has ither definitions.
void main(void)
{
strokeWidthVar = strokeWidth;
+ fillColorVar = vec4(fillColor, fillOpacity);
+ strokeColorVar = vec4(strokeColor, strokeOpacity);
// No stroke or fill implies nothing to draw
if (stroke < 1.0 || strokeWidth <= 0.0 || strokeOpacity <= 0.0) {
- strokeVar = 0.0;
+ strokeColorVar.a = 0.0;
strokeWidthVar = 0.0;
}
- else
- strokeVar = 1.0;
if (fill < 1.0 || radius <= 0.0 || fillOpacity <= 0.0)
- fillVar = 0.0;
- else
- fillVar = 1.0;
+ fillColorVar.a = 0.0;
/* If the point has no visible pixels, skip doing computations on it. */
- if (fillVar == 0.0 && strokeVar == 0.0) {
+ if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0) {
gl_Position = vec4(2, 2, 0, 1);
return;
}
- fillColorVar = vec4 (fillColor, fillOpacity);
- strokeColorVar = vec4 (strokeColor, strokeOpacity);
radiusVar = radius;
// for sprite
gl_Position = (projectionMatrix * modelViewMatrix * vec4(pos, 1.0)).xyzw;

MODIFY
tests/cases/pointFeature.js
tests/cases/pointFeature.js
@@ -372,6 +372,14 @@ describe('geo.pointFeature', function () {
point.updateStyleFromArray('radius', array1, true);
expect(count).toBe(2);
});
+ it('modify and refresh', function () {
+ glCounts = $.extend({}, vgl.mockCounts());
+ point2.modified().draw();
+ expect(count).toBe(2);
+ });
+ waitForIt('next render gl E', function () {
+ return vgl.mockCounts().bufferSubData >= (glCounts.bufferSubData || 0) + 8;
+ });
it('_exit', function () {
expect(point.actors().length).toBe(1);
layer.deleteFeature(point);

Speed up webgl point updates.