Smarter reuse detection

This commit is contained in:
ahocevar
2019-05-21 18:24:02 +02:00
parent d1f1b468b1
commit a45e704be2
7 changed files with 72 additions and 68 deletions

View File

@@ -362,10 +362,12 @@ class Executor extends Disposable {
const declutterArgs = intersects ? const declutterArgs = intersects ?
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] : [context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
null; null;
if (declutterArgs && fillStroke) { if (declutterArgs) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4); if (fillStroke) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
}
declutterGroup.push(declutterArgs);
} }
declutterGroup.push(declutterArgs);
} else if (intersects) { } else if (intersects) {
if (fillStroke) { if (fillStroke) {
this.replayTextBackground_(context, p1, p2, p3, p4, this.replayTextBackground_(context, p1, p2, p3, p4,

View File

@@ -9,7 +9,6 @@ import MapRenderer from './Map.js';
import SourceState from '../source/State.js'; import SourceState from '../source/State.js';
import {replaceChildren} from '../dom.js'; import {replaceChildren} from '../dom.js';
import {labelCache} from '../render/canvas.js'; import {labelCache} from '../render/canvas.js';
import {altShiftKeysOnly} from '../events/condition.js';
/** /**

View File

@@ -6,7 +6,7 @@ import ViewHint from '../../ViewHint.js';
import {containsExtent, intersects} from '../../extent.js'; import {containsExtent, intersects} from '../../extent.js';
import {getIntersection, isEmpty} from '../../extent.js'; import {getIntersection, isEmpty} from '../../extent.js';
import CanvasLayerRenderer from './Layer.js'; import CanvasLayerRenderer from './Layer.js';
import {compose as composeTransform, makeInverse, toString as transformToString, apply as applyTransform} from '../../transform.js'; import {compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
/** /**
* @classdesc * @classdesc

View File

@@ -8,7 +8,6 @@ import RenderEventType from '../../render/EventType.js';
import {rotateAtOffset} from '../../render/canvas.js'; import {rotateAtOffset} from '../../render/canvas.js';
import LayerRenderer from '../Layer.js'; import LayerRenderer from '../Layer.js';
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js'; import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
import ContextEventType from '../../webgl/ContextEventType.js';
/** /**
* @abstract * @abstract
@@ -64,16 +63,20 @@ class CanvasLayerRenderer extends LayerRenderer {
*/ */
this.context = null; this.context = null;
/**
* @type {boolean}
*/
this.containerReused = false;
} }
/** /**
* Get a rendering container from an existing target, if compatible. * Get a rendering container from an existing target, if compatible.
* @param {HTMLElement} target Potential render target. * @param {HTMLElement} target Potential render target.
* @param {import("../../transform").Transform} transform Transform. * @param {import("../../transform").Transform} transform Transform.
* @return {boolean} The target is reused for this layer.
*/ */
useContainer(target, transform) { useContainer(target, transform) {
let reused = false; const layerClassName = this.getLayer().getClassName();
let container, context; let container, context;
if (target) { if (target) {
const canvas = target.firstElementChild; const canvas = target.firstElementChild;
@@ -82,33 +85,33 @@ class CanvasLayerRenderer extends LayerRenderer {
} }
} }
if (context && context.canvas.style.transform === transformToString(transform)) { if (context && context.canvas.style.transform === transformToString(transform)) {
container = target; // Container of the previous layer renderer can be used.
reused = true; target.classList.add(layerClassName);
} else { this.container = target;
context = null; this.context = context;
container = this.container; this.containerReused = true;
if (!container) { } else if (this.containerReused) {
container = document.createElement('div'); // Previously reused container cannot be used any more.
const style = container.style; this.container = null;
style.position = 'absolute'; this.context = null;
style.width = '100%'; this.containerReused = false;
style.height = '100%';
}
} }
if (container !== this.container) { if (!this.container) {
container.classList.add(this.getLayer().getClassName()); container = document.createElement('div');
container.className = layerClassName;
let style = container.style;
style.position = 'absolute';
style.width = '100%';
style.height = '100%';
context = createCanvasContext2D();
const canvas = context.canvas;
container.appendChild(canvas);
style = canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
this.container = container; this.container = container;
if (!context) {
context = createCanvasContext2D();
const canvas = context.canvas;
container.appendChild(canvas);
const style = canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
}
this.context = context; this.context = context;
} }
return reused;
} }
/** /**

View File

@@ -7,7 +7,6 @@ import TileState from '../../TileState.js';
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js'; import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js';
import CanvasLayerRenderer from './Layer.js'; import CanvasLayerRenderer from './Layer.js';
import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js'; import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
import {numberSafeCompareFunction} from '../../array.js';
/** /**
* @classdesc * @classdesc
@@ -234,7 +233,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
-width / 2, -height / 2 -width / 2, -height / 2
); );
const reused = this.useContainer(target, this.pixelTransform_); this.useContainer(target, this.pixelTransform_);
const context = this.context; const context = this.context;
const canvas = context.canvas; const canvas = context.canvas;
@@ -251,7 +250,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
if (canvas.width != width || canvas.height != height) { if (canvas.width != width || canvas.height != height) {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
} else if (!reused) { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }

View File

@@ -70,17 +70,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState, layerState, target) {
const context = this.context;
const canvas = context.canvas;
const replayGroup = this.replayGroup_;
if (!replayGroup || replayGroup.isEmpty()) {
if (canvas.width > 0) {
canvas.width = 0;
}
return canvas;
}
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
@@ -88,6 +78,18 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio); makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform_, this.pixelTransform_); makeInverse(this.inversePixelTransform_, this.pixelTransform_);
this.useContainer(target, this.pixelTransform_);
const context = this.context;
const canvas = context.canvas;
const replayGroup = this.replayGroup_;
if (!replayGroup || replayGroup.isEmpty()) {
if (!this.containerReused && canvas.width > 0) {
canvas.width = 0;
}
return this.container;
}
// resize and clear // resize and clear
const width = Math.round(frameState.size[0] * pixelRatio); const width = Math.round(frameState.size[0] * pixelRatio);
const height = Math.round(frameState.size[1] * pixelRatio); const height = Math.round(frameState.size[1] * pixelRatio);
@@ -98,7 +100,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (canvas.style.transform !== canvasTransform) { if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
} else { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
@@ -166,7 +168,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
canvas.style.opacity = opacity; canvas.style.opacity = opacity;
} }
return canvas; return this.container;
} }
/** /**

View File

@@ -123,27 +123,31 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @inheritDoc * @inheritDoc
*/ */
useContainer(target, transform) { useContainer(target, transform) {
let context; let overlayContext;
if (target && target.childElementCount === 2) { if (target && target.childElementCount === 2) {
context = target.lastElementChild.getContext('2d'); overlayContext = target.lastElementChild.getContext('2d');
if (!context) { if (!overlayContext) {
target = null; target = null;
} }
} else {
context = this.overlayContext_;
if (!this.overlayContext_) {
context = createCanvasContext2D();
const style = context.canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
}
} }
const reused = super.useContainer(target, transform); const containerReused = this.containerReused;
super.useContainer(target, transform);
if (containerReused && !this.containerReused && !overlayContext) {
this.overlayContext_ = null;
}
if (this.containerReused && overlayContext) {
this.overlayContext_ = overlayContext;
}
if (!this.overlayContext_) {
const overlayContext = createCanvasContext2D();
const style = overlayContext.canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
this.overlayContext_ = overlayContext;
}
if (this.container.childElementCount === 1) { if (this.container.childElementCount === 1) {
this.container.appendChild(context.canvas); this.container.appendChild(this.overlayContext_.canvas);
} }
this.overlayContext_ = context;
return reused;
} }
/** /**
@@ -401,7 +405,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (!isEmpty(this.renderTileImageQueue_) && !this.extentChanged) { if (!isEmpty(this.renderTileImageQueue_) && !this.extentChanged) {
this.renderTileImages_(hifi, frameState); this.renderTileImages_(hifi, frameState);
return this.container;
} }
const context = this.overlayContext_; const context = this.overlayContext_;
@@ -427,7 +430,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (canvas.style.transform !== canvasTransform) { if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
} else { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
@@ -496,10 +499,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
canvas.style.opacity = opacity; canvas.style.opacity = opacity;
} }
// Now that we have rendered the tiles we have already, let's prepare new tile images
// for the next frame
this.renderTileImages_(hifi, frameState);
return this.container; return this.container;
} }