"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. * ============================================================================= */ Object.defineProperty(exports, "__esModule", { value: true }); var environment_1 = require("../../environment"); var util = require("../../util"); var shader_compiler = require("./shader_compiler"); function compileProgram(gpgpu, program, inputs, output) { var userCode = program.userCode; var inputInfos = inputs.map(function (input, i) { var shapeInfo = { logicalShape: input.shape, texShape: input.isUniform ? null : input.texData.texShape, isUniform: input.isUniform, isPacked: input.isUniform ? false : input.texData.isPacked, flatOffset: null }; if (input.texData != null && input.texData.slice != null && input.texData.slice.flatOffset > 0) { shapeInfo.flatOffset = input.texData.slice.flatOffset; } return { name: program.variableNames[i], shapeInfo: shapeInfo }; }); var inShapeInfos = inputInfos.map(function (x) { return x.shapeInfo; }); var outShapeInfo = { logicalShape: output.shape, texShape: output.texData.texShape, isUniform: false, isPacked: output.texData.isPacked, flatOffset: null }; var source = shader_compiler.makeShader(inputInfos, outShapeInfo, userCode, program.packedInputs); var webGLProgram = gpgpu.createProgram(source); // Add special uniforms (NAN, INFINITY) var infLoc = null; var nanLoc = gpgpu.getUniformLocation(webGLProgram, 'NAN', false); if (environment_1.env().getNumber('WEBGL_VERSION') === 1) { infLoc = gpgpu.getUniformLocation(webGLProgram, 'INFINITY', false); } // Add user-defined uniforms var uniformLocations = {}; for (var i = 0; i < program.variableNames.length; i++) { var varName = program.variableNames[i]; var shouldThrow = false; uniformLocations[varName] = gpgpu.getUniformLocation(webGLProgram, varName, shouldThrow); uniformLocations["offset" + varName] = gpgpu.getUniformLocation(webGLProgram, "offset" + varName, shouldThrow); } return { program: program, source: source, webGLProgram: webGLProgram, uniformLocations: uniformLocations, inShapeInfos: inShapeInfos, outShapeInfo: outShapeInfo, infLoc: infLoc, nanLoc: nanLoc, }; } exports.compileProgram = compileProgram; function validateBinaryAndProgram(shapeInfos, inputs) { if (shapeInfos.length !== inputs.length) { throw Error("Binary was compiled with " + shapeInfos.length + " inputs, but " + ("was executed with " + inputs.length + " inputs")); } shapeInfos.forEach(function (s, i) { var shapeA = s.logicalShape; var input = inputs[i]; var shapeB = input.shape; if (!util.arraysEqual(shapeA, shapeB)) { throw Error("Binary was compiled with different shapes than " + ("the current args. Shapes " + shapeA + " and " + shapeB + " must match")); } // The input is uploaded as uniform. if (s.isUniform && input.isUniform) { return; } var texShapeA = s.texShape; var texShapeB = input.isUniform ? null : input.texData.texShape; if (!util.arraysEqual(texShapeA, texShapeB)) { throw Error("Binary was compiled with different texture shapes than the" + (" current args. Shape " + texShapeA + " and " + texShapeB + " must match")); } }); } function runProgram(gpgpu, binary, inputs, output, customSetup) { validateBinaryAndProgram(binary.inShapeInfos, inputs); validateBinaryAndProgram([binary.outShapeInfo], [output]); var outTex = output.texData.texture; var outTexShape = output.texData.texShape; if (output.texData.isPacked) { gpgpu.setOutputPackedMatrixTexture(outTex, outTexShape[0], outTexShape[1]); } else { gpgpu.setOutputMatrixTexture(outTex, outTexShape[0], outTexShape[1]); } gpgpu.setProgram(binary.webGLProgram); // Set special uniforms (NAN, INFINITY) if (environment_1.env().getNumber('WEBGL_VERSION') === 1) { if (binary.infLoc !== null) { gpgpu.gl.uniform1f(binary.infLoc, Infinity); } } if (binary.nanLoc !== null) { gpgpu.gl.uniform1f(binary.nanLoc, NaN); } // Set user-defined inputs inputs.forEach(function (input, i) { var varName = binary.program.variableNames[i]; var varLoc = binary.uniformLocations[varName]; var varOffsetLoc = binary.uniformLocations["offset" + varName]; if (varLoc == null) { // The compiler inferred that this variable is not used in this shader. return; } if (input.isUniform) { // Upload the values of the tensor as uniform. if (util.sizeFromShape(input.shape) < 2) { gpgpu.gl.uniform1f(varLoc, input.uniformValues[0]); } else { var vals = input.uniformValues; if (!(vals instanceof Float32Array)) { vals = new Float32Array(vals); } gpgpu.gl.uniform1fv(varLoc, vals); } return; } // If the input was sliced, upload the flat offset index. if (input.texData.slice != null && varOffsetLoc != null) { gpgpu.gl.uniform1i(varOffsetLoc, input.texData.slice.flatOffset); } gpgpu.setInputMatrixTexture(input.texData.texture, varLoc, i); }); if (customSetup != null) { customSetup(gpgpu, binary.webGLProgram); } gpgpu.executeProgram(); } exports.runProgram = runProgram; function makeShaderKey(program, inputs, output) { var keyInputs = ''; inputs.concat(output).forEach(function (x) { var hasOffset = x.texData != null && x.texData.slice != null && x.texData.slice.flatOffset > 0; var texShape = x.isUniform ? 'uniform' : x.texData.texShape; keyInputs += x.shape + "_" + texShape + "_" + hasOffset; }); var keyUserCode = program.userCode; var key = program.constructor.name; // Fast string concat. See https://jsperf.com/string-concatenation/14. key += '_' + keyInputs + '_' + keyUserCode; return key; } exports.makeShaderKey = makeShaderKey; //# sourceMappingURL=gpgpu_math.js.map