handsfree
Version:
Quickly integrate face, hand, and/or pose tracking to your frontend projects in a snap ✨👌
1,035 lines (1,021 loc) • 577 kB
JavaScript
/**
* @license
* Copyright 2020 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tensorflow/tfjs-core'), require('seedrandom')) :
typeof define === 'function' && define.amd ? define(['exports', '@tensorflow/tfjs-core', 'seedrandom'], factory) :
(global = global || self, factory(global.tf = global.tf || {}, global.tf, global.seedrandom));
}(this, (function (exports, tf, seedrandom) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
/**
* @license
* Copyright 2018 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
var contexts = {};
var WEBGL_ATTRIBUTES = {
alpha: false,
antialias: false,
premultipliedAlpha: false,
preserveDrawingBuffer: false,
depth: false,
stencil: false,
failIfMajorPerformanceCaveat: true
};
function setWebGLContext(webGLVersion, gl) {
contexts[webGLVersion] = gl;
}
function getWebGLContext(webGLVersion) {
if (!(webGLVersion in contexts)) {
contexts[webGLVersion] = getWebGLRenderingContext(webGLVersion);
}
var gl = contexts[webGLVersion];
if (gl.isContextLost()) {
delete contexts[webGLVersion];
return getWebGLContext(webGLVersion);
}
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.STENCIL_TEST);
gl.disable(gl.BLEND);
gl.disable(gl.DITHER);
gl.disable(gl.POLYGON_OFFSET_FILL);
gl.disable(gl.SAMPLE_COVERAGE);
gl.enable(gl.SCISSOR_TEST);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
return contexts[webGLVersion];
}
function createCanvas(webGLVersion) {
if (typeof OffscreenCanvas !== 'undefined' && webGLVersion === 2) {
return new OffscreenCanvas(300, 150);
}
else if (typeof document !== 'undefined') {
return document.createElement('canvas');
}
else {
throw new Error('Cannot create a canvas in this context');
}
}
function getWebGLRenderingContext(webGLVersion) {
if (webGLVersion !== 1 && webGLVersion !== 2) {
throw new Error('Cannot get WebGL rendering context, WebGL is disabled.');
}
var canvas = createCanvas(webGLVersion);
canvas.addEventListener('webglcontextlost', function (ev) {
ev.preventDefault();
delete contexts[webGLVersion];
}, false);
if (webGLVersion === 1) {
return (canvas.getContext('webgl', WEBGL_ATTRIBUTES) ||
canvas.getContext('experimental-webgl', WEBGL_ATTRIBUTES));
}
return canvas.getContext('webgl2', WEBGL_ATTRIBUTES);
}
/**
* @license
* Copyright 2017 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
var PackingScheme;
(function (PackingScheme) {
/**
* All values in a single texel are densely packed without any constraints.
*
* This is how the shader encodes a tensor with shape = [2, 3, 4]
* (indices are [batch, row, col]).
*
* 000|001 010|011 020|021
* ------- ------- -------
* 002|003 012|013 022|023
*
* 100|101 110|111 120|121
* ------- ------- -------
* 102|103 112|113 122|123
*
*/
PackingScheme[PackingScheme["DENSE"] = 0] = "DENSE";
/**
* Single texels contain only values from the same batch, and from adjacent
* rows and columns.
*
* This is how the shader encodes a tensor with shape = [2, 3, 5]
* (indices are [batch, row, col]).
*
* 000|001 002|003 004|xxx 020|021 022|023 024|xxx
* ------- ------- ------- ------- ------- -------
* 010|011 012|013 014|xxx xxx|xxx xxx|xxx xxx|xxx
*
* 100|101 102|103 104|xxx 120|121 122|123 124|xxx
* ------- ------- ------- ------- ------- -------
* 110|111 112|113 114|xxx xxx|xxx xxx|xxx xxx|xxx
*
*/
PackingScheme[PackingScheme["SHARED_BATCH"] = 1] = "SHARED_BATCH";
})(PackingScheme || (PackingScheme = {}));
var TextureUsage;
(function (TextureUsage) {
TextureUsage[TextureUsage["RENDER"] = 0] = "RENDER";
TextureUsage[TextureUsage["UPLOAD"] = 1] = "UPLOAD";
TextureUsage[TextureUsage["PIXELS"] = 2] = "PIXELS";
TextureUsage[TextureUsage["DOWNLOAD"] = 3] = "DOWNLOAD";
})(TextureUsage || (TextureUsage = {}));
var PhysicalTextureType;
(function (PhysicalTextureType) {
PhysicalTextureType[PhysicalTextureType["UNPACKED_FLOAT16"] = 0] = "UNPACKED_FLOAT16";
PhysicalTextureType[PhysicalTextureType["UNPACKED_FLOAT32"] = 1] = "UNPACKED_FLOAT32";
PhysicalTextureType[PhysicalTextureType["PACKED_4X1_UNSIGNED_BYTE"] = 2] = "PACKED_4X1_UNSIGNED_BYTE";
PhysicalTextureType[PhysicalTextureType["PACKED_2X2_FLOAT32"] = 3] = "PACKED_2X2_FLOAT32";
PhysicalTextureType[PhysicalTextureType["PACKED_2X2_FLOAT16"] = 4] = "PACKED_2X2_FLOAT16";
})(PhysicalTextureType || (PhysicalTextureType = {}));
function getUnpackedMatrixTextureShapeWidthHeight(rows, columns) {
return [columns, rows];
}
function getUnpackedArraySizeFromMatrixSize(matrixSize, channelsPerTexture) {
return matrixSize * channelsPerTexture;
}
/**
* Get shape for densely packed RGBA texture.
*/
function getDenseTexShape(shape) {
var size = tf.util.sizeFromShape(shape);
var texelsNeeded = Math.ceil(size / 4);
return tf.util.sizeToSquarishShape(texelsNeeded);
}
function getPackedMatrixTextureShapeWidthHeight(rows, columns) {
return [
Math.max(1, Math.ceil(columns / 2)), Math.max(1, Math.ceil(rows / 2))
];
}
function getPackedRGBAArraySizeFromMatrixShape(rows, columns) {
var _a = getPackedMatrixTextureShapeWidthHeight(rows, columns), w = _a[0], h = _a[1];
return w * h * 4;
}
function getTextureConfig(
// tslint:disable-next-line:no-any
gl, textureHalfFloatExtension) {
// tslint:disable-next-line:no-any
var glany = gl;
var internalFormatFloat;
var internalFormatHalfFloat;
var internalFormatPackedHalfFloat;
var internalFormatPackedFloat;
var textureFormatFloat;
var downloadTextureFormat;
var downloadUnpackNumChannels;
var defaultNumChannels;
var textureTypeHalfFloat;
var textureTypeFloat;
if (tf.env().getNumber('WEBGL_VERSION') === 2) {
internalFormatFloat = glany.R32F;
internalFormatHalfFloat = glany.R16F;
internalFormatPackedHalfFloat = glany.RGBA16F;
internalFormatPackedFloat = glany.RGBA32F;
textureFormatFloat = glany.RED;
downloadUnpackNumChannels = 4;
defaultNumChannels = 1;
textureTypeHalfFloat = glany.HALF_FLOAT;
textureTypeFloat = glany.FLOAT;
}
else {
internalFormatFloat = gl.RGBA;
internalFormatHalfFloat = gl.RGBA;
internalFormatPackedHalfFloat = gl.RGBA;
internalFormatPackedFloat = glany.RGBA;
textureFormatFloat = gl.RGBA;
downloadUnpackNumChannels = 4;
defaultNumChannels = 4;
textureTypeHalfFloat = textureHalfFloatExtension != null ?
textureHalfFloatExtension.HALF_FLOAT_OES :
null;
textureTypeFloat = gl.FLOAT;
}
downloadTextureFormat = gl.RGBA;
return {
internalFormatFloat: internalFormatFloat,
internalFormatHalfFloat: internalFormatHalfFloat,
internalFormatPackedHalfFloat: internalFormatPackedHalfFloat,
internalFormatPackedFloat: internalFormatPackedFloat,
textureFormatFloat: textureFormatFloat,
downloadTextureFormat: downloadTextureFormat,
downloadUnpackNumChannels: downloadUnpackNumChannels,
defaultNumChannels: defaultNumChannels,
textureTypeHalfFloat: textureTypeHalfFloat,
textureTypeFloat: textureTypeFloat
};
}
/**
* @license
* Copyright 2017 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
function callAndCheck(gl, func) {
var returnValue = func();
if (tf.env().getBool('DEBUG')) {
checkWebGLError(gl);
}
return returnValue;
}
function checkWebGLError(gl) {
var error = gl.getError();
if (error !== gl.NO_ERROR) {
throw new Error('WebGL Error: ' + getWebGLErrorMessage(gl, error));
}
}
// https://en.wikipedia.org/wiki/Half-precision_floating-point_format
var MIN_FLOAT16 = 5.96e-8;
var MAX_FLOAT16 = 65504;
function canBeRepresented(num) {
if (tf.env().getBool('WEBGL_RENDER_FLOAT32_ENABLED') || num === 0 ||
(MIN_FLOAT16 < Math.abs(num) && Math.abs(num) < MAX_FLOAT16)) {
return true;
}
return false;
}
function getWebGLErrorMessage(gl, status) {
switch (status) {
case gl.NO_ERROR:
return 'NO_ERROR';
case gl.INVALID_ENUM:
return 'INVALID_ENUM';
case gl.INVALID_VALUE:
return 'INVALID_VALUE';
case gl.INVALID_OPERATION:
return 'INVALID_OPERATION';
case gl.INVALID_FRAMEBUFFER_OPERATION:
return 'INVALID_FRAMEBUFFER_OPERATION';
case gl.OUT_OF_MEMORY:
return 'OUT_OF_MEMORY';
case gl.CONTEXT_LOST_WEBGL:
return 'CONTEXT_LOST_WEBGL';
default:
return "Unknown error code " + status;
}
}
function getExtensionOrThrow(gl, extensionName) {
return throwIfNull(gl, function () { return gl.getExtension(extensionName); }, 'Extension "' + extensionName + '" not supported on this browser.');
}
function createVertexShader(gl, vertexShaderSource) {
var vertexShader = throwIfNull(gl, function () { return gl.createShader(gl.VERTEX_SHADER); }, 'Unable to create vertex WebGLShader.');
callAndCheck(gl, function () { return gl.shaderSource(vertexShader, vertexShaderSource); });
callAndCheck(gl, function () { return gl.compileShader(vertexShader); });
if (gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS) === false) {
console.log(gl.getShaderInfoLog(vertexShader));
throw new Error('Failed to compile vertex shader.');
}
return vertexShader;
}
function createFragmentShader(gl, fragmentShaderSource) {
var fragmentShader = throwIfNull(gl, function () { return gl.createShader(gl.FRAGMENT_SHADER); }, 'Unable to create fragment WebGLShader.');
callAndCheck(gl, function () { return gl.shaderSource(fragmentShader, fragmentShaderSource); });
callAndCheck(gl, function () { return gl.compileShader(fragmentShader); });
if (gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS) === false) {
logShaderSourceAndInfoLog(fragmentShaderSource, gl.getShaderInfoLog(fragmentShader));
throw new Error('Failed to compile fragment shader.');
}
return fragmentShader;
}
var lineNumberRegex = /ERROR: [0-9]+:([0-9]+):/g;
function logShaderSourceAndInfoLog(shaderSource, shaderInfoLog) {
var lineNumberRegexResult = lineNumberRegex.exec(shaderInfoLog);
if (lineNumberRegexResult == null) {
console.log("Couldn't parse line number in error: " + shaderInfoLog);
console.log(shaderSource);
return;
}
var lineNumber = +lineNumberRegexResult[1];
var shaderLines = shaderSource.split('\n');
var pad = shaderLines.length.toString().length + 2;
var linesWithLineNumbers = shaderLines.map(function (line, lineNumber) {
return tf.util.rightPad((lineNumber + 1).toString(), pad) + line;
});
var maxLineLength = 0;
for (var i = 0; i < linesWithLineNumbers.length; i++) {
maxLineLength = Math.max(linesWithLineNumbers[i].length, maxLineLength);
}
var beforeErrorLines = linesWithLineNumbers.slice(0, lineNumber - 1);
var errorLine = linesWithLineNumbers.slice(lineNumber - 1, lineNumber);
var afterErrorLines = linesWithLineNumbers.slice(lineNumber);
console.log(beforeErrorLines.join('\n'));
console.log(shaderInfoLog.split('\n')[0]);
console.log("%c " + tf.util.rightPad(errorLine[0], maxLineLength), 'border:1px solid red; background-color:#e3d2d2; color:#a61717');
console.log(afterErrorLines.join('\n'));
}
function createProgram(gl) {
return throwIfNull(gl, function () { return gl.createProgram(); }, 'Unable to create WebGLProgram.');
}
function linkProgram(gl, program) {
callAndCheck(gl, function () { return gl.linkProgram(program); });
if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) {
console.log(gl.getProgramInfoLog(program));
throw new Error('Failed to link vertex and fragment shaders.');
}
}
function validateProgram(gl, program) {
callAndCheck(gl, function () { return gl.validateProgram(program); });
if (gl.getProgramParameter(program, gl.VALIDATE_STATUS) === false) {
console.log(gl.getProgramInfoLog(program));
throw new Error('Shader program validation failed.');
}
}
function createStaticVertexBuffer(gl, data) {
var buffer = throwIfNull(gl, function () { return gl.createBuffer(); }, 'Unable to create WebGLBuffer');
callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, buffer); });
callAndCheck(gl, function () { return gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); });
return buffer;
}
function createStaticIndexBuffer(gl, data) {
var buffer = throwIfNull(gl, function () { return gl.createBuffer(); }, 'Unable to create WebGLBuffer');
callAndCheck(gl, function () { return gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); });
callAndCheck(gl, function () { return gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW); });
return buffer;
}
function getNumChannels() {
if (tf.env().getNumber('WEBGL_VERSION') === 2) {
return 1;
}
return 4;
}
function createTexture(gl) {
return throwIfNull(gl, function () { return gl.createTexture(); }, 'Unable to create WebGLTexture.');
}
function validateTextureSize(width, height) {
var maxTextureSize = tf.env().getNumber('WEBGL_MAX_TEXTURE_SIZE');
if ((width <= 0) || (height <= 0)) {
var requested = "[" + width + "x" + height + "]";
throw new Error('Requested texture size ' + requested + ' is invalid.');
}
if ((width > maxTextureSize) || (height > maxTextureSize)) {
var requested = "[" + width + "x" + height + "]";
var max = "[" + maxTextureSize + "x" + maxTextureSize + "]";
throw new Error('Requested texture size ' + requested +
' greater than WebGL maximum on this browser / GPU ' + max + '.');
}
}
function createFramebuffer(gl) {
return throwIfNull(gl, function () { return gl.createFramebuffer(); }, 'Unable to create WebGLFramebuffer.');
}
function bindVertexBufferToProgramAttribute(gl, program, attribute, buffer, arrayEntriesPerItem, itemStrideInBytes, itemOffsetInBytes) {
var loc = gl.getAttribLocation(program, attribute);
if (loc === -1) {
// The GPU compiler decided to strip out this attribute because it's unused,
// thus no need to bind.
return false;
}
callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, buffer); });
callAndCheck(gl, function () { return gl.vertexAttribPointer(loc, arrayEntriesPerItem, gl.FLOAT, false, itemStrideInBytes, itemOffsetInBytes); });
callAndCheck(gl, function () { return gl.enableVertexAttribArray(loc); });
return true;
}
function bindTextureUnit(gl, texture, textureUnit) {
validateTextureUnit(gl, textureUnit);
callAndCheck(gl, function () { return gl.activeTexture(gl.TEXTURE0 + textureUnit); });
callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, texture); });
}
function unbindTextureUnit(gl, textureUnit) {
validateTextureUnit(gl, textureUnit);
callAndCheck(gl, function () { return gl.activeTexture(gl.TEXTURE0 + textureUnit); });
callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, null); });
}
function getProgramUniformLocationOrThrow(gl, program, uniformName) {
return throwIfNull(gl, function () { return gl.getUniformLocation(program, uniformName); }, 'uniform "' + uniformName + '" not present in program.');
}
function getProgramUniformLocation(gl, program, uniformName) {
return gl.getUniformLocation(program, uniformName);
}
function bindTextureToProgramUniformSampler(gl, texture, uniformSamplerLocation, textureUnit) {
callAndCheck(gl, function () { return bindTextureUnit(gl, texture, textureUnit); });
callAndCheck(gl, function () { return gl.uniform1i(uniformSamplerLocation, textureUnit); });
}
function bindCanvasToFramebuffer(gl) {
callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, null); });
callAndCheck(gl, function () { return gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); });
callAndCheck(gl, function () { return gl.scissor(0, 0, gl.canvas.width, gl.canvas.height); });
}
function bindColorTextureToFramebuffer(gl, texture, framebuffer) {
callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); });
callAndCheck(gl, function () { return gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); });
}
function unbindColorTextureFromFramebuffer(gl, framebuffer) {
callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); });
callAndCheck(gl, function () { return gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0); });
}
function validateFramebuffer(gl) {
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status !== gl.FRAMEBUFFER_COMPLETE) {
throw new Error('Error binding framebuffer: ' + getFramebufferErrorMessage(gl, status));
}
}
function getFramebufferErrorMessage(gl, status) {
switch (status) {
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT';
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT';
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
return 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS';
case gl.FRAMEBUFFER_UNSUPPORTED:
return 'FRAMEBUFFER_UNSUPPORTED';
default:
return "unknown error " + status;
}
}
function throwIfNull(gl, returnTOrNull, failureMessage) {
var tOrNull = callAndCheck(gl, function () { return returnTOrNull(); });
if (tOrNull == null) {
throw new Error(failureMessage);
}
return tOrNull;
}
function validateTextureUnit(gl, textureUnit) {
var maxTextureUnit = gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
var glTextureUnit = textureUnit + gl.TEXTURE0;
if (glTextureUnit < gl.TEXTURE0 || glTextureUnit > maxTextureUnit) {
var textureUnitRange = "[gl.TEXTURE0, gl.TEXTURE" + maxTextureUnit + "]";
throw new Error("textureUnit must be in " + textureUnitRange + ".");
}
}
function getBatchDim(shape, dimsToSkip) {
if (dimsToSkip === void 0) { dimsToSkip = 2; }
return tf.util.sizeFromShape(shape.slice(0, shape.length - dimsToSkip));
}
function getRowsCols(shape) {
if (shape.length === 0) {
throw Error('Cannot get rows and columns of an empty shape array.');
}
return [
shape.length > 1 ? shape[shape.length - 2] : 1, shape[shape.length - 1]
];
}
function getShapeAs3D(shape) {
var shapeAs3D = [1, 1, 1];
var isScalar = shape.length === 0 || (shape.length === 1 && shape[0] === 1);
if (!isScalar) {
shapeAs3D =
[getBatchDim(shape)].concat(getRowsCols(shape));
}
return shapeAs3D;
}
function getTextureShapeFromLogicalShape(logShape, isPacked) {
var _a;
if (isPacked === void 0) { isPacked = false; }
var maxTexSize = tf.env().getNumber('WEBGL_MAX_TEXTURE_SIZE');
if (isPacked) {
maxTexSize = maxTexSize * 2;
// This logic ensures we accurately count the number of packed texels needed
// to accommodate the tensor. We can only pack values in the same texel if
// they are from adjacent pairs of rows/cols within the same batch. So if a
// tensor has 3 rows, we pretend it has 4 rows in order to account for the
// fact that the texels containing the third row are half empty.
logShape = logShape.map(function (d, i) { return i >= logShape.length - 2 ?
tf.util.nearestLargerEven(logShape[i]) :
logShape[i]; });
// Packed texture height is at least 2 (the channel height of a single
// texel).
if (logShape.length === 1) {
logShape = [2, logShape[0]];
}
}
// If logical shape is 2, we don't squeeze, since we want to match physical.
if (logShape.length !== 2) {
var squeezeResult = tf.util.squeezeShape(logShape);
logShape = squeezeResult.newShape;
}
var size = tf.util.sizeFromShape(logShape);
if (logShape.length <= 1 && size <= maxTexSize) {
return [1, size];
}
else if (logShape.length === 2 && logShape[0] <= maxTexSize &&
logShape[1] <= maxTexSize) {
return logShape;
}
else if (logShape.length === 3 && logShape[0] * logShape[1] <= maxTexSize &&
logShape[2] <= maxTexSize) {
return [logShape[0] * logShape[1], logShape[2]];
}
else if (logShape.length === 3 && logShape[0] <= maxTexSize &&
logShape[1] * logShape[2] <= maxTexSize) {
return [logShape[0], logShape[1] * logShape[2]];
}
else if (logShape.length === 4 &&
logShape[0] * logShape[1] * logShape[2] <= maxTexSize &&
logShape[3] <= maxTexSize) {
return [logShape[0] * logShape[1] * logShape[2], logShape[3]];
}
else if (logShape.length === 4 && logShape[0] <= maxTexSize &&
logShape[1] * logShape[2] * logShape[3] <= maxTexSize) {
return [logShape[0], logShape[1] * logShape[2] * logShape[3]];
}
else {
if (isPacked) {
// For packed textures size equals the number of channels required to
// accommodate the texture data. However in order to squarify such that
// inner dimensions stay even, we rewrite size to equal the number of
// texels. Then in the return statement we rehydrate the squarified
// dimensions to channel units.
var batchDim = getBatchDim(logShape);
var rows = 2, cols = 2;
if (logShape.length) {
_a = getRowsCols(logShape), rows = _a[0], cols = _a[1];
}
size = batchDim * (rows / 2) * (cols / 2);
return tf.util.sizeToSquarishShape(size).map(function (d) { return d * 2; });
}
return tf.util.sizeToSquarishShape(size);
}
}
function isEven(n) {
return n % 2 === 0;
}
/**
* This determines whether reshaping a packed texture requires rearranging
* the data within the texture, assuming 2x2 packing.
*/
function isReshapeFree(shape1, shape2) {
shape1 = shape1.slice(-2);
shape2 = shape2.slice(-2);
if (tf.util.arraysEqual(shape1, shape2)) {
return true;
}
if (!shape1.length || !shape2.length) { // One of the shapes is a scalar.
return true;
}
if (shape1[0] === 0 || shape1[1] === 0 || shape2[0] === 0 ||
shape2[1] === 0) {
return true;
}
if (shape1.length !== shape2.length) { // One of the shapes is a vector.
var shape1Cols = shape1.slice(-1)[0];
var shape2Cols = shape2.slice(-1)[0];
if (shape1Cols === shape2Cols) {
return true;
}
if (isEven(shape1Cols) && isEven(shape2Cols) &&
(shape1[0] === 1 || shape2[0] === 1)) {
return true;
}
}
return shape1[1] === shape2[1] && isEven(shape1[0]) && isEven(shape2[0]);
}
// We cache webgl params because the environment gets reset between
// unit tests and we don't want to constantly query the WebGLContext for
// MAX_TEXTURE_SIZE.
var MAX_TEXTURE_SIZE;
var MAX_TEXTURES_IN_SHADER;
function getWebGLMaxTextureSize(webGLVersion) {
if (MAX_TEXTURE_SIZE == null) {
var gl = getWebGLContext(webGLVersion);
MAX_TEXTURE_SIZE = gl.getParameter(gl.MAX_TEXTURE_SIZE);
}
return MAX_TEXTURE_SIZE;
}
function resetMaxTextureSize() {
MAX_TEXTURE_SIZE = null;
}
function resetMaxTexturesInShader() {
MAX_TEXTURES_IN_SHADER = null;
}
function getMaxTexturesInShader(webGLVersion) {
if (MAX_TEXTURES_IN_SHADER == null) {
var gl = getWebGLContext(webGLVersion);
MAX_TEXTURES_IN_SHADER = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
}
// We cap at 16 to avoid spurious runtime "memory exhausted" error.
return Math.min(16, MAX_TEXTURES_IN_SHADER);
}
function getWebGLDisjointQueryTimerVersion(webGLVersion) {
if (webGLVersion === 0) {
return 0;
}
var queryTimerVersion;
var gl = getWebGLContext(webGLVersion);
if (hasExtension(gl, 'EXT_disjoint_timer_query_webgl2') &&
webGLVersion === 2) {
queryTimerVersion = 2;
}
else if (hasExtension(gl, 'EXT_disjoint_timer_query')) {
queryTimerVersion = 1;
}
else {
queryTimerVersion = 0;
}
return queryTimerVersion;
}
function hasExtension(gl, extensionName) {
var ext = gl.getExtension(extensionName);
return ext != null;
}
function isWebGLVersionEnabled(webGLVersion) {
try {
var gl = getWebGLContext(webGLVersion);
if (gl != null) {
return true;
}
}
catch (e) {
return false;
}
return false;
}
function isCapableOfRenderingToFloatTexture(webGLVersion) {
if (webGLVersion === 0) {
return false;
}
var gl = getWebGLContext(webGLVersion);
if (webGLVersion === 1) {
if (!hasExtension(gl, 'OES_texture_float')) {
return false;
}
}
else {
if (!hasExtension(gl, 'EXT_color_buffer_float')) {
return false;
}
}
var isFrameBufferComplete = createFloatTextureAndBindToFramebuffer(gl);
return isFrameBufferComplete;
}
/**
* Check if we can download values from a float/half-float texture.
*
* Note that for performance reasons we use binding a texture to a framebuffer
* as a proxy for ability to download float values later using readPixels. The
* texture params of this texture will not match those in readPixels exactly
* but if we are unable to bind some kind of float texture to the frameBuffer
* then we definitely will not be able to read float values from it.
*/
function isDownloadFloatTextureEnabled(webGLVersion) {
if (webGLVersion === 0) {
return false;
}
var gl = getWebGLContext(webGLVersion);
if (webGLVersion === 1) {
if (!hasExtension(gl, 'OES_texture_float')) {
return false;
}
if (!hasExtension(gl, 'WEBGL_color_buffer_float')) {
return false;
}
}
else {
if (hasExtension(gl, 'EXT_color_buffer_float')) {
return createFloatTextureAndBindToFramebuffer(gl);
}
var COLOR_BUFFER_HALF_FLOAT = 'EXT_color_buffer_half_float';
if (hasExtension(gl, COLOR_BUFFER_HALF_FLOAT)) {
var textureHalfFloatExtension = gl.getExtension(COLOR_BUFFER_HALF_FLOAT);
return createHalfFloatTextureAndBindToFramebuffer(gl, textureHalfFloatExtension);
}
return false;
}
var isFrameBufferComplete = createFloatTextureAndBindToFramebuffer(gl);
return isFrameBufferComplete;
}
function createFloatTextureAndBindToFramebuffer(gl) {
var texConfig = getTextureConfig(gl);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
var width = 1;
var height = 1;
gl.texImage2D(gl.TEXTURE_2D, 0, texConfig.internalFormatFloat, width, height, 0, texConfig.textureFormatFloat, texConfig.textureTypeFloat, null);
var frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
var isFrameBufferComplete = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteTexture(texture);
gl.deleteFramebuffer(frameBuffer);
return isFrameBufferComplete;
}
function createHalfFloatTextureAndBindToFramebuffer(
// tslint:disable-next-line:no-any
gl, textureHalfFloatExtension) {
var texConfig = getTextureConfig(gl, textureHalfFloatExtension);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
var width = 1;
var height = 1;
gl.texImage2D(gl.TEXTURE_2D, 0, texConfig.internalFormatHalfFloat, width, height, 0, texConfig.textureFormatFloat, texConfig.textureTypeHalfFloat, null);
var frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
var isFrameBufferComplete = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteTexture(texture);
gl.deleteFramebuffer(frameBuffer);
return isFrameBufferComplete;
}
function isWebGLFenceEnabled(webGLVersion) {
if (webGLVersion !== 2) {
return false;
}
var gl = getWebGLContext(webGLVersion);
// tslint:disable-next-line:no-any
var isEnabled = gl.fenceSync != null;
return isEnabled;
}
var webgl_util = {
__proto__: null,
callAndCheck: callAndCheck,
canBeRepresented: canBeRepresented,
getWebGLErrorMessage: getWebGLErrorMessage,
getExtensionOrThrow: getExtensionOrThrow,
createVertexShader: createVertexShader,
createFragmentShader: createFragmentShader,
createProgram: createProgram,
linkProgram: linkProgram,
validateProgram: validateProgram,
createStaticVertexBuffer: createStaticVertexBuffer,
createStaticIndexBuffer: createStaticIndexBuffer,
getNumChannels: getNumChannels,
createTexture: createTexture,
validateTextureSize: validateTextureSize,
createFramebuffer: createFramebuffer,
bindVertexBufferToProgramAttribute: bindVertexBufferToProgramAttribute,
bindTextureUnit: bindTextureUnit,
unbindTextureUnit: unbindTextureUnit,
getProgramUniformLocationOrThrow: getProgramUniformLocationOrThrow,
getProgramUniformLocation: getProgramUniformLocation,
bindTextureToProgramUniformSampler: bindTextureToProgramUniformSampler,
bindCanvasToFramebuffer: bindCanvasToFramebuffer,
bindColorTextureToFramebuffer: bindColorTextureToFramebuffer,
unbindColorTextureFromFramebuffer: unbindColorTextureFromFramebuffer,
validateFramebuffer: validateFramebuffer,
getFramebufferErrorMessage: getFramebufferErrorMessage,
getBatchDim: getBatchDim,
getRowsCols: getRowsCols,
getShapeAs3D: getShapeAs3D,
getTextureShapeFromLogicalShape: getTextureShapeFromLogicalShape,
isReshapeFree: isReshapeFree,
getWebGLMaxTextureSize: getWebGLMaxTextureSize,
resetMaxTextureSize: resetMaxTextureSize,
resetMaxTexturesInShader: resetMaxTexturesInShader,
getMaxTexturesInShader: getMaxTexturesInShader,
getWebGLDisjointQueryTimerVersion: getWebGLDisjointQueryTimerVersion,
hasExtension: hasExtension,
isWebGLVersionEnabled: isWebGLVersionEnabled,
isCapableOfRenderingToFloatTexture: isCapableOfRenderingToFloatTexture,
isDownloadFloatTextureEnabled: isDownloadFloatTextureEnabled,
isWebGLFenceEnabled: isWebGLFenceEnabled
};
/**
* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
var ENV = tf.env();
/**
* This file contains WebGL-specific flag registrations.
*/
/**
* True if WebGL is supported.
*/
ENV.registerFlag('HAS_WEBGL', function () { return ENV.getNumber('WEBGL_VERSION') > 0; });
/** 0: No WebGL, 1: WebGL 1.0, 2: WebGL 2.0. */
ENV.registerFlag('WEBGL_VERSION', function () {
if (isWebGLVersionEnabled(2)) {
return 2;
}
else if (isWebGLVersionEnabled(1)) {
return 1;
}
return 0;
});
/** Whether to check for numerical representation problems. */
ENV.registerFlag('WEBGL_CHECK_NUMERICAL_PROBLEMS', function () { return false; });
ENV.registerFlag('WEBGL_BUFFER_SUPPORTED', function () { return ENV.get('WEBGL_VERSION') === 2; });
/** Whether the WebGL backend will sometimes forward ops to the CPU. */
ENV.registerFlag('WEBGL_CPU_FORWARD', function () { return true; });
/** Whether the WebGL backend will always use f16 textures for rendering. */
ENV.registerFlag('WEBGL_FORCE_F16_TEXTURES', function () { return false; });
/** Whether to turn all packing related flags on. */
ENV.registerFlag('WEBGL_PACK', function () { return ENV.getBool('HAS_WEBGL'); });
/** Whether we will pack the batchnormalization op. */
ENV.registerFlag('WEBGL_PACK_NORMALIZATION', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack the clip op. */
ENV.registerFlag('WEBGL_PACK_CLIP', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack the depthwise conv op. */
// TODO: https://github.com/tensorflow/tfjs/issues/1679
ENV.registerFlag('WEBGL_PACK_DEPTHWISECONV', function () { return false; });
/** Whether we will pack binary ops. */
ENV.registerFlag('WEBGL_PACK_BINARY_OPERATIONS', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack unary ops. */
ENV.registerFlag('WEBGL_PACK_UNARY_OPERATIONS', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack array ops. */
ENV.registerFlag('WEBGL_PACK_ARRAY_OPERATIONS', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack image ops. */
ENV.registerFlag('WEBGL_PACK_IMAGE_OPERATIONS', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will pack reduce ops. */
ENV.registerFlag('WEBGL_PACK_REDUCE', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether packed WebGL kernels lazily unpack their outputs. */
ENV.registerFlag('WEBGL_LAZILY_UNPACK', function () { return ENV.getBool('WEBGL_PACK'); });
/** Whether we will use the im2col algorithm to speed up convolutions. */
ENV.registerFlag('WEBGL_CONV_IM2COL', function () { return ENV.getBool('WEBGL_PACK'); });
/** The maximum texture dimension. */
ENV.registerFlag('WEBGL_MAX_TEXTURE_SIZE', function () { return getWebGLMaxTextureSize(ENV.getNumber('WEBGL_VERSION')); });
/** The maximum texture dimension. */
ENV.registerFlag('WEBGL_MAX_TEXTURES_IN_SHADER', function () { return getMaxTexturesInShader(ENV.getNumber('WEBGL_VERSION')); });
/**
* The disjoint_query_timer extension version.
* 0: disabled, 1: EXT_disjoint_timer_query, 2:
* EXT_disjoint_timer_query_webgl2.
* In Firefox with WebGL 2.0,
* EXT_disjoint_timer_query_webgl2 is not available, so we must use the
* WebGL 1.0 extension.
*/
ENV.registerFlag('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION', function () {
var webGLVersion = ENV.getNumber('WEBGL_VERSION');
if (webGLVersion === 0) {
return 0;
}
return getWebGLDisjointQueryTimerVersion(webGLVersion);
});
/**
* Whether the timer object from the disjoint_query_timer extension gives
* timing information that is reliable.
*/
ENV.registerFlag('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE', function () { return ENV.getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0 &&
!tf.device_util.isMobile(); });
/**
* Whether the device is physically capable of rendering to float32 textures.
*/
ENV.registerFlag('WEBGL_RENDER_FLOAT32_CAPABLE', function () { return isCapableOfRenderingToFloatTexture(ENV.getNumber('WEBGL_VERSION')); });
/**
* Whether rendering to float32 textures is enabled. If disabled, renders to
* float16 textures.
*/
ENV.registerFlag('WEBGL_RENDER_FLOAT32_ENABLED', function () {
return ENV.getBool('WEBGL_FORCE_F16_TEXTURES') ?
false :
ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE');
});
/**
* Whether downloading float textures is enabled (16 or 32 bit). If disabled,
* uses IEEE 754 encoding of the float32 values to 4 uint8 when downloading.
*/
ENV.registerFlag('WEBGL_DOWNLOAD_FLOAT_ENABLED', function () { return isDownloadFloatTextureEnabled(ENV.getNumber('WEBGL_VERSION')); });
/** Whether the fence API is available. */
ENV.registerFlag('WEBGL_FENCE_API_ENABLED', function () { return isWebGLFenceEnabled(ENV.getNumber('WEBGL_VERSION')); });
/**
* Tensors with size <= than this will be uploaded as uniforms, not textures.
*/
ENV.registerFlag('WEBGL_SIZE_UPLOAD_UNIFORM', function () {
// Use uniform uploads only when 32bit floats are supported. In
// 16bit
// environments there are problems with comparing a 16bit texture value
// with a 32bit uniform value.
var useUniforms = ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED');
return useUniforms ? 4 : 0;
});
/**
* If the total number of bytes allocated on the GPU is greater than this
* number, we will aggressively delete textures upon disposal with
* gl.deleteMatrixTexture, rather than making them available for reuse.
*
* Default value -1 indicates that we will never aggressively delete textures.
*/
ENV.registerFlag('WEBGL_DELETE_TEXTURE_THRESHOLD', function () {
return -1;
}, function (threshold) {
if (threshold < 0 && threshold !== -1) {
throw new Error("WEBGL_DELETE_TEXTURE_THRESHOLD must be -1 (indicating never " +
("delete) or at least 0, but got " + threshold + "."));
}
});
/**
* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
var AddNProgram = /** @class */ (function () {
function AddNProgram(outputShape, shapes) {
this.outputShape = [];
this.outputShape = outputShape;