mirror of
https://github.com/gpujs/gpu.js.git
synced 2026-01-25 16:08:02 +00:00
Basic return statement, string conversion
Merge commit '40d7f264447ddc51b258ee82520963dc0ae34326' into eugene-prototype Conflicts: src/js-to-webclgl.js
This commit is contained in:
commit
e5b491dcad
139
src/js-regex.js
Normal file
139
src/js-regex.js
Normal file
@ -0,0 +1,139 @@
|
||||
var GPU_regex = (function() {
|
||||
String.prototype.replaceAll = function (find, replace) {
|
||||
var str = this;
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
};
|
||||
|
||||
webCLGL = new WebCLGL();
|
||||
|
||||
function clone(obj) {
|
||||
if(obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
|
||||
return obj;
|
||||
|
||||
var temp = obj.constructor(); // changed
|
||||
|
||||
for(var key in obj) {
|
||||
if(Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
obj['isActiveClone'] = null;
|
||||
temp[key] = clone(obj[key]);
|
||||
delete obj['isActiveClone'];
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||
var ARGUMENT_NAMES = /([^\s,]+)/g;
|
||||
function getParamNames(func) {
|
||||
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
|
||||
var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
|
||||
if(result === null)
|
||||
result = [];
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Does simple validation of the provided function string if it is a function
|
||||
/// this is a basic sanity testing before Jison conversion
|
||||
///
|
||||
/// @param funcStr the input function string
|
||||
///
|
||||
/// @returns boolean
|
||||
function validateStringIsFunction( funcStr ) {
|
||||
if( funcStr != null ) {
|
||||
return (funcStr.slice(0, "function".length).toLowerCase() == "function")
|
||||
}
|
||||
return false;;
|
||||
}
|
||||
|
||||
/// Does the core conversion of a basic Javascript function into a webclgl
|
||||
/// and returns a callable function if valid
|
||||
///
|
||||
/// @param inputFunction The calling to perform the conversion
|
||||
/// @param _threadDim The thread dim array configuration
|
||||
/// @param _blockDim The block dim array configuration
|
||||
/// @param paramObj The parameter object
|
||||
///
|
||||
/// @returns callable function if converted, else returns null
|
||||
function regex( inputFunction, _threadDim, _blockDim ) {
|
||||
var threadDim = clone(_threadDim);
|
||||
var blockDim = clone(_blockDim);
|
||||
|
||||
while (threadDim.length < 3) {
|
||||
threadDim.push(1);
|
||||
}
|
||||
|
||||
while (blockDim.length < 3) {
|
||||
blockDim.push(1);
|
||||
}
|
||||
|
||||
var globalDim = [
|
||||
threadDim[0] * blockDim[0],
|
||||
threadDim[1] * blockDim[1],
|
||||
threadDim[2] * blockDim[2]
|
||||
];
|
||||
|
||||
var totalSize = globalDim[0] * globalDim[1] * globalDim[2];
|
||||
|
||||
var funcStr = inputFunction.toString();
|
||||
var funcBody = funcStr.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
|
||||
|
||||
funcBody = funcBody.replaceAll('var ', 'float ');
|
||||
funcBody = funcBody.replaceAll('this.thread.x', '_x_');
|
||||
funcBody = funcBody.replaceAll('return ', 'out_float = ');
|
||||
|
||||
var argNames = getParamNames(inputFunction);
|
||||
|
||||
var shaderCode = 'void main(';
|
||||
for (var i=0; i<argNames.length; i++) {
|
||||
shaderCode += 'float* ' + argNames[i];
|
||||
if (i!=argNames.length-1) {
|
||||
shaderCode += ', \n';
|
||||
}
|
||||
}
|
||||
shaderCode += ') {\n';
|
||||
shaderCode += ' vec2 _x_ = get_global_id();';
|
||||
shaderCode += funcBody;
|
||||
shaderCode += '}';
|
||||
console.log(shaderCode);
|
||||
|
||||
//var buffer_A = webCLGL.createBuffer(_length, "FLOAT", offset);
|
||||
return function() {
|
||||
|
||||
var argBuffers = [];
|
||||
|
||||
var offset = 0;
|
||||
|
||||
var resultBuffer = webCLGL.createBuffer(totalSize, "FLOAT", offset);
|
||||
|
||||
var argNorm = [];
|
||||
|
||||
for (var i=0; i<argNames.length; i++) {
|
||||
argNorm[i] = arguments[i].map(function(x) {
|
||||
return x / 65535.0;
|
||||
});
|
||||
}
|
||||
|
||||
for (var i=0; i<argNames.length; i++) {
|
||||
argBuffers[i] = webCLGL.createBuffer(argNorm[i].length, "FLOAT", offset);
|
||||
}
|
||||
for (var i=0; i<argNames.length; i++) {
|
||||
webCLGL.enqueueWriteBuffer(argBuffers[i], argNorm[i]);
|
||||
}
|
||||
var kernel = webCLGL.createKernel(shaderCode);
|
||||
for (var i=0; i<argNames.length; i++) {
|
||||
kernel.setKernelArg(i, argBuffers[i]);
|
||||
}
|
||||
webCLGL.enqueueNDRangeKernel(kernel, resultBuffer);
|
||||
|
||||
var result = webCLGL.enqueueReadBuffer_Float(resultBuffer);
|
||||
result = Array.prototype.slice.call(result[0]);
|
||||
result = result.map(function(x) {
|
||||
return Math.round(x * 65535.0 * 100000.0) / 100000.0;
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
return regex;
|
||||
})();
|
||||
@ -1,62 +1,223 @@
|
||||
var GPU_jsStrToWebclglStr = (function() {
|
||||
|
||||
/// @returns the default state paramater set, used across the parser
|
||||
function jison_defaultStateParam(funcStr, inParamObj) {
|
||||
return {
|
||||
// The source code rows array
|
||||
src : funcStr,
|
||||
srcArr : funcStr.split("\n"),
|
||||
|
||||
// The compiler parameter options
|
||||
paramObj : inParamObj,
|
||||
|
||||
// Original main function naming
|
||||
customMainFunctionName : null,
|
||||
|
||||
// Reserved namespace used for GPU.js code
|
||||
reservedNamespace : "gpu_",
|
||||
|
||||
// Current function state, being processed
|
||||
currentFunctionNamespace : null,
|
||||
|
||||
// Annoymous function number tracking
|
||||
annoymousFunctionNumber : 0
|
||||
};
|
||||
}
|
||||
|
||||
/// Parses the source code string
|
||||
///
|
||||
/// @param funcStr the input function string
|
||||
/// @param funcStr the input function string
|
||||
/// @param stateParam the compiled state tracking
|
||||
///
|
||||
/// @returns the parsed json obj
|
||||
function jison_parseFuncStr( funcStr ) {
|
||||
function jison_parseFuncStr( funcStr, stateParam ) {
|
||||
var mainObj = parser.parse( "var main = "+funcStr+";" );
|
||||
if( mainObj == null ) {
|
||||
throw "Failed to parse JS code via JISON";
|
||||
}
|
||||
|
||||
// take out the function object, outside the main var declarations
|
||||
return mainObj.body[0].declarations[0].init;
|
||||
var mainAst = mainObj.body[0].declarations[0].init;
|
||||
|
||||
// Capture the original statment code
|
||||
stateParam.customMainFunctionName = mainAst.id;
|
||||
mainAst.id = "main";
|
||||
|
||||
return mainAst;
|
||||
}
|
||||
|
||||
/// the AST error, with its location. To throw (@TODO add location support)
|
||||
///
|
||||
/// @param error the error message output
|
||||
/// @param ast the AST object where the error is
|
||||
/// @param srcArr the source code array (for better error tracing)
|
||||
function ast_errorOutput(error, ast, srcArr) {
|
||||
/// @param error the error message output
|
||||
/// @param ast the AST object where the error is
|
||||
/// @param stateParam the compiled state tracking
|
||||
function ast_errorOutput(error, ast, stateParam) {
|
||||
return error;
|
||||
}
|
||||
|
||||
/// Prases the abstract syntax tree, genericially to its respective function
|
||||
///
|
||||
/// @param ast the AST object to parse
|
||||
/// @param ast the AST object to parse
|
||||
/// @param retArr return array string
|
||||
/// @param stateParam the compiled state tracking
|
||||
///
|
||||
/// @returns the prased openclgl string array
|
||||
function ast_generic(ast, retArr, paramObj) {
|
||||
function ast_generic(ast, retArr, stateParam) {
|
||||
switch(ast.type) {
|
||||
case "FunctionExpression":
|
||||
return ast_FunctionExpression(ast, retArr, paramObj);
|
||||
return ast_FunctionExpression(ast, retArr, stateParam);
|
||||
case "ReturnStatement":
|
||||
return ast_ReturnStatement(ast, retArr, stateParam);
|
||||
case "Literal":
|
||||
return ast_Literal(ast, retArr, stateParam);
|
||||
}
|
||||
|
||||
throw ast_errorOutput("Unknown ast type : "+ast.type);
|
||||
throw ast_errorOutput("Unknown ast type : "+ast.type, ast, stateParam);
|
||||
}
|
||||
|
||||
/// Prases the abstract syntax tree, to its named function
|
||||
///
|
||||
/// @param ast the AST object to parse
|
||||
/// @param retArr return array string
|
||||
/// @param stateParam the compiled state tracking
|
||||
///
|
||||
/// @returns the appened retArr
|
||||
function ast_FunctionExpression(ast, retArr, stateParam) {
|
||||
|
||||
// Setup the main function
|
||||
if( ast.id == "main" ) {
|
||||
retArr.push("void main(");
|
||||
} else {
|
||||
// @TODO : Suuport return type values
|
||||
retArr.push("void ");
|
||||
|
||||
// Its an Annoymous function, handle it
|
||||
if(ast.id == null) {
|
||||
ast.id = stateParam.reservedNamespace+"a"+stateParam.annoymousFunctionNumber;
|
||||
stateParam.annoymousFunctionNumber++;
|
||||
}
|
||||
|
||||
//Function name
|
||||
retArr.push(ast.id);
|
||||
retArr.push("(");
|
||||
}
|
||||
stateParam.currentFunctionNamespace = ast.id;
|
||||
|
||||
// @TODO : Handle parameters tokens
|
||||
// retArr.push(float* a, float* b)
|
||||
|
||||
// Function opening bracket
|
||||
retArr.push(") { ");
|
||||
|
||||
// Body statement iteration
|
||||
for(var i=0; i<ast.body.length; ++i) {
|
||||
ast_generic(ast.body[i], retArr, stateParam);
|
||||
}
|
||||
|
||||
// Function closing
|
||||
retArr.push("}");
|
||||
return retArr;
|
||||
}
|
||||
|
||||
/// Prases the abstract syntax tree, to return function
|
||||
///
|
||||
/// @param ast the AST object to parse
|
||||
/// @param retArr return array string
|
||||
/// @param stateParam the compiled state tracking
|
||||
///
|
||||
/// @returns the appened retArr
|
||||
function ast_ReturnStatement(ast, retArr, stateParam) {
|
||||
if( stateParam.currentFunctionNamespace == "main" ) {
|
||||
retArr.push("out_float = ");
|
||||
ast_generic(ast.argument, retArr, stateParam);
|
||||
retArr.push("; return; ");
|
||||
} else {
|
||||
throw ast_errorOutput(
|
||||
"Non main function return, is not supported : "+stateParam.currentFunctionNamespace,
|
||||
ast, stateParam
|
||||
);
|
||||
}
|
||||
|
||||
return retArr;
|
||||
}
|
||||
|
||||
/// Prases the abstract syntax tree, literal value
|
||||
///
|
||||
/// @param ast the AST object to parse
|
||||
/// @param retArr return array string
|
||||
/// @param stateParam the compiled state tracking
|
||||
///
|
||||
/// @returns the appened retArr
|
||||
function ast_Literal(ast, retArr, stateParam) {
|
||||
|
||||
// Reject non numeric literals
|
||||
if( isNaN(ast.value) ) {
|
||||
throw ast_errorOutput(
|
||||
"Non-numeric literal not supported : "+ast.value,
|
||||
ast, stateParam
|
||||
);
|
||||
}
|
||||
|
||||
// Push the literal value as a float/int
|
||||
retArr.push( ast.value );
|
||||
|
||||
// If it was an int, node made a float
|
||||
if( Number.isInteger(ast.value) ) {
|
||||
retArr.push(".0");
|
||||
}
|
||||
|
||||
return retArr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
/// Prases the abstract syntax tree, genericially to its respective function
|
||||
///
|
||||
/// @param ast the AST object to parse
|
||||
///
|
||||
/// @returns the prased openclgl string
|
||||
function ast_FunctionExpression(ast, retArr, paramObj) {
|
||||
console.log(arguments);
|
||||
function ast_ForStatement(forNode, retArr) {
|
||||
if (forNode.type != "ForStatement") {
|
||||
throw "error";
|
||||
}
|
||||
retArr.push("for (");
|
||||
ast_generic(forNode.init, retArr);
|
||||
ast_generic(forNode.test, retArr);
|
||||
ast_generic(forNode.update, retArr);
|
||||
retArr.push(")");
|
||||
ast_generic(forNode.body, retArr);
|
||||
return retArr;
|
||||
}
|
||||
|
||||
function ast_ExpressionStatement(expNode, retArr) {
|
||||
if (expNode.type != "ExpressionStatement") {
|
||||
throw "error";
|
||||
}
|
||||
ast_generic(expNode.expression, retArr);
|
||||
retArr.push(";");
|
||||
return retArr;
|
||||
}
|
||||
|
||||
function ast_AssignmentExpression(assNode, retArr) {
|
||||
if (assNode.type != "AssignmentExpression") {
|
||||
throw "error";
|
||||
}
|
||||
|
||||
retArr.push("float");
|
||||
ast_generic(assNode.left, retArr);
|
||||
retArr.push(assNode.operator);
|
||||
ast_generic(assNode.right, retArr);
|
||||
}
|
||||
*/
|
||||
|
||||
/// The function string to
|
||||
///
|
||||
///
|
||||
/// The function string to openslgl code generator
|
||||
function jsStrToWebclglStr( funcStr, _threadDim, _blockDim, paramObj ) {
|
||||
var funcStrLines = funcStr.split("\n");
|
||||
var astOutputObj = jison_parseFuncStr(funcStr);
|
||||
|
||||
var retArr = ast_generic(astOutputObj, [], paramObj);
|
||||
return retArr.join(" ");
|
||||
var stateObj = jison_defaultStateParam(funcStr, paramObj);
|
||||
var astOutputObj = jison_parseFuncStr(funcStr, stateObj);
|
||||
|
||||
var retArr = ast_generic( astOutputObj, [], stateObj );
|
||||
return retArr.join("");
|
||||
}
|
||||
|
||||
return jsStrToWebclglStr;
|
||||
|
||||
31
test/html/basic_sum_gpu_AB.html
Normal file
31
test/html/basic_sum_gpu_AB.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GPU.JS : Basic Sum GPU AB</title>
|
||||
<link rel="stylesheet" href="../lib/qunit-1.20.0.css">
|
||||
|
||||
<!-- jison -->
|
||||
<script src="../../lib/jison.js"></script>
|
||||
|
||||
<!-- webclgl -->
|
||||
<script src="../../lib/WebCLGLUtils.class.js"></script>
|
||||
<script src="../../lib/WebCLGLBuffer.class.js"></script>
|
||||
<script src="../../lib/WebCLGLBufferItem.class.js"></script>
|
||||
<script src="../../lib/WebCLGLKernel.class.js"></script>
|
||||
<script src="../../lib/WebCLGLKernelProgram.class.js"></script>
|
||||
<script src="../../lib/WebCLGL.class.js"></script>
|
||||
|
||||
<!-- gpu.js scripts -->
|
||||
<script src="../../src/js-fallback.js"></script>
|
||||
<script src="../../src/js-to-webclgl.js"></script>
|
||||
<script src="../../src/js-regex.js"></script>
|
||||
<script src="../../src/gpu.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
<script src="../lib/qunit-1.20.0.js"></script>
|
||||
<script src="../src/basic_sum_AB.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -12,7 +12,11 @@ function basic_return( assert, mode ) {
|
||||
}
|
||||
|
||||
QUnit.test( "basic_return (string)", function( assert ) {
|
||||
assert.equal( GPU._jsStrToWebclglStr( "function() { return 42.0; }" ), "", "Basic return string conversion" );
|
||||
assert.equal(
|
||||
GPU._jsStrToWebclglStr( "function() { return 42.0; }" ),
|
||||
"void main() { out_float = 42.0; return; }",
|
||||
"Basic return string conversion"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test( "basic_return (auto)", function( assert ) {
|
||||
|
||||
@ -23,3 +23,12 @@ QUnit.test( "basic_sum_AB (GPU)", function( assert ) {
|
||||
QUnit.test( "basic_sum_AB (CPU)", function( assert ) {
|
||||
basic_sum_AB_test(assert, "cpu");
|
||||
});
|
||||
|
||||
/*
|
||||
// EXAMPLE GLSL
|
||||
void main(float* a, float* b) {
|
||||
vec2 _x_ = get_global_id();
|
||||
float ret = a[_x_] + b[_x_];
|
||||
out_float = ret;
|
||||
}
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user