@tensorflow/tfjs-core
Version:
Hardware-accelerated JavaScript library for machine intelligence
417 lines • 20.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (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 = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, 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 };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var environment_1 = require("../../environment");
var util = require("../../util");
var gpgpu_util = require("./gpgpu_util");
var tex_util = require("./tex_util");
var webgl_util = require("./webgl_util");
var GPGPUContext = (function () {
function GPGPUContext(gl) {
this.outputTexture = null;
this.program = null;
this.disposed = false;
this.autoDebugValidate = false;
this.vertexAttrsAreBound = false;
if (gl != null) {
this.gl = gl;
}
else {
this.gl = gpgpu_util.createWebGLContext();
}
if (environment_1.ENV.get('WEBGL_VERSION') === 1) {
this.textureFloatExtension =
webgl_util.getExtensionOrThrow(this.gl, 'OES_texture_float');
this.colorBufferFloatExtension =
this.gl.getExtension('WEBGL_color_buffer_float');
}
else {
this.colorBufferFloatExtension =
webgl_util.getExtensionOrThrow(this.gl, 'EXT_color_buffer_float');
}
this.loseContextExtension =
webgl_util.getExtensionOrThrow(this.gl, 'WEBGL_lose_context');
if (environment_1.ENV.get('WEBGL_GET_BUFFER_SUB_DATA_ASYNC_EXTENSION_ENABLED')) {
this.getBufferSubDataAsyncExtension =
this.gl.getExtension('WEBGL_get_buffer_sub_data_async');
}
this.vertexBuffer = gpgpu_util.createVertexBuffer(this.gl);
this.indexBuffer = gpgpu_util.createIndexBuffer(this.gl);
this.framebuffer = webgl_util.createFramebuffer(this.gl);
}
GPGPUContext.prototype.dispose = function () {
var _this = this;
if (this.disposed) {
return;
}
if (this.program != null) {
console.warn('Disposing a GPGPUContext that still has a bound WebGLProgram.' +
' This is probably a resource leak, delete the program with ' +
'GPGPUContext.deleteProgram before disposing.');
}
if (this.outputTexture != null) {
console.warn('Disposing a GPGPUContext that still has a bound output matrix ' +
'texture. This is probably a resource leak, delete the output ' +
'matrix texture with GPGPUContext.deleteMatrixTexture before ' +
'disposing.');
}
var gl = this.gl;
webgl_util.callAndCheck(gl, function () { return gl.finish(); });
webgl_util.callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, null); });
webgl_util.callAndCheck(gl, function () { return gl.deleteFramebuffer(_this.framebuffer); });
webgl_util.callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, null); });
webgl_util.callAndCheck(gl, function () { return gl.deleteBuffer(_this.vertexBuffer); });
webgl_util.callAndCheck(gl, function () { return gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); });
webgl_util.callAndCheck(gl, function () { return gl.deleteBuffer(_this.indexBuffer); });
this.loseContextExtension.loseContext();
this.disposed = true;
};
GPGPUContext.prototype.enableAutomaticDebugValidation = function (enabled) {
this.autoDebugValidate = enabled;
webgl_util.enableDebugWebGLErrorChecking(enabled);
};
GPGPUContext.prototype.createMatrixTexture = function (rows, columns) {
this.throwIfDisposed();
return gpgpu_util.createMatrixTexture(this.gl, rows, columns);
};
GPGPUContext.prototype.uploadPixelDataToTexture = function (texture, pixels) {
this.throwIfDisposed();
gpgpu_util.uploadPixelDataToTexture(this.gl, texture, pixels);
};
GPGPUContext.prototype.createPackedMatrixTexture = function (rows, columns) {
this.throwIfDisposed();
return gpgpu_util.createPackedMatrixTexture(this.gl, rows, columns);
};
GPGPUContext.prototype.deleteMatrixTexture = function (texture) {
var _this = this;
this.throwIfDisposed();
if (this.outputTexture === texture) {
webgl_util.unbindColorTextureFromFramebuffer(this.gl, this.framebuffer);
this.outputTexture = null;
}
webgl_util.callAndCheck(this.gl, function () { return _this.gl.deleteTexture(texture); });
};
GPGPUContext.prototype.uploadMatrixToTexture = function (texture, rows, columns, matrix) {
this.throwIfDisposed();
var numChannels = 1;
return gpgpu_util.uploadMatrixToTexture(this.gl, texture, rows, columns, matrix, numChannels);
};
GPGPUContext.prototype.uploadMatrixToPackedTexture = function (texture, rows, columns, matrix) {
this.throwIfDisposed();
return gpgpu_util.uploadMatrixToPackedTexture(this.gl, texture, rows, columns, matrix);
};
GPGPUContext.prototype.downloadMatrixFromTexture = function (texture, rows, columns) {
var _this = this;
return this.downloadMatrixDriver(texture, function () {
return gpgpu_util.downloadMatrixFromOutputTexture(_this.gl, rows, columns);
});
};
GPGPUContext.prototype.downloadMatrixFromTextureAsync = function (texture, rows, columns) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
if (this.getBufferSubDataAsyncExtension == null) {
throw new Error("Cannot download matrix from output texture asynchronously, " +
"WEBGL_get_buffer_sub_data_async is not enabled.");
}
return [2, this.downloadMatrixDriverAsync(texture, function () { return gpgpu_util.downloadMatrixFromOutputTextureAsync(_this.gl, _this.getBufferSubDataAsyncExtension, rows, columns); })];
});
});
};
GPGPUContext.prototype.downloadMatrixFromRGBAColorTexture = function (texture, rows, columns, channels) {
var _this = this;
return this.downloadMatrixDriver(texture, function () { return gpgpu_util.downloadMatrixFromRGBAColorTexture(_this.gl, rows, columns, channels); });
};
GPGPUContext.prototype.downloadMatrixFromPackedTexture = function (texture, rows, columns) {
var _this = this;
return this.downloadMatrixDriver(texture, function () { return gpgpu_util.downloadMatrixFromPackedOutputTexture(_this.gl, rows, columns); });
};
GPGPUContext.prototype.createProgram = function (fragmentShaderSource) {
this.throwIfDisposed();
var gl = this.gl;
var fragmentShader = webgl_util.createFragmentShader(gl, fragmentShaderSource);
var vertexShader = gpgpu_util.createVertexShader(gl);
var program = webgl_util.createProgram(gl);
webgl_util.callAndCheck(gl, function () { return gl.attachShader(program, vertexShader); });
webgl_util.callAndCheck(gl, function () { return gl.attachShader(program, fragmentShader); });
webgl_util.linkProgram(gl, program);
if (this.autoDebugValidate) {
webgl_util.validateProgram(gl, program);
}
if (!this.vertexAttrsAreBound) {
this.setProgram(program);
this.vertexAttrsAreBound = gpgpu_util.bindVertexProgramAttributeStreams(gl, this.program, this.vertexBuffer);
}
return program;
};
GPGPUContext.prototype.deleteProgram = function (program) {
var _this = this;
this.throwIfDisposed();
if (program === this.program) {
this.program = null;
}
if (program != null) {
webgl_util.callAndCheck(this.gl, function () { return _this.gl.deleteProgram(program); });
}
};
GPGPUContext.prototype.setProgram = function (program) {
var _this = this;
this.throwIfDisposed();
this.program = program;
if ((this.program != null) && this.autoDebugValidate) {
webgl_util.validateProgram(this.gl, this.program);
}
webgl_util.callAndCheck(this.gl, function () { return _this.gl.useProgram(program); });
};
GPGPUContext.prototype.getUniformLocation = function (program, uniformName, shouldThrow) {
if (shouldThrow === void 0) { shouldThrow = true; }
this.throwIfDisposed();
if (shouldThrow) {
return webgl_util.getProgramUniformLocationOrThrow(this.gl, program, uniformName);
}
else {
return webgl_util.getProgramUniformLocation(this.gl, program, uniformName);
}
};
GPGPUContext.prototype.getAttributeLocation = function (program, attribute) {
var _this = this;
this.throwIfDisposed();
return webgl_util.callAndCheck(this.gl, function () { return _this.gl.getAttribLocation(program, attribute); });
};
GPGPUContext.prototype.getUniformLocationNoThrow = function (program, uniformName) {
this.throwIfDisposed();
return this.gl.getUniformLocation(program, uniformName);
};
GPGPUContext.prototype.setInputMatrixTexture = function (inputMatrixTexture, uniformLocation, textureUnit) {
this.throwIfDisposed();
this.throwIfNoProgram();
webgl_util.bindTextureToProgramUniformSampler(this.gl, this.program, inputMatrixTexture, uniformLocation, textureUnit);
};
GPGPUContext.prototype.setOutputMatrixTexture = function (outputMatrixTexture, rows, columns) {
this.setOutputMatrixTextureDriver(outputMatrixTexture, columns, rows);
};
GPGPUContext.prototype.setOutputPackedMatrixTexture = function (outputPackedMatrixTexture, rows, columns) {
this.throwIfDisposed();
var _a = tex_util.getPackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];
this.setOutputMatrixTextureDriver(outputPackedMatrixTexture, width, height);
};
GPGPUContext.prototype.setOutputMatrixWriteRegion = function (startRow, numRows, startColumn, numColumns) {
this.setOutputMatrixWriteRegionDriver(startColumn, startRow, numColumns, numRows);
};
GPGPUContext.prototype.setOutputPackedMatrixWriteRegion = function (startRow, numRows, startColumn, numColumns) {
throw new Error('setOutputPackedMatrixWriteRegion not implemented.');
};
GPGPUContext.prototype.debugValidate = function () {
if (this.program != null) {
webgl_util.validateProgram(this.gl, this.program);
}
webgl_util.validateFramebuffer(this.gl);
};
GPGPUContext.prototype.executeProgram = function () {
this.throwIfDisposed();
this.throwIfNoProgram();
var gl = this.gl;
if (this.autoDebugValidate) {
this.debugValidate();
}
webgl_util.callAndCheck(gl, function () { return gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); });
};
GPGPUContext.prototype.blockUntilAllProgramsCompleted = function () {
var _this = this;
this.throwIfDisposed();
webgl_util.callAndCheck(this.gl, function () { return _this.gl.finish(); });
};
GPGPUContext.prototype.getQueryTimerExtension = function () {
if (this.disjointQueryTimerExtension == null) {
this.disjointQueryTimerExtension =
webgl_util.getExtensionOrThrow(this.gl, environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2 ?
'EXT_disjoint_timer_query_webgl2' :
'EXT_disjoint_timer_query');
}
return this.disjointQueryTimerExtension;
};
GPGPUContext.prototype.getQueryTimerExtensionWebGL2 = function () {
return this.getQueryTimerExtension();
};
GPGPUContext.prototype.getQueryTimerExtensionWebGL1 = function () {
return this.getQueryTimerExtension();
};
GPGPUContext.prototype.runQuery = function (queryFn) {
var query = this.beginQuery();
queryFn();
this.endQuery();
return this.pollQueryTime(query);
};
GPGPUContext.prototype.beginQuery = function () {
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2) {
var gl2 = this.gl;
var ext_1 = this.getQueryTimerExtensionWebGL2();
var query_1 = gl2.createQuery();
gl2.beginQuery(ext_1.TIME_ELAPSED_EXT, query_1);
return query_1;
}
var ext = this.getQueryTimerExtensionWebGL1();
var query = ext.createQueryEXT();
ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
return query;
};
GPGPUContext.prototype.endQuery = function () {
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2) {
var gl2 = this.gl;
var ext_2 = this.getQueryTimerExtensionWebGL2();
gl2.endQuery(ext_2.TIME_ELAPSED_EXT);
return;
}
var ext = this.getQueryTimerExtensionWebGL1();
ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
};
GPGPUContext.prototype.isQueryAvailable = function (query, queryTimerVersion) {
if (queryTimerVersion === 0) {
return true;
}
if (queryTimerVersion === 2) {
var gl2 = this.gl;
var ext = this.getQueryTimerExtensionWebGL2();
var available = gl2.getQueryParameter(query, gl2.QUERY_RESULT_AVAILABLE);
var disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);
return available && !disjoint;
}
else {
var ext = this.getQueryTimerExtensionWebGL1();
var available = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
var disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);
return available && !disjoint;
}
};
GPGPUContext.prototype.pollQueryTime = function (query) {
var _this = this;
return new Promise(function (resolve, reject) {
var resolveWithWarning = function () {
console.warn('Disjoint query timer never available.');
resolve(-1);
};
var queryTimerVersion = environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION');
util.repeatedTry(function () { return _this.isQueryAvailable(query, queryTimerVersion); })
.then(function () { return resolve(_this.getQueryTime(query, queryTimerVersion)); })
.catch(resolveWithWarning);
});
};
GPGPUContext.prototype.getQueryTime = function (query, queryTimerVersion) {
if (queryTimerVersion === 0) {
return null;
}
if (queryTimerVersion === 2) {
var gl2 = this.gl;
var timeElapsedNanos = gl2.getQueryParameter(query, gl2.QUERY_RESULT);
return timeElapsedNanos / 1000000;
}
else {
var ext = this.getQueryTimerExtensionWebGL1();
var timeElapsedNanos = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);
return timeElapsedNanos / 1000000;
}
};
GPGPUContext.prototype.downloadMatrixDriverSetup = function (texture) {
this.throwIfDisposed();
webgl_util.bindColorTextureToFramebuffer(this.gl, texture, this.framebuffer);
if (this.autoDebugValidate) {
webgl_util.validateFramebuffer(this.gl);
}
};
GPGPUContext.prototype.downloadMatrixDriverTeardown = function () {
if (this.outputTexture != null) {
webgl_util.bindColorTextureToFramebuffer(this.gl, this.outputTexture, this.framebuffer);
if (this.autoDebugValidate) {
webgl_util.validateFramebuffer(this.gl);
}
}
else {
webgl_util.unbindColorTextureFromFramebuffer(this.gl, this.framebuffer);
}
};
GPGPUContext.prototype.downloadMatrixDriver = function (texture, downloadAndDecode) {
this.downloadMatrixDriverSetup(texture);
var result = downloadAndDecode();
this.downloadMatrixDriverTeardown();
return result;
};
GPGPUContext.prototype.downloadMatrixDriverAsync = function (texture, downloadAndDecode) {
return __awaiter(this, void 0, void 0, function () {
var result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.downloadMatrixDriverSetup(texture);
return [4, downloadAndDecode()];
case 1:
result = _a.sent();
this.downloadMatrixDriverTeardown();
return [2, result];
}
});
});
};
GPGPUContext.prototype.setOutputMatrixTextureDriver = function (outputMatrixTextureMaybePacked, width, height) {
this.throwIfDisposed();
var gl = this.gl;
webgl_util.bindColorTextureToFramebuffer(gl, outputMatrixTextureMaybePacked, this.framebuffer);
if (this.autoDebugValidate) {
webgl_util.validateFramebuffer(gl);
}
this.outputTexture = outputMatrixTextureMaybePacked;
webgl_util.callAndCheck(gl, function () { return gl.viewport(0, 0, width, height); });
webgl_util.callAndCheck(gl, function () { return gl.scissor(0, 0, width, height); });
};
GPGPUContext.prototype.setOutputMatrixWriteRegionDriver = function (x, y, width, height) {
var _this = this;
this.throwIfDisposed();
webgl_util.callAndCheck(this.gl, function () { return _this.gl.scissor(x, y, width, height); });
};
GPGPUContext.prototype.throwIfDisposed = function () {
if (this.disposed) {
throw new Error('Attempted to use disposed GPGPUContext.');
}
};
GPGPUContext.prototype.throwIfNoProgram = function () {
if (this.program == null) {
throw new Error('No GPU program is currently set.');
}
};
return GPGPUContext;
}());
exports.GPGPUContext = GPGPUContext;
//# sourceMappingURL=gpgpu_context.js.map