webcl-nodep
Version:
A fork of node-webcl without dependencies other than OpenCL
369 lines (304 loc) • 10.9 kB
JavaScript
// Copyright (c) 2011-2012, Motorola Mobility, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Motorola Mobility, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var nodejs = (typeof window === 'undefined');
if(nodejs) {
WebCL = require('../webcl');
clu = require('../lib/clUtils');
util = require('util');
fs = require('fs');
WebGL = require('node-webgl');
document = WebGL.document();
log = console.log;
alert = console.log;
//Read and eval library for mat/vec operations
eval(fs.readFileSync(__dirname + '/glMatrix-0.9.5.min.js', 'utf8'));
}
requestAnimationFrame = document.requestAnimationFrame;
//First check if the webcl extension is installed at all
if (WebCL == undefined) {
alert("Unfortunately your system does not support WebCL. "
+ "Make sure that you have the WebCL extension installed.");
return;
}
//Rendering window vars
var window_width = 512;
var window_height = 512;
var mesh_width = 128;
var mesh_height = 128;
//OpenCL vars
var cpPlatform;
var cxGPUContext;
var cdDevices;
var cqCommandQueue;
var ckKernel;
var vbo_cl;
var cpProgram;
var szGlobalWorkSize = [ mesh_width, mesh_height ];
//vbo variables
var vbo;
var gl;
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
var shaderProgram;
//mouse controls
var mouse_old_x, mouse_old_y;
var mouse_buttons = 0;
var rotate_x = 0.0, rotate_y = 0.0;
var translate_z = -3.0;
//Sim and Auto-Verification parameters
var anim = 0.0;
var iFrameCount = 0; // FPS count for averaging
var iFrameTrigger = 90; // FPS trigger for sampling
var iFramesPerSec = 0; // frames per second
var iTestSets = 3;
var g_Index = 0;
document.setTitle("sineGL");
requestAnimFrame = document.requestAnimationFrame;
document.on("mousedown", function(evt) {
mouse(evt, true);
});
document.on("mouseup", function(evt) {
mouse(evt, false);
});
document.on("mousemove", motion);
document.on("resize",function(evt){
console.log('resize to: ('+evt.width+", "+evt.height+")");
document.createWindow(evt.width,evt.height);
gl.viewportWidth=evt.width;
gl.viewportHeight=evt.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
});
main();
function main() {
log('Init GL');
initGL();
// Pick platform
var platformList = WebCL.getPlatforms();
cpPlatform = platformList[0];
// Query the set of GPU devices on this platform
cdDevices = cpPlatform.getDevices(WebCL.DEVICE_TYPE_DEFAULT);
log(" # of Devices Available = " + cdDevices.length);
var device = cdDevices[0];
log(" Using Device 0: " + device.getInfo(WebCL.DEVICE_NAME));
// get CL-GL extension
var extensions = device.getInfo(WebCL.DEVICE_EXTENSIONS);
var hasGLSupport = extensions.search(/gl.sharing/i) >= 0;
log(hasGLSupport ? "GL-CL extension available ;-)" : "No GL support");
if (!hasGLSupport)
return;
// create the OpenCL context
cxGPUContext = WebCL.createContext({
devices: device,
shareGroup: gl,
platform: cpPlatform });
// create a command-queue
cqCommandQueue = cxGPUContext.createCommandQueue(device, 0);
// create the program
var sourceCL = fs.readFileSync(__dirname + '/sine.cl', 'ascii');
cpProgram = cxGPUContext.createProgram(sourceCL);
// build the program
try {
cpProgram.build(device, "-cl-fast-relaxed-math");
} catch (err) {
log('Error building program: ' + err);
}
log("Build Status: "
+ cpProgram.getBuildInfo(device, WebCL.PROGRAM_BUILD_STATUS));
log("Build Options: "
+ cpProgram.getBuildInfo(device, WebCL.PROGRAM_BUILD_OPTIONS));
log("Build Log: " + cpProgram.getBuildInfo(device, WebCL.PROGRAM_BUILD_LOG));
// create the kernel
try {
ckKernel = cpProgram.createKernel("sine_wave");
} catch (err) {
log("Cannot create Kernel: " + err);
return;
}
// create VBO (if using standard GL or CL-GL interop)
createVBO();
// set the args values
ckKernel.setArg(0, vbo_cl);
ckKernel.setArg(1, mesh_width, WebCL.type.UINT);
ckKernel.setArg(2, mesh_height, WebCL.type.UINT);
// run OpenCL kernel once to generate vertex positions
runKernel(0);
// start main rendering loop
DisplayGL();
}
function getShader(gl, id) {
var shaders =
{
"shader-fs" : [
"varying vec4 vColor;",
"void main(void) {",
" gl_FragColor = vColor;",
"}" ].join("\n"),
"shader-vs" : [
"attribute vec3 aVertexPosition;",
"attribute vec4 aVertexColor;",
"uniform mat4 uMVMatrix;",
"uniform mat4 uPMatrix;",
"varying vec4 vColor;",
"void main(void) {",
" gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);",
" vColor = vec4(1,0,0,1);//aVertexColor;", "}" ].join("\n")
};
var shader;
if (!shaders.hasOwnProperty(id))
return null;
var str = shaders[id];
if (id.match(/-fs/)) {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (id.match(/-vs/)) {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute =
gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.vertexColorAttribute =
gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
shaderProgram.pMatrixUniform =
gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform =
gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
function initGL() {
var canvas = document.createElement("mycanvas", window_width, window_height);
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
// init shaders
initShaders();
// default initialization
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.disable(gl.DEPTH_TEST);
// viewport
gl.viewport(0, 0, window_width, window_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// projection
mat4.perspective(60, window_width / window_height, 0.1, 10, pMatrix);
// set view matrix
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [ 0.0, 0.0, translate_z ]);
mat4.rotate(mvMatrix, rotate_x * Math.PI / 180, [ 1.0, 0.0, 0.0 ]);
mat4.rotate(mvMatrix, rotate_y * Math.PI / 180, [ 0.0, 1.0, 0.0 ]);
}
function runKernel(time) {
// map OpenGL buffer object for writing from OpenCL
gl.finish();
cqCommandQueue.enqueueAcquireGLObjects(vbo_cl);
// Set arg 3 and execute the kernel
ckKernel.setArg(3, time, WebCL.type.FLOAT);
cqCommandQueue.enqueueNDRangeKernel(ckKernel, null, szGlobalWorkSize, null);
// unmap buffer object
cqCommandQueue.enqueueReleaseGLObjects(vbo_cl);
cqCommandQueue.finish();
}
function createVBO() {
// create VBO
var size = mesh_width * mesh_height * 4 * 4;
// create buffer object
vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// initialize buffer object
gl.bufferData(gl.ARRAY_BUFFER, size, gl.DYNAMIC_DRAW);
// create OpenCL buffer from GL VBO
vbo_cl = cxGPUContext.createFromGLBuffer(WebCL.MEM_WRITE_ONLY, vbo);
}
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
function DisplayGL(time) {
// increment the geometry computation parameter (or set to reference for Q/A check)
anim += 0.01;
// run OpenCL kernel to generate vertex positions
runKernel(anim);
// clear graphics then render from the vbo
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 4, gl.FLOAT,
false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.POINTS, 0, mesh_width * mesh_height);
requestAnimationFrame(DisplayGL);
}
function mouse(evt, isDown) {
//log('mouse event: button=' + evt.button);
if (isDown)
mouse_buttons |= 1 << evt.button;
else
mouse_buttons = 0;
mouse_old_x = evt.x;
mouse_old_y = evt.y;
}
function motion(evt) {
var dx = (evt.x - mouse_old_x);
var dy = (evt.y - mouse_old_y);
//log('mouse motion: dx=' + dx + " dy=" + dy+ "button="+mouse_buttons);
if (mouse_buttons & 1) {
rotate_x += dy * 0.2;
rotate_y += dx * 0.2;
} else if (mouse_buttons & 2) {
translate_z += dy * 0.01;
}
mouse_old_x = evt.x;
mouse_old_y = evt.y;
// set view matrix
//gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [ 0.0, 0.0, translate_z ]);
mat4.rotate(mvMatrix, rotate_x * Math.PI / 180, [ 1.0, 0.0, 0.0 ]);
mat4.rotate(mvMatrix, rotate_y * Math.PI / 180, [ 0.0, 1.0, 0.0 ]);
}