"use strict";
|
/**
|
* @license
|
* Copyright 2017 Google Inc. 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 __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 = 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 };
|
}
|
};
|
Object.defineProperty(exports, "__esModule", { value: true });
|
var environment_1 = require("../../environment");
|
var util = require("../../util");
|
var canvas_util_1 = require("./canvas_util");
|
var gpgpu_util = require("./gpgpu_util");
|
var tex_util = require("./tex_util");
|
var webgl_util = require("./webgl_util");
|
var GPGPUContext = /** @class */ (function () {
|
function GPGPUContext(gl) {
|
this.outputTexture = null;
|
this.program = null;
|
this.disposed = false;
|
this.vertexAttrsAreBound = false;
|
this.itemsToPoll = [];
|
var glVersion = environment_1.env().getNumber('WEBGL_VERSION');
|
if (gl != null) {
|
this.gl = gl;
|
canvas_util_1.setWebGLContext(glVersion, gl);
|
}
|
else {
|
this.gl = canvas_util_1.getWebGLContext(glVersion);
|
}
|
// WebGL 2.0 enables texture floats without an extension.
|
var COLOR_BUFFER_FLOAT = 'WEBGL_color_buffer_float';
|
var COLOR_BUFFER_HALF_FLOAT = 'EXT_color_buffer_half_float';
|
if (environment_1.env().getNumber('WEBGL_VERSION') === 1) {
|
var TEXTURE_FLOAT = 'OES_texture_float';
|
var TEXTURE_HALF_FLOAT = 'OES_texture_half_float';
|
this.textureFloatExtension =
|
webgl_util.getExtensionOrThrow(this.gl, this.debug, TEXTURE_FLOAT);
|
if (webgl_util.hasExtension(this.gl, TEXTURE_HALF_FLOAT)) {
|
this.textureHalfFloatExtension = webgl_util.getExtensionOrThrow(this.gl, this.debug, TEXTURE_HALF_FLOAT);
|
}
|
else if (environment_1.env().get('WEBGL_FORCE_F16_TEXTURES')) {
|
throw new Error('GL context does not support half float textures, yet the ' +
|
'environment flag WEBGL_FORCE_F16_TEXTURES is set to true.');
|
}
|
this.colorBufferFloatExtension = this.gl.getExtension(COLOR_BUFFER_FLOAT);
|
if (webgl_util.hasExtension(this.gl, COLOR_BUFFER_HALF_FLOAT)) {
|
this.colorBufferHalfFloatExtension = webgl_util.getExtensionOrThrow(this.gl, this.debug, COLOR_BUFFER_HALF_FLOAT);
|
}
|
else if (environment_1.env().get('WEBGL_FORCE_F16_TEXTURES')) {
|
throw new Error('GL context does not support color renderable half floats, yet ' +
|
'the environment flag WEBGL_FORCE_F16_TEXTURES is set to true.');
|
}
|
}
|
else {
|
COLOR_BUFFER_FLOAT = 'EXT_color_buffer_float';
|
if (webgl_util.hasExtension(this.gl, COLOR_BUFFER_FLOAT)) {
|
this.colorBufferFloatExtension =
|
this.gl.getExtension(COLOR_BUFFER_FLOAT);
|
}
|
else if (webgl_util.hasExtension(this.gl, COLOR_BUFFER_HALF_FLOAT)) {
|
this.colorBufferHalfFloatExtension =
|
this.gl.getExtension(COLOR_BUFFER_HALF_FLOAT);
|
}
|
else {
|
throw new Error('GL context does not support color renderable floats');
|
}
|
}
|
this.vertexBuffer = gpgpu_util.createVertexBuffer(this.gl, this.debug);
|
this.indexBuffer = gpgpu_util.createIndexBuffer(this.gl, this.debug);
|
this.framebuffer = webgl_util.createFramebuffer(this.gl, this.debug);
|
this.textureConfig =
|
tex_util.getTextureConfig(this.gl, this.textureHalfFloatExtension);
|
}
|
Object.defineProperty(GPGPUContext.prototype, "debug", {
|
get: function () {
|
return environment_1.env().getBool('DEBUG');
|
},
|
enumerable: true,
|
configurable: true
|
});
|
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, this.debug, function () { return gl.finish(); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, null); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.deleteFramebuffer(_this.framebuffer); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, null); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.deleteBuffer(_this.indexBuffer); });
|
this.disposed = true;
|
};
|
GPGPUContext.prototype.createFloat32MatrixTexture = function (rows, columns) {
|
this.throwIfDisposed();
|
return gpgpu_util.createFloat32MatrixTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
};
|
GPGPUContext.prototype.createFloat16MatrixTexture = function (rows, columns) {
|
this.throwIfDisposed();
|
return gpgpu_util.createFloat16MatrixTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
};
|
GPGPUContext.prototype.createUnsignedBytesMatrixTexture = function (rows, columns) {
|
this.throwIfDisposed();
|
return gpgpu_util.createUnsignedBytesMatrixTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
};
|
GPGPUContext.prototype.uploadPixelDataToTexture = function (texture, pixels) {
|
this.throwIfDisposed();
|
gpgpu_util.uploadPixelDataToTexture(this.gl, this.debug, texture, pixels);
|
};
|
GPGPUContext.prototype.uploadDenseMatrixToTexture = function (texture, width, height, data) {
|
this.throwIfDisposed();
|
gpgpu_util.uploadDenseMatrixToTexture(this.gl, this.debug, texture, width, height, data, this.textureConfig);
|
};
|
GPGPUContext.prototype.createFloat16PackedMatrixTexture = function (rows, columns) {
|
this.throwIfDisposed();
|
return gpgpu_util.createFloat16PackedMatrixTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
};
|
GPGPUContext.prototype.createPackedMatrixTexture = function (rows, columns) {
|
this.throwIfDisposed();
|
return gpgpu_util.createPackedMatrixTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
};
|
GPGPUContext.prototype.deleteMatrixTexture = function (texture) {
|
var _this = this;
|
this.throwIfDisposed();
|
if (this.outputTexture === texture) {
|
webgl_util.unbindColorTextureFromFramebuffer(this.gl, this.debug, this.framebuffer);
|
this.outputTexture = null;
|
}
|
webgl_util.callAndCheck(this.gl, this.debug, function () { return _this.gl.deleteTexture(texture); });
|
};
|
GPGPUContext.prototype.downloadByteEncodedFloatMatrixFromOutputTexture = function (texture, rows, columns) {
|
var _this = this;
|
return this.downloadMatrixDriver(texture, function () { return gpgpu_util.downloadByteEncodedFloatMatrixFromOutputTexture(_this.gl, _this.debug, rows, columns, _this.textureConfig); });
|
};
|
GPGPUContext.prototype.downloadPackedMatrixFromBuffer = function (buffer, batch, rows, columns, physicalRows, physicalCols) {
|
return gpgpu_util.downloadPackedMatrixFromBuffer(this.gl, buffer, batch, rows, columns, physicalRows, physicalCols, this.textureConfig);
|
};
|
GPGPUContext.prototype.downloadFloat32MatrixFromBuffer = function (buffer, size) {
|
return gpgpu_util.downloadFloat32MatrixFromBuffer(this.gl, buffer, size);
|
};
|
GPGPUContext.prototype.createBufferFromTexture = function (texture, rows, columns) {
|
this.bindTextureToFrameBuffer(texture);
|
var result = gpgpu_util.createBufferFromOutputTexture(this.gl, this.debug, rows, columns, this.textureConfig);
|
this.unbindTextureToFrameBuffer();
|
return result;
|
};
|
GPGPUContext.prototype.createAndWaitForFence = function () {
|
var fenceContext = this.createFence(this.gl);
|
return this.pollFence(fenceContext);
|
};
|
GPGPUContext.prototype.createFence = function (gl) {
|
var _this = this;
|
var query;
|
var isFencePassed;
|
if (environment_1.env().getBool('WEBGL_FENCE_API_ENABLED')) {
|
var gl2_1 = gl;
|
var sync_1 = gl2_1.fenceSync(gl2_1.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
gl.flush();
|
isFencePassed = function () {
|
var status = gl2_1.clientWaitSync(sync_1, 0, 0);
|
return status === gl2_1.ALREADY_SIGNALED ||
|
status === gl2_1.CONDITION_SATISFIED;
|
};
|
query = sync_1;
|
}
|
else if (environment_1.env().getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {
|
query = this.beginQuery();
|
this.endQuery();
|
isFencePassed = function () { return _this.isQueryAvailable(query, environment_1.env().getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION')); };
|
}
|
else {
|
// If we have no way to fence, return true immediately. This will fire in
|
// WebGL 1.0 when there is no disjoint query timer. In this case, because
|
// the fence passes immediately, we'll immediately ask for a download of
|
// the texture, which will cause the UI thread to hang.
|
isFencePassed = function () { return true; };
|
}
|
return { query: query, isFencePassed: isFencePassed };
|
};
|
GPGPUContext.prototype.downloadMatrixFromPackedTexture = function (texture, physicalRows, physicalCols) {
|
var _this = this;
|
return this.downloadMatrixDriver(texture, function () { return gpgpu_util.downloadMatrixFromPackedOutputTexture(_this.gl, _this.debug, physicalRows, physicalCols); });
|
};
|
GPGPUContext.prototype.createProgram = function (fragmentShaderSource) {
|
this.throwIfDisposed();
|
var gl = this.gl;
|
var fragmentShader = webgl_util.createFragmentShader(gl, this.debug, fragmentShaderSource);
|
var vertexShader = gpgpu_util.createVertexShader(gl, this.debug);
|
var program = webgl_util.createProgram(gl, this.debug);
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.attachShader(program, vertexShader); });
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.attachShader(program, fragmentShader); });
|
webgl_util.linkProgram(gl, this.debug, program);
|
if (this.debug) {
|
webgl_util.validateProgram(gl, this.debug, program);
|
}
|
if (!this.vertexAttrsAreBound) {
|
this.setProgram(program);
|
this.vertexAttrsAreBound = gpgpu_util.bindVertexProgramAttributeStreams(gl, this.debug, 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, this.debug, function () { return _this.gl.deleteProgram(program); });
|
}
|
};
|
GPGPUContext.prototype.setProgram = function (program) {
|
var _this = this;
|
this.throwIfDisposed();
|
this.program = program;
|
if ((this.program != null) && this.debug) {
|
webgl_util.validateProgram(this.gl, this.debug, this.program);
|
}
|
webgl_util.callAndCheck(this.gl, this.debug, 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, this.debug, 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, this.debug, 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.debug, 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.debug, this.program);
|
}
|
webgl_util.validateFramebuffer(this.gl);
|
};
|
GPGPUContext.prototype.executeProgram = function () {
|
this.throwIfDisposed();
|
this.throwIfNoProgram();
|
var gl = this.gl;
|
if (this.debug) {
|
this.debugValidate();
|
}
|
webgl_util.callAndCheck(gl, this.debug, 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, this.debug, function () { return _this.gl.finish(); });
|
};
|
GPGPUContext.prototype.getQueryTimerExtension = function () {
|
if (this.disjointQueryTimerExtension == null) {
|
this.disjointQueryTimerExtension =
|
webgl_util.getExtensionOrThrow(this.gl, this.debug, environment_1.env().getNumber('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.beginQuery = function () {
|
if (environment_1.env().getNumber('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().getNumber('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.waitForQueryAndGetTime = function (query) {
|
return __awaiter(this, void 0, void 0, function () {
|
var _this = this;
|
return __generator(this, function (_a) {
|
switch (_a.label) {
|
case 0: return [4 /*yield*/, util.repeatedTry(function () { return _this.disposed || // while testing contexts are created / disposed
|
// in rapid succession, so without this check we
|
// may poll for the query timer indefinitely
|
_this.isQueryAvailable(query, environment_1.env().getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION')); })];
|
case 1:
|
_a.sent();
|
return [2 /*return*/, this.getQueryTime(query, environment_1.env().getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION'))];
|
}
|
});
|
});
|
};
|
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 milliseconds.
|
return timeElapsedNanos / 1000000;
|
}
|
else {
|
var ext = this.getQueryTimerExtensionWebGL1();
|
var timeElapsedNanos = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);
|
// Return milliseconds.
|
return timeElapsedNanos / 1000000;
|
}
|
};
|
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);
|
if (this.disjoint == null) {
|
this.disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);
|
}
|
return available && !this.disjoint;
|
}
|
else {
|
var ext = this.getQueryTimerExtensionWebGL1();
|
var available = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
|
if (this.disjoint == null) {
|
this.disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);
|
}
|
return available && !this.disjoint;
|
}
|
};
|
GPGPUContext.prototype.pollFence = function (fenceContext) {
|
var _this = this;
|
return new Promise(function (resolve) {
|
_this.addItemToPoll(function () { return fenceContext.isFencePassed(); }, function () { return resolve(); });
|
});
|
};
|
GPGPUContext.prototype.pollItems = function () {
|
// Find the last query that has finished.
|
var index = linearSearchLastTrue(this.itemsToPoll.map(function (x) { return x.isDoneFn; }));
|
for (var i = 0; i <= index; ++i) {
|
var resolveFn = this.itemsToPoll[i].resolveFn;
|
resolveFn();
|
}
|
this.itemsToPoll = this.itemsToPoll.slice(index + 1);
|
};
|
GPGPUContext.prototype.addItemToPoll = function (isDoneFn, resolveFn) {
|
var _this = this;
|
this.itemsToPoll.push({ isDoneFn: isDoneFn, resolveFn: resolveFn });
|
if (this.itemsToPoll.length > 1) {
|
// We already have a running loop that polls.
|
return;
|
}
|
// Start a new loop that polls.
|
util.repeatedTry(function () {
|
_this.pollItems();
|
// End the loop if no more items to poll.
|
return _this.itemsToPoll.length === 0;
|
});
|
};
|
GPGPUContext.prototype.bindTextureToFrameBuffer = function (texture) {
|
this.throwIfDisposed();
|
webgl_util.bindColorTextureToFramebuffer(this.gl, this.debug, texture, this.framebuffer);
|
if (this.debug) {
|
webgl_util.validateFramebuffer(this.gl);
|
}
|
};
|
GPGPUContext.prototype.unbindTextureToFrameBuffer = function () {
|
if (this.outputTexture != null) {
|
webgl_util.bindColorTextureToFramebuffer(this.gl, this.debug, this.outputTexture, this.framebuffer);
|
if (this.debug) {
|
webgl_util.validateFramebuffer(this.gl);
|
}
|
}
|
else {
|
webgl_util.unbindColorTextureFromFramebuffer(this.gl, this.debug, this.framebuffer);
|
}
|
};
|
GPGPUContext.prototype.downloadMatrixDriver = function (texture, downloadAndDecode) {
|
this.bindTextureToFrameBuffer(texture);
|
var result = downloadAndDecode();
|
this.unbindTextureToFrameBuffer();
|
return result;
|
};
|
GPGPUContext.prototype.setOutputMatrixTextureDriver = function (outputMatrixTextureMaybePacked, width, height) {
|
this.throwIfDisposed();
|
var gl = this.gl;
|
webgl_util.bindColorTextureToFramebuffer(gl, this.debug, outputMatrixTextureMaybePacked, this.framebuffer);
|
if (this.debug) {
|
webgl_util.validateFramebuffer(gl);
|
}
|
this.outputTexture = outputMatrixTextureMaybePacked;
|
webgl_util.callAndCheck(gl, this.debug, function () { return gl.viewport(0, 0, width, height); });
|
webgl_util.callAndCheck(gl, this.debug, 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, this.debug, 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;
|
/**
|
* Finds the index of the last true element using linear search.
|
* Note: We can't do binary search because Chrome expects us to explicitly
|
* test all fences before download:
|
* https://github.com/tensorflow/tfjs/issues/1145
|
*/
|
function linearSearchLastTrue(arr) {
|
var i = 0;
|
for (; i < arr.length; ++i) {
|
var isDone = arr[i]();
|
if (!isDone) {
|
break;
|
}
|
}
|
return i - 1;
|
}
|
exports.linearSearchLastTrue = linearSearchLastTrue;
|
//# sourceMappingURL=gpgpu_context.js.map
|