GPGPU Javascript library
npm install webclgl
Features:
- Basic numerical calculus on GPU.
- WebGL graphics allowing write multiple shaders, interconnect and save arguments.
- WebCLGL handle any WebGL operation preparing all neccesary resources (buffers and programs initialization, vertex/fragment programs buffers interconnection, Renders to texture, etc... reducing time to write any advanced shaders.
``html`
npm install webclgl`html`
`js
// TYPICAL A + B WITH CPU
var arrayResult = [];
for(var n = 0; n < _length; n++) {
var sum = arrayA[n]+arrayB[n];
arrayResult[n] = sum;
}
// PERFORM A + B WITH GPU
var arrayResult = gpufor({"float A": arrayA, "float B": arrayB}, "n",
"float sum = A[n]+B[n];"+
"return sum;");
`
- gpufor A+B
`js
var num = 0.01;
// CPU
var arrayResult = [];
for(var n = 0; n < _length; n++) {
var sum = arrayA[n]+arrayB[n]+num;
arrayResult[n] = sum;
}
// GPU
var arrayResult = gpufor({"float A": arrayA, "float B": arrayB, "float num": num}, "n",
"float sum = A[n]+B[n]+num;"+
"return sum;");
`
- gpufor A+B+number
`js`
var arrayResult = gpufor({"float A": arrayA, "float4 B": arrayB}, "n",
"float _A = A[n];"+
"vec4 _B = B[n];"+
"float sum = _A+_B.z;"+
"return sum;");
- gpufor vector read
`js`
var arrayResult = gpufor({"float4 A": arrayA, "float4 B": arrayB}, "n", "FLOAT4",
"vec4 _A = A[n];"+
"vec4 _B = B[n];"+
"vec4 sum = _A+_B;"+
"return sum;");
- gpufor vector output
`html`
`js`
var gpufG = gpufor( document.getElementById("graph"), // canvas or existings WebGL context
{"float4* posXYZW": arrayNodePosXYZW,
"float4* dir": arrayNodeDir,
"float*attr nodeId": arrayNodeId,
"mat4 PMatrix": transpose(getProyection()),
"mat4 cameraWMatrix": transpose(new Float32Array([ 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, -100.0,
0.0, 0.0, 0.0, 1.0])),
"mat4 nodeWMatrix": transpose(new Float32Array([1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0]))},
// KERNEL PROGRAM (update "dir" & "posXYZW" in return instruction)
{"type": "KERNEL",
"name": "PROG_KERNEL",
"viewSource": false,
"config": ["n", ["dir","posXYZW"],
// head
'',
// source
'vec3 currentPos = posXYZW[n].xyz;'+
'vec3 newDir = dir[n].xyz*0.995;'+
'return [vec4(newDir,0.0), vec4(currentPos,1.0)+vec4(newDir,0.0)];'],
"depthTest": true,
"blend": false,
"blendEquation": "FUNC_ADD",
"blendSrcMode": "SRC_ALPHA",
"blendDstMode": "ONE_MINUS_SRC_ALPHA"},
// GRAPHIC PROGRAM
{"type": "GRAPHIC",
"name": "PROG_GRAPHIC",
"viewSource": false,
"config": [ // vertex head
'',
// vertex source
'vec2 xx = get_global_id(nodeId[], uBufferWidth, 1.0);'+
'vec4 nodePosition = posXYZW[xx];'+ // now use the updated posXYZW
'mat4 nodepos = nodeWMatrix;'+
'nodepos[3][0] = nodePosition.x;'+
'nodepos[3][1] = nodePosition.y;'+
'nodepos[3][2] = nodePosition.z;'+
'gl_Position = PMatrix cameraWMatrix nodepos * vec4(1.0, 1.0, 1.0, 1.0);'+
'gl_PointSize = 2.0;',
// fragment head
'',
// fragment source
'return vec4(1.0, 1.0, 1.0, 1.0);' // color
],
"drawMode": 4,
"depthTest": true,
"blend": false,
"blendEquation": "FUNC_ADD",
"blendSrcMode": "SRC_ALPHA",
"blendDstMode": "ONE_MINUS_SRC_ALPHA"}
);
`js
var tick = function() {
window.requestAnimFrame(tick);
gpufG.processKernels();
var gl = gpufG.getCtx();
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, 512, 512);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//gpufG.setArg("pole1X", 30);
gpufG.processGraphic("posXYZW");
};
`
- gpufor graphic output
- gpufor graphic output (using custom geometry)
First program type KERNEL is a fragment program that perform a RenderToTexture updating "dir" and "posXYZW" buffers. Second program type GRAPHIC is a vertex and fragment program with output to direct screen (framebuffer=null) because we not indicate output on this program.
You can use multiples KERNELS or GRAPHICS on any order. Anterior example only use two programs, KERNEL("dir","posXYZW")->GRAPHIC(null=screen) but you can select an appropiate order for you algorithm. Examples:
GRAPHIC("a","b")->KERNEL(null)
KERNEL("a")->GRAPHIC("b")->KERNEL(null)
In case of you not indicate output it will be the same like indicate null as output [null].
`js`
// GRAPHIC PROGRAM
{"type": "GRAPHIC",
"config": [ [null],
// vertex head
'',
...
or
`js`
// GRAPHIC PROGRAM
{"type": "GRAPHIC",
"config": [ null,
// vertex head
'',
...
You can indicate arguments with one Json as second argument. With setArg method you can update any argument and to add new arguments with addArgument/setArg.
`js`
gpufG.addArg("float4* destination");
gpufG.setArg("destination", destinationArray);
`
Also you can get an argument from others gpufor and to shared a same buffer.
js`
other_gpufG.getGPUForArg("destination", gpufG);
...
gpufG.setArg("destination", destinationArray); // update destination for gpufG and other_gpufG
Variable type | Value
----------------------- |-------------------------------
float* | Array
float4* | Array
float | 30
float4 | [30.0, 10.0, 5.0, 100.0]
float Array | (example: float varname[64];)
mat4 | new Float32Array([1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -100.0, 0.0, 0.0, 0.0, 1.0]);
float*attr | Array
float4*attr | Array
Use float4 instead vec4 only in the definition of the variables (not in code).
`js
var gpufG = gpufor( document.getElementById("graph"),
{'float4* posXYZW': null,
"float4* data": null,
"float*attr currentId": null,
"float*attr otherId": null,
'float4*attr currentVertexPos': null,
'float4*attr currentVertexNormal': null,
'float4*attr currentVertexTexture': null,
'indices': null,
'mat4 PMatrix': null,
'mat4 cameraWMatrix': null,
'mat4 nodeWMatrix': null,
'float textureWidth': null,
'float4* ImgB': null},
{"type": "KERNEL",
"name": "PROG_KERNEL",
"viewSource": false,
"config": ["x", ["posXYZW"],
// head
'',
// source
'float cId = currentId[x];'+
'vec4 currentPosition = posXYZW[x];'+
'float anyData = data[x].x;'+
'float oId = otherId[x];'+
'vec2 xb = get_global_id(oId, uBufferWidth, 6.0);'+ // uBufferWidth is built-in variable
'vec4 otherPosition = posXYZW[xb];'+
'float otherData = data[xb].x;'+
'vec2 texCoord = get_global_id(vec2(64.0, 128.0), textureWidth);'+
'vec4 textureColor = ImgB[texCoord];'+
'...'
],
"depthTest": true,
"blend": false,
"blendEquation": "FUNC_ADD",
"blendSrcMode": "SRC_ALPHA",
"blendDstMode": "ONE_MINUS_SRC_ALPHA"},
{"type": "GRAPHIC",
"name": "PROG_GRAPHIC",
"viewSource": false,
"config": [ // vertex head
'',
// vertex source
'float cId = currentId[];'+
'float oId = otherId[];'+
'vec4 vp = currentVertexPos[];'+
'vec4 vn = currentVertexNormal[];'+
'vec4 vt = currentVertexTexture[];'+
'vec2 x = get_global_id(cId, uBufferWidth, 6.0);'+
'vec4 currentPosition = posXYZW[x];'+
'float anyData = data[x].x;'+
'vec2 xb = get_global_id(oId, uBufferWidth, 6.0);'+
'vec4 otherPosition = posXYZW[xb];'+
'float otherData = data[xb].x;'+
'...',
// fragment head
'',
// fragment source
'vec2 texCoord = get_global_id(vCoord, textureWidth);'+
'vec4 textureColor = ImgB[texCoord];'+
'...'
],
"drawMode": 4,
"depthTest": true,
"blend": false,
"blendEquation": "FUNC_ADD",
"blendSrcMode": "SRC_ALPHA",
"blendDstMode": "ONE_MINUS_SRC_ALPHA"}
);
`
*attr for indicate arguments of type "attributes" (Graphic program only). Allow update values and to be written by a kernel program; attr no. Allow access to another ID; attr Only can access to own ID. *
For to access to any value in graphic program must use before get_global_id.
`js`
var gpufG = gpufor( document.getElementById("graph"), // canvas or existings WebGL context
{"float* A": arrayA,
"float* B": arrayB,
"float* result": null},
// KERNEL PROGRAM 1
{"type": "KERNEL",
"name": "PROG_KERNEL_1",
"viewSource": false,
"config": ["n", ["A","B"],
// head
'',
// source
"float sum = A[n]+B[n];"+
"return [sum, sum+sum];"]},
// KERNEL PROGRAM 2
{"type": "KERNEL",
"name": "PROG_KERNEL_2",
"viewSource": false,
"config": ["n", ["result"],
// head
'',
// source
"float sum = A[n]+B[n];"+ // sum+(sum+sum)
"return sum;"]}
);
gpufG.processKernels();
var arrayResult = gpufG.readArg("result");
- SCEJS use WebCLGL as low level layer. You can See this for other advanced examples.
`