diff options
10 files changed, 571 insertions, 95 deletions
diff --git a/make/build-test.xml b/make/build-test.xml index b7220aed6..d4274cd76 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -478,7 +478,7 @@ <batchtest todir="${results.test}"> <fileset dir="${classes}"> - <include name="${java.dir.junit}/**/acore/TestSharedContextVBO**"/> + <include name="${java.dir.junit}/**/acore/TestSharedContext**"/> <exclude name="**/*$$*"/> </fileset> <formatter usefile="false" type="brief"/> diff --git a/make/scripts/tests-win.bat b/make/scripts/tests-win.bat index 71ac8c43d..0632c24b0 100755 --- a/make/scripts/tests-win.bat +++ b/make/scripts/tests-win.bat @@ -14,10 +14,10 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedConte REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3 %* -scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 %* +REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3b %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextWithJTabbedPaneAWT %* -REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 %* +scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextNewtAWTBug523 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListAWT %* diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 0f3388fb3..6a8ff80ca 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -377,10 +377,10 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3 $* -testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3b $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextWithJTabbedPaneAWT $* -#testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextNewtAWTBug523 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListAWT $* diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 5e3731984..1268e9569 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -52,6 +52,7 @@ import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; +import javax.media.opengl.GLSharedContextSetter; import javax.media.opengl.Threading; import jogamp.nativewindow.x11.X11Util; @@ -85,7 +86,7 @@ import com.jogamp.opengl.JoglVersion; * Implementation allows use of custom {@link GLCapabilities}. * </p> */ -public class GLCanvas extends Canvas implements GLAutoDrawable { +public class GLCanvas extends Canvas implements GLAutoDrawable, GLSharedContextSetter { private static final boolean DEBUG = Debug.debug("GLCanvas"); /* @@ -103,7 +104,6 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final RecursiveLock lock = LockFactory.createRecursiveLock(); private final GLDrawableHelper helper = new GLDrawableHelper(); - private final GLContext shareWith; private final GLCapabilitiesImmutable capsRequested; private final GLCapabilitiesChooser capsChooser; @@ -124,6 +124,10 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { /* Flag indicating whether an unprocessed reshape is pending. */ private volatile boolean sendReshape; // volatile: maybe written by WindowManager thread w/o locking + private static String getThreadName() { return Thread.currentThread().getName(); } + private static String toHexString(int v) { return "0x"+Integer.toHexString(v); } + private static String toHexString(long v) { return "0x"+Long.toHexString(v); } + /* * Invokes init(...) on all GLEventListeners. Assumes context is current when run. */ @@ -263,6 +267,36 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /** + * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * on the SWT thread. + * + * @param parent + * Required (non-null) parent Composite. + * @param style + * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the + * Canvas constructor, so OpenGL handles the background. + * @param caps + * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the + * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are + * actually used may differ based on the capabilities of the graphics device. + * @param chooser + * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the + * requested GLCapabilities, and the available capabilities of the graphics device. + * @return a new instance + */ + public static GLCanvas create(final Composite parent, final int style, final GLCapabilitiesImmutable caps, + final GLCapabilitiesChooser chooser) { + final GLCanvas[] res = new GLCanvas[] { null }; + parent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + res[0] = new GLCanvas( parent, style, caps, chooser ); + } + }); + return res[0]; + } + + /** * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser, GLContext)} * on the SWT thread. * @@ -281,6 +315,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. * @return a new instance + * @deprecated Use {@link #create(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}. */ public static GLCanvas create(final Composite parent, final int style, final GLCapabilitiesImmutable caps, final GLCapabilitiesChooser chooser, final GLContext shareWith) { @@ -309,8 +345,31 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param capsChooser * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the * requested GLCapabilities, and the available capabilities of the graphics device. + */ + public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, + final GLCapabilitiesChooser capsChooser) { + this(parent, style, capsReqUser, capsChooser, null); + } + + /** + * Creates a new SWT GLCanvas. + * + * @param parent + * Required (non-null) parent Composite. + * @param style + * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the + * Canvas constructor, so OpenGL handles the background. + * @param capsReqUser + * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the + * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are + * actually used may differ based on the capabilities of the graphics device. + * @param capsChooser + * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the + * requested GLCapabilities, and the available capabilities of the graphics device. * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. + * @deprecated Use {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}. */ public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, final GLCapabilitiesChooser capsChooser, final GLContext shareWith) { @@ -347,7 +406,9 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { this.capsRequested = capsReqUser; this.capsChooser = capsChooser; - this.shareWith = shareWith; + if( null != shareWith ) { + helper.setSharedContext(null, shareWith); + } // post create .. when ready gdkWindow = 0; @@ -376,6 +437,16 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { addListener (SWT.Dispose, listener); } + @Override + public final void setSharedContext(GLContext sharedContext) throws IllegalStateException { + helper.setSharedContext(this.context, sharedContext); + } + + @Override + public final void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { + helper.setSharedAutoDrawable(this, sharedAutoDrawable); + } + private final UpstreamSurfaceHook swtCanvasUpStreamHook = new UpstreamSurfaceHook() { @Override public final void create(ProxySurface s) { /* nop */ } @@ -411,7 +482,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { final boolean drawableOK = null != _drawable && _drawable.isRealized(); if(DEBUG) { final long dh = drawableOK ? _drawable.getHandle() : 0; - System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle 0x"+Long.toHexString(dh)); + System.err.println(getThreadName()+": GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle "+toHexString(dh)); } if( drawableOK ) { if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { @@ -451,7 +522,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } } - /** assumes drawable == null || !drawable.isRealized() ! Checks of !isDispose() and isVisible() */ + /** assumes drawable == null (implying !drawable.isRealized()) ! Checks of !isDispose() and isVisible() */ protected final boolean validateDrawableAndContextWithCheck() { if( !isValidAndVisibleOnEDT() ) { return false; @@ -459,41 +530,55 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { return validateDrawableAndContextPostCheck(); } - /** assumes drawable == null || !drawable.isRealized() ! No check of !isDispose() and isVisible() */ - protected final boolean validateDrawableAndContextPostCheck() { - final Rectangle nClientArea = clientArea; - if(0 >= nClientArea.width || 0 >= nClientArea.height) { - return false; - } + private final boolean isDrawableAndContextValid() { + // drawable != null implies drawable.isRealized()==true + return null != drawable && null != context; + } - final boolean res; + /** assumes drawable == null (implying !drawable.isRealized()) || context == null ! No check of !isDispose() and isVisible() */ + private final boolean validateDrawableAndContextPostCheck() { + boolean res; final RecursiveLock _lock = lock; _lock.lock(); try { if(null == drawable) { - createDrawableAndContext(); + // 'displayable' (isValidAndVisibleOnEDT()) must have been checked upfront if appropriate! + createDrawableImpl(); // checks clientArea size (i.e. drawable size) and perf. realization } - if(null != drawable) { - drawable.setRealized(true); - res = drawable.isRealized(); + final GLDrawable _drawable = drawable; + if ( null != _drawable ) { + // drawable realization goes in-hand w/ it's construction + if( null == context ) { + // re-try context creation + res = createContextImpl(_drawable); // pending creation. + } else { + res = true; + } + if(res) { + sendReshape = true; + } } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": null drawable"); + } res = false; } - } finally { - _lock.unlock(); - } - - if(res) { - sendReshape = true; if(DEBUG) { - System.err.println("SWT GLCanvas realized! "+this+", "+drawable); - // Thread.dumpStack(); + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": "+res+", drawable-realized "+drawable.isRealized()+", has context "+(null!=context)); } + } finally { + _lock.unlock(); } return res; } - - private final void createDrawableAndContext() { + private final void createDrawableImpl() { + final Rectangle nClientArea = clientArea; + if(0 >= nClientArea.width || 0 >= nClientArea.height) { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": drawable could not be created: size < 0x0"); + } + return; // early out + } final AbstractGraphicsDevice device = screen.getDevice(); device.open(); @@ -503,7 +588,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( capsRequested, capsRequested, capsChooser, screen, VisualIDHolder.VID_UNDEFINED); if(DEBUG) { - System.err.println("SWT.GLCanvas.X11 factory: "+factory+", chosen config: "+cfg); + System.err.println(getThreadName()+": SWT.GLCanvas.X11 "+toHexString(hashCode())+": factory: "+factory+", chosen config: "+cfg); } if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); @@ -515,7 +600,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { x11Window = SWTAccessor.createCompatibleX11ChildWindow(screen, this, visualID, clientArea.width, clientArea.height); nativeWindowHandle = x11Window; } else { - throw new GLException("Could not choose valid visualID: 0x"+Integer.toHexString(visualID)+", "+this); + throw new GLException("Could not choose valid visualID: "+toHexString(visualID)+", "+this); } } else { nativeWindowHandle = SWTAccessor.getWindowHandle(this); @@ -526,9 +611,35 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { ProxySurface proxySurface = glFactory.createProxySurface(device, screen.getIndex(), nativeWindowHandle, capsRequested, capsChooser, swtCanvasUpStreamHook); // Associate a GL surface with the proxy - drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); - context = (GLContextImpl) drawable.createContext(shareWith); - context.setContextCreationFlags(additionalCtxCreationFlags); + final GLDrawableImpl _drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + _drawable.setRealized(true); + if(!_drawable.isRealized()) { + // oops + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": Drawable could not be realized: "+_drawable); + } + } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Drawable created and realized"); + } + drawable = _drawable; + } + } + private boolean createContextImpl(final GLDrawable drawable) { + final GLContext[] shareWith = { null }; + if( !helper.isSharedGLContextPending(shareWith) ) { + context = (GLContextImpl) drawable.createContext(shareWith[0]); + context.setContextCreationFlags(additionalCtxCreationFlags); + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Context created: has shared "+(null != shareWith[0])); + } + return true; + } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Context !created: pending share"); + } + return false; + } } @Override @@ -555,8 +666,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final void displayIfNoAnimatorNoCheck() { if ( !helper.isAnimatorAnimatingOnOtherThread() ) { - final boolean drawableOK = null != drawable && drawable.isRealized(); - if( drawableOK || validateDrawableAndContextPostCheck() ) { + if( isDrawableAndContextValid() || validateDrawableAndContextPostCheck() ) { runInGLThread(makeCurrentAndDisplayOnGLAction); } } @@ -568,8 +678,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void display() { - final boolean drawableOK = null != drawable && drawable.isRealized(); - if( drawableOK || validateDrawableAndContextWithCheck() ) { + if( isDrawableAndContextValid() || validateDrawableAndContextWithCheck() ) { runInGLThread(makeCurrentAndDisplayOnGLAction); } } @@ -876,7 +985,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { return "SWT-GLCanvas[Realized "+isRealized()+ ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ ",\n\tFactory "+getFactory()+ - ",\n\thandle 0x"+Long.toHexString(getHandle())+ + ",\n\thandle "+toHexString(getHandle())+ ",\n\tDrawable size "+dw+"x"+dh+ ",\n\tSWT size "+getWidth()+"x"+getHeight()+"]"; } @@ -895,7 +1004,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { shell.setSize(128,128); shell.setLayout(new FillLayout()); - final GLCanvas canvas = new GLCanvas(shell, 0, caps, null, null); + final GLCanvas canvas = new GLCanvas(shell, 0, caps, null); canvas.addGLEventListener(new GLEventListener() { @Override diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java index 5cf2e4b24..710a9772b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java @@ -50,7 +50,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** - * Sharing the VBO of 3 GearsES2 instances, each in their own GLCanvas. + * Sharing the VBO of 3 GearsES2 instances, each in their own AWT GLCanvas. * <p> * This is achieved by using the 1st GLCanvas as the <i>master</i> * and using the build-in blocking mechanism to postpone creation diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java index 07b9fd4eb..c35b0658c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java @@ -50,7 +50,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** - * Sharing the VBO of 3 GearsES2 instances, each in their own GLJPanel. + * Sharing the VBO of 3 GearsES2 instances, each in their own AWT GLJPanel. * <p> * This is achieved by using the 1st GLJPanel as the <i>master</i> * and using the build-in blocking mechanism to postpone creation diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java new file mode 100644 index 000000000..9b6ab88fa --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java @@ -0,0 +1,367 @@ +/** + * Copyright 2010 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.acore; + +import java.util.List; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLProfile; + +import com.jogamp.nativewindow.swt.SWTAccessor; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.swt.GLCanvas; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +/** + * Sharing the VBO of 3 GearsES2 instances, each in their own SWT GLCanvas. + * <p> + * This is achieved by using the 1st GLCanvas as the <i>master</i> + * and using the build-in blocking mechanism to postpone creation + * of the 2nd and 3rd GLCanvas until the 1st GLCanvas's GLContext becomes created. + * </p> + * <p> + * Above method allows random creation of the 1st GLCanvas <b>in theory</b>, which triggers + * creation of the <i>dependent</i> other GLCanvas sharing it's GLContext.<br> + * However, since this test may perform on the <i>main thread</i> we have + * to initialize all in order, since otherwise the <i>test main thread</i> + * itself blocks SWT GLCanvas creation .. + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestSharedContextVBOES2SWT3 extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + + @BeforeClass + public static void initClass() { + if(GLProfile.isAvailable(GLProfile.GL2ES2)) { + glp = GLProfile.get(GLProfile.GL2ES2); + Assert.assertNotNull(glp); + caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + width = 256; + height = 256; + } else { + setTestSupported(false); + } + } + + Display display = null; + Shell shell1 = null; + Composite composite1 = null; + Shell shell2 = null; + Composite composite2 = null; + Shell shell3 = null; + Composite composite3 = null; + + @Before + public void init() { + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display = new Display(); + Assert.assertNotNull( display ); + }}); + display.syncExec(new Runnable() { + public void run() { + shell1 = new Shell( display ); + shell1.setLayout( new FillLayout() ); + composite1 = new Composite( shell1, SWT.NO_BACKGROUND ); + composite1.setLayout( new FillLayout() ); + + shell2 = new Shell( display ); + shell2.setLayout( new FillLayout() ); + composite2 = new Composite( shell2, SWT.NO_BACKGROUND ); + composite2.setLayout( new FillLayout() ); + + shell3 = new Shell( display ); + shell3.setLayout( new FillLayout() ); + composite3 = new Composite( shell3, SWT.NO_BACKGROUND ); + composite3.setLayout( new FillLayout() ); + }}); + } + + @After + public void release() { + Assert.assertNotNull( display ); + Assert.assertNotNull( shell1 ); + Assert.assertNotNull( composite1 ); + Assert.assertNotNull( shell2 ); + Assert.assertNotNull( composite2 ); + Assert.assertNotNull( shell3 ); + Assert.assertNotNull( composite3 ); + try { + display.syncExec(new Runnable() { + public void run() { + composite3.dispose(); + shell3.dispose(); + composite2.dispose(); + shell2.dispose(); + composite1.dispose(); + shell1.dispose(); + }}); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display.dispose(); + }}); + } + catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + display = null; + shell1 = null; + composite1 = null; + shell2 = null; + composite2 = null; + shell3 = null; + composite3 = null; + } + + protected GLCanvas createGLCanvas(final Shell shell, final Composite composite, final int x, final int y, GearsES2 gears) throws InterruptedException { + final GLCanvas glCanvas = GLCanvas.create( composite, 0, caps, null); + Assert.assertNotNull( glCanvas ); + glCanvas.addGLEventListener(gears); + display.syncExec(new Runnable() { + public void run() { + shell.setText("SWT GLCanvas Shared Gears Test"); + shell.setSize( width, height); + shell.setLocation(x, y); + } } ); + return glCanvas; + } + + @Test + public void test01SyncedOneAnimator() throws InterruptedException { + final Animator animator = new Animator(); + final GearsES2 g1 = new GearsES2(0); + final GLCanvas c1 = createGLCanvas(shell1, composite1, 0, 0, g1); + animator.add(c1); + + final GearsES2 g2 = new GearsES2(0); + g2.setSharedGears(g1); + final GLCanvas c2 = createGLCanvas(shell2, composite2, 0+width, 0+0, g2); + c2.setSharedAutoDrawable(c1); + animator.add(c2); + + final GearsES2 g3 = new GearsES2(0); + g3.setSharedGears(g1); + final GLCanvas c3 = createGLCanvas(shell3, composite3, 0, height, g3); + c3.setSharedAutoDrawable(c1); + animator.add(c3); + + display.syncExec(new Runnable() { + public void run() { + shell1.open(); // master .. + shell2.open(); // shall wait until f1 is ready + shell3.open(); // shall wait until f1 is ready + } } ); + animator.start(); // kicks off GLContext .. and hence gears of f2 + f3 completion + + Thread.sleep(1000/60*10); // wait ~10 frames giving a chance to create (blocking until master share is valid) + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c1, true)); + Assert.assertTrue("Gears1 not initialized", g1.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c2, true)); + Assert.assertTrue("Gears2 not initialized", g2.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c3, true)); + Assert.assertTrue("Gears3 not initialized", g3.waitForInit(true)); + + final GLContext ctx1 = c1.getContext(); + final GLContext ctx2 = c2.getContext(); + final GLContext ctx3 = c3.getContext(); + { + final List<GLContext> ctx1Shares = ctx1.getCreatedShares(); + final List<GLContext> ctx2Shares = ctx2.getCreatedShares(); + final List<GLContext> ctx3Shares = ctx3.getCreatedShares(); + System.err.println("XXX-C-3.1:"); + MiscUtils.dumpSharedGLContext(ctx1); + System.err.println("XXX-C-3.2:"); + MiscUtils.dumpSharedGLContext(ctx2); + System.err.println("XXX-C-3.3:"); + MiscUtils.dumpSharedGLContext(ctx3); + + Assert.assertTrue("Ctx1 is not shared", ctx1.isShared()); + Assert.assertTrue("Ctx2 is not shared", ctx2.isShared()); + Assert.assertTrue("Ctx3 is not shared", ctx3.isShared()); + Assert.assertEquals("Ctx1 has unexpected number of created shares", 2, ctx1Shares.size()); + Assert.assertEquals("Ctx2 has unexpected number of created shares", 2, ctx2Shares.size()); + Assert.assertEquals("Ctx3 has unexpected number of created shares", 2, ctx3Shares.size()); + } + + Assert.assertTrue("Gears1 is shared", !g1.usesSharedGears()); + Assert.assertTrue("Gears2 is not shared", g2.usesSharedGears()); + Assert.assertTrue("Gears3 is not shared", g3.usesSharedGears()); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + animator.stop(); + + display.syncExec(new Runnable() { + public void run() { + c3.dispose(); + c2.dispose(); + c1.dispose(); + } } ); + } + + @Test + public void test02AsyncEachAnimator() throws InterruptedException { + final Animator a1 = new Animator(); + final GearsES2 g1 = new GearsES2(0); + final GLCanvas c1 = createGLCanvas(shell1, composite1, 0, 0, g1); + a1.add(c1); + display.syncExec(new Runnable() { + public void run() { + shell1.open(); + } } ); + a1.start(); + + + Thread.sleep(1000/60*10); // wait ~10 frames giving a chance to create (blocking until master share is valid) + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c1, true)); + Assert.assertTrue("Gears1 not initialized", g1.waitForInit(true)); + + final Animator a2 = new Animator(); + final GearsES2 g2 = new GearsES2(0); + g2.setSharedGears(g1); + final GLCanvas c2 = createGLCanvas(shell2, composite2, width, 0, g2); + c2.setSharedAutoDrawable(c1); + a2.add(c2); + display.syncExec(new Runnable() { + public void run() { + shell2.open(); + } } ); + a2.start(); + + Thread.sleep(200); // wait a while .. + + final Animator a3 = new Animator(); + final GearsES2 g3 = new GearsES2(0); + g3.setSharedGears(g1); + final GLCanvas c3 = createGLCanvas(shell3, composite3, 0, height, g3); + c3.setSharedAutoDrawable(c1); + a3.add(c3); + display.syncExec(new Runnable() { + public void run() { + shell3.open(); + } } ); + a3.start(); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c2, true)); + Assert.assertTrue("Gears2 not initialized", g2.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c3, true)); + Assert.assertTrue("Gears3 not initialized", g3.waitForInit(true)); + + final GLContext ctx1 = c1.getContext(); + final GLContext ctx2 = c2.getContext(); + final GLContext ctx3 = c3.getContext(); + { + final List<GLContext> ctx1Shares = ctx1.getCreatedShares(); + final List<GLContext> ctx2Shares = ctx2.getCreatedShares(); + final List<GLContext> ctx3Shares = ctx3.getCreatedShares(); + System.err.println("XXX-C-3.1:"); + MiscUtils.dumpSharedGLContext(ctx1); + System.err.println("XXX-C-3.2:"); + MiscUtils.dumpSharedGLContext(ctx2); + System.err.println("XXX-C-3.3:"); + MiscUtils.dumpSharedGLContext(ctx3); + + Assert.assertTrue("Ctx1 is not shared", ctx1.isShared()); + Assert.assertTrue("Ctx2 is not shared", ctx2.isShared()); + Assert.assertTrue("Ctx3 is not shared", ctx3.isShared()); + Assert.assertEquals("Ctx1 has unexpected number of created shares", 2, ctx1Shares.size()); + Assert.assertEquals("Ctx2 has unexpected number of created shares", 2, ctx2Shares.size()); + Assert.assertEquals("Ctx3 has unexpected number of created shares", 2, ctx3Shares.size()); + } + + Assert.assertTrue("Gears1 is shared", !g1.usesSharedGears()); + Assert.assertTrue("Gears2 is not shared", g2.usesSharedGears()); + Assert.assertTrue("Gears3 is not shared", g3.usesSharedGears()); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + a1.stop(); + a2.stop(); + a3.stop(); + + display.syncExec(new Runnable() { + public void run() { + c3.dispose(); + c2.dispose(); + c1.dispose(); + } } ); + } + + static long duration = 1000; // ms + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + /** + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + System.err.println(stdin.readLine()); */ + org.junit.runner.JUnitCore.main(TestSharedContextVBOES2SWT3.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java index df7a25448..b6463ac0f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java @@ -3,14 +3,14 @@ * * 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 @@ -20,12 +20,12 @@ * 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.demos.es2.swt; import java.io.IOException; @@ -65,7 +65,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestGearsES2SWT extends UITestCase { +public class TestGearsES2SWT extends UITestCase { static int screenIdx = 0; static PointImmutable wpos; static DimensionImmutable wsize, rwsize=null; @@ -83,7 +83,7 @@ public class TestGearsES2SWT extends UITestCase { static boolean forceGL3 = false; static boolean mainRun = false; static boolean exclusiveContext = false; - + @BeforeClass public static void initClass() { if(null == wsize) { @@ -98,16 +98,16 @@ public class TestGearsES2SWT extends UITestCase { Display display = null; Shell shell = null; Composite composite = null; - + @Before public void init() { SWTAccessor.invoke(true, new Runnable() { - public void run() { + public void run() { display = new Display(); Assert.assertNotNull( display ); }}); display.syncExec(new Runnable() { - public void run() { + public void run() { shell = new Shell( display ); Assert.assertNotNull( shell ); shell.setLayout( new FillLayout() ); @@ -141,21 +141,21 @@ public class TestGearsES2SWT extends UITestCase { shell = null; composite = null; } - + protected void runTestGL(GLCapabilitiesImmutable caps) throws InterruptedException, InvocationTargetException { System.err.println("requested: vsync "+swapInterval+", "+caps); - - final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null, null); + + final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null); Assert.assertNotNull( canvas ); - + final GearsES2 demo = new GearsES2(swapInterval); demo.setPMVUseBackingArray(pmvUseBackingArray); canvas.addGLEventListener(demo); - + Animator animator = new Animator(); animator.setModeBits(false, Animator.MODE_EXPECT_AWT_RENDERING_THREAD); animator.setExclusiveContext(exclusiveContext); - + animator.add(canvas); animator.start(); Assert.assertTrue(animator.isStarted()); @@ -172,9 +172,9 @@ public class TestGearsES2SWT extends UITestCase { shell.open(); } }); - + animator.setUpdateFPSFrames(60, showFPS ? System.err : null); - + while(animator.isAnimating() && !canvas.isRealized() && animator.getTotalFPSDuration()<duration) { if( !display.readAndDispatch() ) { // blocks on linux .. display.sleep(); @@ -184,7 +184,7 @@ public class TestGearsES2SWT extends UITestCase { System.err.println("NW chosen: "+canvas.getDelegatedDrawable().getChosenGLCapabilities()); System.err.println("GL chosen: "+canvas.getChosenGLCapabilities()); System.err.println("window pos/siz: "+canvas.getLocation()+" "+canvas.getWidth()+"x"+canvas.getHeight()); - + if( null != rwsize ) { for(int i=0; i<50; i++) { // 500 ms dispatched delay if( !display.readAndDispatch() ) { @@ -199,7 +199,7 @@ public class TestGearsES2SWT extends UITestCase { }); System.err.println("window resize pos/siz: "+canvas.getLocation()+" "+canvas.getWidth()+"x"+canvas.getHeight()); } - + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { if( !display.readAndDispatch() ) { // blocks on linux .. display.sleep(); @@ -212,7 +212,7 @@ public class TestGearsES2SWT extends UITestCase { Assert.assertFalse(animator.isAnimating()); Assert.assertFalse(animator.isStarted()); Assert.assertEquals(null, canvas.getExclusiveContextThread()); - + display.syncExec(new Runnable() { public void run() { canvas.dispose(); @@ -234,7 +234,7 @@ public class TestGearsES2SWT extends UITestCase { final GLCapabilities caps = new GLCapabilities( glp ); caps.setBackgroundOpaque(opaque); if(-1 < forceAlpha) { - caps.setAlphaBits(forceAlpha); + caps.setAlphaBits(forceAlpha); } runTestGL(caps); if(loop_shutdown) { @@ -246,7 +246,7 @@ public class TestGearsES2SWT extends UITestCase { @Test public void test02GL3() throws InterruptedException, InvocationTargetException { if(mainRun) return; - + if( !GLProfile.isAvailable(GLProfile.GL3) ) { System.err.println("GL3 n/a"); return; @@ -255,13 +255,13 @@ public class TestGearsES2SWT extends UITestCase { final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps); } - + public static void main(String args[]) throws IOException { mainRun = true; - + int x=0, y=0, w=640, h=480, rw=-1, rh=-1; boolean usePos = false; - + for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { i++; @@ -320,7 +320,7 @@ public class TestGearsES2SWT extends UITestCase { if( 0 < rw && 0 < rh ) { rwsize = new Dimension(rw, rh); } - + if(usePos) { wpos = new Point(x, y); } @@ -329,9 +329,9 @@ public class TestGearsES2SWT extends UITestCase { System.err.println("resize "+rwsize); System.err.println("screen "+screenIdx); System.err.println("translucent "+(!opaque)); - System.err.println("forceAlpha "+forceAlpha); + System.err.println("forceAlpha "+forceAlpha); System.err.println("fullscreen "+fullscreen); - System.err.println("pmvDirect "+(!pmvUseBackingArray)); + System.err.println("pmvDirect "+(!pmvUseBackingArray)); System.err.println("loops "+loops); System.err.println("loop shutdown "+loop_shutdown); System.err.println("forceES2 "+forceES2); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java index 8b4e095f3..fd6d370ac 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java @@ -227,7 +227,7 @@ public class TestSWTBug643AsyncExec extends UITestCase { final GLAutoDrawable glad; if( useJOGLGLCanvas ) { final GearsES2 demo = new GearsES2(); - final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null, null); + final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null); final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory(); swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys); glc.addGLEventListener( demo ) ; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java index a1d8d40c2..b38bf0c2c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java @@ -3,14 +3,14 @@ * * 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 @@ -20,12 +20,12 @@ * 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.swt; import javax.media.opengl.GLAutoDrawable; @@ -60,13 +60,13 @@ import com.jogamp.opengl.util.texture.TextureIO; /** * Tests that a basic SWT app can open without crashing under different GL profiles. - * <p> + * <p> * Uses JOGL's new SWT GLCanvas, * which allows utilizing custom GLCapability settings, * independent from the already instantiated SWT visual. * </p> * <p> - * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ + * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ * SWT running on Mac OSX, i.e. to enforce UI action on the main thread. * </p> * @author Wade Walker, et al. @@ -76,7 +76,7 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { static int duration = 250; static boolean doAnimation = true; - + static final int iwidth = 640; static final int iheight = 480; @@ -92,12 +92,12 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { @Before public void init() { SWTAccessor.invoke(true, new Runnable() { - public void run() { + public void run() { display = new Display(); Assert.assertNotNull( display ); }}); display.syncExec(new Runnable() { - public void run() { + public void run() { shell = new Shell( display ); Assert.assertNotNull( shell ); shell.setLayout( new FillLayout() ); @@ -134,14 +134,14 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { protected void runTestAGL( GLCapabilitiesImmutable caps, GLEventListener demo ) throws InterruptedException { final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false); - - final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null, null); + + final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null); Assert.assertNotNull( canvas ); canvas.addGLEventListener( demo ); canvas.addGLEventListener(new GLEventListener() { int displayCount = 0; - public void init(final GLAutoDrawable drawable) { } + public void init(final GLAutoDrawable drawable) { } public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } public void display(final GLAutoDrawable drawable) { if(displayCount < 3) { @@ -149,21 +149,21 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { } } public void dispose(final GLAutoDrawable drawable) { } - }); - + }); + display.syncExec(new Runnable() { public void run() { shell.setText( getSimpleTestName(".") ); shell.setSize( 640, 480 ); shell.open(); } } ); - + Animator anim = new Animator(); if(doAnimation) { anim.add(canvas); anim.start(); - } - + } + long lStartTime = System.currentTimeMillis(); long lEndTime = lStartTime + duration; try { @@ -177,9 +177,9 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { throwable.printStackTrace(); Assume.assumeNoException( throwable ); } - + anim.stop(); - + display.syncExec(new Runnable() { public void run() { canvas.dispose(); @@ -198,7 +198,7 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { caps.setNumSamples(2); runTestAGL( caps, new MultisampleDemoES2(true) ); } - + static int atoi(String a) { int i=0; try { |