gpu.js/dist/backend/function-builder-base.js

373 lines
12 KiB
JavaScript

'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
module.exports = function () {
/**
* @constructor FunctionBuilderBase
*
* @desc This handles all the raw state, converted state, etc. of a single function.
* [INTERNAL] A collection of functionNodes.
*
* @prop {Object} nodeMap - Object map, where nodeMap[function] = new FunctionNode;
* @prop {Object} gpu - The current gpu instance bound to this builder
* @prop {Object} rootKernel - The root kernel object, contains the paramNames, dimensions etc.
*
*/
function FunctionBuilderBase(gpu) {
_classCallCheck(this, FunctionBuilderBase);
this.nodeMap = {};
this.nativeFunctions = {};
this.nativeVariables = {};
this.gpu = gpu;
this.rootKernel = null;
this.Node = null;
}
_createClass(FunctionBuilderBase, [{
key: 'addNativeFunction',
value: function addNativeFunction(functionName, glslFunctionString) {
this.nativeFunctions[functionName] = glslFunctionString;
}
}, {
key: 'addNativeVariable',
value: function addNativeVariable(variableName, variable) {
this.nativeVariables[variableName] = variable;
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name addFunction
*
* @desc Instantiates a FunctionNode, and add it to the nodeMap
*
* @param {String} functionName - Function name to assume, if its null, it attempts to extract from the function
* @param {Function} jsFunction - JS Function to do conversion
* @param {Object} [options]
* @param {String[]|Object} [paramTypes] - Parameter type array, assumes all parameters are 'float' if falsey
* @param {String} [returnType] - The return type, assumes 'float' if falsey
*
*/
}, {
key: 'addFunction',
value: function addFunction(functionName, jsFunction, options, paramTypes, returnType) {
this.addFunctionNode(new this.Node(functionName, jsFunction, options, paramTypes, returnType).setAddFunction(this.addFunction.bind(this)));
}
}, {
key: 'addFunctions',
value: function addFunctions(functions, options) {
if (functions) {
if (Array.isArray(functions)) {
for (var i = 0; i < functions.length; i++) {
this.addFunction(null, functions[i], options);
}
} else {
for (var p in functions) {
this.addFunction(p, functions[p], options);
}
}
}
}
}, {
key: 'addNativeFunctions',
value: function addNativeFunctions(nativeFunctions) {
for (var functionName in nativeFunctions) {
if (!nativeFunctions.hasOwnProperty(functionName)) continue;
this.addNativeFunction(functionName, nativeFunctions[functionName]);
}
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name addFunctionNode
*
* @desc Add the function node directly
*
* @param {functionNode} inNode - functionNode to add
*
*/
}, {
key: 'addFunctionNode',
value: function addFunctionNode(inNode) {
this.nodeMap[inNode.functionName] = inNode;
if (inNode.isRootKernel) {
this.rootKernel = inNode;
}
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name traceFunctionCalls
*
* @desc Trace all the depending functions being called, from a single function
*
* This allow for 'unneeded' functions to be automatically optimized out.
* Note that the 0-index, is the starting function trace.
*
* @param {String} functionName - Function name to trace from, default to 'kernel'
* @param {String[]} retList - Returning list of function names that is traced. Including itself.
* @param {Object} [parent] - Parent node
*
* @returns {String[]} Returning list of function names that is traced. Including itself.
*/
}, {
key: 'traceFunctionCalls',
value: function traceFunctionCalls(functionName, retList, parent) {
functionName = functionName || 'kernel';
retList = retList || [];
var fNode = this.nodeMap[functionName];
if (fNode) {
// Check if function already exists
var functionIndex = retList.indexOf(functionName);
if (functionIndex === -1) {
retList.push(functionName);
if (parent) {
fNode.parent = parent;
}
fNode.getFunctionString(); //ensure JS trace is done
for (var i = 0; i < fNode.calledFunctions.length; ++i) {
this.traceFunctionCalls(fNode.calledFunctions[i], retList, fNode);
}
} else {
/**
* https://github.com/gpujs/gpu.js/issues/207
* if dependent function is already in the list, because a function depends on it, and because it has
* already been traced, we know that we must move the dependent function to the end of the the retList.
* */
var dependantFunctionName = retList.splice(functionIndex, 1)[0];
retList.push(dependantFunctionName);
}
}
if (this.nativeFunctions[functionName]) {
if (retList.indexOf(functionName) >= 0) {
// Does nothing if already traced
} else {
retList.push(functionName);
}
}
return retList;
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name addKernel
*
* @desc Add a new kernel to this instance
*
* @param {String} fnString - Kernel function as a String
* @param {Object} options - Settings object to set constants, debug mode, etc.
* @param {Array} paramNames - Parameters of the kernel
* @param {Array} paramTypes - Types of the parameters
*
*
* @returns {Object} The inserted kernel as a Kernel Node
*
*/
}, {
key: 'addKernel',
value: function addKernel(fnString, options, paramNames, paramTypes) {
var kernelNode = new this.Node('kernel', fnString, options, paramTypes);
kernelNode.setAddFunction(this.addFunction.bind(this));
kernelNode.paramNames = paramNames;
kernelNode.paramTypes = paramTypes;
kernelNode.isRootKernel = true;
this.addFunctionNode(kernelNode);
return kernelNode;
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name addSubKernel
*
* @desc Add a new sub-kernel to the current kernel instance
*
* @param {Function} jsFunction - Sub-kernel function (JavaScript)
* @param {Object} options - Settings object to set constants, debug mode, etc.
* @param {Array} paramNames - Parameters of the sub-kernel
* @param {Array} returnType - Return type of the subKernel
*
* @returns {Object} The inserted sub-kernel as a Kernel Node
*
*/
}, {
key: 'addSubKernel',
value: function addSubKernel(jsFunction, options, paramTypes, returnType) {
var kernelNode = new this.Node(null, jsFunction, options, paramTypes, returnType);
kernelNode.setAddFunction(this.addFunction.bind(this));
kernelNode.isSubKernel = true;
this.addFunctionNode(kernelNode);
return kernelNode;
}
/**
* @memberOf CPUFunctionBuilder#
* @name getPrototypeString
* @function
*
* @desc Return the string for a function
*
* @param {String} functionName - Function name to trace from. If null, it returns the WHOLE builder stack
*
* @returns {String} The full string, of all the various functions. Trace optimized if functionName given
*
*/
}, {
key: 'getPrototypeString',
value: function getPrototypeString(functionName) {
return this.getPrototypes(functionName).join('\n');
}
/**
* @memberOf CPUFunctionBuilder#
* @name getPrototypeString
* @function
*
* @desc Return the string for a function
*
* @param {String} [functionName] - Function name to trace from. If null, it returns the WHOLE builder stack
*
* @returns {Array} The full string, of all the various functions. Trace optimized if functionName given
*
*/
}, {
key: 'getPrototypes',
value: function getPrototypes(functionName) {
this.rootKernel.generate();
if (functionName) {
return this.getPrototypesFromFunctionNames(this.traceFunctionCalls(functionName, []).reverse());
}
return this.getPrototypesFromFunctionNames(Object.keys(this.nodeMap));
}
}, {
key: 'getStringFromNativeVariables',
value: function getStringFromNativeVariables() {
var variabels = this.nativeVariables;
var result = [];
for (var p in variabels) {
result.push(variabels[p].getDeclarationString());
}
return result.join('\n');
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name getStringFromFunctionNames
*
* @desc Get string from function names
*
* @param {String[]} functionList - List of function to build string
*
* @returns {String} The string, of all the various functions. Trace optimized if functionName given
*
*/
}, {
key: 'getStringFromFunctionNames',
value: function getStringFromFunctionNames(functionList) {
var ret = [];
for (var i = 0; i < functionList.length; ++i) {
var node = this.nodeMap[functionList[i]];
if (node) {
ret.push(this.nodeMap[functionList[i]].getFunctionString());
}
}
return ret.join('\n');
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name getPrototypeStringFromFunctionNames
*
* @desc Return string of all functions converted
*
* @param {String[]} functionList - List of function names to build the string.
* @param {Object} [opt - Settings object passed to functionNode. See functionNode for more details.
*
* @returns {Array} Prototypes of all functions converted
*
*/
}, {
key: 'getPrototypesFromFunctionNames',
value: function getPrototypesFromFunctionNames(functionList, opt) {
var ret = [];
for (var i = 0; i < functionList.length; ++i) {
var functionName = functionList[i];
var node = this.nodeMap[functionName];
if (node) {
ret.push(node.getFunctionPrototypeString(opt));
} else if (this.nativeFunctions[functionName]) {
ret.push(this.nativeFunctions[functionName]);
}
}
return ret;
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name getPrototypeStringFromFunctionNames
*
* @desc Return string of all functions converted
*
* @param {String[]} functionList - List of function names to build the string.
* @param {Object} opt - Settings object passed to functionNode. See functionNode for more details.
*
* @returns {String} Prototype string of all functions converted
*
*/
}, {
key: 'getPrototypeStringFromFunctionNames',
value: function getPrototypeStringFromFunctionNames(functionList, opt) {
return this.getPrototypesFromFunctionNames(functionList, opt).toString();
}
/**
* @memberOf FunctionBuilderBase#
* @function
* @name getString
*
* Get string for a particular function name
*
* @param {String} functionName - Function name to trace from. If null, it returns the WHOLE builder stack
*
* @returns {String} The string, of all the various functions. Trace optimized if functionName given
*
*/
}, {
key: 'getString',
value: function getString(functionName, opt) {
if (opt === undefined) {
opt = {};
}
if (functionName) {
return this.getStringFromNativeVariables() + this.getStringFromFunctionNames(this.traceFunctionCalls(functionName, [], opt).reverse(), opt);
}
return this.getStringFromNativeVariables() + this.getStringFromFunctionNames(Object.keys(this.nodeMap), opt);
}
}]);
return FunctionBuilderBase;
}();