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 ?
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
null;
if (declutterArgs && fillStroke) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
if (declutterArgs) {
if (fillStroke) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
}
declutterGroup.push(declutterArgs);
}
declutterGroup.push(declutterArgs);
} else if (intersects) {
if (fillStroke) {
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 {replaceChildren} from '../dom.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 {getIntersection, isEmpty} from '../../extent.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

View File

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

View File

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

View File

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

View File

@@ -123,27 +123,31 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @inheritDoc
*/
useContainer(target, transform) {
let context;
let overlayContext;
if (target && target.childElementCount === 2) {
context = target.lastElementChild.getContext('2d');
if (!context) {
overlayContext = target.lastElementChild.getContext('2d');
if (!overlayContext) {
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) {
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) {
this.renderTileImages_(hifi, frameState);
return this.container;
}
const context = this.overlayContext_;
@@ -427,7 +430,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform;
}
} else {
} else if (!this.containerReused) {
context.clearRect(0, 0, width, height);
}
@@ -496,10 +499,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
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;
}