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

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



On Nov 15, 2010, at 5:09 PM, Gregg Tavares (wrk) wrote:

> 
> 
> ...> I'm fine with 3 with the caveats that I mentioned before. Namely that toDataURL, readPixels, drawImage, texImage2D(canvas3d, ...) all work as expected. Namely that reading the canvas through any of those calls gives you the contents what you see displayed until first draw call after a swap. I mentioned 2 ways to implement that. Either don't issue the clear until the first draw call after a swap or, read from the display buffer after a swap, read from the draw buffer after a draw,
> 
> But that is exactly the case that is expensive or impossible on some embedded hardware (at least). You can never get access to the contents you see displayed. Once the drawing buffer is displayed, its contents are not longer available to be read. Essentially the problem is this:
> 
> 1) All OpenGL-like implementations (including D3D) do an explicit Present() (a). WebGL hides this by saying that this Present() is implicitly done on return from any JS function in which WebGL drawing is done. But when Present() is actually done is not well defined.
> 
> 2) In some implementations (mostly on the Desktop), Present() is simply a message to the compositor that the current drawing buffer should be composited with the rest of the page. The drawing buffer image doesn't change so it can be used until new WebGL calls are made which overwrite it.
> 
> 3) Some hardware doesn't work that way. In the hardware used in the iPhone, for instance, Present() actually takes the drawing buffer away from the WebGL context and uses it in a compositing operation that might not even be in sync with the WebGL rendering process. So there is no access to the drawing buffer possible after Present(). If you need access to it, you'd have to make a (costly) copy before issuing the Present() call. Given that a lot of mobile hardware is similar to that in iPhone, I would assume similar issues exist.
> 
> 4) It would be a shame if the default WebGL operation required that copy. It would mean that platforms that can least afford it (mobile) would be the most heavily penalized. All for the possibility that some fairly rare operations might be called.
> 
> Of those operations, I'm not sure readPixels() should be included. It seems reasonable that readPixels() would have to be called before a Present() (implicit or explicit) is performed. The real question is what are the rules for calling toDataURL(), or calling drawImage or texImage2D with a WebGL context.
> 
> An illustrative example was raised at the last F2F that involved taking a snapshot of a running WebGL game. It is interesting because you don't want to penalize the performance of your game just on the odd chance that someone might hit control-S to capture a screen snapshot. Assuming such a penalty were not the default, then what would the author have to do when control-S is pressed? The problem is that the control-S handler would come in as a browser event so you won't know if an implicit Present() had been called and whether or not the data in the current drawing buffer is valid.
> 
> I'm not sure this is a real issue though. For an app that is continuously drawn, you can just as easily set a flag when control-S comes in and then do a toDataURL after the next render if that flag is set. Calling toDataURL after rendering the current scene and before returning from that rendering operation ensures that the data in the drawing buffer is valid.
> 
> I think the real problem is in calls to drawImage() or texImage2D() with a WebGL context. Since these are rendering to different 2D or WebGL Canvas contexts, you can't be sure of the state of the WebGL context you're trying to use as the image source. How do you solve that problem? I think adding context attributes and the like are overkill. There's no need to mark a WebGL context as "preserving the drawing buffer" for it's entire life. I think it's also a mistake to have a WebGL context that requires a Present() call.
> 
> I think it's better to just acknowledge that using a WebGL context as an image source is not "free". Doing it requires cooperation on the part of the context wanting to use a WebGL image source and the WebGL context being used as the source. We can have a Present() call, but make it optional and pass a parameter to it. Passing true says that the current drawing buffer should still be available after the Present() call. Also, passing false should say that the buffer will not be available after Present(), rather than making it undefined whether or not it is available, for consistency. If Present() is not called on return from a JS call that did some rendering, then it would be implicitly called as before, with a param of false. Using a WebGL context as an image source when Present(true) had been previously called on that context causes the contents of the drawing buffer when Present(true) was called to be used as that image source. Otherwise using that context will result in an image of transparent black (0x00000000) being used.
> 
> Adding a Present function seems like it certainly has advantages. Why not require it instead of having the current behavior? Like others have mentioned, this makes it more like real OpenGL and makes it easy to spread out rendering across callbacks, possibly making it better for web worker stuff in the future as well.

So you're saying we use my proposal but require Present()? I was thinking about compatibility with existing content, but I suppose we're early enough that it's not a big issue. You're right that explicit Present() makes it easy to split the render across multiple calls. And calling Present() (without a param) would be the same as Present(false) so by default you'd get the faster form.

And this solves another issue I was concerned about. Before Present() is called, toDataURL() and using the WebGL context as a source image would work as expected; the current (unpresented) contents of the drawing buffer would be used. But what about after the drawing function returns. If you don't know when Present() will be called, how do you know when the contents of the drawing buffer become invalid? With explicit Present() that question goes away. If the author knows when Present() will be called, toDataURL() and using the WebGL context as an image source can be done without using Present(true), as long as the author is careful about the order of operations. Present(true) is just there as a way to decouple presenting the drawing buffer to the compositor and using it as an image source.

-----
~Chris
cmarrin@apple.com





-----------------------------------------------------------
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: