{"id":22120091,"url":"https://github.com/joshbrew/gpujsutils","last_synced_at":"2025-03-24T06:26:11.491Z","repository":{"id":44646734,"uuid":"426359267","full_name":"joshbrew/gpujsutils","owner":"joshbrew","description":"gpujs wrapper with a stable (slightly modified) source build of gpujs. This has our FFT magic used in Brains@Play. ","archived":false,"fork":false,"pushed_at":"2023-10-12T06:50:40.000Z","size":723,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-14T11:03:15.889Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshbrew.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-09T19:26:50.000Z","updated_at":"2024-02-24T13:49:43.000Z","dependencies_parsed_at":"2024-10-04T12:39:35.303Z","dependency_job_id":"0c486c9d-4dad-4530-99f7-bd21a112a6e1","html_url":"https://github.com/joshbrew/gpujsutils","commit_stats":null,"previous_names":["brainsatplay/gpujsutils"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2Fgpujsutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2Fgpujsutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2Fgpujsutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2Fgpujsutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshbrew","download_url":"https://codeload.github.com/joshbrew/gpujsutils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245066675,"owners_count":20555427,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T14:20:26.829Z","updated_at":"2025-03-24T06:26:11.464Z","avatar_url":"https://github.com/joshbrew.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## gpujsutils\n\n![gpujsutils-status](https://img.shields.io/npm/v/gpujsutils.svg) \n![gpujsutils-downloads](https://img.shields.io/npm/dt/gpujsutils.svg)\n![gpujsutils-l](https://img.shields.io/npm/l/gpujsutils)\n\n[gpu.js](https://github.com/gpujs) is an amazing library for writing gpu kernels in plain js. This wrapper makes life easier to use it with a stable gpu.js bundle and adds some flexible macros. This revolve around persistent kernels with resizable i/o on-the-fly so we can make the best use of the performance benefits of parallelization. This is even better with web workers (see our MagicWorker library)\n\nSee GPU.js docs for information on how to write kernels\n\n```\nnpm i gpujsutils\n```\n#### Create a GPU util instance, + general utility functions\n```js\nimport {gpuUtils, makeKrnl, makeCanvasKrnl} from 'gpuUtils'\n\nconst gpuutils = new gpuUtils();\n```\n\n#### Add a GPU utilty function which can be called in kernels (see gpujs docs for more)\n```js\n\nfunction rms(arr, mean, len) { //root mean square error\n    var est = 0;\n    var vari = 0;\n    for (var i = 0; i \u003c len; i++) {\n        vari = arr[i]-mean;\n        est += vari*vari;\n    }\n    return Math.sqrt(est/len);\n}\n\ngpuutils.addFunction(rms);\n\n```\n\n#### Create a GPU kernel with default settings\n```js\n\nfunction transpose2DKern(mat2) { //Transpose a 2D matrix, meant to be combined\n    return mat2[this.thread.y][this.thread.x];\n}\n\nlet kernel = makeKrnl(\n    gpuutils.gpu, //the actual GPUjs instance, used normally  \n    transpose2DKern, //the kernel\n{ //kernel settings, meant to use all of the flexibility features by default (e.g. dynamic sizing)\n  setDynamicOutput: true,\n  setDynamicArguments: true,\n  setPipeline: true,\n  setImmutable: true,\n  setGraphical: false\n}); //makeKrnl(gpuutils.gpu);\n\nlet mat2 = [[1,2,3,4],[5,6,7,8],[8,9,10,11],[12,13,14,15]];\n\nlet result = kernel(mat2)\n\n//OR to add to the gpu utilities\n\nkernel = gpuutils.addKernel('transpose2D', transpose2DKern);\nresult = gpuutils.callKernel('transpose2D',mat2);\n\n\n```\n\n#### Create a kernel that renders to a canvas\n```js\n\n//From a gpujs observable: https://observablehq.com/@robertleeplummerjr/video-convolution-using-gpu-js\nfunction ImgConv2DKern(img, width, height, kernel, kernelLength) {\n    let kernelRadius = (Math.sqrt(kernelLength) - 1) / 2;\n    const kSize = 2 * kernelRadius + 1;\n    let r = 0, g = 0, b = 0;\n\n    let i = -kernelRadius;\n    let kernelOffset = 0;\n    while (i \u003c= kernelRadius) {\n        if (this.thread.x + i \u003c 0 || this.thread.x + i \u003e= width) {\n            i++;\n            continue;\n        }\n\n        let j = -kernelRadius;\n        while (j \u003c= kernelRadius) {\n            if (this.thread.y + j \u003c 0 || this.thread.y + j \u003e= height) {\n                j++;\n                continue;\n            }\n\n            kernelOffset = (j + kernelRadius) * kSize + i + kernelRadius;\n            const weights = kernel[kernelOffset];\n            const pixel = img[this.thread.y + i][this.thread.x + j];\n            r += pixel.r * weights;\n            g += pixel.g * weights;\n            b += pixel.b * weights;\n            j++;\n        }\n        i++;\n    }\n\n    this.color(r, g, b);\n}\n\n\nlet kernel = makeCanvasKernel( \n    gpu,\n    ImgConv2DKern,\n    {\n        output: [300,300],\n        setDynamicArguments: true,\n        setDynamicOutput: true,\n        setPipeline: false,\n        setImmutable: true,\n        setGraphical: true\n    },\n    divId //id of the div to append a new canvas to. Leave blank to append to body\n);\n\nkernel(video); //input an image or video from a source\n\n//OR to add to the gpu utilities\n\nkernel = gpuutils.addCanvasKernel('imgConv', ImgConv2DKern);\ngpuutils.callCanvasKernel('imgConv',video, [video.width,video.height]);\n\n\n\n```\n\n\n### Combine Kernels\n```js\n\n//adapted from gpujs tutorial\nconst add = gpuutils.addKernel('add',function(a, b) {\n  return a[this.thread.x] + b[this.thread.x];\n}).setOutput([20]);\n\nconst multiply = gpuutils.addKernel('multiply',function(a, b) {\n  return a[this.thread.x] * b[this.thread.x];\n}).setOutput([20]);\n\n//multi-step operations\nconst superKernel = gpuutils.combineKernels(\n    'superKernel', //name the combined kernel\n    ['add','multiply'], \n    function(a, b, c) {\n        return multiply(add(a, b), c);\n    }\n);\n\nlet result = gpuutils.callKernel('superKernel',[3,4,5]);\n\n```\n\n### Default Macros\n```js\n\n//pass signal buffer to receive an ordered amplitude spectrum based 0.5x the size of sample rate (nyquist frequency)\ngpuutils.gpuDFT(\n    signalBuffer, //the signal buffer\n    nSeconds, //number of seconds of data. sample rate = length/nSeconds \n    scalar, //can apply a scalar multiplier to the amplitudes\n    texOut //receive a texture map out instead of arrays?\n);\n\n//or\ngpuutils.gpuFFT(...); //faster\n\n\n// pass a 1D array of evenly-sized signal buffers to receive a list of ordered amplitude spectrums 0.5x the size of sample rate (nyquist frequency)\ngpuutils.MultiChannelDFT(\n    signalBuffer,  //1D list of evenly sized signal buffers\n    nSeconds, //number of seconds of data. sample rate = length/nSeconds \n    scalar, //can apply a scalar multiplier to the amplitudes\n    false //receive a texture map out instead of arrays?\n);\n\n//or \ngpuutils.MultiChannelFFT(...); //faster\n\n// pass a 1D array of evenly-sized signal buffers to receive a list of ordered amplitude spectrums 0.5x the size of sample rate (nyquist frequency), between the two frequencies. Better with more seconds or higher samplerate\ngpuutils.MultiChannelDFT_Bandpass(\n    signalBuffer,  //1D list of evenly sized signal buffers\n    nSeconds, //number of seconds of data. sample rate = length/nSeconds \n    freqStart, //start frequency e.g. 3Hz\n    freqEnd, //end Frequency e.g. 100Hz\n     scalar, //can apply a scalar multiplier to the amplitudes\n    false //receive a texture map out instead of arrays?\n);\n\n//or \ngpuutils.MultiChannelFFT_BandPass(...);\n\n```\n\n\n### Default Kernels\n```js\n\n    gpuutils.dft //discrete fourier transform\n    gpuutils.idft //inverse DFT (untested :P)\n    gpuutils.dft_windowed //DFT between two frequencies, need sufficient sample rate or number of seconds of data\n    gpuutils.idft_windowed //inverse dft to reverse the bandpassed dft (untested)\n    gpuutils.fft //fast fourier transform, simply decimates the number of samples used to compute lower frequency amplitudes\n    gpuutils.ifft //inverse fft (untested)\n    gpuutils.fft_windowed //bandpassed fft\n    gpuutils.ifft_windowed  //inverse bandpassed fft (untested)\n    gpuutils.listdft2D  //pass an array of arrays in of the same length to return a list of DFTs (broken) \n    gpuutils.listdft1D   //pass a single array of evenly sized sample sets of data to return the DFTs. \n    gpuutils.listdft1D_windowed  //etc\n    gpuutils.listfft1D             //etc\n    gpuutils.listfft1D_windowed     //tc\n    gpuutils.listidft1D_windowed  //untested\n    gpuutils.listifft1D_windowed  //untested\n    gpuutils.bulkArrayMul \n    gpuutils.correlograms; //cross correlations, untested\n    gpuutils.correlogramsPC; //precomputed means and estimators\n\n```\n\nThere's a few other things used internally but they're not that useful.\n\n\n\n\nJoshua Brewster \u0026 Dovydas Stirpeika\nLicense: AGPL v3.0","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshbrew%2Fgpujsutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshbrew%2Fgpujsutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshbrew%2Fgpujsutils/lists"}