Allow canvas reuse for WebGL layers
This commit is contained in:
@@ -97,6 +97,7 @@ export const AttributeType = {
|
||||
* @property {Object<string,UniformValue>} [uniforms] Uniform definitions; property names must match the uniform
|
||||
* names in the provided or default shaders.
|
||||
* @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions
|
||||
* @property {string} [canvasCacheKey] The cache key for the canvas.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -107,6 +108,78 @@ export const AttributeType = {
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CanvasCacheItem
|
||||
* @property {HTMLCanvasElement} canvas Canvas element.
|
||||
* @property {number} users The count of users of this canvas.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Object<string,CanvasCacheItem>}
|
||||
*/
|
||||
const canvasCache = {};
|
||||
|
||||
/**
|
||||
* @param {string} key The cache key for the canvas.
|
||||
* @return {string} The shared cache key.
|
||||
*/
|
||||
function getSharedCanvasCacheKey(key) {
|
||||
return 'shared/' + key;
|
||||
}
|
||||
|
||||
let uniqueCanvasCacheKeyCount = 0;
|
||||
|
||||
/**
|
||||
* @return {string} The unique cache key.
|
||||
*/
|
||||
function getUniqueCanvasCacheKey() {
|
||||
const key = 'unique/' + uniqueCanvasCacheKeyCount;
|
||||
uniqueCanvasCacheKeyCount += 1;
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key The cache key for the canvas.
|
||||
* @return {HTMLCanvasElement} The canvas.
|
||||
*/
|
||||
function getCanvas(key) {
|
||||
let cacheItem = canvasCache[key];
|
||||
if (!cacheItem) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.left = '0';
|
||||
cacheItem = {users: 0, canvas};
|
||||
canvasCache[key] = cacheItem;
|
||||
}
|
||||
|
||||
cacheItem.users += 1;
|
||||
return cacheItem.canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key The cache key for the canvas.
|
||||
*/
|
||||
function releaseCanvas(key) {
|
||||
const cacheItem = canvasCache[key];
|
||||
if (!cacheItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
cacheItem.users -= 1;
|
||||
if (cacheItem.users > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const canvas = cacheItem.canvas;
|
||||
const gl = getContext(canvas);
|
||||
const extension = gl.getExtension('WEBGL_lose_context');
|
||||
if (extension) {
|
||||
extension.loseContext();
|
||||
}
|
||||
|
||||
delete canvasCache[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* This class is intended to provide low-level functions related to WebGL rendering, so that accessing
|
||||
@@ -248,13 +321,19 @@ class WebGLHelper extends Disposable {
|
||||
this.boundHandleWebGLContextRestored_ =
|
||||
this.handleWebGLContextRestored.bind(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.canvasCacheKey_ = options.canvasCacheKey
|
||||
? getSharedCanvasCacheKey(options.canvasCacheKey)
|
||||
: getUniqueCanvasCacheKey();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.canvas_ = document.createElement('canvas');
|
||||
this.canvas_.style.position = 'absolute';
|
||||
this.canvas_.style.left = '0';
|
||||
this.canvas_ = getCanvas(this.canvasCacheKey_);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -368,6 +447,14 @@ class WebGLHelper extends Disposable {
|
||||
this.startTime_ = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} canvasCacheKey The canvas cache key.
|
||||
* @return {boolean} The provided key matches the one this helper was constructed with.
|
||||
*/
|
||||
canvasCacheKeyMatches(canvasCacheKey) {
|
||||
return this.canvasCacheKey_ === getSharedCanvasCacheKey(canvasCacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a WebGL extension. If the extension is not supported, null is returned.
|
||||
* Extensions are cached after they are enabled for the first time.
|
||||
@@ -443,10 +530,8 @@ class WebGLHelper extends Disposable {
|
||||
this.boundHandleWebGLContextRestored_
|
||||
);
|
||||
|
||||
const extension = this.gl_.getExtension('WEBGL_lose_context');
|
||||
if (extension) {
|
||||
extension.loseContext();
|
||||
}
|
||||
releaseCanvas(this.canvasCacheKey_);
|
||||
|
||||
delete this.gl_;
|
||||
delete this.canvas_;
|
||||
}
|
||||
@@ -481,6 +566,7 @@ class WebGLHelper extends Disposable {
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(
|
||||
gl.ONE,
|
||||
|
||||
@@ -22,11 +22,12 @@ const DEFAULT_FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D u_image;
|
||||
uniform float u_opacity;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(u_image, v_texCoord);
|
||||
gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -86,11 +87,12 @@ const DEFAULT_FRAGMENT_SHADER = `
|
||||
* precision mediump float;
|
||||
*
|
||||
* uniform sampler2D u_image;
|
||||
* uniform float u_opacity;
|
||||
*
|
||||
* varying vec2 v_texCoord;
|
||||
*
|
||||
* void main() {
|
||||
* gl_FragColor = texture2D(u_image, v_texCoord);
|
||||
* gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
@@ -148,6 +150,10 @@ class WebGLPostProcessingPass {
|
||||
this.renderTargetProgram_,
|
||||
'u_screenSize'
|
||||
);
|
||||
this.renderTargetOpacityLocation_ = gl.getUniformLocation(
|
||||
this.renderTargetProgram_,
|
||||
'u_opacity'
|
||||
);
|
||||
this.renderTargetTextureLocation_ = gl.getUniformLocation(
|
||||
this.renderTargetProgram_,
|
||||
'u_image'
|
||||
@@ -258,8 +264,6 @@ class WebGLPostProcessingPass {
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.renderTargetTexture_);
|
||||
|
||||
// render the frame buffer to the canvas
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
@@ -279,6 +283,9 @@ class WebGLPostProcessingPass {
|
||||
gl.uniform2f(this.renderTargetUniformLocation_, size[0], size[1]);
|
||||
gl.uniform1i(this.renderTargetTextureLocation_, 0);
|
||||
|
||||
const opacity = frameState.layerStatesArray[frameState.layerIndex].opacity;
|
||||
gl.uniform1f(this.renderTargetOpacityLocation_, opacity);
|
||||
|
||||
this.applyUniforms(frameState);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
|
||||
Reference in New Issue
Block a user