- From: Glenn Maynard <glenn@bluegoji.com>
- Date: Sun, 20 Oct 2013 10:33:13 -0500
- To: whatwg <whatwg@whatwg.org>
- Cc: Kenneth Russell <kbr@google.com>, Robert O'Callahan <robert@ocallahan.org>
(This is a spin-off thread from "Canvas in workers". Some of this is written in terms of the WorkerCanvas proposal, but it works fine with the current CanvasProxy API. I'm skipping some steps here and going straight to a proposal, since my main goal at the moment is to detangle this from the other thread...) Here's a way to synchronize updates to DOM changes, so scenes rendered in a worker only appear when the UI thread is ready for them to be. - Add a flag to the Canvas to enable this. For now, let's call this explicitpresent, eg. <canvas explicitpresent>. - When a script finishes rendering (eg. calls commit()), the buffer is not automatically displayed. Instead, it's simply made available to be displayed. - Add a method, Canvas.present(), to present the most recently-available frame. To describe this in terms of triple-buffering, you have three buffers: a rendering buffer (aka the backbuffer), a display buffer (aka the front-buffer), and a ready buffer. You render (possibly in a worker) to the rendering buffer. When you're finished, you call commit(), and the rendering buffer and the ready buffer are swapped. Now that a new frame is ready, you can call canvas.present() to swap the ready buffer and the display buffer. Essentially, that's it. You don't actually need to allocate a third buffer, as long as the user doesn't start rendering a new frame before present()ing the previous one. This could be a behind-the-scenes optimization to avoid the extra memory cost--only allocate a third buffer if actually needed. It must not be possible for the UI thread to detect whether present() did anything--if there's no frame in the ready buffer, nothing changes and the UI thread can't detect this. Similarly, it must not be possible for the rendering thread to detect if the ready frame has been presented. These rules are to prevent exposing asynchronous behavior. Example: <canvas id=canvas explicitpresent> <script> var canvas = document.querySelector("#canvas"); var worker = createWorker(); worker.postMessage({ cmd: "init", canvas: canvas.getWorkerCanvas(), }); worker.onmessage = function(e) { // The worker told us that a frame has been committed. Present it for display. canvas.present(); // Tell the worker that it should start rendering the next frame. worker.postMessage({cmd: "update"}); // Do any DOM changes here, to synchronize them with displaying the new canvas. updateUI(); } </script> Worker: onmessage = function(e) { // On initialization only: if(e.data.cmd == "init") canvas = e.data.canvas; // Render our scene. renderFrame(canvas); // Commit the scene. canvas.commit(); // Tell the main thread that the frame is ready. postMessage("present"); } function renderFrame(workerCanvas) { } -- Glenn Maynard
Received on Sunday, 20 October 2013 15:33:38 UTC