From 0a9172de8ede414a30b3e18410c8dec4987be516 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Wed, 17 Oct 2018 13:07:16 -0400 Subject: [PATCH 1/2] Overallocate geomBuffer. When reusing an existing buffer for webGL, permit it to be larger than strictly necessary. If reallocating an existing buffer, allocate some extra space. For dynamic data sets, this avoids reallocating buffers on every geometry update, substantially reducing garbage collection. In one examples with ~35,000 lines containing a total of ~1,000,000 vertices where the number of vertices changes periodically, this reduced geometry update time by ~200 ms. --- CHANGELOG.md | 1 + src/util/common.js | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7582ce9487..fc18c3ad35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Coordinate transforms on flat arrays are now faster (#939) - `convertColor` is memoized to speed up repeated calls (#936) - All features have a `featureType` property (#931) +- When changing geometry sizes, buffers are reallocated less (#941) ### Changes - Removed the dependency on the vgl module for the `object` and `timestamp` classes (#918) diff --git a/src/util/common.js b/src/util/common.js index bef3afbb25..453537689e 100644 --- a/src/util/common.js +++ b/src/util/common.js @@ -343,17 +343,41 @@ var util = { * @param {vgl.geometryData} geom The geometry to reference and modify. * @param {string} srcName The name of the source. * @param {number} len The number of elements for the array. + * @param {number} [allowLarger=0.2] If the existing buffer is larger than + * requested, don't reallocate it unless it exceeds the size of + * `len * (1 + allowLarger)`. + * @param {number} [allocateLarger=0.1] If reallocating an existing buffer, + * allocate `len * (1 + allocateLarger)` to reduce the need to reallocate + * on subsequent calls. If this is the first allocation (the previous + * size was 0), `len` is allocated. * @returns {Float32Array} A buffer for the named source. * @memberof geo.util */ - getGeomBuffer: function (geom, srcName, len) { - var src = geom.sourceByName(srcName), data; + getGeomBuffer: function (geom, srcName, len, allowLarger, allocateLarger) { + allowLarger = allowLarger === undefined ? 0.2 : allowLarger; + allocateLarger = allocateLarger === undefined ? 0.1 : allocateLarger; + var src = geom.sourceByName(srcName), + data = src.data(), + allow = Math.floor((allowLarger + 1) * len); data = src.data(); - if (data instanceof Float32Array && data.length === len) { + /* If the current buffer is either the length we want or no larger than a + * factor of allowBigger more in size, just return it. */ + if (data instanceof Float32Array && (data.length === len || (data.length >= len && data.length <= allow))) { return data; } - data = new Float32Array(len); + /* If we need to allocate a new buffer (smaller or larger), and we have an + * existing, non-zero-length buffer, allocate a larger than needed buffer. + * Add an extra factor of allocateLarger, but if a power-of-two is between + * the specified size and the larger permitted size, perfer the power-of- + * two. */ + var allocate = len; + if (data instanceof Float32Array && data.length && len && allocateLarger > 0) { + allocate = Math.min( + Math.floor((allocateLarger + 1) * len), + Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)))); + } + data = new Float32Array(allocate); src.setData(data); return data; }, From 190838147f8bfdfd0eab6d844928ab8be8e76577 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Tue, 30 Oct 2018 11:10:41 -0400 Subject: [PATCH 2/2] Remove power-of-two rounding. --- src/util/common.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/util/common.js b/src/util/common.js index 453537689e..e49174463c 100644 --- a/src/util/common.js +++ b/src/util/common.js @@ -368,14 +368,10 @@ var util = { } /* If we need to allocate a new buffer (smaller or larger), and we have an * existing, non-zero-length buffer, allocate a larger than needed buffer. - * Add an extra factor of allocateLarger, but if a power-of-two is between - * the specified size and the larger permitted size, perfer the power-of- - * two. */ + * Add an extra factor of allocateLarger. */ var allocate = len; if (data instanceof Float32Array && data.length && len && allocateLarger > 0) { - allocate = Math.min( - Math.floor((allocateLarger + 1) * len), - Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)))); + allocate = Math.floor((allocateLarger + 1) * len); } data = new Float32Array(allocate); src.setData(data);