diff options
author | Sven Gothel <[email protected]> | 2013-02-15 17:15:49 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-02-15 17:15:49 +0100 |
commit | 2aeff053c55dadafb94bfbba661250e0c96f1fe5 (patch) | |
tree | f65c8fd9a2ccd3b44bb90a59b99fe59fa58fcb88 | |
parent | f6e6fab2a7ddfb5c9b614cb072c27ff697629161 (diff) |
Fix Bug 691 (part-2): Extra '[subLayer release]' is wrong, since 'CGL.releaseNSOpenGLLayer' triggers release - but very late w/ AWT usage.
OSXUtil_RemoveCASublayer0's added '[subLayer release]' in commit f6e6fab2a7ddfb5c9b614cb072c27ff697629161
is wrong, since 'CGL.releaseNSOpenGLLayer' actually does trigger it's release.
This was not seen w/ AWT tests, since it happens very later.
A NewtCanvasAWT test disclosed this error -> removed that extra release call.
The culprit for the late release w/ AWT usage was CGL.createNSOpenGLLayer's call in the current thread.
Moving it to the Main-Thread fixed the problem.
All CALayer lifecycle calls are issued on the Main-Thread now.
NSOpenGLLayer's CVDisplayLink OpenGL fitting via 'CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext'
is now performed at it's context creation in 'NSOpenGLLayer::openGLContextForPixelFormat'.
The 'extra' release of the NSOpenGLLayer's NSOpenGLContext as introduced in commit f6e6fab2a7ddfb5c9b614cb072c27ff697629161
is still valid.
13 files changed, 438 insertions, 107 deletions
diff --git a/make/config/jogl/cgl-macosx-CustomJavaCode.java b/make/config/jogl/cgl-macosx-CustomJavaCode.java new file mode 100644 index 000000000..b9a37d0c6 --- /dev/null +++ b/make/config/jogl/cgl-macosx-CustomJavaCode.java @@ -0,0 +1,22 @@ + +/** + * Creates the NSOpenGLLayer for FBO/PBuffer w/ optional GL3 shader program on Main-Thread + */ +public static long createNSOpenGLLayer(final long ctx, final int gl3ShaderProgramName, final long fmt, final long p, + final int texID, final boolean opaque, final int texWidth, final int texHeight) { + return OSXUtil.RunOnMainThread(true, new Function<Long, Object>() { + public Long eval(Object... args) { + return Long.valueOf( createNSOpenGLLayerImpl(ctx, gl3ShaderProgramName, fmt, p, texID, opaque, texWidth, texHeight) ); + } } ).longValue(); +} + +/** + * Releases the NSOpenGLLayer on Main-Thread + */ +public static void releaseNSOpenGLLayer(final long nsOpenGLLayer) { + OSXUtil.RunOnMainThread(true, new Runnable() { + public void run() { + releaseNSOpenGLLayerImpl(nsOpenGLLayer); + } } ); +} + diff --git a/make/config/jogl/cgl-macosx.cfg b/make/config/jogl/cgl-macosx.cfg index 203802d29..98123f605 100644 --- a/make/config/jogl/cgl-macosx.cfg +++ b/make/config/jogl/cgl-macosx.cfg @@ -34,6 +34,13 @@ Opaque long NSOpenGLLayer * CustomCCode #include </usr/include/machine/types.h> CustomCCode #include "macosx-window-system.h" +AccessControl createNSOpenGLLayerImpl PRIVATE +AccessControl releaseNSOpenGLLayerImpl PRIVATE +RenameJavaMethod createNSOpenGLLayer createNSOpenGLLayerImpl +RenameJavaMethod releaseNSOpenGLLayer releaseNSOpenGLLayerImpl + +IncludeAs CustomJavaCode CGL cgl-macosx-CustomJavaCode.java + # Implement the first argument to getProcAddress as String instead # of byte[] ArgumentIsString getProcAddress 0 @@ -53,3 +60,5 @@ DropUniqVendorExtensions SGIX DropUniqVendorExtensions SUN DropUniqVendorExtensions WIN +Import com.jogamp.common.util.Function +Import jogamp.nativewindow.macosx.OSXUtil diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 198a8f2e6..5f5248156 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -34,7 +34,7 @@ uname -a | grep -i Darwin && MOSX=1 if [ $MOSX -eq 1 ] ; then echo setup OSX environment vars #export NSZombieEnabled=YES - export NSTraceEvents=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 @@ -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 -Dnativewindow.debug.JAWT" + #D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.JAWT -Dnewt.debug.Window" #D_ARGS="-Djogl.debug.GLContext.TraceSwitch" #D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLCode" #D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLState" @@ -311,6 +311,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.awt.TestGLCanvasAddRemove01SwingAWT $* +testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAddRemove02NewtCanvasAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableFactoryNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* @@ -416,11 +418,6 @@ function testawtswt() { #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 $* diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 0deaa2987..838a0387d 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -709,10 +709,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl // still having a valid OLS attached to surface (parent OLS could have been removed) ols.detachSurfaceLayer(); } - OSXUtil.RunOnMainThread(true, new Runnable() { - public void run() { - CGL.releaseNSOpenGLLayer(nsOpenGLLayer); - } } ); + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); if( null != gl3ShaderProgram ) { gl3ShaderProgram.destroy(MacOSXCGLContext.this.gl.getGL3()); gl3ShaderProgram = null; diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m index 4334fc676..8d1286169 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m @@ -75,8 +75,11 @@ extern GLboolean glIsVertexArray (GLuint array); - (void)setView:(NSView *)view { DBG_PRINT("MyNSOpenGLContext.setView: this.0 %p, view %p\n", self, view); + // NSLog(@"MyNSOpenGLContext::setView: %@",[NSThread callStackSymbols]); if(NULL != view) { [super setView:view]; + } else { + [self clearDrawable]; } DBG_PRINT("MyNSOpenGLContext.setView.X\n"); } @@ -302,13 +305,6 @@ static const GLfloat gl_verts[] = { } } if(NULL != displayLink) { - cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [parentCtx CGLContextObj], [parentPixelFmt CGLPixelFormatObj]); - if(kCVReturnSuccess != cvres) { - DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); - displayLink = NULL; - } - } - if(NULL != displayLink) { cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); if(kCVReturnSuccess != cvres) { DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); @@ -453,10 +449,20 @@ static const GLfloat gl_verts[] = { - (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat { - DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, parent %p\n", - self, (int)[self retainCount], pixelFormat, parentCtx); + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, parent %p, DisplayLink %p\n", + self, (int)[self retainCount], pixelFormat, parentCtx, displayLink); // NSLog(@"MyNSOpenGLLayer::openGLContextForPixelFormat: %@",[NSThread callStackSymbols]); myCtx = [[MyNSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx]; +#ifndef HAS_CADisplayLink + if(NULL != displayLink) { + CVReturn cvres; + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.1: setup DisplayLink %p\n", displayLink); + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [myCtx CGLContextObj], [pixelFormat CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + } + } +#endif DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.X: new-ctx %p\n", myCtx); return myCtx; } @@ -487,7 +493,6 @@ static const GLfloat gl_verts[] = { // [[self openGLContext] release]; if( NULL != myCtx ) { [myCtx release]; - // [myCtx dealloc]; myCtx = NULL; } parentCtx = NULL; diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 2e133c22f..b765a68c3 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -136,8 +136,11 @@ public class OSXUtil implements ToolkitProperties { return GetNSWindow0(nsView); } - public static long CreateCALayer(int x, int y, int width, int height) { - return CreateCALayer0(x, y, width, height); + public static long CreateCALayer(final int x, final int y, final int width, final int height) { + return OSXUtil.RunOnMainThread(true, new Function<Long, Object>() { + public Long eval(Object... args) { + return Long.valueOf( CreateCALayer0(x, y, width, height) ); + } } ).longValue(); } public static void AddCASublayer(final long rootCALayer, final long subCALayer) { if(0==rootCALayer || 0==subCALayer) { @@ -145,7 +148,7 @@ public class OSXUtil implements ToolkitProperties { } RunOnMainThread(true, new Runnable() { public void run() { - AddCASublayer0(rootCALayer, subCALayer); + AddCASublayer0(rootCALayer, subCALayer); } }); } @@ -205,6 +208,13 @@ public class OSXUtil implements ToolkitProperties { } } + private static Runnable _nop = new Runnable() { public void run() {}; }; + + /** Issues a {@link #RunOnMainThread(boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done. */ + public static void WaitUntilFinish() { + RunOnMainThread(true, _nop); + } + /** * Run on OSX UI main thread. * <p> diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 3fa320042..83f3c821f 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -32,6 +32,7 @@ #include <stdarg.h> #include <unistd.h> #include <AppKit/AppKit.h> +#import <QuartzCore/QuartzCore.h> #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" @@ -323,6 +324,64 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0 return res; } +/** + * Track lifecycle via DBG_PRINT messages, if VERBOSE is enabled! + */ +@interface MyCALayer: CALayer +{ +} +- (id)init; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif + +@end + +@implementation MyCALayer + +- (id)init +{ + DBG_PRINT("MyCALayer.0\n"); + MyCALayer * o = [super init]; + DBG_PRINT("MyNSOpenGLContext.init.X: new %p\n", o); + DBG_PRINT("MyCALayer.0\n"); + return o; +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyCALayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyCALayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyCALayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyCALayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT("MyCALayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::dealloc: %@",[NSThread callStackSymbols]); + [super dealloc]; + // DBG_PRINT("MyCALayer.dealloc.X: %p\n", self); +} + +#endif + + +@end + /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateCALayer0 @@ -333,7 +392,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - CALayer* layer = [[CALayer alloc] init]; + MyCALayer* layer = [[MyCALayer alloc] init]; DBG_PRINT("CALayer::CreateCALayer.0: root %p %d/%d %dx%d (refcnt %d)\n", layer, (int)x, (int)y, (int)width, (int)height, (int)[layer retainCount]); // avoid zero size if(0 == width) { width = 32; } @@ -349,12 +408,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 // no animations for add/remove/swap sublayers etc // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] [layer removeAllAnimations]; + // [layer addAnimation:nil forKey:kCATransition]; [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [layer setNeedsDisplayOnBoundsChange: YES]; DBG_PRINT("CALayer::CreateCALayer.1: root %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); - DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); - [pool release]; + DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); return (jlong) ((intptr_t) layer); } @@ -367,8 +426,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); CGRect lRectRoot = [rootLayer frame]; @@ -385,6 +444,9 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 rootLayer, (int)[rootLayer retainCount], subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + // simple 1:1 layout ! [subLayer setFrame:lRectRoot]; [rootLayer addSublayer:subLayer]; @@ -392,14 +454,19 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 // no animations for add/remove/swap sublayers etc // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] [rootLayer removeAllAnimations]; + // [rootLayer addAnimation:nil forKey:kCATransition]; [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [rootLayer setNeedsDisplayOnBoundsChange: YES]; [subLayer removeAllAnimations]; + // [sublayer addAnimation:nil forKey:kCATransition]; [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [subLayer setNeedsDisplayOnBoundsChange: YES]; + + [CATransaction commit]; + + [pool release]; DBG_PRINT("CALayer::AddCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); - JNF_COCOA_EXIT(env); } /* @@ -410,19 +477,26 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); (void)rootLayer; // no warnings DBG_PRINT("CALayer::RemoveCASublayer0.0: root %p (refcnt %d) .sub %p (refcnt %d)\n", rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + [subLayer removeFromSuperlayer]; - [subLayer release]; + // [subLayer release] is called explicitly, e.g. via CGL.releaseNSOpenGLLayer(..) (MyNSOpenGLLayer::releaseLayer) + + [CATransaction commit]; + + [pool release]; DBG_PRINT("CALayer::RemoveCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); - JNF_COCOA_EXIT(env); } /* @@ -433,14 +507,13 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 (JNIEnv *env, jclass unused, jlong caLayer) { - JNF_COCOA_ENTER(env); - CALayer* layer = (CALayer*) ((intptr_t) caLayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* layer = (MyCALayer*) ((intptr_t) caLayer); DBG_PRINT("CALayer::DestroyCALayer0.0: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); - [layer release]; // Var.A - // [layer dealloc]; // Var.B -> SIGSEGV + [layer release]; // Trigger release of root CALayer + [pool release]; DBG_PRINT("CALayer::DestroyCALayer0.X: root %p\n", layer); - JNF_COCOA_EXIT(env); } /* @@ -451,18 +524,18 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) { - JNF_COCOA_ENTER(env); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); if (NULL == dsi) { NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); return JNI_FALSE; } - CALayer* layer = (CALayer*) (intptr_t) caLayer; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]); - surfaceLayers.layer = layer; // already incr. retain count + surfaceLayers.layer = [layer retain]; // Pairs w/ Unset + [pool release]; DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); - JNF_COCOA_EXIT(env); return JNI_TRUE; } @@ -474,23 +547,23 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) { - JNF_COCOA_ENTER(env); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); if (NULL == dsi) { NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); return JNI_FALSE; } - CALayer* layer = (CALayer*) (intptr_t) caLayer; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; if(layer != surfaceLayers.layer) { NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); return JNI_FALSE; } DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + [layer release]; // Pairs w/ Set surfaceLayers.layer = NULL; - [layer release]; // Var.A + [pool release]; DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); - JNF_COCOA_EXIT(env); return JNI_TRUE; } diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 89a749c51..6fc5a46ce 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -397,11 +397,12 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto if(DEBUG) { System.err.println("NewtCanvasAWT.removeNotify: "+newtChild+", from "+cont); } + // Detach OLS early.. final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(newtChild, true); if(null != ols && ols.isSurfaceLayerAttached()) { ols.detachSurfaceLayer(); - } - reparentWindow(false, cont); + } + reparentWindow(false, cont); // will destroy context (offscreen -> onscreen) and implicit detachSurfaceLayer (if still attached) if(null != jawtWindow) { NewtFactoryAWT.destroyNativeWindow(jawtWindow); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java index 90407166f..8cc094276 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java @@ -33,9 +33,7 @@ import java.awt.Button; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import javax.media.opengl.GLAnimatorControl; @@ -70,6 +68,7 @@ public class TestOffscreenLayer01GLCanvasAWT extends UITestCase { static Dimension frameSize1; static Dimension preferredGLSize; static long durationPerTest = 1000; + static boolean waitForKey = false; @BeforeClass public static void initClass() { @@ -189,7 +188,10 @@ public class TestOffscreenLayer01GLCanvasAWT extends UITestCase { Thread.sleep(durationPerTest/2); - end(animator1, frame1, null); + end(animator1, frame1, null); + if( waitForKey ) { + UITestCase.waitForKey("Continue"); + } } public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { @@ -214,7 +216,6 @@ public class TestOffscreenLayer01GLCanvasAWT extends UITestCase { } public static void main(String args[]) throws IOException { - boolean waitForKey = false; for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { durationPerTest = atoi(args[++i]); @@ -234,11 +235,7 @@ public class TestOffscreenLayer01GLCanvasAWT extends UITestCase { } } if(waitForKey) { - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - System.err.println("Press enter to continue"); - try { - System.err.println(stdin.readLine()); - } catch (IOException e) { } + UITestCase.waitForKey("Start"); } String tstname = TestOffscreenLayer01GLCanvasAWT.class.getName(); /* diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java index e4a3bce71..2236f4b05 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java @@ -33,9 +33,7 @@ import java.awt.Button; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import javax.media.opengl.GLAnimatorControl; @@ -70,6 +68,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { static Dimension frameSize1; static Dimension preferredGLSize; static long durationPerTest = 1000; + static boolean waitForKey = false; @BeforeClass public static void initClass() { @@ -79,7 +78,6 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { } private void setupFrameAndShow(final Frame f, java.awt.Component comp) throws InterruptedException, InvocationTargetException { - Container c = new Container(); c.setLayout(new BorderLayout()); c.add(new Button("north"), BorderLayout.NORTH); @@ -169,7 +167,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glWindow1, true)); Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); Assert.assertEquals(true, newtCanvasAWT1.isOffscreenLayerSurfaceEnabled()); - + GLAnimatorControl animator1 = new Animator(glWindow1); if(!noAnimation) { animator1.start(); @@ -187,6 +185,9 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { Thread.sleep(durationPerTest/2); end(animator1, frame1, glWindow1); + if( waitForKey ) { + UITestCase.waitForKey("Continue"); + } } public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { @@ -211,7 +212,6 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { } public static void main(String args[]) throws IOException { - boolean waitForKey = false; for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { durationPerTest = atoi(args[++i]); @@ -231,11 +231,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { } } if(waitForKey) { - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - System.err.println("Press enter to continue"); - try { - System.err.println(stdin.readLine()); - } catch (IOException e) { } + UITestCase.waitForKey("Start"); } String tstname = TestOffscreenLayer02NewtCanvasAWT.class.getName(); /* diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove01SwingAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove01SwingAWT.java index 76bb6362f..5e879d7ed 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove01SwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove01SwingAWT.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2013 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -33,9 +33,7 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import javax.media.opengl.GLCapabilities; @@ -106,21 +104,11 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { public void run() { jPanel[0] = new JPanel(); jPanel[0].setLayout(new BorderLayout()); - // jPanel[0].add(glcContainer[0], BorderLayout.CENTER); - - // final Container container2 = new Container(); - // container2.setLayout(new BorderLayout()); - // container2.add(jPanel1, BorderLayout.CENTER); - - final JPanel jPanel2 = new JPanel(); - jPanel2.setLayout(new BorderLayout()); - // jPanel2.add(container2, BorderLayout.CENTER); - jPanel2.add(jPanel[0], BorderLayout.CENTER); - + final JFrame jFrame1 = new JFrame("JFrame #"+num); // jFrame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // equivalent to Frame, use windowClosing event! - jFrame1.getContentPane().add(jPanel2); + jFrame1.getContentPane().add(jPanel[0]); jFrame1.setSize(width, height); top[0] = jFrame1; @@ -137,14 +125,6 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { } } ); } - protected void remove(final Container cont, final Component comp) - throws InterruptedException, InvocationTargetException - { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - cont.remove(comp); - } } ); - } protected void dispose(final GLCanvas glc) throws InterruptedException, InvocationTargetException { @@ -176,20 +156,17 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { throws AWTException, InterruptedException, InvocationTargetException { - // final JFrame[] parkingFrame = new JFrame[] { null }; - // final JPanel parkingPanel = createParkingSlot(parkingFrame, 2, 2); - for(int i=0; i<addRemoveOpCount; i++) { final GLCanvas glc = new GLCanvas(caps); Assert.assertNotNull(glc); + if(shallUseOffscreenFBOLayer || shallUseOffscreenPBufferLayer) { + glc.setShallUseOffscreenLayer(true); + } Dimension glc_sz = new Dimension(width, height); glc.setMinimumSize(glc_sz); glc.setPreferredSize(glc_sz); glc.setSize(glc_sz); glc.addGLEventListener(new Gears()); - glc.setAutoSwapBufferMode(false); - // add(parkingPanel, glc); - // remove(parkingPanel, glc); final JFrame[] top = new JFrame[] { null }; final Container glcCont = create(top, width, height, i); @@ -200,15 +177,13 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { final long t0 = System.currentTimeMillis(); do { glc.display(); - glc.swapBuffers(); Thread.sleep(10); } while ( ( System.currentTimeMillis() - t0 ) < durationPerTest ) ; System.err.println("GLCanvas isOffscreenLayerSurfaceEnabled: "+glc.isOffscreenLayerSurfaceEnabled()+": "+glc.getChosenGLCapabilities()); - // glc.destroy(); dispose(top[0]); - } + } } @Test @@ -216,11 +191,9 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { throws AWTException, InterruptedException, InvocationTargetException { GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); - if(shallUseOffscreenFBOLayer) { - caps.setOnscreen(false); - } if(shallUseOffscreenPBufferLayer) { caps.setPBuffer(true); + caps.setOnscreen(true); // simulate normal behavior .. } runTestGL(caps, addRemoveCount); } @@ -230,7 +203,7 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { if(args[i].equals("-time")) { i++; try { - durationPerTest = Integer.parseInt(args[i]); + durationPerTest = Long.parseLong(args[i]); } catch (Exception ex) { ex.printStackTrace(); } } else if(args[i].equals("-loops")) { i++; @@ -245,12 +218,14 @@ public class TestGLCanvasAddRemove01SwingAWT extends UITestCase { waitForKey = true; } } + System.err.println("waitForKey "+waitForKey); + + System.err.println("addRemoveCount "+addRemoveCount); + System.err.println("shallUseOffscreenFBOLayer "+shallUseOffscreenFBOLayer); System.err.println("shallUseOffscreenPBufferLayer "+shallUseOffscreenPBufferLayer); if(waitForKey) { - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - System.err.println("Press enter to continue"); - System.err.println(stdin.readLine()); + UITestCase.waitForKey("Start"); } org.junit.runner.JUnitCore.main(TestGLCanvasAddRemove01SwingAWT.class.getName()); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove02NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove02NewtCanvasAWT.java new file mode 100644 index 000000000..3f9d677f9 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAddRemove02NewtCanvasAWT.java @@ -0,0 +1,238 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.awt; + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestGLCanvasAddRemove02NewtCanvasAWT extends UITestCase { + static long durationPerTest = 50; + static int addRemoveCount = 15; + static boolean shallUseOffscreenFBOLayer = false; + static boolean shallUseOffscreenPBufferLayer = false; + static GLProfile glp; + static int width, height; + static boolean waitForKey = false; + + @BeforeClass + public static void initClass() { + if(GLProfile.isAvailable(GLProfile.GL2)) { + glp = GLProfile.get(GLProfile.GL2); + Assert.assertNotNull(glp); + width = 640; + height = 480; + } else { + setTestSupported(false); + } + } + + @AfterClass + public static void releaseClass() { + } + + protected JPanel createParkingSlot(final JFrame[] top, final int width, final int height) + throws InterruptedException, InvocationTargetException + { + final JPanel[] jPanel = new JPanel[] { null }; + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jPanel[0] = new JPanel(); + jPanel[0].setLayout(new BorderLayout()); + + final JFrame jFrame1 = new JFrame("Parking Slot"); + // jFrame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + jFrame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // equivalent to Frame, use windowClosing event! + jFrame1.getContentPane().add(jPanel[0]); + jFrame1.setSize(width, height); + + top[0] = jFrame1; + } } ); + return jPanel[0]; + } + + protected JPanel create(final JFrame[] top, final int width, final int height, final int num) + throws InterruptedException, InvocationTargetException + { + final JPanel[] jPanel = new JPanel[] { null }; + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jPanel[0] = new JPanel(); + jPanel[0].setLayout(new BorderLayout()); + + final JFrame jFrame1 = new JFrame("JFrame #"+num); + // jFrame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + jFrame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // equivalent to Frame, use windowClosing event! + jFrame1.getContentPane().add(jPanel[0]); + jFrame1.setSize(width, height); + + top[0] = jFrame1; + } } ); + return jPanel[0]; + } + + protected void add(final Container cont, final Component comp) + throws InterruptedException, InvocationTargetException + { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + cont.add(comp, BorderLayout.CENTER); + } } ); + } + + protected void dispose(final GLCanvas glc) + throws InterruptedException, InvocationTargetException + { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + glc.destroy(); + } } ); + } + + protected void setVisible(final JFrame jFrame, final boolean visible) throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + if( visible ) { + jFrame.validate(); + jFrame.pack(); + } + jFrame.setVisible(visible); + } } ) ; + } + + protected void dispose(final JFrame jFrame) throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jFrame.dispose(); + } } ) ; + } + + protected void runTestGL(GLCapabilities caps, int addRemoveOpCount) + throws AWTException, InterruptedException, InvocationTargetException + { + + for(int i=0; i<addRemoveOpCount; i++) { + final GLWindow glw = GLWindow.create(caps); + + final NewtCanvasAWT glc = new NewtCanvasAWT(glw); + Assert.assertNotNull(glc); + if(shallUseOffscreenFBOLayer || shallUseOffscreenPBufferLayer) { + glc.setShallUseOffscreenLayer(true); + } + Dimension glc_sz = new Dimension(width, height); + glc.setMinimumSize(glc_sz); + glc.setPreferredSize(glc_sz); + glc.setSize(glc_sz); + glw.addGLEventListener(new Gears()); + + final JFrame[] top = new JFrame[] { null }; + final Container glcCont = create(top, width, height, i); + add(glcCont, glc); + + setVisible(top[0], true); + + final long t0 = System.currentTimeMillis(); + do { + glw.display(); + Thread.sleep(10); + } while ( ( System.currentTimeMillis() - t0 ) < durationPerTest ) ; + + System.err.println("GLCanvas isOffscreenLayerSurfaceEnabled: "+glc.isOffscreenLayerSurfaceEnabled()+": "+glw.getChosenGLCapabilities()); + + dispose(top[0]); + glw.destroy(); + } + } + + @Test + public void test01() + throws AWTException, InterruptedException, InvocationTargetException + { + GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); + if(shallUseOffscreenPBufferLayer) { + caps.setPBuffer(true); + caps.setOnscreen(true); // get native NEWT Window, not OffscreenWindow + } + + runTestGL(caps, addRemoveCount); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + durationPerTest = Long.parseLong(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(args[i].equals("-loops")) { + i++; + try { + addRemoveCount = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(args[i].equals("-layeredFBO")) { + shallUseOffscreenFBOLayer = true; + } else if(args[i].equals("-layeredPBuffer")) { + shallUseOffscreenPBufferLayer = true; + } else if(args[i].equals("-wait")) { + waitForKey = true; + } + } + System.err.println("waitForKey "+waitForKey); + + System.err.println("addRemoveCount "+addRemoveCount); + + System.err.println("shallUseOffscreenFBOLayer "+shallUseOffscreenFBOLayer); + System.err.println("shallUseOffscreenPBufferLayer "+shallUseOffscreenPBufferLayer); + if(waitForKey) { + UITestCase.waitForKey("Start"); + } + org.junit.runner.JUnitCore.main(TestGLCanvasAddRemove02NewtCanvasAWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java b/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java index b028df377..44e2eeda7 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java +++ b/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java @@ -28,7 +28,10 @@ package com.jogamp.opengl.test.junit.util; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.Iterator; import java.util.List; @@ -141,6 +144,14 @@ public abstract class UITestCase { System.err.println("++++ UITestCase.tearDown: "+getFullTestName(" - ")); } + public static void waitForKey(String preMessage) { + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println(preMessage+"> Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (IOException e) { } + } + static final String unsupportedTestMsg = "Test not supported on this platform."; public String getSnapshotFilename(int sn, String postSNDetail, GLCapabilitiesImmutable caps, int width, int height, boolean sinkHasAlpha, String fileSuffix, String destPath) { |