Skip to content

Commit

Permalink
Overallocate geomBuffer.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
manthey committed Oct 18, 2018
1 parent 2246030 commit bd5abc6
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
32 changes: 28 additions & 4 deletions src/util/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
Expand Down

0 comments on commit bd5abc6

Please sign in to comment.