UNPKG

webcl-nodep

Version:

A fork of node-webcl without dependencies other than OpenCL

255 lines (220 loc) 7.75 kB
/* * Compute contains all WebCL initializations and runtime for our kernel * that update a texture. */ function Compute() { var /* cl_context */ clContext; var /* cl_command_queue */ clQueue; var /* cl_program */ clProgram; var /* cl_device_id */ clDevice; var /* cl_device_type */ clDeviceType = WebCL.DEVICE_TYPE_GPU; var /* cl_image */ clTexture; var /* cl_kernel */ clKernel; var max_workgroup_size, max_workitem_sizes, warp_size; var TextureWidth, TextureHeight; var COMPUTE_KERNEL_ID; var COMPUTE_KERNEL_NAME; var nodejs = (typeof window === 'undefined'); /* * Initialize WebCL context sharing WebGL context * * @param gl WebGLContext * @param kernel_id the <script> id of the kernel source code * @param kernel_name name of the __kernel method */ function init(gfx, kernel_id, kernel_name) { log('init CL'); var gl = gfx.gl(); if(gl === 'undefined' || kernel_id === 'undefined' || kernel_name === 'undefined') throw 'Expecting init(gl, kernel_id, kernel_name)'; COMPUTE_KERNEL_ID = kernel_id; COMPUTE_KERNEL_NAME = kernel_name; // Pick platform var platformList = WebCL.getPlatforms(); var platform = platformList[0]; // create the OpenCL context try { clContext = WebCL.createContext({ deviceType: clDeviceType, shareGroup: gl, platform: platform }); } catch(err) { throw "Error: Failed to create context! "+err; } var device_ids = clContext.getInfo(WebCL.CONTEXT_DEVICES); if (!device_ids) { throw "Error: Failed to retrieve compute devices for context!"; } // check we have the right device type var device_found = false; for(var i=0,l=device_ids.length;i<l;++i ) { device_type = device_ids[i].getInfo(WebCL.DEVICE_TYPE); if (device_type == clDeviceType) { clDevice = device_ids[i]; device_found = true; break; } } if (!device_found) throw "Error: Failed to locate compute device!"; if (!clDevice.getInfo(WebCL.DEVICE_IMAGE_SUPPORT)) throw "Application requires images: Images not supported on this device."; // Create a command queue try { clQueue = clContext.createCommandQueue(clDevice, 0); } catch(ex) { throw "Error: Failed to create a command queue! "+ex; } // Report the device vendor and device name var vendor_name = clDevice.getInfo(WebCL.DEVICE_VENDOR); var device_name = clDevice.getInfo(WebCL.DEVICE_NAME); log(" Connecting to " + vendor_name + " " + device_name); log(" Global mem cache size: " + (clDevice.getInfo(WebCL.DEVICE_GLOBAL_MEM_CACHE_SIZE)/1024) + "kB " ); log(" Local mem size : " + (clDevice.getInfo(WebCL.DEVICE_LOCAL_MEM_SIZE)/1024) + "kB " ); log(" Max compute units : " + clDevice.getInfo(WebCL.DEVICE_MAX_COMPUTE_UNITS)); log(" Max work-item sizes : "+clDevice.getInfo(WebCL.DEVICE_MAX_WORK_ITEM_SIZES)); log(" Max work-group size : "+clDevice.getInfo(WebCL.DEVICE_MAX_WORK_GROUP_SIZE)); init_cl_buffers(); init_cl_kernels(); } /* * Initialize WebCL kernels */ function init_cl_kernels() { log(' setup CL kernel'); clProgram = null; if(!nodejs) { var sourceScript = document.getElementById(COMPUTE_KERNEL_ID); if (!sourceScript) throw "Can't find CL source <script>"; var str = ""; var k = sourceScript.firstChild; while (k) { if (k.nodeType == 3) { str += k.textContent; } k = k.nextSibling; } if (sourceScript.type == "x-webcl") source = str; else throw "<script> type should be x-webcl"; } else { log("Loading kernel source from file '" + COMPUTE_KERNEL_ID + "'..."); source = fs.readFileSync(__dirname + '/' + COMPUTE_KERNEL_ID, 'ascii'); if (!source) throw "Error: Failed to load kernel source!"; } // Create the compute program from the source buffer try { clProgram = clContext.createProgram(source); } catch(ex) { throw "Error: Failed to create compute program! "+ex; } // Build the program executable try { clProgram.build(clDevice, '-cl-fast-relaxed-math -cl-mad-enable -DMAC'); } catch (err) { throw "Error: Failed to build program executable!\n" + clProgram.getBuildInfo(clDevice, WebCL.PROGRAM_BUILD_LOG); } // Create the compute kernels from within the program try { clKernel = clProgram.createKernel(COMPUTE_KERNEL_NAME); } catch(ex) { throw "Error: Failed to create compute kernel! "+ex; } // Get the device intrinsics for executing the kernel on the device max_workgroup_size = clKernel.getWorkGroupInfo(clDevice, WebCL.KERNEL_WORK_GROUP_SIZE); warp_size=clKernel.getWorkGroupInfo(clDevice, WebCL.KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE); log(' max workgroup size: '+max_workgroup_size); log(' local mem used : '+clKernel.getWorkGroupInfo(clDevice, WebCL.KERNEL_LOCAL_MEM_SIZE)+" bytes"); log(' private mem used : '+clKernel.getWorkGroupInfo(clDevice, WebCL.KERNEL_PRIVATE_MEM_SIZE)+" bytes"); log(' warp size : '+warp_size); } /* * (Re-)set kernel arguments * * @param time timestamp in ms (as given by new Date().getTime() * @param image_width width of the image * @param image_height height of the image */ function resetKernelArgs(time, image_width, image_height) { TextureWidth = image_width; TextureHeight = image_height; // set the kernel args try { clKernel.setArg(0, clTexture); clKernel.setArg(1, time, WebCL.type.FLOAT); } catch (err) { throw "Failed to set row kernel args! " + err; } } /* * Initialize WebCL buffers */ function init_cl_buffers() { //log(' create CL buffers'); } /* * Configure shared data with WebGL i.e. our texture * * @param gl WebGLContext * @param glTexture WebGLTexture to share with WebCL */ function configure_shared_data(gfx, glTexture) { var gl=gfx.gl(); // Create OpenCL representation of OpenGL Texture if(clTexture) clTexture.release(); clTexture = null; try { clTexture = clContext.createFromGLTexture(WebCL.MEM_WRITE_ONLY, gl.TEXTURE_2D, 0, glTexture); } catch (ex) { throw "Error: Failed to create CL Texture object. " + ex; } return clTexture; } /* * Execute kernel possibly at each frame before rendering results with WebGL * * @param gl WebGLContext */ function execute_kernel(gl) { // Sync GL and acquire buffer from GL gl.flush(); clQueue.enqueueAcquireGLObjects(clTexture); // Set global and local work sizes for kernel var local = []; local[0] = warp_size; local[1] = max_workgroup_size / local[0]; var global = [ clu.DivUp(TextureWidth, local[0]) * local[0], clu.DivUp(TextureHeight, local[1]) * local[1] ]; // default values //var local = null; //var global = [ TextureWidth, TextureHeight ]; try { clQueue.enqueueNDRangeKernel(clKernel, null, global, local); } catch (err) { throw "Failed to enqueue kernel! " + err; } // Release GL texture clQueue.enqueueReleaseGLObjects(clTexture); clQueue.flush(); } return { 'init':init, 'configure_shared_data': configure_shared_data, 'resetKernelArgs': resetKernelArgs, 'execute_kernel': execute_kernel, 'getKernel' : function() { return clKernel; }, 'clean': function() {} } } module.exports=Compute;