May a Web Worker render on WebGL-Canvas? - javascript

I don't understand how web-workers works... Are web-workers parallel or just preempted?
Is it safe for a web-workers to render to a webgl context?
If I have only a web-worker rendering to webgl context, and my main "thread" is not invoking the worker also, is it safe to the web-worker to render to the webgl context?

When a Web Worker is created, you give it a URI pointing to a JavaScript file. It loads that JavaScript file in a new OS-level thread. You can't control affinity to specific cores or thread priorities, (as of this writing), but the underlying Thread created is real and unfettered. By default, JavaScript running in a Web Worker's thread has NO access to the DOM: you are not given access to the window object nor any DOM-related Classes.
The semantics of the Web Worker thread make it nearly completely unmoored from the default DOM thread. First thing that's interesting is that the Web Worker can run in 100% CPU usage infinite loops without worrying about freezing up the UI. This means the dreaded "Warning: Unresponsive script" message box cannot be triggered by a Web Worker!
The tradeoff of being unmoored is your ability to synchronize and communicate between DOM and worker threads is limited. The explicit conduit between worker and DOM is the postMessage() API for sending data and the onmessage event for receiving events. You can postMessage with strings and objects where your data is cloned from source thread's heap into target thread's heap. onmessage events are only received by your Web Worker when it is idle. This means, in order for onmessage events to be delivered from the DOM to your Web Worker in a timely fashion, the worker must yield frequently; this may put a wrinkle in the way you want to write your code.
It's important to understand that there are a special class of "Transferable Objects" in modern JavaScript implementations where objects that you send to postMessage() are not cloned, but rather ownership of the object is transferred from one thread to another. These are the types of data you want to send to postMessage() whenever possible; any time data is cloned when calling postMessage(), you create TONS of garbage to be GC'd and system performance will suffer.
The collection of Transferable Object types out there has been steadily growing, and the Mozilla Development Network, WhatWG, and W3C are great places to watch the spec research in this area. I couldn't even tell you all of the things that can be Transferred across threads in the browser nowadays, but if I made you a comprehensive list, it'd likely be out of date in a year or less.
Regarding your original question, on Firefox 44+, you can now partially transfer a Canvas to a WebWorker via the HTMLCanvasElement#transferControlToOffscreen function. transferControlToOffscreen creates a Transferable OffscreenCanvas object that you can postMessage over to a Web Worker. On the Web Worker, you can acquire a webgl CanvasContext and issue drawing commands to the canvas from the worker thread without having direct access to the actual canvas tag's DOM that still lives over with the DOM thread.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/transferControlToOffscreen
https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/

This question has an answer that basically states you can't use webgl from a web worker as web workers don't have access to the DOM and you have to call getContext() on a canvas object to get the webgl context.

Related

Web Workers - do they create actual threads?

I have always thought that web workers create separate threads, but today I ran into the spec on w3c website. Below is a citation about web workers:
This allows for thread-like operation with message-passing as the
coordination mechanism.
The question is - if it is thread-like, not actual thread what is an advantage(performance wise) of using this technology?
Any help will be appreciated!
Yes, web workers create actual threads (or processes, the spec is flexible on this). According to the Web Workers specification, when a worker is created the first step is:
Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.
For the purposes of timing APIs, this is the official moment of creation of the worker.
(W3C Web Workers specification section 4.4)
So it is explicitly specified that code running in Web Workers run in actual threads or processes.
Although it is possible to implement Workers without threads (note the "equivalent construct" language) for use on systems that don't support threads, all browser implementations implement Web Workers as threads.
A web worker runs in a single thread isolated from the main thread, the way they pass messages around is thread-like and works differently depending on whether you're using dedicated (can only be accessed from the script that created it) or shared (can be accessed by any script within the same domain via a port object) workers.
EDIT:
Updated answer to reflect my comment from months ago. While a SINGLE web worker runs in an isolated thread it doesn't mean each additional worker will run in the same thread.
According to MDN,
Web Workers are a mechanism by which a script operation can be made to run in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.
So, each worker does not create a separate thread, but all workers are running in a single separate thread.
I guess, like just in other things, the implementation and approach may differ from browser to browser.

Why does web workers does not give access to DOM object?

I have been using web-workers in javascript. It would have been an icing on the cake if window, document references were present in web workers context.
I would like to know for what reason was it chosen to not make these references accessible in workers?
Also is there any work-around to use these references?
Standard JavaScript and the DOM API have absolutely no exclusion mechanisms allowing several threads to safely access the same objects.
The solution that is most often chosen to allow multi-tasking in JavaScript is to isolate threads and only let them exchange through messages (or events). Giving access to the DOM to webworkers would break that isolation.
Note that this isn't totally specific to JavaScript: almost all GUI frameworks, whatever the language, restrict the modifications of the GUI to one dedicated thread. JavaScript is more restrictive as most often (always in the browser) you can't share objects at all.
The simple workaround is to let your main thread in the browser do the modifications you need to do, when the background thread gives it the instruction through messages. Or rather: do only the CPU extensive tasks in the webworker, letting the main thread obtain the input data, and update the DOM when the webworker sends the output data.

Is there a way to instantiate a CanvasRenderingContext2D object without the document for use in a web worker?

Here's what I know how to do:
var buffer=document.createElement("canvas").getContext("2d");
Here's what I want to do:
var buffer=CanvasRenderingContext2D();
Is this possible? Is there a way to create a CanvasRenderingContext2D object without the document's createElement method?
The reason I'd like to know is because I'm working with web workers, and I'd like to see if I can move some of the drawing to a worker. The drawing operations would stay in the separate thread and the final rendering to the display canvas would be done in the main document thread. I'm also not sure if that's possible.
If anyone has any information on either of these topics (web workers and drawing or ways to instantiate CanvasRenderingContext2D), please let me know!
Thanks!
Edit:
For reference, the context of my project is creating a game loop. I've noticed that drawing is pretty much my most cpu intensive task, eating a whopping 10% of my cpu according to profiles done with Chrome dev tools. If there were some way of doing all the image buffering on the web worker and then passing a rendering context (or something) back to the main document thread to do the final drawing to the display canvas, it would be a huge load off of the main thread, which would handle input and repeated calls to requestAnimationFrame, which would handle the final drawing to the "canvas" element.
Now, I'm not sure if this is possible, like I said before, but I've looked at a lot of tutorials that say web workers are great for image editing applications (although none of them go into detail). Maybe this is referring to filter functions that loop over every pixel in the image and perform a cpu intensive filter function, but really, if those functions have access to the image data array, then why wouldn't I be able to access the image for basic drawing operations in the same web worker?
Anyway, that's the context of the project: creating a game loop that can handle buffering images in a web worker so the main thread can focus on updating the display "canvas" element and collecting user input.
Web workers do not natively support DOM objects.
So canvas's CanvasRenderingContext2D is not natively available inside web workers.
To get CanvasRenderingContext2D inside a web worker you must reproduce all of its methods and properties (or at least as many methods and properties that are needed for your app).
This is obviously a large and daunting task.
GitHub's Automattic Group has done just that to create html5 canvas support for NodeJS: https://github.com/Automattic/node-canvas/tree/master/src You could use this as a starting point and convert needed portions of it to javascript. It is still a large and daunting task.
But there is still more work to do...
After you've recreated the required methods and properties and done your work on the worker, you must still marshall the CanvasRenderingContext2D properties back to the main thread. You must also marshall the pixel data that your web-worker-rendering-context has drawn back to the main thread.
I don't know of anyone whose done the code for this. It's more common to:
Marshall data from the main thread to workers.
Use code in the worker to create your desired data.
Marshall data from the worker back to the main thread.

Transferring data using Emscripten Worker API without copying

Is there a way to get Emscripten to transfer, and not copy, data between web workers and the main UI thread?
Emscripten has an API that manages communication between Web Workers, which I believes just uses the postMessage / onmessage mechanism under the hood. Looking in the source for the Emscripten Worker API, it appears that it doesn't use the transferList option when it calls postMessage, and so the data gets copied.
Actually, I think it gets copied at least twice: first by the browser between the threads, and then a second time by Emscripten to get it into the Emscripten-managed heap-space. And if you want the data to continue to survive on the receiving end after the callback, it would have to be copied a third time, as according to the docs the data passed to the callback is only guaranteed to exist during the callback.
Repeating my question from the top: is there a way to get Emscripten to avoid all this copying by transferring, and not copying, data between web workers and the main UI thread?
This is possible if you make use of SharedArrayBuffer. Recently, the Emscripten guys added experimental support for pthread in Emscripten, which use this feature. However, only the Firefox nightly supports SharedArrayBuffers at the moment, so this is not widely adopted yet.

multi threading using an iframe

I am trying to simulate multi threading using an iframe but I have come across a situation which I do not know if it actually utilizes the iframe process (thread) on its own.
For instance, If I call a method which lays inside an iframe, will it run using the thread created by the iframe or will it run using the main parent window thread?
If it is the latter, then is it possible to change the scope so that the iframe calls the method (so that the program uses a different thread from that of the parent window)
EDIT:
Maybe I should have been more clear on this but I do not want to use WebWorkers simply because I do not have access to the DOM elements.
If you want to run some background tasks just use WebWorkers.
Generally you don't need to multi thread js code. You should use event loops instead.
Take a look at Using web workers from the MDN docs.
The Worker interface spawns real OS-level threads, and concurrency can
cause interesting effects in your code if you aren't careful. However,
in the case of web workers, the carefully controlled communication
points with other threads means that it's actually very hard to cause
concurrency problems. There's no access to non-thread safe components
or the DOM and you have to pass specific data in and out of a thread
through serialized objects. So you have to work really hard to cause
problems in your code.
John Resig wrote Computing with JavaScript Web Workersn back in 2009 on this topic. However, according to When can I use, there is no IE support until IE10 so it may not fit your needs.

Categories

Resources