Skip to content

Commit

Permalink
Fix OSX CALayer Bug 690 and Bug 691: Occasional Freeze on CVDisplayLi…
Browse files Browse the repository at this point in the history
…nkStop; Layers and native GL-Context are _not_ Released ; Java Side wait for Main-Thread

- Fix Bug 690: Occasional Freeze on CVDisplayLinkStop
  - NSOpenGLLayer.disableAnimation() shall not claim the renderLock mutex,
    since the CVDisplayLink callback could be waiting for the lock.
    This waiting callback could freeze the call to CVDisplayLinkStop.

- Fix Bug 691: Layers and native GL-Context are _not_ Released
  - Following proper release cycle:

    Context unrealized:
      - JAWTWindow.detachSurfaceLayer() -> OSXUtil.RemoveCASublayer(..)
      - CGL.releaseNSOpenGLLayer(..)

    JAWTWindow.destroy()
      - MacOSXJAWTWindow.UnsetJAWTRootSurfaceLayer(..)
      - OSXUtil.DestroyCALayer(..)

  - 'Magic' CALayer release calls (w/o manual retain beforehand) at:
     - OSXUtil.RemoveCASublayer(..): [subLayer release]
     - MacOSXJAWTWindow.UnsetJAWTRootSurfaceLayer(..): [rootLayer release]
     - OSXUtil.DestroyCALayer(..): [rootLayer release]

  - 'Magic' NSOpenGLLayer's NSOpenGLContext dealloc:
     - [NSOpenGLContext clearDrawable]
     - CGLDestroyContext( [NSOpenGLContext CGLContextObj] )

- Java Side wait for Main-Thread
  - Waiting for the delegated Main-Thread on the Java side eases debugging
    and won't block the Main-Thread in native code.

  - Utilizing this for all CALayer calls

Test case: TestGLCanvasAddRemove01SwingAWT
  • Loading branch information
sgothel committed Feb 14, 2013
1 parent d477943 commit f6e6fab
Show file tree
Hide file tree
Showing 12 changed files with 596 additions and 139 deletions.
2 changes: 1 addition & 1 deletion make/scripts/tests-osx-x64-java7.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export JAVA_HOME PATH

spath=`dirname $0`

. $spath/tests.sh $JAVA_HOME/bin/java -d64 ../build-macosx-java7 $*
. $spath/tests.sh $JAVA_HOME/bin/java -d64 ../build-macosx $*


4 changes: 4 additions & 0 deletions make/scripts/tests-osx-x64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH

JAVA_HOME=`/usr/libexec/java_home -version 1.6`
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH

spath=`dirname $0`

. $spath/tests.sh /usr/bin/java -d64 ../build-macosx $*
Expand Down
14 changes: 10 additions & 4 deletions make/scripts/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ MOSX_MT=0
uname -a | grep -i Darwin && MOSX=1
if [ $MOSX -eq 1 ] ; then
echo setup OSX environment vars
export NSZombieEnabled=YES
#export NSZombieEnabled=YES
export NSTraceEvents=YES
#export OBJC_PRINT_EXCEPTIONS=YES
echo NSZombieEnabled $NSZombieEnabled 2>&1 | tee -a java-run.log
Expand Down Expand Up @@ -89,7 +89,7 @@ function jrun() {
#D_ARGS="-Djogl.debug.FBObject"
#D_ARGS="-Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.GLSLCode -Djogl.debug.DebugGL -Djogl.debug.TraceGL"
#D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLContext.TraceSwitch"
#D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLContext.TraceSwitch -Dnativewindow.debug.JAWT"
#D_ARGS="-Djogl.debug.GLContext.TraceSwitch"
#D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLState"
Expand Down Expand Up @@ -175,7 +175,7 @@ function jrun() {
#D_ARGS="-Dnewt.debug.Window"
#D_ARGS="-Xprof"
#D_ARGS="-Dnativewindow.debug=all"
#D_ARGS="-Djogl.debug.GLCanvas"
#D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.Java2D -Djogl.debug.GLJPanel"
#D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.Animator"
#D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.X11Util.XSync"
#D_ARGS="-Dnativewindow.debug.X11Util.XSync -Dnativewindow.debug.ToolkitLock.TraceLock"
Expand Down Expand Up @@ -415,6 +415,12 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.newt.event.TestNewtKeyPressReleaseUnmaskRepeatAWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testawt com.jogamp.opengl.test.junit.newt.event.TestNewtKeyCodesAWT $*

#testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT $*
testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAddRemove01SwingAWT $*

#testawt com.jogamp.opengl.test.junit.newt.event.TestNewtKeyCodeModifiersAWT $*
#testawt com.jogamp.opengl.test.junit.newt.event.TestNewtEventModifiersNEWTWindowAWT $*
#testawt com.jogamp.opengl.test.junit.newt.event.TestNewtEventModifiersAWTCanvas $*
Expand Down Expand Up @@ -538,7 +544,7 @@ function testawtswt() {
# ATI/Linux: XCB Unknown request in queue while dequeuing
# Most likely this is a multi-threaded client and XInitThreads has not been called
# ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed
testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimNEWT $*
# this one works - though !
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext02FPSAnimNEWT $*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,10 @@ public void swapBuffers(boolean doubleBuffered) {
// still having a valid OLS attached to surface (parent OLS could have been removed)
ols.detachSurfaceLayer();
}
CGL.releaseNSOpenGLLayer(nsOpenGLLayer);
OSXUtil.RunOnMainThread(true, new Runnable() {
public void run() {
CGL.releaseNSOpenGLLayer(nsOpenGLLayer);
} } );
if( null != gl3ShaderProgram ) {
gl3ShaderProgram.destroy(MacOSXCGLContext.this.gl.getGL3());
gl3ShaderProgram = null;
Expand Down
116 changes: 85 additions & 31 deletions src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
//
// #define DBG_PERF 1

// #define DBG_LIFECYCLE 1

/**
* Capture setView(NULL), which produces a 'invalid drawable' message
*
Expand All @@ -52,6 +54,10 @@ @interface MyNSOpenGLContext: NSOpenGLContext
- (id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share;
- (void)setView:(NSView *)view;
- (void)update;
#ifdef DBG_LIFECYCLE
- (id)retain;
- (oneway void)release;
#endif
- (void)dealloc;

@end
Expand Down Expand Up @@ -82,11 +88,36 @@ - (void)update
DBG_PRINT("MyNSOpenGLContext.update.X\n");
}

#ifdef DBG_LIFECYCLE

- (id)retain
{
DBG_PRINT("MyNSOpenGLContext::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
// NSLog(@"MyNSOpenGLContext::retain: %@",[NSThread callStackSymbols]);
id o = [super retain];
DBG_PRINT("MyNSOpenGLContext::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]);
return o;
}

- (oneway void)release
{
DBG_PRINT("MyNSOpenGLContext::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
[super release];
// DBG_PRINT("MyNSOpenGLContext::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
}

#endif

- (void)dealloc
{
DBG_PRINT("MyNSOpenGLContext.dealloc: this.0 %p\n", self);
CGLContextObj cglCtx = [self CGLContextObj];
DBG_PRINT("MyNSOpenGLContext::dealloc.0 %p (refcnt %d) - CGL-Ctx %p\n", self, (int)[self retainCount], cglCtx);
[self clearDrawable];
if( NULL != cglCtx ) {
CGLDestroyContext( cglCtx );
}
[super dealloc];
DBG_PRINT("MyNSOpenGLContext.dealloc.X: %p\n", self);
// DBG_PRINT("MyNSOpenGLContext.dealloc.X: %p\n", self);
}

@end
Expand All @@ -95,6 +126,7 @@ @interface MyNSOpenGLLayer: NSOpenGLLayer
{
@private
GLfloat gl_texCoords[8];
NSOpenGLContext* myCtx;

@protected
NSOpenGLContext* parentCtx;
Expand Down Expand Up @@ -150,6 +182,10 @@ - (void)disableAnimation;
- (void)pauseAnimation:(Bool)pause;
- (void)deallocPBuffer;
- (void)releaseLayer;
#ifdef DBG_LIFECYCLE
- (id)retain;
- (oneway void)release;
#endif
- (void)dealloc;
- (void)setSwapInterval:(int)interval;
- (void)tick;
Expand Down Expand Up @@ -209,6 +245,7 @@ - (id) setupWithContext: (NSOpenGLContext*) _parentCtx
pthread_mutex_init(&renderLock, &renderLockAttr); // recursive
pthread_cond_init(&renderSignal, NULL); // no attribute

myCtx = NULL;
{
int i;
for(i=0; i<8; i++) {
Expand Down Expand Up @@ -418,15 +455,15 @@ - (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFor
{
DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, parent %p\n",
self, (int)[self retainCount], pixelFormat, parentCtx);
NSOpenGLContext * nctx = [[MyNSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx];
DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.X: new-ctx %p\n", nctx);
return nctx;
// NSLog(@"MyNSOpenGLLayer::openGLContextForPixelFormat: %@",[NSThread callStackSymbols]);
myCtx = [[MyNSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx];
DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.X: new-ctx %p\n", myCtx);
return myCtx;
}

- (void)disableAnimation
{
DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink);
pthread_mutex_lock(&renderLock);
DBG_PRINT("MyNSOpenGLLayer::disableAnimation.0: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink);
[self setAsynchronous: NO];
if(NULL != displayLink) {
#ifdef HAS_CADisplayLink
Expand All @@ -438,35 +475,63 @@ - (void)disableAnimation
#endif
displayLink = NULL;
}
pthread_mutex_unlock(&renderLock);
DBG_PRINT("MyNSOpenGLLayer::disableAnimation.X: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink);
}

- (void)releaseLayer
{
DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
pthread_mutex_lock(&renderLock);
[self disableAnimation];
pthread_mutex_lock(&renderLock);
[self deallocPBuffer];
[[self openGLContext] release];
// [[self openGLContext] release];
if( NULL != myCtx ) {
[myCtx release];
// [myCtx dealloc];
myCtx = NULL;
}
parentCtx = NULL;
[parentPixelFmt release];
[self release];
DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
pthread_mutex_unlock(&renderLock);
[self release];
DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p\n", self);
}

#ifdef DBG_LIFECYCLE

- (id)retain
{
DBG_PRINT("MyNSOpenGLLayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
// NSLog(@"MyNSOpenGLLayer::retain: %@",[NSThread callStackSymbols]);
id o = [super retain];
DBG_PRINT("MyNSOpenGLLayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]);
return o;
}

- (oneway void)release
{
DBG_PRINT("MyNSOpenGLLayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
// NSLog(@"MyNSOpenGLLayer::release: %@",[NSThread callStackSymbols]);
[super release];
// DBG_PRINT("MyNSOpenGLLayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
}

#endif

- (void)dealloc
{
DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]);
// NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]);

pthread_mutex_lock(&renderLock);
[self disableAnimation];
pthread_mutex_lock(&renderLock);
[self deallocPBuffer];
// [[self openGLContext] dealloc];
pthread_mutex_unlock(&renderLock);
pthread_cond_destroy(&renderSignal);
pthread_mutex_destroy(&renderLock);
[super dealloc];
DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self);
// DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self);
}

- (Bool)isGLSourceValid
Expand Down Expand Up @@ -752,32 +817,27 @@ - (void)waitUntilRenderSignal: (long) to_micros
@end

NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, int gl3ShaderProgramName, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, uint32_t texID, Bool opaque, int texWidth, int texHeight) {
// This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ?
// However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO.
// return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID
// opaque: opaque texWidth: texWidth texHeight: texHeight];

return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx gl3ShaderProgramName: (GLuint)gl3ShaderProgramName pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID
opaque: opaque texWidth: texWidth texHeight: texHeight];
}

void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
[l setSwapInterval: interval];
[pool release];
}

void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
[l waitUntilRenderSignal: to_micros];
[pool release];
}

void setNSOpenGLLayerNeedsDisplayFBO(NSOpenGLLayer* layer, uint32_t texID) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
Bool shallDraw;

// volatile OK
Expand All @@ -799,8 +859,8 @@ void setNSOpenGLLayerNeedsDisplayFBO(NSOpenGLLayer* layer, uint32_t texID) {
}

void setNSOpenGLLayerNeedsDisplayPBuffer(NSOpenGLLayer* layer, NSOpenGLPixelBuffer* p) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
Bool shallDraw;

if( NO == [l isSamePBuffer: p] ) {
Expand All @@ -825,16 +885,10 @@ void setNSOpenGLLayerNeedsDisplayPBuffer(NSOpenGLLayer* layer, NSOpenGLPixelBuff
}

void releaseNSOpenGLLayer(NSOpenGLLayer* layer) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l);

if ( [NSThread isMainThread] == YES ) {
[l releaseLayer];
} else {
[l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO];
}

[l releaseLayer];
DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l);
[pool release];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public final void attachSurfaceLayer(final long layerHandle) throws NativeWindow
}
try {
if(DEBUG) {
System.err.println("JAWTWindow.attachSurfaceHandle(): 0x"+Long.toHexString(layerHandle) + ", bounds "+bounds);
System.err.println("JAWTWindow.attachSurfaceHandle(): "+toHexString(layerHandle) + ", bounds "+bounds);
}
attachSurfaceLayerImpl(layerHandle);
offscreenSurfaceLayer = layerHandle;
Expand All @@ -229,7 +229,7 @@ public final void detachSurfaceLayer() throws NativeWindowException {
}
try {
if(DEBUG) {
System.err.println("JAWTWindow.detachSurfaceHandle(): 0x"+Long.toHexString(offscreenSurfaceLayer));
System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer));
}
detachSurfaceLayerImpl(offscreenSurfaceLayer);
offscreenSurfaceLayer = 0;
Expand Down Expand Up @@ -341,7 +341,7 @@ public final int lockSurface() throws NativeWindowException, RuntimeException {
if(LOCK_SUCCESS == res && drawable_old != drawable) {
res = LOCK_SURFACE_CHANGED;
if(DEBUG) {
System.err.println("JAWTWindow: surface change 0x"+Long.toHexString(drawable_old)+" -> 0x"+Long.toHexString(drawable));
System.err.println("JAWTWindow: surface change "+toHexString(drawable_old)+" -> "+toHexString(drawable));
// Thread.dumpStack();
}
}
Expand Down Expand Up @@ -549,8 +549,8 @@ public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("JAWT-Window["+
"windowHandle 0x"+Long.toHexString(getWindowHandle())+
", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+
"windowHandle "+toHexString(getWindowHandle())+
", surfaceHandle "+toHexString(getSurfaceHandle())+
", bounds "+bounds+", insets "+insets+
", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface);
if(null!=component) {
Expand All @@ -566,4 +566,8 @@ public String toString() {

return sb.toString();
}

protected final String toHexString(long l) {
return "0x"+Long.toHexString(l);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import org.eclipse.swt.widgets.Control;

import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowFactory;
Expand All @@ -49,7 +48,6 @@
import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;

import jogamp.nativewindow.macosx.OSXUtil;
import jogamp.nativewindow.x11.X11Lib;
Expand Down
Loading

0 comments on commit f6e6fab

Please sign in to comment.