Closed Bug 782785 Opened 12 years ago Closed 12 years ago

Compositing of WebGL canvases on B2G is broken unless canvas width is a multiple of 32

Categories

(Core :: Graphics, defect)

ARM
Gonk (Firefox OS)
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla17

People

(Reporter: bjacob, Assigned: jgilbert)

References

Details

Attachments

(1 file, 2 obsolete files)

Note that bug 782786 can also explain WebGL canvas compositing failing in B2G.
Hoho,

[Child 1069] ###!!! ASSERTION: gfxImageSurface stride isn't what we expect!: 'isurf->Stride() == mBounds.width * 4', file /hack/b2g/B2G/gecko/gfx/layers/basic/BasicCanvasLayer.cpp, line 175
[Child 1069] WARNING: ReadPixelsIntoImageSurface called with wrong size or stride surface: file /hack/b2g/B2G/gecko/gfx/gl/GLContext.cpp, line 2019
[Parent 381] WARNING: NS_ENSURE_TRUE(AttrToDataProp(attr, prop)) failed: file /hack/b2g/B2G/gecko/content/html/content/src/nsDOMStringMap.cpp, line 166

Maybe the real number is not exactly 160 but some divisor of it.
Indeed, the real criterion is: width must be a multiple of 32. So 480, 512, 544, 576 work, but not 496 or 528.
Summary: Compositing of WebGL canvases on B2G is broken unless canvas width is a multiple of 160 → Compositing of WebGL canvases on B2G is broken unless canvas width is a multiple of 32
I believe we'll end up using 32-bit surfaces when reading back, so this may mean that the surfaces need to be a multiple of 128 bytes.  That sounds suspiciously familiar ....
It looks like the destSurface we're passed in UpdateSurface is a different size than mBounds. This patch assumes (and asserts) that the destSurface is always larger than the area we're reading. We reuse the temp-surface code to create a correctly-sized buffer to read into, before copying into the destination surface.
(In reply to Chris Jones [:cjones] [:warhammer] from comment #4)
> I believe we'll end up using 32-bit surfaces when reading back

We are -- and Jeff's patch MOZ_ASSERTs that.
Works!
Comment on attachment 651940 [details] [diff] [review]
allow for readback onto too-large surfaces

Review of attachment 651940 [details] [diff] [review]:
-----------------------------------------------------------------

::: gfx/layers/basic/BasicCanvasLayer.cpp
@@ +166,4 @@
>      if (aDestSurface) {
> +      resultSurf = static_cast<gfxImageSurface*>(aDestSurface);
> +
> +      if (resultSurf->mSize != readSize) {

mSize is not public; changing this to GetSize() worked.
Attachment #651940 - Flags: review+
Hm, I replied too fast -- I had tried a build without the patch, and inadvertently used the modified page that used a size multiple of 32.

With the patch, I currently get a crash, debugging.
FYI: Last week I tried debugging the crash, but I wouldn't get any symbols when debugging a child process. Debugging the main process does find all the symbols. The GDB variables such as solib-search-path are all identical between the two cases. I followed these instructions:
https://developer.mozilla.org/en-US/docs/Mozilla/Boot_to_Gecko/Debugging_on_Boot_to_Gecko
I have not seen that problem.  You should drop by #b2g.
Depends on: 784085
Filed bug 784085 with a patch by jrmuizel that fixes it.
Here is the crash:

Program received signal SIGSEGV, Segmentation fault.
0x4199465a in mozilla::layers::BasicCanvasLayer::UpdateSurface (this=0x21b9c28, aDestSurface=0x226aa78, aMaskLayer=0x0)
    at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicCanvasLayer.cpp:185
185         MOZ_ASSERT(readSurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");
(gdb) bt
#0  0x4199465a in mozilla::layers::BasicCanvasLayer::UpdateSurface (this=0x21b9c28, aDestSurface=0x226aa78, aMaskLayer=0x0)
    at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicCanvasLayer.cpp:185
#1  0x4199532e in mozilla::layers::BasicShadowableCanvasLayer::Paint (this=0x21b9c28, aContext=0x22328b8, aMaskLayer=0x0)
    at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicCanvasLayer.cpp:442
#2  0x41991d96 in mozilla::layers::BasicLayerManager::PaintLayer (this=0x2146f48, aTarget=0x22328b8, aLayer=0x21b9c28, 
    aCallback=0x4065bde1 <mozilla::FrameLayerBuilder::DrawThebesLayer(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, nsIntRegion const&, void*)>, 
    aCallbackData=0xbee5e55c, aReadback=0xbee5dfbc) at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicLayerManager.cpp:830
#3  0x41991e28 in mozilla::layers::BasicLayerManager::PaintLayer (this=0x2146f48, aTarget=0x22328b8, aLayer=0x22326f8, 
    aCallback=0x4065bde1 <mozilla::FrameLayerBuilder::DrawThebesLayer(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, nsIntRegion const&, void*)>, 
    aCallbackData=0xbee5e55c, aReadback=0x0) at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicLayerManager.cpp:843
#4  0x419908c0 in mozilla::layers::BasicLayerManager::EndTransactionInternal (this=0x2146f48, 
    aCallback=0x4065bde1 <mozilla::FrameLayerBuilder::DrawThebesLayer(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, nsIntRegion const&, void*)>, 
    aCallbackData=0xbee5e55c, aFlags=mozilla::layers::LayerManager::END_NO_COMPOSITE) at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicLayerManager.cpp:464
#5  0x41990342 in mozilla::layers::BasicLayerManager::EndTransaction (this=0x2146f48, 
    aCallback=0x4065bde1 <mozilla::FrameLayerBuilder::DrawThebesLayer(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, nsIntRegion const&, void*)>, 
    aCallbackData=0xbee5e55c, aFlags=mozilla::layers::LayerManager::END_NO_COMPOSITE) at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicLayerManager.cpp:390
#6  0x419928c0 in mozilla::layers::BasicShadowLayerManager::EndTransaction (this=0x2146f48, 
    aCallback=0x4065bde1 <mozilla::FrameLayerBuilder::DrawThebesLayer(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, nsIntRegion const&, void*)>, 
    aCallbackData=0xbee5e55c, aFlags=mozilla::layers::LayerManager::END_NO_COMPOSITE) at /hack/b2g/B2G/gecko/gfx/layers/basic/BasicLayerManager.cpp:1043
#7  0x406a270c in nsDisplayList::PaintForFrame (this=0xbee5e940, aBuilder=0xbee5e55c, aCtx=0x0, aForFrame=0x229de38, aFlags=13)
    at /hack/b2g/B2G/gecko/layout/base/nsDisplayList.cpp:1040
#8  0x406a21ec in nsDisplayList::PaintRoot (this=0xbee5e940, aBuilder=0xbee5e55c, aCtx=0x0, aFlags=13) at /hack/b2g/B2G/gecko/layout/base/nsDisplayList.cpp:939
#9  0x406cac6e in nsLayoutUtils::PaintFrame (aRenderingContext=0x0, aFrame=0x229de38, aDirtyRegion=..., aBackstop=4294967295, aFlags=772)
    at /hack/b2g/B2G/gecko/layout/base/nsLayoutUtils.cpp:1868
#10 0x406edbd0 in PresShell::Paint (this=0x2291cc8, aViewToPaint=0x21a5010, aDirtyRegion=..., aType=nsIPresShell::PaintType_NoComposite, aWillSendDidPaint=true)
    at /hack/b2g/B2G/gecko/layout/base/nsPresShell.cpp:5337
#11 0x40c8320e in nsViewManager::ProcessPendingUpdatesForView (this=0x21b7128, aView=0x21a5010, aFlushDirtyRegion=true)
    at /hack/b2g/B2G/gecko/view/src/nsViewManager.cpp:428
#12 0x40c85596 in nsViewManager::ProcessPendingUpdates (this=0x21b7128) at /hack/b2g/B2G/gecko/view/src/nsViewManager.cpp:1369
#13 0x406fc034 in nsRefreshDriver::Notify (this=0x21b4c90, aTimer=0x2327b48) at /hack/b2g/B2G/gecko/layout/base/nsRefreshDriver.cpp:421
#14 0x418aa8f2 in nsTimerImpl::Fire (this=0x2327b48) at /hack/b2g/B2G/gecko/xpcom/threads/nsTimerImpl.cpp:476
#15 0x418aacae in nsTimerEvent::Run (this=0x1f500b0) at /hack/b2g/B2G/gecko/xpcom/threads/nsTimerImpl.cpp:556
#16 0x418a4c1a in nsThread::ProcessNextEvent (this=0x1f49c20, mayWait=false, result=0xbee5ee07) at /hack/b2g/B2G/gecko/xpcom/threads/nsThread.cpp:624
#17 0x4184a1ca in NS_ProcessNextEvent_P (thread=0x1f49c20, mayWait=false) at /hack/b2g/B2G/objdir-gecko/xpcom/build/nsThreadUtils.cpp:220
#18 0x416949ee in mozilla::ipc::MessagePump::Run (this=0x1f3e370, aDelegate=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/glue/MessagePump.cpp:82
#19 0x41694e6a in mozilla::ipc::MessagePumpForChildProcess::Run (this=0x1f3e370, aDelegate=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/glue/MessagePump.cpp:211
#20 0x418f2e60 in MessageLoop::RunInternal (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:208
#21 0x418f2dfa in MessageLoop::RunHandler (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:201
#22 0x418f2da2 in MessageLoop::Run (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:175
#23 0x4156581e in nsBaseAppShell::Run (this=0x2129150) at /hack/b2g/B2G/gecko/widget/xpwidgets/nsBaseAppShell.cpp:163
#24 0x404133c6 in XRE_RunAppShell () at /hack/b2g/B2G/gecko/toolkit/xre/nsEmbedFunctions.cpp:646
---Type <return> to continue, or q <return> to quit---
#25 0x41694dc4 in mozilla::ipc::MessagePumpForChildProcess::Run (this=0x1f3e370, aDelegate=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/glue/MessagePump.cpp:197
#26 0x418f2e60 in MessageLoop::RunInternal (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:208
#27 0x418f2dfa in MessageLoop::RunHandler (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:201
#28 0x418f2da2 in MessageLoop::Run (this=0xbee5f90c) at /hack/b2g/B2G/gecko/ipc/chromium/src/base/message_loop.cc:175
#29 0x40412e7c in XRE_InitChildProcess (aArgc=3, aArgv=0xbee5fa94, aProcess=GeckoProcessType_Content) at /hack/b2g/B2G/gecko/toolkit/xre/nsEmbedFunctions.cpp:485
#30 0x000085be in main (argc=5, argv=0xbee5fa94) at /hack/b2g/B2G/gecko/ipc/app/MozillaRuntimeMain.cpp:48
(gdb) p readSurf.get()->Stride()
$4 = 2048
(gdb) p mBounds.width
$5 = 500
(gdb) p readSurf.get()->Width()
$7 = 500

Jeff Muizelaar tells me that there is absolutely no guarantee that Stride == 4 * Width so that assertion is wrong. The only guarantee is Stride >= 4 & Width.
Normally we would want to force an explicit stride when creating this surface. But I don't know how to do that. The surface here is a AutoOpenSurface (it is the aDestSurface passed to UpdateSurface). I don't know anything about that stuff, or why it would use such a large stride (2048 bytes for width=500 means 48 extra bytes or 12 extra pixels).
(In reply to Benoit Jacob [:bjacob] from comment #18)
> Normally we would want to force an explicit stride when creating this
> surface. But I don't know how to do that. The surface here is a
> AutoOpenSurface (it is the aDestSurface passed to UpdateSurface). I don't
> know anything about that stuff, or why it would use such a large stride
> (2048 bytes for width=500 means 48 extra bytes or 12 extra pixels).

Maybe it's reusing a surface that's >= the requested width,height?
Try this?
Attachment #651940 - Attachment is obsolete: true
Attachment #653567 - Flags: review?(bjacob)
This seems to be severely bitrotted.
(In reply to Chris Jones [:cjones] [:warhammer] from comment #21)
> This seems to be severely bitrotted.

It applies cleanly for me. What problem are you seeing?
$ hg tip
changeset:   102864:0900ffbccd14
tag:         tip
user:        Wes Kocher <wkocher@mozilla.com>
date:        Mon Aug 20 16:13:46 2012 -0500
summary:     Bug 784113 - Update Jetpack code being tested against mozilla-central.

$ hg qimport -n webgl https://bugzilla.mozilla.org/attachment.cgi?id=653567
adding webgl to series file
$ hg qpush
applying webgl
patching file gfx/gl/GLContext.cpp
Hunk #2 FAILED at 1992
1 out of 2 hunks FAILED -- saving rejects to file gfx/gl/GLContext.cpp.rej
patching file gfx/gl/GLContext.h
Hunk #1 FAILED at 1379
1 out of 1 hunks FAILED -- saving rejects to file gfx/gl/GLContext.h.rej
patching file gfx/layers/basic/BasicCanvasLayer.cpp
Hunk #2 FAILED at 149
1 out of 2 hunks FAILED -- saving rejects to file gfx/layers/basic/BasicCanvasLayer.cpp.rej
patching file gfx/layers/d3d10/CanvasLayerD3D10.cpp
Hunk #1 FAILED at 152
1 out of 1 hunks FAILED -- saving rejects to file gfx/layers/d3d10/CanvasLayerD3D10.cpp.rej
patching file gfx/layers/d3d9/CanvasLayerD3D9.cpp
Hunk #1 FAILED at 102
1 out of 1 hunks FAILED -- saving rejects to file gfx/layers/d3d9/CanvasLayerD3D9.cpp.rej
patching file gfx/layers/opengl/CanvasLayerOGL.cpp
Hunk #1 FAILED at 201
1 out of 1 hunks FAILED -- saving rejects to file gfx/layers/opengl/CanvasLayerOGL.cpp.rej
patch failed, unable to continue (try -v)
patch failed, rejects left in working dir
errors during apply, please fix and refresh webgl
You're applying against inbound, not m-c. Inbound has at least one patch from me that breaks this.
Specifically, bug 783663 conflicts with this. I'll de-bitrot it tomorrow assuming bug 783663 survives the merge.
Does that make it more or less bitrotted? ;)
The new patch works!
Comment on attachment 653567 [details] [diff] [review]
Use temp surfaces with correct stride for reads.

Review of attachment 653567 [details] [diff] [review]:
-----------------------------------------------------------------

::: gfx/layers/basic/BasicCanvasLayer.cpp
@@ +200,5 @@
>      if (currentFramebuffer != mCanvasFramebuffer)
>        mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
>  
>      // We need to Flush() the surface before modifying it outside of cairo.
> +    readSurf->Flush();

Can you explain the flushes there? What was the conclusion from the discussion of whether flushes have any usefulness? The world will end in finite time, too.
Attachment #653567 - Flags: review?(bjacob) → review+
Oh oops, that's a surface flush, not a glFlush. Sorry.
Whiteboard: [rplus]
Attached patch de-bitrottedSplinter Review
Patch to push.
Assignee: nobody → jgilbert
Attachment #653567 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #653997 - Flags: review+
https://hg.mozilla.org/mozilla-central/rev/854c1028d147
Status: ASSIGNED → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla17
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: