Bug 34719

Summary: WebGL rendering results must be made available to Canvas.toDataURL and 2D drawImage
Product: WebKit Reporter: Kenneth Russell <kbr>
Component: WebGLAssignee: Zhenyao Mo <zmo>
Status: RESOLVED FIXED    
Severity: Normal CC: cmarrin, gman, jamesr, japhet, mdelaney7, oliver, simon.fraser, vangelis, webkit-ews, zherczeg, zmo
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Attachments:
Description Flags
patch
simon.fraser: review-, simon.fraser: commit-queue-
revised patch: responding to Simon Fraser's review
simon.fraser: review+, simon.fraser: commit-queue-
revised patch: responding to Simon Fraser and kbr's review
zmo: commit-queue-
revised patch: fix a bug
zmo: commit-queue-
revised patch: resolving svn merge conflicts
zmo: commit-queue-
revised patch: deal with Qt part of GraphicsContext3D
none
revised patch: fix a ChangeLog issue
none
revised patch: fix the Qt bug
none
revised patch
none
revised patch
japhet: review-
revised patch
japhet: review+
Patch fixing compiler warning japhet: review+, kbr: commit-queue-

Description Kenneth Russell 2010-02-08 13:01:19 PST
Rendering into one Canvas element using WebGL and then drawing that Canvas into another using CanvasRenderingContext2D.drawImage() does not always work. Appropriate hooks need to be placed in the Canvas implementation to force the WebGL context to prepare its contents for drawing via the 2D Canvas APIs.
Comment 1 Kenneth Russell 2010-06-08 11:23:41 PDT
The same problem exists with Canvas.toDataURL().

Both of these APIs must respect the premultipliedAlpha flag in the WebGLContextAttributes.
Comment 2 Zhenyao Mo 2010-07-03 16:40:08 PDT
Created attachment 60461 [details]
patch

Tested in both Safari and Chrome in Mac in Release mode.
Comment 3 Simon Fraser (smfr) 2010-07-03 22:30:01 PDT
Comment on attachment 60461 [details]
patch

paintRenderingResultsToCanvas is leaking 'pixels'.
Comment 4 Zhenyao Mo 2010-07-04 14:57:52 PDT
Created attachment 60482 [details]
revised patch: responding to Simon Fraser's review

Use OwnArrayPtr for pixels to avoid leak.
Comment 5 Simon Fraser (smfr) 2010-07-06 13:01:04 PDT
Comment on attachment 60482 [details]
revised patch: responding to Simon Fraser's review


WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:256
 +      // BEGIN: the same code as in WebGraphicsContext3DDefaultImpl.cpp::readBackFramebuffer
Either share the code, or remove the comment. As-is, the comment is not useful.

Can you share code with GraphicsContext3D::readPixels()?

WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:290
 +      CGImageRef cgImage = CGImageCreate(m_currentWidth,
You should use RetainPtr for the dataProvider, colorSpace and cgImage.

Do you need to save/restore the state in the imageBuffer->context()?

WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:307
 +      // We want to completely overwrite the previous frame's rendering results.

Is that described in a spec anywhere?

r=me
Comment 6 Kenneth Russell 2010-07-07 19:10:04 PDT
Comment on attachment 60482 [details]
revised patch: responding to Simon Fraser's review

Generally looks good, but one high-level comment about code refactoring which I would prefer be done.


WebCore/platform/graphics/GraphicsContext3D.h:711
 +          void paintRenderingResultsToCanvas(WebGLRenderingContext*context);
Formatting: WebGLRenderingContext* context

WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:256
 +      // BEGIN: the same code as in WebGraphicsContext3DDefaultImpl.cpp::readBackFramebuffer
The CG portions of this code should be refactored rather than duplicated. Given that the original code came from GraphicsContext3D.cpp in WebKit/chromium/src, it should be possible to refactor it into WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp. It might be necessary to split it into two routines (before/after readback), or pass a callback function. If it seems reasonable to do the refactoring, please do so.
Comment 7 Kenneth Russell 2010-07-07 19:14:28 PDT
(In reply to comment #5)
> WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:307
>  +      // We want to completely overwrite the previous frame's rendering results.
> 
> Is that described in a spec anywhere?

The comment refers to the fact that the kCGBlendModeCopy blend mode is used, so that transparent pixels aren't blended with any content previously in the image.
Comment 8 Simon Fraser (smfr) 2010-07-07 19:22:15 PDT
(In reply to comment #7)
> (In reply to comment #5)
> > WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:307
> >  +      // We want to completely overwrite the previous frame's rendering results.
> > 
> > Is that described in a spec anywhere?
> 
> The comment refers to the fact that the kCGBlendModeCopy blend mode is used, so that transparent pixels aren't blended with any content previously in the image.

I realize that, but where is that behavior spec'd? I imagine this affect the outcome of mixing a 2D and 2D context on the same canvas, but I'd hope that transparent pixels in the 3D context wouldn't clobber earlier 2D drawing.
Comment 9 Kenneth Russell 2010-07-07 19:33:57 PDT
(In reply to comment #8)
> (In reply to comment #7)
> > (In reply to comment #5)
> > > WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:307
> > >  +      // We want to completely overwrite the previous frame's rendering results.
> > > 
> > > Is that described in a spec anywhere?
> > 
> > The comment refers to the fact that the kCGBlendModeCopy blend mode is used, so that transparent pixels aren't blended with any content previously in the image.
> 
> I realize that, but where is that behavior spec'd? I imagine this affect the outcome of mixing a 2D and 2D context on the same canvas, but I'd hope that transparent pixels in the 3D context wouldn't clobber earlier 2D drawing.

There have been some changes pending to the HTML Canvas specification for some time now regarding mixing of contexts, and I believe the latest resolution is that using the 2D and 3D contexts simultaneously will be explicitly disallowed in the spec. Regardless, even if you're just using the 3D context, it's still necessary to completely overwrite the rendering results. Consider the case where you draw one 3D scene with a certain set of pixels as transparent, and then perform a drawImage call with that canvas as source. Then draw a different 3D scene with a different set of transparent pixels, and perform another similar drawImage call (into a second, clean, canvas). It would be an error if portions of the first scene were visible where the pixels are transparent in the second scene because the data read back from the graphics card was blended with the previously read back data.
Comment 10 Simon Fraser (smfr) 2010-07-07 20:41:43 PDT
Fair enough.
Comment 11 Simon Fraser (smfr) 2010-07-08 22:44:28 PDT
This may also fix bug 30722.
Comment 12 Zhenyao Mo 2010-07-10 12:28:12 PDT
(In reply to comment #5)
> (From update of attachment 60482 [details])
> 
> WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:256
>  +      // BEGIN: the same code as in WebGraphicsContext3DDefaultImpl.cpp::readBackFramebuffer
> Either share the code, or remove the comment. As-is, the comment is not useful.

Removed.

> 
> Can you share code with GraphicsContext3D::readPixels()?

readPixels() logic is different.  Here we always read from backbuffer, whereas readPixels might read from user created fbo.

> 
> WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:290
>  +      CGImageRef cgImage = CGImageCreate(m_currentWidth,
> You should use RetainPtr for the dataProvider, colorSpace and cgImage.
> 
> Do you need to save/restore the state in the imageBuffer->context()?

Done.

> 
> WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:307
>  +      // We want to completely overwrite the previous frame's rendering results.
> 
> Is that described in a spec anywhere?
> 
> r=me
Comment 13 Zhenyao Mo 2010-07-10 12:28:48 PDT
(In reply to comment #6)
> (From update of attachment 60482 [details])
> Generally looks good, but one high-level comment about code refactoring which I would prefer be done.
> 
> 
> WebCore/platform/graphics/GraphicsContext3D.h:711
>  +          void paintRenderingResultsToCanvas(WebGLRenderingContext*context);
> Formatting: WebGLRenderingContext* context

Done.

> 
> WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:256
>  +      // BEGIN: the same code as in WebGraphicsContext3DDefaultImpl.cpp::readBackFramebuffer
> The CG portions of this code should be refactored rather than duplicated. Given that the original code came from GraphicsContext3D.cpp in WebKit/chromium/src, it should be possible to refactor it into WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp. It might be necessary to split it into two routines (before/after readback), or pass a callback function. If it seems reasonable to do the refactoring, please do so.

Done.
Comment 14 Zhenyao Mo 2010-07-10 12:30:02 PDT
Created attachment 61159 [details]
revised patch: responding to Simon Fraser and kbr's review
Comment 15 Zhenyao Mo 2010-07-10 17:47:42 PDT
Created attachment 61170 [details]
revised patch: fix a bug

in WebGLRenderingContext::markedContextChanged(), always set the dirty flag when context has changed.

Also, add another test canvas-test.html for this change.  (This test is copied from WebGL conformance tests with minor modifications).
Comment 16 Zhenyao Mo 2010-07-10 18:27:53 PDT
Yike, this patch is so out-of-date.  CanvasSurface.h/cpp is gone.  Have to manually merge.

Add jamesr@chromium.org to cc list since he did the code refactoring.
Comment 17 Zhenyao Mo 2010-07-10 18:35:15 PDT
Created attachment 61172 [details]
revised patch: resolving svn merge conflicts
Comment 18 Zhenyao Mo 2010-07-13 18:15:56 PDT
Created attachment 61447 [details]
revised patch: deal with Qt part of GraphicsContext3D

Try my luck!
Comment 19 Zhenyao Mo 2010-07-13 18:18:19 PDT
Created attachment 61449 [details]
revised patch: fix a ChangeLog issue
Comment 20 Early Warning System Bot 2010-07-13 18:27:43 PDT
Attachment 61449 [details] did not build on qt:
Build output: http://webkit-commit-queue.appspot.com/results/3523150
Comment 21 Zhenyao Mo 2010-07-13 18:42:56 PDT
Created attachment 61451 [details]
revised patch: fix the Qt bug
Comment 22 Zhenyao Mo 2010-07-13 19:13:15 PDT
Created attachment 61457 [details]
revised patch

Seems like Qt/Gtk/Win bots failure may have nothing to do with CG stuff.  Revert the changes I made based on the blame-CG assumption.
Comment 23 Zhenyao Mo 2010-07-15 13:44:11 PDT
Created attachment 61712 [details]
revised patch

Using kbr's script to sync the two tests in this patch with khronos conformance tests.  No other changes,
Comment 24 Kenneth Russell 2010-07-15 14:12:35 PDT
Comment on attachment 61712 [details]
revised patch

Looks good. Thanks for waiting and keeping the tests in sync.
Comment 25 Nate Chapin 2010-07-15 15:44:00 PDT
Comment on attachment 61712 [details]
revised patch


> +#if ENABLE(3D_CANVAS)
> +    if (sourceCanvas->is3D()) {
> +        WebGLRenderingContext* context3d = reinterpret_cast<WebGLRenderingContext*>(sourceCanvas->renderingContext());
> +        context3d->paintRenderingResultsToCanvas();
> +    }
> +#endif
> +

We probably shouldn't be doing 3D things in CanvasRenderingContext2D.



> +  intervalId = window.setInterval(function() {

If there's any way to make this test work without setInterval, please do so, lest it be slow and flaky.
Comment 26 Zhenyao Mo 2010-07-15 16:49:51 PDT
Created attachment 61747 [details]
revised patch
Comment 27 Kenneth Russell 2010-07-15 16:53:47 PDT
Comment on attachment 61747 [details]
revised patch

This looks better to me.

I think the setInterval call is needed in the test (I'm not the test author but there's probably a reason it was used), but the modifications that have been made should prevent any flakiness.
Comment 28 Nate Chapin 2010-07-15 16:58:30 PDT
Comment on attachment 61747 [details]
revised patch

Alright, sounds good.
Comment 29 Zhenyao Mo 2010-07-15 18:01:14 PDT
Committed r63502: <http://trac.webkit.org/changeset/63502>
Comment 30 Zoltan Herczeg 2010-07-19 00:27:52 PDT
This patch does not builds on mac-leopard:

/Users/hzoli/WebKitHZ/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm: In member function 'void WebCore::GraphicsContext3D::paintRenderingResultsToCanvas(WebCore::WebGLRenderingContext*)':
/Users/hzoli/WebKitHZ/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:257: warning: 'mustRestoreFBO' may be used uninitialized in this function

I think it should be false by default, isn't it?
Comment 31 Kenneth Russell 2010-07-19 14:57:07 PDT
(In reply to comment #30)
> This patch does not builds on mac-leopard:
> 
> /Users/hzoli/WebKitHZ/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm: In member function 'void WebCore::GraphicsContext3D::paintRenderingResultsToCanvas(WebCore::WebGLRenderingContext*)':
> /Users/hzoli/WebKitHZ/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm:257: warning: 'mustRestoreFBO' may be used uninitialized in this function
> 
> I think it should be false by default, isn't it?

Yes, you're right. I'll upload a patch fixing this. Not sure why it wasn't caught by the bots.
Comment 32 Kenneth Russell 2010-07-19 14:58:18 PDT
Created attachment 61996 [details]
Patch fixing compiler warning

From the ChangeLog:

Fixed compiler warning introduced by original patch. No new tests; covered by existing tests.
Comment 33 Kenneth Russell 2010-07-19 18:45:47 PDT
Committed r63705: <http://trac.webkit.org/changeset/63705>
Comment 34 Simon Fraser (smfr) 2010-07-19 20:24:37 PDT
Does this fix bug 30722?
Comment 35 Kenneth Russell 2010-07-20 09:59:35 PDT
(In reply to comment #34)
> Does this fix bug 30722?

I'm not sure (and Mo is on vacation this week). Was there a test case for 30722?
Comment 36 Simon Fraser (smfr) 2010-07-22 15:08:24 PDT
This caused bug 42852.
Comment 37 Simon Fraser (smfr) 2010-07-22 17:43:24 PDT
(In reply to comment #35)
> (In reply to comment #34)
> > Does this fix bug 30722?
> 
> I'm not sure (and Mo is on vacation this week). Was there a test case for 30722?

See bug 42862.