Monday, December 29, 2014

Hardware accelerated general purpose computation in javascript. (gpgpu)

General-purpose computing on graphics processing units (GPGPU, rarely GPGP or GP²U) is the utilization of a graphics processing unit (GPU), which typically handles computation only for computer graphics, to perform computation in applications traditionally handled by the central processing unit (CPU). The use of multiple graphics cards in one computer, or large numbers of graphics chips, further parallelizes the already parallel nature of graphics processing. In addition, even a single GPU-CPU framework provides advantages that multiple CPU's on their own do not offer due to specialization in each chip.
source: wikipedia
So why would you want to do this in javascript? Well for one its awesome! The fact that you can now run code directly on the GPU via WebGL shaders makes general purpose computation on accelerated hardware now possible. Secondly, unlike javascript, shaders are compiled and are optimized for parallel operations. SO I thought, why wait for WebCL when i could just do it myself with WebGL shaders? I used three.js to take care of most of the WebGL grunt work which majorly simplified the setup code. I ended up with a small function that accepts a shader, an array of input data, and a callback function. It looks like this.
 gpgpu(shader, dataset, function (gpuout) { 
    /* do somthing with gpuout array */
});
So generally speaking, the way this works is a texture is created from an array of input data. This texture is loaded into the video card. A fragment shader renders onto a plane using the texture as input data. This plane is then rendered to a buffer which is then dumped back into a javascript array. If the whole process sounds inefficient its because it is. Luckily the speed increase of running computations on accelerated hardware usually makes up for the performance hit moving all the data back and forth. I have found that this approach tends to work best for computationally expensive functions and larger datasets. although the gpgpu function can accept a dataset as small as 16 floats.
Once I wrote a javascript function and its GLSL shader equivalent, I was able to run a test to compare the speed of native javascript vs. the same function written as a WebGL shader. Amazing! in some cases the WebGL shader was as much as 100x faster that its javascript counterpart. Finally I thought it would be cool to only have to write the code once so i wrote a very simple javascript -> GLSL cross compiler. I ended up with something that looks like this.
gpgpu(
    glsl(function(val){ 
        return Math.sqrt(val);
    }), 
    dataset, 
    function (gpuout) { 
    /* do somthing with gpuout array */
});
Leave a comment and let me know what you think and feel free to check out the live demo. There is a code editor window where you can modify the javascript/shader and see the execution times of the CPU vs the GPU. :)



No comments:

Post a Comment