Possible crash in OpenGL renderer on OSX

Hello,

 

I'm currently trying to switch from the software renderer to the OpenGL one.

I'm having a strange crash, not related to drawing in a currently cached Image outside of the OpenGL Render Thread:

 At the end of OpenGLContext::CachedImage::renderFrame(), I have "isUpdating" true and the crash occurs somewhere in "drawComponentBuffers" (it crashes on a call to glDrawArrays(), in OpenGLContext::copyTexture() ).

Since "isUpdating" is true, the Message Thread isn't locked at this point.

Meanwhile, the Message Thread is currently executing the timerCallback of ImageCache::Pimpl.

I am suspecting the ImageCache::Pimpl to be deleting an Image used in drawComponentBuffers.

If you're confident that this is a juce bug rather than a mistake in your own code, could you give us a short piece of test code we could use to reproduce it?

I can't reproduce it easily, it only happened in 2 debug sessions today. It might be something else. I'll update here if I can manage to reproduce/isolate it and create a prototype.

What I don't understand is why drawComponentBuffers() can be called with the Message Thread unlocked, or if it needs to be unlocked.

drawComponentBuffers is ok to be called unlocked, because it should only be using internal images, so should be safe. There's nothing in there that uses images from the ImageCache, so I don't think that can be related (?)

Just had another very similar crash, in the MessageThread this time:

#10 0x0000000103a9cc97 in juce::OpenGLTexture::release (this=0x1eedb2bf0) at juce_OpenGLTexture.cpp:168
#11 0x0000000103a9cb98 in juce::OpenGLTexture::~OpenGLTexture (this=0x1eedb2bf0) at juce_OpenGLTexture.cpp:41
#12 0x0000000103a9a945 in juce::OpenGLTexture::~OpenGLTexture (this=0x1eedb2bf0) at juce_OpenGLTexture.cpp:40
#13 0x0000000103aaf1b0 in juce::OpenGLRendering::CachedImageList::CachedImage::~CachedImage (this=0x1eedb2be0) at juce_OpenGLGraphicsContext.cpp:102
#14 0x0000000103aaf0d5 in juce::OpenGLRendering::CachedImageList::CachedImage::~CachedImage (this=0x1eedb2be0) at juce_OpenGLGraphicsContext.cpp:99
#15 0x0000000103aaf08a in juce::ContainerDeletePolicy<juce::OpenGLRendering::CachedImageList::CachedImage>::destroy (object=0x1eedb2be0) at juce_ContainerDeletePolicy.h:48
#16 0x0000000103aaf058 in juce::ScopedPointer<juce::OpenGLRendering::CachedImageList::CachedImage>::~ScopedPointer (this=0x7fff5fbfd708) at juce_ScopedPointer.h:100
#17 0x0000000103aaf035 in juce::ScopedPointer<juce::OpenGLRendering::CachedImageList::CachedImage>::~ScopedPointer (this=0x7fff5fbfd708) at juce_ScopedPointer.h:100
#18 0x0000000103aaef0c in juce::OwnedArray<juce::OpenGLRendering::CachedImageList::CachedImage, juce::DummyCriticalSection>::remove (this=0x1911894b0, indexToRemove=895, deleteObject=true) at juce_OwnedArray.h:606
#19 0x0000000103abc3bf in juce::OpenGLRendering::CachedImageList::imageDataBeingDeleted (this=0x191189490, im=0x1eedb4100) at juce_OpenGLGraphicsContext.cpp:161
#20 0x0000000103abc4af in non-virtual thunk to juce::OpenGLRendering::CachedImageList::imageDataBeingDeleted(juce::ImagePixelData*) (this=0x1911894a0, im=0x1eedb4100) at juce_OpenGLGraphicsContext.cpp:171
#21 0x000000010385ee3e in juce::ListenerList<juce::ImagePixelData::Listener, juce::Array<juce::ImagePixelData::Listener*, juce::DummyCriticalSection, 0> >::call<juce::ImagePixelData*> (this=0x1eedb4138, callbackFunction=
) at juce_ListenerList.h:167
#22 0x00000001037e1eec in juce::ImagePixelData::~ImagePixelData (this=0x1eedb4100) at juce_Image.cpp:34
#23 0x00000001038c009f in juce::CoreGraphicsImage::~CoreGraphicsImage (this=0x1eedb4100) at juce_mac_CoreGraphicsContext.mm:52
#24 0x00000001038bfd15 in juce::CoreGraphicsImage::~CoreGraphicsImage (this=0x1eedb4100) at juce_mac_CoreGraphicsContext.mm:49
#25 0x00000001038bfd38 in juce::CoreGraphicsImage::~CoreGraphicsImage (this=0x1eedb4100) at juce_mac_CoreGraphicsContext.mm:49
#26 0x00000001038b8ade in juce::ContainerDeletePolicy<juce::ImagePixelData>::destroy (object=0x1eedb4100) at juce_ContainerDeletePolicy.h:48
#27 0x00000001038b8a8c in juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::decIfNotNull (o=0x1eedb4100) at juce_ReferenceCountedObject.h:366
#28 0x00000001038b8e78 in juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::~ReferenceCountedObjectPtr (this=0x1eedb0df0) at juce_ReferenceCountedObject.h:327
#29 0x000000010385ef75 in juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::~ReferenceCountedObjectPtr (this=0x1eedb0df0) at juce_ReferenceCountedObject.h:326
#30 0x00000001037e2b9a in juce::Image::~Image (this=0x1eedb0df0) at juce_Image.cpp:254
#31 0x00000001037c9525 in juce::Image::~Image (this=0x1eedb0df0) at juce_Image.cpp:253
#32 0x00000001038c7ef5 in juce::ImageCache::Pimpl::Item::~Item (this=0x1eedb0df0) at juce_ImageCache.cpp:139
#33 0x00000001038c7ed5 in juce::ImageCache::Pimpl::Item::~Item (this=0x1eedb0df0) at juce_ImageCache.cpp:139
#34 0x00000001038c7e8a in juce::ContainerDeletePolicy<juce::ImageCache::Pimpl::Item>::destroy (object=0x1eedb0df0) at juce_ContainerDeletePolicy.h:48
#35 0x00000001038c7e58 in juce::ScopedPointer<juce::ImageCache::Pimpl::Item>::~ScopedPointer (this=0x7fff5fbfdae8) at juce_ScopedPointer.h:100
#36 0x00000001038c7e35 in juce::ScopedPointer<juce::ImageCache::Pimpl::Item>::~ScopedPointer (this=0x7fff5fbfdae8) at juce_ScopedPointer.h:100
#37 0x00000001038c7cec in juce::OwnedArray<juce::ImageCache::Pimpl::Item, juce::DummyCriticalSection>::remove (this=0x10c4466a0, indexToRemove=6344, deleteObject=true) at juce_OwnedArray.h:606
#38 0x00000001038c79f5 in juce::ImageCache::Pimpl::timerCallback (this=0x10c446670) at juce_ImageCache.cpp:118

With the OpenGL render thread being at the same point as last times:

#11 0x00007fff879c48e7 in glDrawArrays_ACC_Exec ()
#12 0x0000000103a99fe2 in juce::OpenGLContext::copyTexture (this=0x10c9fa110, targetClipArea=@0x1ad12ad18, anchorPosAndTextureSize=@0x1ad12ad18, contextWidth=1280, contextHeight=698, flippedVertically=false) at juce_OpenGLContext.cpp:933
#13 0x0000000103aa5c3a in juce::OpenGLContext::CachedImage::drawComponentBuffer (this=0x1a386d6e0) at juce_OpenGLContext.cpp:293
#14 0x0000000103aa5697 in juce::OpenGLContext::CachedImage::renderFrame (this=0x1a386d6e0) at juce_OpenGLContext.cpp:203
#15 0x0000000103aa6a71 in juce::OpenGLContext::CachedImage::run (this=0x1a386d6e0) at juce_OpenGLContext.cpp:375
#16 0x0000000103aa6b5c in non-virtual thunk to juce::OpenGLContext::CachedImage::run() (this=0x1a386d6e8) at juce_OpenGLContext.cpp:382

 

Are you using your own GL images that you're keeping in the ImageCache?

Not sure what you mean, but I would answer no: I only create software juce::Image, as it was when using the software renderer.

The only Images create/deleted (that I'm aware of) are buffered images of a waveform, created when needed, then scrolled, then released when obsolete.

They are created as such (from OpenGL render thread):

Image image(Image::ARGB, width, height, true);

Graphics g(image);

/* painting in g */

Painted (displayed) multiple times with successive calls to drawImageAt().

And image is released (deleted) when considered obsolete, in OpenGL render thread as well.

All my assumptions were wrong. Locking the MessageThread for drawComponentBuffers doesn't help and neither does deactivating the mentioned waveform...

I found something horrible in the code: a png decoded from a BinaryBuilt resource in a paint callback, at each paint... Removing this helped a bit, but now it still crashes after about 35 minutes of run time, each time, but only on an Intel HD 3000 on OSX (Yosemite). The crash happens in glDeleteTexture(). I saw another thread talking about this exact same issue, I will post my feedback there.

Thanks.

Yeah, I'll look into this soon, it may be something that needs to be fixed in the GL image caching code.