From 8edaa9780455b60f6034a78970cab4f516d4b061 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 17 Feb 2013 03:25:34 +0100 Subject: NEWT/OSX: Fix Memory Leak ; Fix Occasional Crash Duer to Lifecycle Ops not on Main-Thread. - Fix Memory Leak - NewtWindow::dealloc -> [NewtView release]: Fixes NewtView leak - NewtView::dealloc -> removeTrackingRect: Removes occasional crash (double free of TrackingRect) - Fix Occasional Crash Duer to Lifecycle Ops not on Main-Thread. Perform OSX WindowDriver ops on Main-Thread: - close0 - changeContentView0 - createWindow0 - Cleaned up AddRemove unit tests, added TestAddRemove03GLWindowNEWT --- make/scripts/tests-osx-x64-java7.sh | 1 - make/scripts/tests-osx-x64.sh | 1 - make/scripts/tests.sh | 9 +- .../jogamp/newt/driver/macosx/WindowDriver.java | 43 +++++-- src/newt/native/MacWindow.m | 31 +++-- src/newt/native/NewtMacWindow.m | 32 +++-- .../acore/TestAddRemove01GLCanvasSwingAWT.java | 35 +++--- .../TestAddRemove02GLWindowNewtCanvasAWT.java | 37 +++--- .../jogl/acore/TestAddRemove03GLWindowNEWT.java | 130 +++++++++++++++++++++ .../awt/TestBug664GLCanvasSetVisibleSwingAWT.java | 4 +- 10 files changed, 248 insertions(+), 75 deletions(-) create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove03GLWindowNEWT.java diff --git a/make/scripts/tests-osx-x64-java7.sh b/make/scripts/tests-osx-x64-java7.sh index 378938167..e1b07202b 100755 --- a/make/scripts/tests-osx-x64-java7.sh +++ b/make/scripts/tests-osx-x64-java7.sh @@ -10,4 +10,3 @@ spath=`dirname $0` . $spath/tests.sh $JAVA_HOME/bin/java -d64 ../build-macosx $* - diff --git a/make/scripts/tests-osx-x64.sh b/make/scripts/tests-osx-x64.sh index 01f3e1bb2..fe2d2c4ec 100755 --- a/make/scripts/tests-osx-x64.sh +++ b/make/scripts/tests-osx-x64.sh @@ -10,4 +10,3 @@ spath=`dirname $0` . $spath/tests.sh /usr/bin/java -d64 ../build-macosx $* - diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 400f3f023..5a7c0f0ec 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -34,8 +34,8 @@ uname -a | grep -i Darwin && MOSX=1 if [ $MOSX -eq 1 ] ; then echo setup OSX environment vars #export NSZombieEnabled=YES - #export NSTraceEvents=YES - #export OBJC_PRINT_EXCEPTIONS=YES + export NSTraceEvents=YES + export OBJC_PRINT_EXCEPTIONS=YES echo NSZombieEnabled $NSZombieEnabled 2>&1 | tee -a java-run.log echo NSTraceEvents $NSTraceEvents 2>&1 | tee -a java-run.log echo OBJC_PRINT_EXCEPTIONS $OBJC_PRINT_EXCEPTIONS 2>&1 | tee -a java-run.log @@ -302,7 +302,8 @@ function testawtswt() { #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove01GLCanvasSwingAWT $* -#testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove02GLWindowNewtCanvasAWT $* +testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove02GLWindowNewtCanvasAWT $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove03GLWindowNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableFactoryOffscrnCapsNEWT $* @@ -434,7 +435,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.caps.TestBug605FlippedImageAWT $* #testawt com.jogamp.opengl.test.junit.jogl.glsl.TestShaderCompilationBug459AWT -testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol01AWT $* +#testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol01AWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT $* #testawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol03NewtAWT $* diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java index 5755bdf11..89d53fbeb 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java @@ -50,6 +50,7 @@ import jogamp.newt.WindowImpl; import jogamp.newt.driver.DriverClearFocus; import jogamp.newt.driver.DriverUpdatePosition; +import com.jogamp.common.util.Function; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyEvent; @@ -86,7 +87,10 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl sscSurfaceHandle = 0; isOffscreenInstance = false; if (0 != handle) { - close0(handle); + OSXUtil.RunOnMainThread(true, new Runnable() { + public void run() { + close0( handle ); + } } ); } } catch (Throwable t) { if(DEBUG_IMPLEMENTATION) { @@ -378,24 +382,36 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl try { if(0!=getWindowHandle()) { // save the view .. close the window - surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0); + surfaceHandle = OSXUtil.RunOnMainThread(true, new Function() { + public Long eval(Object... args) { + return Long.valueOf( + changeContentView0(getParentWindowHandle(), getWindowHandle(), 0) ); + } } ).longValue(); if(recreate && 0==surfaceHandle) { throw new NativeWindowException("Internal Error - recreate, window but no view"); } - close0(getWindowHandle()); + OSXUtil.RunOnMainThread(true, new Runnable() { + public void run() { + close0( getWindowHandle() ); + } } ); setWindowHandle(0); } else { surfaceHandle = 0; } - setWindowHandle(createWindow0(getParentWindowHandle(), - pS.getX(), pS.getY(), width, height, - (getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance), - fullscreen, - ((isUndecorated() || offscreenInstance) ? - NSBorderlessWindowMask : - NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), - NSBackingStoreBuffered, - getScreen().getIndex(), surfaceHandle)); + + setWindowHandle( OSXUtil.RunOnMainThread(true, new Function() { + public Long eval(Object... args) { + return Long.valueOf( + createWindow0( getParentWindowHandle(), + pS.getX(), pS.getY(), width, height, + (getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance), + fullscreen, + ( (isUndecorated() || offscreenInstance) ? NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask ), + NSBackingStoreBuffered, + getScreen().getIndex(), surfaceHandle) ); + } } ).longValue() ); + if (getWindowHandle() == 0) { throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); } @@ -411,6 +427,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } protected static native boolean initIDs0(); + /** Must be called on Main-Thread */ private native long createWindow0(long parentWindowHandle, int x, int y, int w, int h, boolean opaque, boolean fullscreen, int windowStyle, int backingStoreType, @@ -422,9 +439,11 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl /** in case of a child window, it actually only issues orderBack(..) */ private native void orderOut0(long window); private native void orderFront0(long window); + /** Must be called on Main-Thread */ private native void close0(long window); private native void setTitle0(long window, String title); private native long contentView0(long window); + /** Must be called on Main-Thread */ private native long changeContentView0(long parentWindowOrViewHandle, long window, long view); private native void setContentSize0(long window, int w, int h); private native void setFrameTopLeftPoint0(long parentWindowHandle, long window, int x, int y); diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index b9c339285..94363624f 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -553,7 +553,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0 return (jboolean) res; } -/* +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: createWindow0 * Signature: (JIIIIZIIIJ)J @@ -706,19 +708,10 @@ NS_ENDHANDLER return (jlong) ((intptr_t) myWindow); } -// Footnote: Our view handling produces random 'Assertion failure' even w/o parenting: -// -// [NSThemeFrame lockFocus], /SourceCache/AppKit/AppKit-1138.23/AppKit.subproj/NSView.m:6053 -// [NSThemeFrame(0x7fe94bc72c80) lockFocus] failed with window=0x7fe94bc445a0, windowNumber=9425, [self isHiddenOrHasHiddenAncestor]=0 -// .. -// AppKit 0x00007fff89621001 -[NSView lockFocus] + 250 -// AppKit 0x00007fff8961eafa -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 3780 -// AppKit 0x00007fff8961793e -[NSView displayIfNeeded] + 1676 -// AppKit 0x00007fff8961707d _handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 648 -// - -/* +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: close0 * Signature: (J)V @@ -761,8 +754,6 @@ NS_DURING [mView exitFullScreenModeWithOptions: NULL]; } // Note: mWin's release will also release it's mView! - // [mWin setContentView: nil]; - // [mView release]; } NS_HANDLER NS_ENDHANDLER @@ -770,7 +761,8 @@ NS_ENDHANDLER if(NULL!=pWin) { [mWin detachFromParent: pWin]; } - [mWin performSelectorOnMainThread:@selector(orderOut:) withObject:mWin waitUntilDone:NO]; + // [mWin performSelectorOnMainThread:@selector(orderOut:) withObject:mWin waitUntilDone:NO]; + [mWin orderOut: mWin]; DBG_PRINT( "windowClose.1 - %p,%d view %p,%d, parent %p\n", mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); @@ -778,7 +770,8 @@ NS_ENDHANDLER // Only release window, if release is not yet in process. // E.g. destroyNotifySent:=true set by NewtMacWindow::windowWillClose(), i.e. window-close was clicked. if(!destroyNotifySent) { - [mWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + // [mWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + [mWin release]; } DBG_PRINT( "windowClose.X - %p,%d, released %d, view %p,%d, parent %p\n", @@ -960,7 +953,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_contentView0 return res; } -/* +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: changeContentView * Signature: (J)J diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 5b826566b..e69f74dfb 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -107,6 +107,7 @@ static jmethodID windowRepaintID = NULL; - (id)initWithFrame:(NSRect)frameRect { + id res = [super initWithFrame:frameRect]; javaWindowObject = NULL; jvmHandle = NULL; @@ -129,28 +130,35 @@ static jmethodID windowRepaintID = NULL; */ myCursor = NULL; - return [super initWithFrame:frameRect]; + DBG_PRINT("NewtView::create: %p (refcnt %d)\n", res, (int)[res retainCount]); + return res; } - (void) release { + DBG_PRINT("NewtView::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); #ifdef VERBOSE_ON - NSLog(@"NewtView::release\n"); - NSLog(@"%@",[NSThread callStackSymbols]); + // NSLog(@"%@",[NSThread callStackSymbols]); #endif [super release]; } - (void) dealloc { + DBG_PRINT("NewtView::dealloc.0: %p (refcnt %d), ptrTrackingTag %d\n", self, (int)[self retainCount], (int)ptrTrackingTag); if(softLocked) { NSLog(@"NewtView::dealloc: softLock still hold @ dealloc!\n"); } + if(0 != ptrTrackingTag) { + // [self removeCursorRect: ptrRect cursor: myCursor]; + [self removeTrackingRect: ptrTrackingTag]; + ptrTrackingTag = 0; + } pthread_mutex_destroy(&softLockSync); #ifdef VERBOSE_ON - NSLog(@"NewtView::dealloc\n"); - NSLog(@"%@",[NSThread callStackSymbols]); + //NSLog(@"%@",[NSThread callStackSymbols]); #endif + DBG_PRINT("NewtView::dealloc.X: %p\n", self); [super dealloc]; } @@ -390,25 +398,31 @@ static jmethodID windowRepaintID = NULL; mouseInside = NO; cursorIsHidden = NO; realized = YES; + DBG_PRINT("NewtWindow::create: %p (refcnt %d)\n", res, (int)[res retainCount]); return res; } - (void) release { + DBG_PRINT("NewtWindow::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); #ifdef VERBOSE_ON - NSLog(@"NewtWindow::release\n"); - NSLog(@"%@",[NSThread callStackSymbols]); + // NSLog(@"%@",[NSThread callStackSymbols]); #endif [super release]; } - (void) dealloc { + DBG_PRINT("NewtWindow::dealloc.0: %p (refcnt %d)\n", self, (int)[self retainCount]); #ifdef VERBOSE_ON - NSLog(@"NewtWindow::dealloc\n"); - NSLog(@"%@",[NSThread callStackSymbols]); + // NSLog(@"%@",[NSThread callStackSymbols]); #endif + NewtView* mView = (NewtView *)[self contentView]; + if( NULL != mView ) { + [mView release]; + } [super dealloc]; + DBG_PRINT("NewtWindow::dealloc.X: %p\n", self); } - (void) setUnrealized diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java index a14364e05..ce8f9adc8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java @@ -50,13 +50,14 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.UITestCase; public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { static long durationPerTest = 50; static int addRemoveCount = 15; - static boolean shallUseOffscreenFBOLayer = false; + static boolean noOnscreenTest = false; + static boolean noOffscreenTest = false; static boolean shallUseOffscreenPBufferLayer = false; static GLProfile glp; static int width, height; @@ -64,8 +65,8 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { @BeforeClass public static void initClass() { - if(GLProfile.isAvailable(GLProfile.GL2)) { - glp = GLProfile.get(GLProfile.GL2); + if(GLProfile.isAvailable(GLProfile.GL2ES2)) { + glp = GLProfile.get(GLProfile.GL2ES2); Assert.assertNotNull(glp); width = 640; height = 480; @@ -139,6 +140,7 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { { for(int i=0; i