[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Public WebGL] double-buffering and back buffer preservation

I also like option 2 – I agree that it does require the application author to be more aware of the end of their activity but with respect to the rest of the complexity of using WebGL to do anything I see that as one of the simplest possible additions. I’d argue against making it an option, though, as it would make it easier for developers to unknowingly opt-out of potential browser optimizations or make bad decisions – ‘works fine without double buffering, so why do it?’ without thinking of the implications on other platforms.

Plus, it mirrors most/all desktop graphics APIs where explicit swaps/presents are required at the end of frames. As an OpenGL/DirectX dev it still feels weird to me to not have anything at the end of my render method :)



Ben Vanik

Live Labs / Seadragon


From: owner-public_webgl@khronos.org [mailto:owner-public_webgl@khronos.org] On Behalf Of Brian Cornell
Sent: Monday, November 15, 2010 2:16 PM
To: Vladimir Vukicevic
Cc: public webgl
Subject: Re: [Public WebGL] double-buffering and back buffer preservation


Another use case to consider: Option #2 would allow applications to use WebWorkers for mutitheaded work that is used in rendering. Say I want to:


a) do some expensive rendering that takes ~10 ms.

b) do some expensive computation that takes ~10 ms (but doesn't involve rendering)

c) render something based on the computation in b that takes ~2 ms


Because receiving a message from a worker requires returning control to the browser, my options currently are:


X: a, b, and c sequentially with no workers: ~22 ms

Y: start b in a worker, then to a, do c in the event handler for the response from b: ~12 ms but I end up returning control to the browser with a partially rendered scene and potentially having that displayed to the user before the scene is finished

Z: Start b in a worker, do A rendered into a texture, in the event handler for the response from b, render the texture to the screen and do c: ~12ms plus the time to copy the texture, but I use more memory and lose support for multisampling the rendering of a.


Now if we had option #2 where I could explicitly swap when I'm ready to display, then I could have the best combination:


Start b in a worker

Draw a to the screen

In b's event handler draw c to the screen and swap

Total: 12 ms with no downsides (on a multi-core machine)


So I would vote for a solution like #2 where one of the context creation attribute specifies whether I want manual double buffering. If I don't set that option or set it to false, the current behavior is maintained, whether double buffering is used in some way or not. If I set it to true, then the WebGL implementation will attempt to use double buffering if possible. If it succeeds in using double buffering (which I can query through a getParameter call), then I manually switch buffers using present() as mentioned above, and nothing will be displayed until I do.


This would give both simplicity for apps that don't care, and functionality for performance critical applications.




On Mon, Nov 15, 2010 at 1:56 PM, Vladimir Vukicevic <vladimir@mozilla.com> wrote:

One of the major issues that came up during the last f2f was that the current canvas model is not the most efficient for implementing on hardware, especially on mobile hardware.  The current model was based on how the 2D canvas works: drawing happens during content JS script, and as soon as control is returned to the browser, it's supposed to be presented for display.  Content can also read back the current contents of the displayed image (in 2D canvas, via getImageData; in WebGL, via readPixels; and in both via toDataURL).

However, most 3D hardware doesn't really want to work like that -- they're optimized for double-buffering, where you draw a scene to the back buffer, and then swap buffers; after a swap, the new back buffer contains garbage.  Implementing the current canvas semantics is not a big issue on the desktop, because there is cpu/gpu/bandwidth to spare, but it's a pretty big deal on mobile.

We identified a few different options:

1) Do nothing.  Leave things as it is.  There would be fairly significant overhead that all apps would pay, even if they never want to call readPixels or toDataURL.

2) Add explicit double-buffering to WebGL canvases, and add an explicit present() call.  This complicates things for developers, because they need to then actually make this present() call, and can potentially result in higher memory usage due to some implementations needing to keep around both a front and back buffer, where before they could be effectively single-buffered.

3) Add implicit double-buffering to canvas.  Follow the same semantics as canvas does currently -- swap happens whenever control is returned to the browser -- but always enforce an uninitialized/cleared back buffer after each swap.

4) Like #2 and #3, by adding a context attribute that allows the author to choose which they would want.

5) Like #1 (do nothing), but add a context attribute for the author to indicate whether readback from the window/canvas buffer will ever be done.  If it's set to true, then dimply disallow readPixels/toDataURL when framebuffer 0 is bound (or have them always return all black).

We identified a few different use cases that should be considered.  Printing and screenshots were two, along with using a WebGL canvas as a texImage2D source, and using a WebGL canvas as a 2D canvas drawImage source.

Note that even with implicit double-buffering, it's possible to use a FBO to build up a scene across many events and only draw it to the drawbuffer once (just like you can do today, with #1).  Adding context attributes complicates the implementations, potentially significantly, so I'd like to avoid 4 and 5.

I'd lean towards #3, but what are the list's thoughts on this?

   - Vlad
You are currently subscribed to public_webgl@khronos.org.
To unsubscribe, send an email to majordomo@khronos.org with
the following command in the body of your email: