Paint the image to a canvas, then grab the imagedata off of it, split it into as many parts as you have threads, then use the "transferrableObjects" property of postMessage to zero-copy transfer the data to each worker to be processed, transferred back, and re-stitched together.
It's pretty powerful and suprisingly easy to work with once you understand it.
[0] is a snippet from the code, but be gentile... It was a personal project where I was trying out polymer 0.5 and made a lot of questionable design choices...
Also, I've heard of the idea of using webworkers as a "first class" platform. That is do all of the core parts of your application in them and only use the "main" thread as a "ui" thread. I haven't gotten a chance to try it out, but it seems like a great idea that could really work well in some SPAs.
[0] https://github.com/Klathmon/stitchpics/blob/master/app/eleme...
Like I say, more than happy to be corrected, because that sort of thing would be incredibly helpful. Really, anything that lets you mess with a disconnected DOM in the background and then attach it in the foreground could be useful but (and, again, I'm very happy to be corrected), I don't think you can do this.
https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCa...
Having said that, if you want fast image manipulation, you're probably better off doing direct manipulation of Uint8Clamped arrays anyway, since that can be much faster.
Wouldn't most CPU's these days be smart enough to detect advancing the index by 4, and then using offsets?
So:
for(let i = 0; i < someUint8Array.length; i += 4){
let R = someUint8Array[i], G = someUint8Array[i+1],
B = someUint8Array[i+2], A = someUint8Array[i+3];
// ... manipulations here
}I have a feeling it's more of a JS JIT thing than a CPU prefetcher thing, but honestly I'm not really sure.
In my program I linked above, it was actually faster to use Uint32array everywhere and then use functions to pull the 4 color values from it and another function to push the 4 values back to a uint32.
Granted, it's been over a year since I last benchmarked that code, but I did reuse some of the image code recently and found iterating over a Uint32array to be significantly faster. (And funnily enough, manually unrolling the loop of Uint32array to something similar to what you wrote gave an additional small performance boost, but it was small enough to be not worth the extra weirdness in the code to me)
At the very least it can show you some of the gotchas with bit shifting in JS (like how values often look negative until they are placed into a Uint32array then they become positive integers, and how you need to check for endianness)
To your point about direct manipulation, I think you may be right. I'm talking about drawing rather than image processing, and no way I want to effectively re-implement a bunch of Canvas2D primitives, but what I could do is draw the image once on the foreground thread, extract the raw bytes, and then rotate those using image processing into a bunch of target arrays in the background. I'd then pass those arrays back to the foreground and create a set of corresponding images.
The only issue here, and I'd need to benchmark this, is that it's not clear to me how much of the time is spent drawing versus actually creating the images. If creating images is expensive this might not yield much of a gain.
The upshot is that this starts to sound like quite a bit of work when, what I could do, and which would be much simpler, is reduce the fidelity slightly: e.g., by rendering only 180 or 120 images, and tweaking the minimum angular velocity appropriately to avoid jerky animation.
And then I suppose I'm back to the point that somebody else made, which is that Web Workers may not be that useful in the real world. :/
I saw a library a while ago that was trying to re-implement the canvas primitives using only typed arrays so it was worker safe but I'm not sure what happened to it.
- This might lead to the odd jaggy artifact because I'm rotating bitmaps rather than vectors,
- It might not speed things up that much because I still need to create images from these arrays,
- It starts to seem like quite a lot of work; maybe I'd be better off reducing the number of images slightly, and compensating by speeding up the minimum angular velocity.
You can see what I'm up against at https://arcade.ly/games/asteroids/. (Also, see my comment above, where I've made substantially the same points.)
I expected to instantiate a WebWorker with a function, and was surprised to discover you have to give it a separate JavaScript file. It is not easy to adopt.
They are an excellent fit for anything that requires heavy number-crunching, and little or no DOM manipulation or network communication.
Another thing was to offload tasks such as encoding GIF frames, which is also working pretty well.
I guess for off-screen image manipulation (if for whatever reason you can't use WebGL and shaders) you'd have to resort to manual pixel manipulation by sending Uint8ClampedArrays back and forth. At least they're transferable by default.
[0] https://github.com/bvaughn/react-virtualized-select
[1] https://github.com/bvaughn/react-select-fast-filter-options
Edit: Shameless Recruiting Plug. If any of you out there are js performance pros and well acquainted with this sort of thing, please reach out as I'm looking for help optimizing further and I'm a bit out of my depth on some of it. Currently this would be a contract position but could grow to something more if that is desired.
Basically to move as much processing client side as possible/reasonable so the server doesn't have to do it.
* Did not read article yet and am not sure about SharedArray structure.