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

Re: [Public WebGL] inconsistent clear behavior for preserveDrawingBuffer: false (the default)

(replying to the entire list this time)

On Sat, Jun 9, 2012 at 6:38 AM, Benoit Jacob <bjacob@mozilla.com> wrote:

On Fri, Jun 1, 2012 at 2:14 PM, Benoit Jacob <bjacob@mozilla.com> wrote:

I was trying to repo an error mentioned in another thread

Here's my test

The spec says

WebGL presents its drawing buffer to the HTML page compositor immediately before a compositing operation, but only if the drawing buffer has been modified since the last compositing operation. Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer. By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above.

In the sample I clear the drawing buffer to green. Then 1 second later I issue some GL commands to see what happens.  These 6 commands should not effect what is displayed

        gl.bindTexture(gl.TEXTURE_2D, gl.createTexture());
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        var p = new Uint8Array(4);
        gl.readPixels(0,0,1,1,gl.RGBA,gl.UNSIGNED_BYTE, p);

What I find is Firefox ends up reflecting that the backbuffer has been cleared if I call gl.readPixels. On other words it recomposites the page with the cleared drawing buffer. As far as I can tell from the spec that's a bug. The drawing buffer has not been modified so  it should not be composited again.
In Mozilla's implementation, readPixel checks if the backbuffer needs a clear (which is the case if preserveDrawingBuffer is false and the drawing buffer hasn't been cleared since it was last presented). If it does find that it needs a clear, then it clears it and requests it to be composited again.

How else should it behave?

It should perhaps make a copy and of the backbuffer to use for composition, if necessary, and clear the WebGL-visible backbuffer. This is what WebKit does, though I realize it's a real pain to do. 
I really hope that that isn't required by the WebGL spec; if it were, I would argue that developers probably wouldn't want that if they knew that it caused that inefficiency.

Anyway: in Mozilla's implementation, readPixels is clearing the backbuffer as if it were a draw-operation. If I remove this clearing, Gregg's testcase succeeds (stays green) and the conformance tests still pass. So I guess it was just a bug that readPixels was clearing the backbuffer as a draw-op and that's all we need to fix here? I wonder, then, why WebKit is making this copy?
Technically, it's not the draw-op that clears the framebuffer, but the present from the canvas. Therefore, the readPixels (or drawImage or texImage from the canvas) after the present has to return the cleared values, and it's just an implementation detail that this happens in the readpixels itself.  Making a copy shouldn't generally be necessary, as it only needs to happen in the case where they're doing a read from the canvas immediately after it's been presented (before any draw to it happens). Reads the are guaranteed to return all zeros aren't that useful in practice.

I don't believe there's a test-case for this yet, as guaranteeing this does the right thing is hard without being able to see the onscreen result. 

In retrospect, I think it would have made sense for me not to have made a copy in the readPixels case, but instead to fake out the result of the readPixels (or other operation) to be zero in these circumstances. I may fix that now....


A runnable testcase could be very useful here.


On Chrome if I call gl.drawArrays(gl.TRIANGLE, 0, 0) the drawing buffer is not recomposited. That could be argued either way. The drawing buffer did not get modified but it's a special case. I could easily call gl.drawArrays with a real program and real data that doesn't actually end up modifying the drawing buffer.  I think this means the spec should be more clear. Instead of saying "but only if the drawing buffer has been modified since the last compositing operation" it should be specific and say " but only if clear, drawArrays or drawElements have been called since the last compositing operation".


Unfortunately there is no way to write conformance tests for these cases. In all cases the drawing buffer is cleared correctly and so calling readPixels to verify will pass on all browsers. This is only something browser vendors can test themselves with screen captures or other browser specific test.