Skip to content

Commit

Permalink
Merge pull request #975 from OpenGeoscience/auto-merge-contexts
Browse files Browse the repository at this point in the history
Autoshare webgl renderers.
  • Loading branch information
manthey authored Apr 3, 2019
2 parents a06dfc6 + 3987655 commit 3b8a970
Show file tree
Hide file tree
Showing 26 changed files with 711 additions and 4,663 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Unreleased

### Improvements
### Features
- Layers that use webgl renderers automatically share contexts when possible. Layers can switch renderers manually as well. This largely avoids the limitation of number of webgl contexts in a browser.
- Support affine transforms in the proj4 string (#986)

### Changes
Expand Down
4,860 changes: 239 additions & 4,621 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"kdbush": "^3.0.0",
"mousetrap": "^1.6.0",
"proj4": "^2.4.4",
"vgl": "0.3.10"
"vgl": "0.3.11"
},
"optionalDependencies": {
"d3": "^3.5.16",
Expand Down
2 changes: 1 addition & 1 deletion src/canvas/quadFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ var canvas_quadFeature = function (arg) {
}
}
});
if (render) {
if (render && m_this.renderer()) {
m_this.renderer()._render();
}
if (changing) {
Expand Down
13 changes: 7 additions & 6 deletions src/feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ var geo_event = require('./event');
* bin number, their order relative to one another is indeterminate and may
* be unstable. A value of `null` will use the current position of the
* feature within its parent's list of children as the bin number.
* @property {geo.renderer?} [renderer] A reference to the renderer used for
* the feature.
* @property {geo.renderer} [renderer] A reference to the renderer used for
* the feature. If `null` or unset or identical to `layer.renderer()`, the
* layer's renderer is used.
* @property {geo.feature.styleSpec} [style] An object that contains style
* values for the feature.
*/
Expand Down Expand Up @@ -120,7 +121,7 @@ var feature = function (arg) {
m_gcs = arg.gcs,
m_visible = arg.visible === undefined ? true : arg.visible,
m_bin = arg.bin === undefined ? null : arg.bin,
m_renderer = arg.renderer === undefined ? null : arg.renderer,
m_renderer = arg.renderer === undefined || (m_layer && arg.renderer === m_layer.renderer()) ? null : arg.renderer,
m_dataTime = timestamp(),
m_buildTime = timestamp(),
m_updateTime = timestamp(),
Expand Down Expand Up @@ -574,7 +575,7 @@ var feature = function (arg) {
* @returns {geo.renderer} The renderer used to render the feature.
*/
this.renderer = function () {
return m_renderer;
return m_renderer || (m_layer && m_layer.renderer());
};

/**
Expand Down Expand Up @@ -610,8 +611,8 @@ var feature = function (arg) {
var map = m_layer.map();
c = map.gcsToWorld(c, m_this.gcs());
c = map.worldToDisplay(c);
if (m_renderer.baseToLocal) {
c = m_renderer.baseToLocal(c);
if (m_this.renderer().baseToLocal) {
c = m_this.renderer().baseToLocal(c);
}
return c;
};
Expand Down
18 changes: 18 additions & 0 deletions src/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ var rendererForAnnotations = require('./registry').rendererForAnnotations;
* to determine the renderer. If a {@link geo.renderer} instance, the
* renderer is not recreated; not all renderers can be shared by multiple
* layers.
* @property {boolean} [autoshareRenderer=true] If truthy and the renderer
* supports it, auto-share renderers between layers. Currently, auto-sharing
* can only occur for webgl renderers, and will only occur between adjacent
* layers than have the same opacity. Shared renderers has slightly
* different behavior than non-shared renderers: changing z-index may result
* in rerendering and be slightly slower; only one DOM canvas is used for all
* shared renderers. Some features have slight z-stacking differences in
* shared versus non-shared renderers.
* @property {HTMLElement} [canvas] If specified, use this canvas rather than
* a canvas associaied with the renderer directly. Renderers may not support
* sharing a canvas.
Expand Down Expand Up @@ -87,6 +95,7 @@ var layer = function (arg) {
arg.renderer instanceof renderer ? arg.renderer.api() : arg.renderer) : (
arg.annotations ? rendererForAnnotations(arg.annotations) :
rendererForFeatures(arg.features)),
m_autoshareRenderer = arg.autoshareRenderer === undefined ? true : arg.autoshareRenderer,
m_dataTime = timestamp(),
m_updateTime = timestamp(),
m_sticky = arg.sticky === undefined ? true : arg.sticky,
Expand Down Expand Up @@ -125,6 +134,15 @@ var layer = function (arg) {
return m_rendererName;
};

/**
* Get the setting of autoshareRenderer.
*
* @returns {boolean}
*/
this.autoshareRenderer = function () {
return m_autoshareRenderer;
};

/**
* Get or set the z-index of the layer. The z-index controls the display
* order of the layers in much the same way as the CSS z-index property.
Expand Down
4 changes: 2 additions & 2 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -1761,13 +1761,13 @@ var map = function (arg) {
layer.node().children('canvas').each(function () {
var canvasElem = $(this);
defer = defer.then(function () {
if (layer.renderer().api() === 'webgl') {
if (layer.renderer() && layer.renderer().api() === 'webgl') {
layer.renderer()._renderFrame();
}
drawLayerImageToContext(context, opacity, canvasElem, canvasElem[0]);
});
});
if (layer.node().children().not('canvas').length || !layer.node().children().length) {
if ((layer.node().children().not('canvas').length || !layer.node().children().length) && (!layer.renderer() || layer.renderer().api() !== 'webgl')) {
defer = defer.then(function () {
return util.htmlToImage(layer.node(), 1).done(function (img) {
drawLayerImageToContext(context, 1, $([]), img);
Expand Down
9 changes: 9 additions & 0 deletions src/webgl/contourFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ var webgl_contourFeature = function (arg) {
m_mapper.setGeometryData(geom);
};

/**
* List vgl actors.
*
* @returns {vgl.actor[]} The list of actors.
*/
this.actors = function () {
return m_actor ? [m_actor] : [];
};

/**
* Build.
*/
Expand Down
140 changes: 140 additions & 0 deletions src/webgl/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,31 @@ var registerLayerAdjustment = require('../registry').registerLayerAdjustment;
var webgl_layer = function () {
'use strict';

var createRenderer = require('../registry').createRenderer;
var geo_event = require('../event');
var webglRenderer = require('./webglRenderer');

var m_this = this,
s_init = this._init,
s_opacity = this.opacity,
s_visible = this.visible,
s_zIndex = this.zIndex;

/**
* Get or set the current layer opacity. The opacity is in the range [0-1].
*
* @param {number} [opacity] If specified, set the opacity. Otherwise,
* return the opacity.
* @returns {number|this} The current opacity or the current layer.
*/
this.opacity = function (opacity) {
var result = s_opacity.apply(m_this, arguments);
if (opacity !== undefined && m_this.initialized()) {
m_this.map()._updateAutoshareRenderers();
}
return result;
};

/**
* Get/Set visibility of the layer.
*
Expand Down Expand Up @@ -45,9 +66,128 @@ var webgl_layer = function () {
/* If the z-index has changed, schedule rerendering the layer. */
m_this.map().scheduleAnimationFrame(m_this._update, true);
m_this.renderer()._render();
m_this.map()._updateAutoshareRenderers();
}
return result;
};

/**
* Move all of the objects associated with this layer to a different webgl
* renderer. This runs the _cleanup routine for any feature or child of the
* layer (if it has one), removes all actors associated with this layer from
* the existing renderer, then adds those actors to the new renderer and
* calls `_update` on any feature that had a `_cleanup` routine. If desired,
* the old and new renderers are both asked to rerender. If moving multiple
* renderers for multiple layers, rerendering can be delayed.
*
* @param {geo.webgl.webglRenderer} newRenderer The renderer to move to.
* @param {boolean} [rerender=false] If truthy, rerender after the switch.
* @returns {this}
*/
this.switchRenderer = function (newRenderer, rerender) {
if (newRenderer instanceof webglRenderer && newRenderer !== m_this.renderer()) {
var oldRenderer = m_this.renderer(),
actors = [],
updates = [];
m_this.map().listSceneObjects([m_this]).forEach(function (obj) {
if (obj._cleanup) {
obj._cleanup();
if (obj._update) {
updates.push(obj);
}
}
if (obj.actors) {
actors = actors.concat(obj.actors());
}
});
actors.forEach(function (actor) {
oldRenderer.contextRenderer().removeActor(actor);
newRenderer.contextRenderer().addActor(actor);
});
m_this._renderer(newRenderer);
m_this._canvas(newRenderer.canvas());
if (rerender && (actors.length || updates.length)) {
oldRenderer._render();
updates.forEach(function (obj) {
obj._update();
});
newRenderer._render();
}
}
return m_this;
};

/**
* Initialize after the layer is added to the map.
*
* @returns {this}
*/
this._init = function () {

var map = m_this.map();
if (!map._updateAutoshareRenderers) {
/**
* Update all webgl autoshareRenderer layers so that appropriate groups
* of layers share renderers. Each group must (a) be continguous in
* z-space (not separated by a non-autoshare layer or a non-webgl layer),
* and (b) have the same opacity. The lowest layer in each group will
* contain the actual canvas and context. This rerenders as needed.
*/
map._updateAutoshareRenderers = function () {
var layers = map.sortedLayers(),
renderer,
used_canvases = [],
canvases = [],
rerender_list = [],
opacity;
layers.forEach(function (layer) {
if (!layer.autoshareRenderer() || !layer.renderer() || layer.renderer().api() !== webglRenderer.apiname) {
renderer = null;
} else if (!renderer || layer.opacity() !== opacity) {
if (!layer.node()[0].contains(layer.renderer().canvas()[0])) {
layer.switchRenderer(createRenderer(webglRenderer.apiname, layer), false);
rerender_list.push(layer.renderer());
}
renderer = layer.renderer();
used_canvases.push(renderer.canvas()[0]);
opacity = layer.opacity();
} else {
if (layer.renderer() !== renderer) {
rerender_list.push(layer.renderer());
canvases.push(layer.renderer().canvas()[0]);
layer.switchRenderer(renderer, false);
rerender_list.push(layer.renderer());
}
}
});
layers.forEach(function (layer) {
if (rerender_list.indexOf(layer.renderer()) >= 0) {
if (layer._update) {
layer._update();
}
}
});
layers.forEach(function (layer) {
if (rerender_list.indexOf(layer.renderer()) >= 0) {
layer.renderer()._render();
rerender_list = rerender_list.filter((val) => val !== layer.renderer());
}
});
canvases.forEach(function (canvas) {
if (used_canvases.indexOf(canvas) < 0) {
canvas.remove();
used_canvases.push(canvas);
}
});
};

map.geoOn(geo_event.layerAdd, () => map._updateAutoshareRenderers());
map.geoOn(geo_event.layerRemove, () => map._updateAutoshareRenderers());
}

return s_init.apply(m_this, arguments);
};

};

registerLayerAdjustment('webgl', 'all', webgl_layer);
Expand Down
9 changes: 3 additions & 6 deletions src/webgl/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,15 +461,12 @@ var webgl_lineFeature = function (arg) {
};

/**
* Return list of vgl actors used for rendering.
* List vgl actors.
*
* @returns {vgl.actor[]}
* @returns {vgl.actor[]} The list of actors.
*/
this.actors = function () {
if (!m_actor) {
return [];
}
return [m_actor];
return m_actor ? [m_actor] : [];
};

/**
Expand Down
4 changes: 2 additions & 2 deletions src/webgl/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,9 @@ var webgl_pointFeature = function (arg) {
}

/**
* Return list of vgl actors used for rendering.
* List vgl actors.
*
* @returns {vgl.actor[]}
* @returns {vgl.actor[]} The list of actors.
*/
this.actors = function () {
if (!m_actor) {
Expand Down
9 changes: 9 additions & 0 deletions src/webgl/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,15 @@ var webgl_polygonFeature = function (arg) {
s_init.call(m_this, arg);
};

/**
* List vgl actors.
*
* @returns {vgl.actor[]} The list of actors.
*/
this.actors = function () {
return [m_actor];
};

/**
* Build.
*
Expand Down
Loading

0 comments on commit 3b8a970

Please sign in to comment.