/**
* 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.acore.glels;
import java.awt.Dimension;
import java.awt.Frame;
import com.jogamp.opengl.GLAnimatorControl;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLContext;
import com.jogamp.opengl.GLDrawableFactory;
import com.jogamp.opengl.GLOffscreenAutoDrawable;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import jogamp.nativewindow.jawt.JAWTUtil;
import com.jogamp.newt.Screen;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.GLEventListenerState;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
import com.jogamp.opengl.test.junit.util.UITestCase;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
/**
* Test re-association of GLContext/GLDrawables,
* here GLContext's survival of GLDrawable destruction
* and reuse w/ new or recreated GLDrawable.
* <p>
* Test utilizes {@link GLEventListenerState} for preserving the
* GLAutoDrawable state, i.e. GLContext, all GLEventListener
* and the GLAnimatorControl association.
* </p>
* <p>
* See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
* </p>
*/
public abstract class GLContextDrawableSwitchBase1 extends UITestCase {
static protected enum GLADType { GLCanvasOnscreen, GLCanvasOffscreen, GLWindow, GLOffscreen };
// default period for 1 GLAD cycle
static long duration = 1000; // ms
static int width, height;
static GLCapabilities getCaps(final String profile) {
if( !GLProfile.isAvailable(profile) ) {
System.err.println("Profile "+profile+" n/a");
return null;
}
return new GLCapabilities(GLProfile.get(profile));
}
@BeforeClass
public static void initClass() {
width = 256;
height = 256;
}
static void setGLCanvasSize(final GLCanvas glc, final Dimension new_sz) {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
glc.setMinimumSize(new_sz);
glc.setPreferredSize(new_sz);
glc.setSize(new_sz);
} } );
} catch( final Throwable throwable ) {
throwable.printStackTrace();
Assume.assumeNoException( throwable );
}
}
static void setFrameVisible(final Frame frame) throws InterruptedException {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
frame.pack();
frame.setVisible(true);
}});
} catch( final Throwable throwable ) {
throwable.printStackTrace();
Assume.assumeNoException( throwable );
}
}
static void destroyFrame(final Frame frame) throws InterruptedException {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
frame.dispose();
}});
} catch( final Throwable throwable ) {
throwable.printStackTrace();
Assume.assumeNoException( throwable );
}
}
private GLOffscreenAutoDrawable createGLOffscreenAutoDrawable(final GLCapabilities caps, final int width, final int height) throws InterruptedException {
final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
return factory.createOffscreenAutoDrawable(null, caps, null, width, height);
}
protected static boolean validateOnOffscreenLayer(final GLADType gladType1, final GLADType gladType2) {
final boolean useOffscreenLayer = GLADType.GLCanvasOffscreen == gladType1 || GLADType.GLCanvasOffscreen == gladType2 ;
final boolean useOnscreenLayer = GLADType.GLCanvasOnscreen == gladType1 || GLADType.GLCanvasOnscreen == gladType2 ;
if( useOffscreenLayer ) {
if( !JAWTUtil.isOffscreenLayerSupported() ) {
System.err.println("Platform doesn't support offscreen rendering.");
return false;
}
} else if( useOnscreenLayer ) {
if( JAWTUtil.isOffscreenLayerRequired() ) {
System.err.println("Platform requires offscreen rendering.");
return false;
}
}
return true;
}
protected void testGLADOneLifecycle(final Screen screen, final GLCapabilities caps, final GLADType gladType, final int width,
final int height, final GLEventListenerCounter glelTracker,
final SnapshotGLEventListener snapshotGLEventListener, final GLEventListenerState glelsIn, final GLEventListenerState glelsOut[], final GLAnimatorControl animator)
throws InterruptedException {
System.err.println("GLAD Lifecycle.0 "+gladType+", restoring "+((null!=glelsIn)?true:false)+", preserving "+((null!=glelsOut)?true:false));
final Frame frame;
final GLAutoDrawable glad;
if( GLADType.GLCanvasOnscreen == gladType ) {
if( jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerRequired() ) {
throw new InternalError("Platform requires offscreen rendering, but onscreen requested: "+gladType);
}
frame = new Frame("AWT GLCanvas");
glad = new GLCanvas(caps);
setGLCanvasSize((GLCanvas)glad, new Dimension(width, height));
frame.add((GLCanvas)glad);
} else if( GLADType.GLCanvasOffscreen == gladType ) {
if( !jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerSupported() ) {
throw new InternalError("Platform doesn't support offscreen rendering: "+gladType);
}
frame = new Frame("AWT GLCanvas");
glad = new GLCanvas(caps);
((GLCanvas)glad).setShallUseOffscreenLayer(true);
setGLCanvasSize((GLCanvas)glad, new Dimension(width, height));
frame.add((GLCanvas)glad);
} else if( GLADType.GLWindow == gladType ) {
frame = null;
if( null != screen ) {
glad = GLWindow.create(screen, caps);
} else {
glad = GLWindow.create(caps);
}
((GLWindow)glad).setTitle("Newt GLWindow");
((GLWindow)glad).setSize(width, height);
} else if( GLADType.GLOffscreen == gladType ) {
frame = null;
glad = this.createGLOffscreenAutoDrawable(caps, width, height);
} else {
throw new InternalError("Unsupported: "+gladType);
}
if( null == glelsIn ) {
if( null != animator ) {
animator.add(glad);
}
glad.addGLEventListener(glelTracker);
glad.addGLEventListener(new GearsES2(1));
glad.addGLEventListener(snapshotGLEventListener);
}
snapshotGLEventListener.setMakeSnapshot();
if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) {
setFrameVisible(frame);
Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true));
} else if( GLADType.GLWindow == gladType ) {
((GLWindow)glad).setVisible(true);
}
Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, true));
Assert.assertNotNull(glad.getContext());
Assert.assertTrue(glad.isRealized());
if( null != glelsIn ) {
Assert.assertEquals(0, glad.getGLEventListenerCount());
System.err.println(".. restoring.0");
glelsIn.moveTo(glad);
System.err.println(".. restoring.X");
Assert.assertEquals(1, glelTracker.initCount);
Assert.assertTrue(1 <= glelTracker.reshapeCount);
Assert.assertTrue(1 <= glelTracker.displayCount);
Assert.assertEquals(0, glelTracker.disposeCount);
Assert.assertEquals(3, glad.getGLEventListenerCount());
Assert.assertEquals(glelsIn.context, glad.getContext());
Assert.assertEquals(glelsIn.listenerCount(), glad.getGLEventListenerCount());
Assert.assertEquals(glelsIn.context.getGLReadDrawable(), glad.getDelegatedDrawable());
Assert.assertEquals(glelsIn.context.getGLDrawable(), glad.getDelegatedDrawable());
Assert.assertEquals(false, glelsIn.isOwner());
}
for (int wait=0; wait<AWTRobotUtil.POLL_DIVIDER &&
( 1 > glelTracker.initCount || 1 > glelTracker.reshapeCount || 1 > glelTracker.displayCount );
wait++) {
Thread.sleep(AWTRobotUtil.TIME_SLICE);
}
final long t0 = System.currentTimeMillis();
long t1 = t0;
while( ( t1 - t0 ) < duration ) {
Thread.sleep(100);
t1 = System.currentTimeMillis();
}
Assert.assertEquals(1, glelTracker.initCount);
Assert.assertTrue(1 <= glelTracker.reshapeCount);
Assert.assertTrue(1 <= glelTracker.displayCount);
Assert.assertEquals(0, glelTracker.disposeCount);
if( null != glelsOut ) {
final GLContext context1 = glad.getContext();
System.err.println(".. preserving.0");
glelsOut[0] = GLEventListenerState.moveFrom(glad);
System.err.println(".. preserving.X");
Assert.assertEquals(context1, glelsOut[0].context);
Assert.assertNull(context1.getGLReadDrawable());
Assert.assertNull(context1.getGLDrawable());
Assert.assertEquals(3, glelsOut[0].listenerCount());
Assert.assertEquals(true, glelsOut[0].isOwner());
Assert.assertEquals(null, glad.getContext());
Assert.assertEquals(0, glad.getGLEventListenerCount());
}
if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) {
destroyFrame(frame);
Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, false));
} else if( GLADType.GLWindow == gladType ) {
glad.destroy();
} else if( GLADType.GLOffscreen == gladType ) {
glad.destroy();
}
Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, false));
Assert.assertEquals(1, glelTracker.initCount);
Assert.assertTrue(1 <= glelTracker.reshapeCount);
Assert.assertTrue(1 <= glelTracker.displayCount);
if( null != glelsOut ) {
Assert.assertEquals(0, glelTracker.disposeCount);
} else {
Assert.assertEquals(1, glelTracker.disposeCount);
}
System.err.println("GLAD Lifecycle.X "+gladType);
}
}