- From: Glenn Maynard <glenn@zewt.org>
- Date: Wed, 16 May 2012 20:17:12 -0500
- To: Gregg Tavares (勤) <gman@google.com>
- Cc: public-webapps@w3.org
- Message-ID: <CABirCh-im9uVbSAp=HM9tj1QqhyvWpgxjWhDYz6E1S8=zEa1vQ@mail.gmail.com>
On Wed, May 16, 2012 at 2:30 PM, Gregg Tavares (勤) <gman@google.com> wrote: > Some Ideas > > **) Create context in main page, pass to worker* > Transferring an active context from one thread to another (at the implementation level) can be hard. It's much simpler to only create new the contexts in the thread they'll be used, never allowing contexts to be moved from thread to thread. Here's a first-pass approach: 1: Add HTMLCanvasElement.getBackbuffer, which returns a lightweight Backbuffer interface associated with the HTMLCanvasElement. This has only one method, getContext, which is equivalent to canvas.getContext. (This is exactly like the suggestion for making images available in threads.) 2: Backbuffer can be transferred from one thread to another, using the transfer mechanism. On transfer, any WebGL contexts (and other context types) in the thread associated with the same backbuffer are destroyed (putting exactly what "destroyed" means aside for later). Additionally, when a Backbuffer is transferred, the underlying backbuffer of the HTMLCanvasElement is considered owned by the new thread. All instances of Backbuffer for that HTMLCanvasElement, including newly-created ones, are neutered unless the backbuffer is transferred back to the UI thread. 3: As long as the backbuffer of an HTMLCanvasElement is owned by a thread other than the UI thread, calls to the following methods on the associated HTMLCanvasElement raise an exception: getBackbuffer, getContext, toBlob, toDataURL. This takes effect synchronously, as soon as transfer happens (right when you postMessage the Backbuffer somewhere else). 4: When a Worker receives a Backbuffer, it can call Backbuffer.getContext to create a WebGLContext (with exactly the same rules as HTMLCanvasElement.getContext). The results of rendering to that context are visible in the associated HTMLCanvasElement in the main thread. This ensures that only one thread can ever have an open context for any backbuffer, and that pixel readback functions (toBlob and toDataURL) can't expose the asynchronous nature of what's going on. The transfer mechanics are rough and need refining. For offscreen rendering in a thread, just allow constructing Backbuffer; for example, var backbuffer = new Backbuffer(1024, 768); var ctx = backbuffer.getContext("webgl"); backbuffer.resize(1920, 1200); Backbuffer.resize is equivalent to resizing a Canvas, and only available for Backbuffers you create yourself, not for ones created via HTMLCanvasElement.getBackBuffer. One problem that I havn't attempted to solve here: when the HTMLCanvasElement is resized in the UI thread, it results in changes to drawingBufferWidth/drawingBufferHeight. This would expose asynchronous behavior. Instead, it would probably need to apply the change (from the thread's perspective) in a queued task, so you have to return to the event loop for it to be applied. If a thread is killed by the browser (eg. due to a CPU quota), the backbuffers it owns are orphaned; you can no longer create contexts for it. You need to create a new Canvas. This isn't great, but workers don't really seem to try to make it possible to recover from this anyway. interface CanvasBackbuffer { object? getContext(DOMString contextId, any... args); } [Constructor(unsigned long width, unsigned long height)] interface Backbuffer : CanvasBackbuffer { void resize(unsigned long width, unsigned long height); } interface HTMLCanvasElement : HTMLElement { CanvasBackbuffer getBackbuffer(); } The Backbuffer ctor is available in workers. Importantly, you can start by just implementing the Backbuffer constructor. That would only allow the simpler case of offscreen rendering. -- Glenn Maynard
Received on Thursday, 17 May 2012 01:17:35 UTC