Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoshare webgl renderers. #975

Merged
merged 3 commits into from
Apr 3, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### 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.

### Changes
- The point clustering radius value is now in display pixels (#983)

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