Closed
Bug 875218
Opened 11 years ago
Closed 11 years ago
Skia/GL: Valgrind says that we are leaking the entire Skia GrContext
Categories
(Core :: Graphics: Canvas2D, defect)
Tracking
()
RESOLVED
FIXED
People
(Reporter: bjacob, Unassigned)
References
Details
Attachments
(6 files, 2 obsolete files)
7.36 KB,
patch
|
bjacob
:
review+
|
Details | Diff | Splinter Review |
32.13 KB,
patch
|
Details | Diff | Splinter Review | |
3.38 KB,
patch
|
mattwoodrow
:
review+
|
Details | Diff | Splinter Review |
29.42 KB,
patch
|
mattwoodrow
:
review+
|
Details | Diff | Splinter Review |
2.80 KB,
patch
|
gw280
:
review+
|
Details | Diff | Splinter Review |
936 bytes,
patch
|
mattwoodrow
:
review+
|
Details | Diff | Splinter Review |
Running online Canvas 2D tests, and quitting the browser, Valgrind memcheck claims that we're leaking lots of memory, ==12176== LEAK SUMMARY: ==12176== definitely lost: 1,034,257 bytes in 4,104 blocks ==12176== indirectly lost: 26,698,847 bytes in 24,091 blocks ==12176== possibly lost: 174,632,314 bytes in 325,330 blocks and most of it seems to originate from a single issue, namely, that we leak the Skia GrContext. The log is huge, but the first relevant report is ==12176== 24 bytes in 1 blocks are possibly lost in loss record 3,098 of 17,272 ==12176== at 0x402C7C1: malloc (vg_replace_malloc.c:292) ==12176== by 0x4041EE4: moz_xmalloc (mozalloc.cpp:54) ==12176== by 0x85E7E8F: GrContext::init(GrBackend, long) (mozalloc.h:201) ==12176== by 0x85E7EEB: GrContext::Create(GrBackend, long) (GrContext.cpp:71) ==12176== by 0x827BDC1: gfxPlatform::CreateDrawTargetForFBO(unsigned int, mozilla::gl::GLContext*, mozilla::gfx::IntSize const&, mozilla::gfx::SurfaceFormat) (gfxPlatform.cpp:817) ==12176== by 0x73B0EC1: mozilla::dom::CanvasRenderingContext2D::EnsureTarget() (CanvasRenderingContext2D.cpp:805) ==12176== by 0x73B86A0: mozilla::dom::CanvasRenderingContext2D::GetInputStream(char const*, unsigned short const*, nsIInputStream**) (CanvasRenderingContext2D.cpp:974) ==12176== by 0x7458EF1: mozilla::dom::HTMLCanvasElement::ExtractData(nsAString_internal const&, nsAString_internal const&, nsIInputStream**, bool&) (HTMLCanvasElement.cpp:438) ==12176== by 0x745965C: mozilla::dom::HTMLCanvasElement::ToDataURLImpl(JSContext*, nsAString_internal const&, JS::Value const&, nsAString_internal&) (HTMLCanvasElement.cpp:530) ==12176== by 0x7FE5F5A: mozilla::dom::HTMLCanvasElement::ToDataURL(JSContext*, nsAString_internal const&, mozilla::dom::Optional<mozilla::dom::LazyRootedValue> const&, nsAString_internal&, mozilla::ErrorResult&) (HTMLCanvasElement.h:111) ==12176== by 0x7FE61FF: mozilla::dom::HTMLCanvasElementBinding::toDataURL(JSContext*, JS::Handle<JSObject*>, mozilla::dom::HTMLCanvasElement*, unsigned int, JS::Value*) (HTMLCanvasElementBinding.cpp:202) ==12176== by 0x7FE5B1B: mozilla::dom::HTMLCanvasElementBinding::genericMethod(JSContext*, unsigned int, JS::Value*) (HTMLCanvasElementBinding.cpp:574) And after that, we have a bunch of leak reports for stuff under GrContext, including apparently every GL-related structure under it --- it seems that we're just never freeing either the OpenGL resources or the other kinds of resources allocated by SkiaGL. OpenGL example: ==12176== 83,165,184 bytes in 2,538 blocks are possibly lost in loss record 17,272 of 17,272 ==12176== at 0x402C7C1: malloc (vg_replace_malloc.c:292) ==12176== by 0x2E5D031F: ??? (in /usr/lib/x86_64-linux-gnu/dri/i965_dri.so) ==12176== by 0x2E8C2D88: _mesa_BufferDataARB (in /usr/lib/x86_64-linux-gnu/dri/libdricore.so) ==12176== by 0x73C7036: mozilla::gl::GLContext::raw_fBufferData(unsigned int, long, void const*, unsigned int) (GLContext.h:1702) ==12176== by 0x73C70CD: mozilla::gl::GLContext::fBufferData(unsigned int, long, void const*, unsigned int) (GLContext.h:1708) ==12176== by 0x862080F: GrGpuGL::onCreateVertexBuffer(unsigned int, bool) (GrGpuGL.cpp:1169) ==12176== by 0x85DD531: GrBufferAllocPool::GrBufferAllocPool(GrGpu*, GrBufferAllocPool::BufferType, bool, unsigned long, int) (GrBufferAllocPool.cpp:48) ==12176== by 0x85DD5A5: GrVertexBufferAllocPool::GrVertexBufferAllocPool(GrGpu*, bool, unsigned long, int) (GrBufferAllocPool.cpp:386) ==12176== by 0x85E3F4F: GrContext::setupDrawBuffer() (GrContext.cpp:1605) ==12176== by 0x85E7EAA: GrContext::init(GrBackend, long) (GrContext.cpp:129) ==12176== by 0x85E7EEB: GrContext::Create(GrBackend, long) (GrContext.cpp:71) ==12176== by 0x827BDC1: gfxPlatform::CreateDrawTargetForFBO(unsigned int, mozilla::gl::GLContext*, mozilla::gfx::IntSize const&, mozilla::gfx::SurfaceFormat) (gfxPlatform.cpp:817) ==12176= Non-OpenGL example: ==12176== 48 bytes in 1 blocks are possibly lost in loss record 7,189 of 17,272 ==12176== at 0x402C877: malloc (vg_replace_malloc.c:291) ==12176== by 0x402C8F1: realloc (vg_replace_malloc.c:688) ==12176== by 0x859F7F2: sk_realloc_throw(void*, unsigned long) (SkMemory_malloc.cpp:27) ==12176== by 0x85FB3BE: SkTDArray<GrResourceEntry*>::growBy(unsigned long) (SkTDArray.h:355) ==12176== by 0x85FB478: SkTDArray<GrResourceEntry*>::insert(unsigned long, unsigned long, GrResourceEntry* const*) (SkTDArray.h:197) ==12176== by 0x85FB4FF: GrTHashTable<GrResourceEntry, GrResourceKey, 8ul>::insert(GrResourceKey const&, GrResourceEntry*) (GrTHashCache.h:172) ==12176== by 0x85FB67A: GrResourceCache::addResource(GrResourceKey const&, GrResource*, unsigned int) (GrResourceCache.cpp:215) ==12176== by 0x85E7478: GrContext::createTexture(GrTextureParams const*, GrTextureDesc const&, GrCacheID const&, void*, unsigned long) (GrContext.cpp:421) ==12176== by 0x86086CC: sk_gr_create_bitmap_texture(GrContext*, bool, GrTextureParams const*, SkBitmap const&) (SkGr.cpp:142) ==12176== by 0x8608841: GrLockAndRefCachedBitmapTexture(GrContext*, SkBitmap const&, GrTextureParams const*) (SkGr.cpp:189) ==12176== by 0x8604A4F: SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice*, SkBitmap const&, GrTextureParams const*) (SkGpuDevice.cpp:115) ==12176== by 0x8604AC9: SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture(SkGpuDevice*, SkBitmap const&, GrTextureParams const*, GrTexture**) (SkGpuDevice.cpp:95)
Reporter | ||
Comment 1•11 years ago
|
||
The other part of this leak is we're leaking the DrawTargets: ==12176== 96 bytes in 1 blocks are possibly lost in loss record 10,777 of 17,272 ==12176== at 0x402C877: malloc (vg_replace_malloc.c:291) ==12176== by 0x402C8F1: realloc (vg_replace_malloc.c:688) ==12176== by 0x859F7F2: sk_realloc_throw(void*, unsigned long) (SkMemory_malloc.cpp:27) ==12176== by 0x85791A6: SkTDArray<SkClipStack::ClipCallbackData>::growBy(unsigned long) (SkTDArray.h:355) ==12176== by 0x8579241: SkTDArray<SkClipStack::ClipCallbackData>::append(unsigned long, SkClipStack::ClipCallbackData const*) (SkTDArray.h:176) ==12176== by 0x8579299: SkClipStack::addPurgeClipCallback(void (*)(int, void*), void*) const (SkClipStack.cpp:731) ==12176== by 0x857325C: SkCanvas::setDevice(SkDevice*) (SkCanvas.cpp:624) ==12176== by 0x853A9EE: mozilla::gfx::DrawTargetSkia::InitWithFBO(unsigned int, GrContext*, mozilla::gfx::IntSize const&, mozilla::gfx::SurfaceFormat) (DrawTargetSkia.cpp: 657) ==12176== by 0x85298AB: mozilla::gfx::Factory::CreateSkiaDrawTargetForFBO(unsigned int, GrContext*, mozilla::gfx::IntSize const&, mozilla::gfx::SurfaceFormat) (Factory.cpp:448) ==12176== by 0x827BDF0: gfxPlatform::CreateDrawTargetForFBO(unsigned int, mozilla::gl::GLContext*, mozilla::gfx::IntSize const&, mozilla::gfx::SurfaceFormat) (gfxPlatform.cpp:822) ==12176== by 0x73B0EC1: mozilla::dom::CanvasRenderingContext2D::EnsureTarget() (CanvasRenderingContext2D.cpp:805) ==12176== by 0x73B62EC: mozilla::dom::CanvasRenderingContext2D::EnsureWritablePath() (CanvasRenderingContext2D.cpp:1862) It's not clear to me how we manage to leak them, as they are reference-counted and we don't create cycles.
Comment 2•11 years ago
|
||
I've been enumerating through the possibilities for how best to deal with the GrContext leaking, but I can't think of a better way to do it than to modify the GLContext itself. The issue being that we want to be able to maintain a 1:1 mapping of GrContext<->GLContext, and ensure the GrContext gets destroyed when the GLContext gets destroyed.
Attachment #754064 -
Flags: review?(bjacob)
Reporter | ||
Comment 3•11 years ago
|
||
Comment on attachment 754064 [details] [diff] [review] Manage GrContext deletion Review of attachment 754064 [details] [diff] [review]: ----------------------------------------------------------------- There is no way that it is legitimate for class GLContext, which should be a thin abstraction over an OpenGL or OpenGL ES context and framebuffer, to have anything Skia-specific. Let's talk about this next week.
Attachment #754064 -
Flags: review?(bjacob) → review-
Comment 4•11 years ago
|
||
OK, so I think to solve the "independent of GLContext" bit will be to ensure that we maintain the std::map in GLContextSkia (which implements CreateGrContextFromGLContext) which will ensure that if we call CreateGrContextFromGLContext with a GLContext that already has an associated GrContext, we just return that, but that still won't solve the issue of ensuring the GrContext gets deleted when the GLContext goes away. Unfortunately, I really don't see any method short of some pretty unsavoury code that will satisfy the deletion, as logically the GLContext owns the GrContext. The best I can come up with right now is adding functionality to set a user callback that gets called when the GLContext gets destroyed, which will ensure our GrContext gets deleted. That ensures that GLContext doesn't have any knowledge of Skia itself. Alternatively: we could look into ensuring that for Skia purposes, the CanvasRenderingContext2D is the sole owner of the GLContext (which it currently is, but it's not currently the owner of the GrContext) and the GrContext, then ensure deletion occurs properly in there. The issue I have with this, though, is that we will need to be very careful in the future if/when we start to own GLContexts for Skia/GL purposes in different parts of the codebase (for content, for example).
Comment 5•11 years ago
|
||
What's the problem with just having the DrawTargetSkia (or a new DrawTargetSkiaGL) own the GrContext?
Comment 6•11 years ago
|
||
The GrContext needs to be managed alongside the GLContext, so unless the DrawTargetSkia owns the GLContext as well (which it can't, due to Azure dependencies not being allowed in that direction), it won't help us.
Comment 7•11 years ago
|
||
(In reply to George Wright (:gw280) from comment #6) > The GrContext needs to be managed alongside the GLContext, so unless the > DrawTargetSkia owns the GLContext as well (which it can't, due to Azure > dependencies not being allowed in that direction), it won't help us. One thing that seems weird to me is that we can have multiple DrawTargets using the same GLContext (and by extension, GrContext). Does that really happen in practice? I guess the idea would be that you could pass a different FBO (but we don't)? If we could eliminate the need for this, the ownership of the GrContext could be separated from the GLContext and instead transferred to DrawTargetSkia.
Reporter | ||
Comment 8•11 years ago
|
||
Filed bug 876859 about the DrawTarget leak.
Comment 9•11 years ago
|
||
Attachment #754064 -
Attachment is obsolete: true
Attachment #755622 -
Flags: review?(bjacob)
Reporter | ||
Comment 10•11 years ago
|
||
Comment on attachment 755622 [details] [diff] [review] Hold GrContext in an SkRefPtr Review of attachment 755622 [details] [diff] [review]: ----------------------------------------------------------------- I must be getting something wrong here, because if the reasoning below is correct, we are immediately destroying the GrContext we just created. Where is my mistake? ::: gfx/thebes/gfxPlatform.cpp @@ +809,4 @@ > gfxPlatform::CreateDrawTargetForFBO(unsigned int aFBOID, mozilla::gl::GLContext* aGLContext, const IntSize& aSize, SurfaceFormat aFormat) > { > NS_ASSERTION(mPreferredCanvasBackend, "No backend."); > + RefPtr<DrawTarget> target = nullptr; Please configure your git or hg to generate patches with 8 lines of context. @@ +813,5 @@ > #ifdef USE_SKIA_GPU > if (mPreferredCanvasBackend == BACKEND_SKIA) { > static uint8_t sGrContextKey; > + GrGLInterface* grInterface = CreateGrInterfaceFromGLContext(aGLContext); > + SkRefPtr<GrContext> ctx = GrContext::Create(kOpenGL_Shaders_GrEngine, (GrPlatform3DContext)grInterface); If I understand correctly, at this point the refcount of *ctx is 1... @@ +817,5 @@ > + SkRefPtr<GrContext> ctx = GrContext::Create(kOpenGL_Shaders_GrEngine, (GrPlatform3DContext)grInterface); > + > + // Unfortunately Factory can't depend on GLContext, so it needs to be passed a > + // GrContext instead. > + target = Factory::CreateSkiaDrawTargetForFBO(aFBOID, ctx, aSize, aFormat); If I understand correctly, the newly created target holds a RefPtr to *ctx, so at this point the refcount of *ctx is now 2... @@ +819,5 @@ > + // Unfortunately Factory can't depend on GLContext, so it needs to be passed a > + // GrContext instead. > + target = Factory::CreateSkiaDrawTargetForFBO(aFBOID, ctx, aSize, aFormat); > + // Finally, unref ctx as we are passing ownership to DrawTargetSkia > + ctx->unref(); So now the recount of *ctx is back to 1... @@ +824,1 @@ > } Now the |ctx| RefPtr has gone out of scope, which, if I understand correctly, decrements the refcount of *ctx, so at this point the refcount goes to 0 and *ctx gets destroyed. Is this correct?
Attachment #755622 -
Flags: review?(bjacob)
Comment 11•11 years ago
|
||
Huh, that's right. I wonder why it didn't crash then when I tested it...
Comment 12•11 years ago
|
||
Let's fix this.
Attachment #755622 -
Attachment is obsolete: true
Attachment #757563 -
Flags: review?(bjacob)
Reporter | ||
Comment 13•11 years ago
|
||
Comment on attachment 757563 [details] [diff] [review] GrContext management v2 Review of attachment 757563 [details] [diff] [review]: ----------------------------------------------------------------- ::: gfx/thebes/gfxPlatform.cpp @@ +830,3 @@ > > + // Unfortunately Factory can't depend on GLContext, so it needs to be passed a > + // GrContext instead. trailing space
Attachment #757563 -
Flags: review?(bjacob) → review+
Comment 15•11 years ago
|
||
Backed out because of build bustage: https://hg.mozilla.org/integration/mozilla-inbound/rev/14b5a5165e47
Comment 16•11 years ago
|
||
/me sobs
Reporter | ||
Comment 17•11 years ago
|
||
Fixed by http://hg.mozilla.org/projects/graphics/rev/cc14e4fce5cb on the Graphics branch.
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Comment 18•11 years ago
|
||
Comment 19•11 years ago
|
||
Comment 20•11 years ago
|
||
Updated•11 years ago
|
Attachment #769690 -
Flags: review?(matt.woodrow)
Attachment #769690 -
Flags: review?(gwright)
Updated•11 years ago
|
Attachment #769691 -
Flags: review?(matt.woodrow)
Attachment #769691 -
Flags: review?(gwright)
Updated•11 years ago
|
Attachment #769692 -
Flags: review?(matt.woodrow)
Attachment #769692 -
Flags: review?(gwright)
Comment 21•11 years ago
|
||
George, Matt: these are bjacob's patches from last week (or earlier). We need them to be reviewed before landing the graphics branch. Whoever can get to them first wins the prize!
Comment 22•11 years ago
|
||
Comment on attachment 769690 [details] [diff] [review] Refactor the ownership model under DrawTargetSkia Review of attachment 769690 [details] [diff] [review]: ----------------------------------------------------------------- ::: content/canvas/src/CanvasRenderingContext2D.cpp @@ +810,5 @@ > + GLContext::ContextFlagsNone); > + > + if (glContext) { > + mTarget = Factory::CreateUninitializedDrawTargetSkiaWithGLContext(glContext); > + GrGLInterface* i = CreateGrInterfaceFromDrawTarget(mTarget); This should be SkTAutoUnref. It's really weird to have a raw pointer to a refcounted object, and then expect an object to take ownership of it without adding a reference. ::: gfx/2d/2D.h @@ +870,5 @@ > + > +#ifdef USE_SKIA_GPU > + virtual void InitWithGrGLInterface(GrGLInterface* aGrGLInterface, > + const IntSize &aSize, > + SurfaceFormat aFormat) I really don't like this API change. Can someone explain why we need to construct this using two calls, rather than one (like all the other DT types).
Comment 23•11 years ago
|
||
Kinda ugly to have mozilla includes in skia code, but we need to stop this sort of bug happening again.
Attachment #769778 -
Flags: review?(gwright)
Comment 24•11 years ago
|
||
Comment on attachment 769691 [details] [diff] [review] Fix refcounting issues Review of attachment 769691 [details] [diff] [review]: ----------------------------------------------------------------- ::: gfx/2d/DrawTargetSkia.cpp @@ +658,5 @@ > + // The SkAutoTUnref's here ensure that we do not addref aGrGLInterface and the > + // newly created GrContext: in the Skia/WebKit world, refcounted objects are born > + // already addref'd! Accidentally addref'ing them a second time by assigning them > + // to SkRefPtr's is a cause of leaks. > + mGrGLInterface = SkAutoTUnref<GrGLInterface>(aGrGLInterface); This change can go away with my suggestion from the other patch. Adding a reference to the raw pointer passed in here makes sense.
Attachment #769691 -
Flags: review?(matt.woodrow)
Attachment #769691 -
Flags: review?(gwright)
Attachment #769691 -
Flags: review+
Updated•11 years ago
|
Attachment #769692 -
Flags: review?(matt.woodrow)
Attachment #769692 -
Flags: review?(gwright)
Attachment #769692 -
Flags: review+
Reporter | ||
Comment 25•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #22) > Comment on attachment 769690 [details] [diff] [review] > Refactor the ownership model under DrawTargetSkia > > Review of attachment 769690 [details] [diff] [review]: > ----------------------------------------------------------------- > > ::: content/canvas/src/CanvasRenderingContext2D.cpp > @@ +810,5 @@ > > + GLContext::ContextFlagsNone); > > + > > + if (glContext) { > > + mTarget = Factory::CreateUninitializedDrawTargetSkiaWithGLContext(glContext); > > + GrGLInterface* i = CreateGrInterfaceFromDrawTarget(mTarget); > > This should be SkTAutoUnref. It's really weird to have a raw pointer to a > refcounted object, and then expect an object to take ownership of it without > adding a reference. I agree that this is weird, but this is what Skia (or WebKit, or Blink) reference counting conventions are. Let's paste one more line of context here: mTarget = Factory::CreateUninitializedDrawTargetSkiaWithGLContext(glContext); GrGLInterface* i = CreateGrInterfaceFromDrawTarget(mTarget); mTarget->InitWithGrGLInterface(i, size, format); Let's go inside InitWithGrGLInterface, in DrawTargetSkia.cpp: mGrGLInterface = SkAutoTUnref<GrGLInterface>(aGrGLInterface); mGrContext = SkAutoTUnref<GrContext>(GrContext::Create(kOpenGL_GrBackend, backendContext)); So yes, it's true that passing this already-addref'd aGrGLInterface forces InitWithGrGLInterface to wrap it in a SkAutoTUnref... but at the next line, it has to do the same anyway for the context, because Skia's GrContext::Create does exactly the same --- return a plain pointer to something that is already addref'd. In fact, the problem boils down to refcounted objects being created with a refcount of 1 in the Skia/WebKit/Blink world, so that 'operator new' is the basic, unavoidable source of plain pointers to already-addrefed objects. See this email to dev-platform: https://groups.google.com/forum/#!topic/mozilla.dev.platform/0Xe5YLQDkuU I don't like this refcounting syntax at all --- I much prefer Mozilla's approach --- but we don't get to choose that. I think that the 'GrGLInterface* i' should stay the way that it is. It's in fact only used to split a long line of C++ into two lines of code, and the thing that it's communicating from one line of code to the next, _is_ a 'GrGLInterface*'.
Reporter | ||
Comment 26•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #23) > Created attachment 769778 [details] [diff] [review] > Hook SkRefCnt into our leak reporting tools > > Kinda ugly to have mozilla includes in skia code, but we need to stop this > sort of bug happening again. Just to be clear, there was no bug remaining here --- no GrGLInterface is being leaked here anymore, because the SkTAutoUnref wrapping was done in the callee, InitWithGrGLInterface. That said, more leak reporting tools are very helpful! Especially with Skia using reference-counting semantics that differ in tricky ways from ours.
Reporter | ||
Comment 27•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #22) > ::: gfx/2d/2D.h > @@ +870,5 @@ > > + > > +#ifdef USE_SKIA_GPU > > + virtual void InitWithGrGLInterface(GrGLInterface* aGrGLInterface, > > + const IntSize &aSize, > > + SurfaceFormat aFormat) > > I really don't like this API change. Can someone explain why we need to > construct this using two calls, rather than one (like all the other DT > types). Indeed, this really deserves an explanation. I tried very hard to make it a single creation call, as you suggest and mention is done for other DrawTarget types. The basic problem here is that multiple things need to be created at the same time: * the GLContext * the GrGLInterface * the DrawTargetSkia If it were just that, then we could still hide the creation of all these things inside of a single function. But the next problem is that Moz2D doesn't want to have a dependency on GLContext. So the GLContext itself has to be created separately. One could then ask: why not have DrawTargetSkia take a GLContext, and take care of creating the GrGLInterface wrapping it? The answer is again: because DrawTargetSkia is in moz2d, which can't depend on GLContext, and creating a GrGLInterface wrapper requires the definition of GLContext, at least to determine whether it's a ES or non-ES context --- see towards the end of CreateGrInterfaceFromDrawTarget, in GLContextSkia.cpp: // We support both desktop GL and GLES2 GLContext* context = static_cast<GLContext*>(drawTarget->GetGLContext()); if (context->IsGLES2()) { i->fBindingsExported = kES2_GrGLBinding; } else { i->fBindingsExported = kDesktop_GrGLBinding; } We could of course extract that information, pass it around as a separate argument... but I think you'd agree that that would be worse. In the end, we are creating multiple things that don't want to depend on each other but whose creation needs information from each other, so we have a solid reason to do this in more than one call. I actually like that Moz2D gains the ability to create a SkiaGL draw target from a GrGLInterface, because that (contrary to our GLContext) is the standard way for Skia to call into an arbitrary GL implementation. Before the present patches, it was not possible at all to use moz2d with Skia/GL without dependency on libxul with anything else than the default system GL. Now, it's very easy, you just need to provide a Skia GrGLInterface.
Comment 28•11 years ago
|
||
(In reply to Benoit Jacob [:bjacob] from comment #25) > > I agree that this is weird, but this is what Skia (or WebKit, or Blink) > reference counting conventions are. Let's paste one more line of context > here: > > mTarget = > Factory::CreateUninitializedDrawTargetSkiaWithGLContext(glContext); > GrGLInterface* i = CreateGrInterfaceFromDrawTarget(mTarget); > mTarget->InitWithGrGLInterface(i, size, format); > > Let's go inside InitWithGrGLInterface, in DrawTargetSkia.cpp: > > mGrGLInterface = SkAutoTUnref<GrGLInterface>(aGrGLInterface); > mGrContext = SkAutoTUnref<GrContext>(GrContext::Create(kOpenGL_GrBackend, > backendContext)); > > So yes, it's true that passing this already-addref'd aGrGLInterface forces > InitWithGrGLInterface to wrap it in a SkAutoTUnref... but at the next line, > it has to do the same anyway for the context, because Skia's > GrContext::Create does exactly the same --- return a plain pointer to > something that is already addref'd. > > In fact, the problem boils down to refcounted objects being created with a > refcount of 1 in the Skia/WebKit/Blink world, so that 'operator new' is the > basic, unavoidable source of plain pointers to already-addrefed objects. > > See this email to dev-platform: > https://groups.google.com/forum/#!topic/mozilla.dev.platform/0Xe5YLQDkuU > > I don't like this refcounting syntax at all --- I much prefer Mozilla's > approach --- but we don't get to choose that. > > I think that the 'GrGLInterface* i' should stay the way that it is. It's in > fact only used to split a long line of C++ into two lines of code, and the > thing that it's communicating from one line of code to the next, _is_ a > 'GrGLInterface*'. The standard skia conventions that I see are either: Object *obj = Object::Create(); // use obj. obj->unref(); or SkTAutoUnref<Object> obj(Object::Create()); // use obj. The important part is that the unref (implicit through SkTAutoUnref or explicit) is in the same scope as the ::Create call. The convention is indeed different to ours, but it's still easy enough to track when reference counts change. Taking an already refed object and handing over ownership to a child without changing reference counts is much more confusing. For the GrContext we should do: SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, backendContext)); mGrContext = gr.get();
Reporter | ||
Comment 29•11 years ago
|
||
Oh, one more thing: you might ask, why is the GrGLInterface-creating function taking a DrawTargetSkia, and not a GLContext --- since all it really seems to need, is the DT's GLContext? The answer is that the GrGLInterface needs to be able to get back to the GLContext, but it can only have a raw pointer to it, because that's how Skia works (besides, Skia has no idea how to do mozilla refcounting). We felt very uncomfortable about this unavoidable raw pointer from a Skia object (the GrGLInterface) to a mozilla object (the GLContext)... especially as it was shown to actually go dangling and be a cause of crashes. So we refactored the ownership model between the objects at hand here (the CanvasRenderingContext2D, the DrawTargetSkia, the GLContext, the Skia GrContext/GrGLInterface) to make this raw pointer the least scary possible (and in particular, to make it provably never-dangling). Here's the old (current mozilla-central, before merging in the graphics branch) ownership model: _ _ _ _ CanvasRenderingContext2D / | | | V | regular Gecko stuff | (libxul) GLContext | | ^ | . | ---------------------|----------------------------------- . | . | . V . DrawTargetSkia Moz2D . | . | ---------------------|----------------------------------- . | . V . . . . GrContext Skia Here the plain arrows are strong references, See the long backwards dotted arrow (dotted means raw pointer) from the GrContext (I'm hiding the GrGLInterface behind the GrContext for simplicity, but of course it's really from the GrGLInterface) to the GLContext. The new ownership model, post-ownership-refactoring, currently on graphics branch, is: CanvasRenderingContext2D | GLContext | ^ | regular Gecko stuff | | (libxul) \ | ----------\----------|----------------------------------- \ | \ | \ | Moz2D \ | \ V DrawTargetSkia ^ | . | ------------------.--|----------------------------------- . | . V GrContext Skia Indeed, we decided (we == George and I) that the least scary kind of raw pointer is a raw pointer that just walks back a strong reference. Since the DrawTargetSkia keeps the GrContext/GrGLInterface objects alive, it's not too bad to have them have a raw pointer back to the DrawTargetSkia --- it's easy to ensure that such a raw pointer never goes dangling. Some more details in here (this was discussed at length during Skia meetings): https://wiki.mozilla.org/Mobile/SkiaGL#ownership_model Anyway, I hope that this explains why GLContextSkia.cpp offers a CreateGrInterfaceFromDrawTarget and not a CreateGrInterfaceFromGLContext.
Reporter | ||
Comment 30•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #28) > The standard skia conventions that I see are either: > > Object *obj = Object::Create(); > // use obj. > obj->unref(); > > or > > SkTAutoUnref<Object> obj(Object::Create()); > // use obj. > > The important part is that the unref (implicit through SkTAutoUnref or > explicit) is in the same scope as the ::Create call. I'm OK with the second way. I don't want to oppose the change you're suggesting, I was just explaining how the current code was non-leaking and perhaps even sane. Not opposing the change you're suggesting though, so do feel free. As long as we use SkTAutoUnref suitably so that we don't leak or crash, and as long as we don't make any manual calls to unref(), I'm happy. > For the GrContext we should do: > > SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, > backendContext)); > mGrContext = gr.get(); That's equivalent to the current code, mGrContext = SkAutoTUnref<GrContext>(GrContext::Create(kOpenGL_GrBackend, backendContext));
Comment 31•11 years ago
|
||
Comment on attachment 769778 [details] [diff] [review] Hook SkRefCnt into our leak reporting tools Review of attachment 769778 [details] [diff] [review]: ----------------------------------------------------------------- Trailing spaces, but this is fine for now. We should discuss with upstream the best way to integrate this sort of functionality.
Attachment #769778 -
Flags: review?(gwright) → review+
Reporter | ||
Comment 32•11 years ago
|
||
Talked IRL with Matt ; agreed on a nicer DrawTargetSkia creation API; landed on graphics branch: http://hg.mozilla.org/projects/graphics/rev/7c29148e23bb
Reporter | ||
Comment 33•11 years ago
|
||
Applied Matt's recommendations for the way to create Skia refcounted objects and using SkAutoTUnref, http://hg.mozilla.org/projects/graphics/rev/837a6eda082c
Comment 34•11 years ago
|
||
Attachment #770560 -
Flags: review?(matt.woodrow)
Updated•11 years ago
|
Attachment #770560 -
Flags: review?(matt.woodrow) → review+
Comment 35•11 years ago
|
||
Matt complained on IRC that my last review request wasn't exciting enough, so here's some ASCII art of a couple of sheep: __ _ .-.' `; `-._ __ _ (_, .-:' `; `-._ ,'o"( (_, ) (__,-' ,'o"( )> ( (__,-' ) `-'._.--._( ) ||| |||`-'._.--._.-' ||| |||
Comment 36•11 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/2301a291c22e https://hg.mozilla.org/integration/mozilla-inbound/rev/27b5ff51b940 https://hg.mozilla.org/integration/mozilla-inbound/rev/9eee173ece11 https://hg.mozilla.org/integration/mozilla-inbound/rev/7c9da71aacd4 https://hg.mozilla.org/integration/mozilla-inbound/rev/5934bdc064ad
Comment 37•11 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/2301a291c22e https://hg.mozilla.org/mozilla-central/rev/27b5ff51b940 https://hg.mozilla.org/mozilla-central/rev/9eee173ece11 https://hg.mozilla.org/mozilla-central/rev/7c9da71aacd4 https://hg.mozilla.org/mozilla-central/rev/5934bdc064ad
Updated•11 years ago
|
Attachment #769690 -
Flags: review?(matt.woodrow)
Comment 38•10 years ago
|
||
Comment on attachment 769690 [details] [diff] [review] Refactor the ownership model under DrawTargetSkia No longer an issue.
Attachment #769690 -
Flags: review?(gwright)
You need to log in
before you can comment on or make changes to this bug.
Description
•