/** * 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.ect; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Window; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.nativewindow.Capabilities; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLProfile; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.AfterClass; import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** * ExclusiveContextThread base implementation to test correctness of the ExclusiveContext feature _and_ AnimatorBase. */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public abstract class ExclusiveContextBase00 extends UITestCase { static boolean testExclusiveWithAWT = false; static final int durationParts = 9; static long duration = 320 * durationParts; // ms ~ 20 frames static boolean showFPS = false; static int showFPSRate = 100; static final int demoWinSize = 128; static InsetsImmutable insets = null; static int num_x, num_y; static int swapInterval = 0; @BeforeClass public static void initClass00() { final Window dummyWindow = NewtFactory.createWindow(new Capabilities()); dummyWindow.setSize(demoWinSize, demoWinSize); dummyWindow.setVisible(true); Assert.assertEquals(true, dummyWindow.isVisible()); Assert.assertEquals(true, dummyWindow.isNativeValid()); insets = dummyWindow.getInsets(); final int scrnHeight = dummyWindow.getScreen().getHeight(); final int scrnWidth = dummyWindow.getScreen().getWidth(); final int[] demoScreenSize = dummyWindow.convertToPixelUnits(new int[] { demoWinSize, demoWinSize }); final int[] insetsScreenSize = dummyWindow.convertToPixelUnits(new int[] { insets.getTotalWidth(), insets.getTotalHeight() }); num_x = scrnWidth / ( demoScreenSize[0] + insetsScreenSize[0] ) - 2; num_y = scrnHeight / ( demoScreenSize[1] + insetsScreenSize[1] ) - 2; dummyWindow.destroy(); } @AfterClass public static void releaseClass00() { } protected abstract boolean isAWTTestCase(); protected abstract Thread getAWTRenderThread(); protected abstract AnimatorBase createAnimator(); protected abstract GLAutoDrawable createGLAutoDrawable(String title, int x, int y, int width, int height, GLCapabilitiesImmutable caps); protected abstract void setGLAutoDrawableVisible(GLAutoDrawable[] glads); protected abstract void destroyGLAutoDrawableVisible(GLAutoDrawable glad); protected void runTestGL(final GLCapabilitiesImmutable caps, final int drawableCount, final boolean exclusive, final boolean preAdd, final boolean shortenTest) throws InterruptedException { final boolean useAWTRenderThread = isAWTTestCase(); if( useAWTRenderThread && exclusive ) { if( testExclusiveWithAWT ) { System.err.println("Warning: Testing AWT + Exclusive -> Not advised!"); } else { System.err.println("Info: Skip test: AWT + Exclusive!"); return; } } if( useAWTRenderThread && exclusive && !testExclusiveWithAWT) { System.err.println("Skip test: AWT + Exclusive -> Not advised!"); return; } final Thread awtRenderThread = getAWTRenderThread(); final AnimatorBase animator = createAnimator(); if( !useAWTRenderThread ) { animator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD); } final GLAutoDrawable[] drawables = new GLAutoDrawable[drawableCount]; for(int i=0; i<drawableCount; i++) { final int x = ( i % num_x ) * ( demoWinSize + insets.getTotalHeight() ) + insets.getLeftWidth(); final int y = ( (i / num_x) % num_y ) * ( demoWinSize + insets.getTotalHeight() ) + insets.getTopHeight(); drawables[i] = createGLAutoDrawable("Win #"+i, x, y, demoWinSize, demoWinSize, caps); Assert.assertNotNull(drawables[i]); final GearsES2 demo = new GearsES2(swapInterval); demo.setVerbose(false); drawables[i].addGLEventListener(demo); } if( preAdd ) { for(int i=0; i<drawableCount; i++) { animator.add(drawables[i]); } if( exclusive ) { if( useAWTRenderThread ) { Assert.assertEquals(null, animator.setExclusiveContext(awtRenderThread)); } else { Assert.assertEquals(false, animator.setExclusiveContext(true)); } } } Assert.assertFalse(animator.isAnimating()); Assert.assertFalse(animator.isStarted()); // Animator Start Assert.assertTrue(animator.start()); Assert.assertTrue(animator.isStarted()); if( preAdd ) { Assert.assertTrue(animator.isAnimating()); } else { Assert.assertFalse(animator.isAnimating()); if( exclusive ) { if( useAWTRenderThread ) { Assert.assertEquals(null, animator.setExclusiveContext(awtRenderThread)); } else { Assert.assertEquals(false, animator.setExclusiveContext(true)); } } for(int i=0; i<drawableCount; i++) { animator.add(drawables[i]); } Assert.assertTrue(animator.isAnimating()); } Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); // After start, ExclusiveContextThread is set { final Thread ect = animator.getExclusiveContextThread(); if(exclusive) { if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } } else { Assert.assertEquals(null, ect); } for(int i=0; i<drawableCount; i++) { Assert.assertEquals(ect, drawables[i].getExclusiveContextThread()); } setGLAutoDrawableVisible(drawables); } animator.setUpdateFPSFrames(showFPSRate, showFPS ? System.err : null); // Normal run .. Thread.sleep(duration/durationParts); // 1 if( !shortenTest ) { // Disable/Enable exclusive mode manually for all GLAutoDrawable if(exclusive) { final Thread ect = animator.getExclusiveContextThread(); if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } for(int i=0; i<drawableCount; i++) { final Thread t = drawables[i].setExclusiveContextThread(null); Assert.assertEquals(ect, t); } Thread.sleep(duration/durationParts); // 2 for(int i=0; i<drawableCount; i++) { // poll until clearing drawable ECT is established { boolean ok = null == drawables[i].getExclusiveContextThread(); int c = 0; while(!ok && c<5*50) { // 5*50*20 = 5s TO Thread.sleep(20); ok = null == drawables[i].getExclusiveContextThread(); c++; } if(c>0) { System.err.println("Clearing drawable ECT was done 'later' @ "+(c*20)+"ms, ok "+ok); } Assert.assertEquals(true, ok); } final Thread t = drawables[i].setExclusiveContextThread(ect); Assert.assertEquals(null, t); } Thread.sleep(duration/durationParts); // 3 } // Disable/Enable exclusive mode via Animator for all GLAutoDrawable if(exclusive) { final Thread ect = animator.getExclusiveContextThread(); if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } Assert.assertEquals(true, animator.setExclusiveContext(false)); Assert.assertFalse(animator.isExclusiveContextEnabled()); for(int i=0; i<drawableCount; i++) { Assert.assertEquals(null, drawables[i].getExclusiveContextThread()); } Thread.sleep(duration/durationParts); // 4 Assert.assertEquals(null, animator.setExclusiveContext(ect)); Assert.assertTrue(animator.isExclusiveContextEnabled()); Assert.assertEquals(ect, animator.getExclusiveContextThread()); for(int i=0; i<drawableCount; i++) { Assert.assertEquals(ect, drawables[i].getExclusiveContextThread()); } Thread.sleep(duration/durationParts); // 5 } Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); Assert.assertTrue(animator.isStarted()); Assert.assertTrue(animator.isAnimating()); Assert.assertFalse(animator.isPaused()); // Animator Pause Assert.assertTrue(animator.pause()); Assert.assertTrue(animator.isStarted()); Assert.assertFalse(animator.isAnimating()); Assert.assertTrue(animator.isPaused()); Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); if(exclusive) { final Thread ect = animator.getExclusiveContextThread(); if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } } else { Assert.assertEquals(null, animator.getExclusiveContextThread()); } for(int i=0; i<drawableCount; i++) { Assert.assertEquals(null, drawables[i].getExclusiveContextThread()); } Thread.sleep(duration/durationParts); // 6 // Animator Resume Assert.assertTrue(animator.resume()); Assert.assertTrue(animator.isStarted()); Assert.assertTrue(animator.isAnimating()); Assert.assertFalse(animator.isPaused()); Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); if(exclusive) { final Thread ect = animator.getExclusiveContextThread(); if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } for(int i=0; i<drawableCount; i++) { Assert.assertEquals(ect, drawables[i].getExclusiveContextThread()); } } else { Assert.assertEquals(null, animator.getExclusiveContextThread()); for(int i=0; i<drawableCount; i++) { Assert.assertEquals(null, drawables[i].getExclusiveContextThread()); } } Thread.sleep(duration/durationParts); // 7 // Animator Stop #1 Assert.assertTrue(animator.stop()); Assert.assertFalse(animator.isAnimating()); Assert.assertFalse(animator.isStarted()); Assert.assertFalse(animator.isPaused()); Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); Assert.assertEquals(null, animator.getExclusiveContextThread()); for(int i=0; i<drawableCount; i++) { Assert.assertEquals(null, drawables[i].getExclusiveContextThread()); } Thread.sleep(duration/durationParts); // 8 // Animator Re-Start Assert.assertTrue(animator.start()); Assert.assertTrue(animator.isStarted()); Assert.assertTrue(animator.isAnimating()); Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); // After start, ExclusiveContextThread is set { final Thread ect = animator.getExclusiveContextThread(); if(exclusive) { if( useAWTRenderThread ) { Assert.assertEquals(awtRenderThread, ect); } else { Assert.assertEquals(animator.getThread(), ect); } } else { Assert.assertEquals(null, ect); } for(int i=0; i<drawableCount; i++) { Assert.assertEquals(ect, drawables[i].getExclusiveContextThread()); } } Thread.sleep(duration/durationParts); // 9 // Remove all drawables .. while running! for(int i=0; i<drawableCount; i++) { final GLAutoDrawable drawable = drawables[i]; animator.remove(drawable); Assert.assertEquals(null, drawable.getExclusiveContextThread()); } Assert.assertTrue(animator.isStarted()); Assert.assertFalse(animator.isAnimating()); // no drawables in list! } // !shortenTest // Animator Stop #2 Assert.assertTrue(animator.stop()); Assert.assertFalse(animator.isAnimating()); Assert.assertFalse(animator.isStarted()); Assert.assertFalse(animator.isPaused()); Assert.assertEquals(exclusive, animator.isExclusiveContextEnabled()); Assert.assertEquals(null, animator.getExclusiveContextThread()); // Destroy GLWindows for(int i=0; i<drawableCount; i++) { destroyGLAutoDrawableVisible(drawables[i]); Assert.assertEquals(true, AWTRobotUtil.waitForRealized(drawables[i], false)); } } @Test public void test01NormalPre_1Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 1 /* numWin */, false /* exclusive */, true /* preAdd */, false /* short */); } @Test public void test02NormalPost_1Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 1 /* numWin */, false /* exclusive */, false /* preAdd */, true /* short */); } @Test public void test03ExclPre_1Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 1 /* numWin */, true /* exclusive */, true /* preAdd */, false /* short */); } @Test public void test04ExclPost_1Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 1 /* numWin */, true /* exclusive */, false /* preAdd */, true /* short */); } @Test public void test05NormalPre_4Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 4 /* numWin */, false /* exclusive */, true /* preAdd */, false /* short */); } @Test public void test06NormalPost_4Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 4 /* numWin */, false /* exclusive */, false /* preAdd */, true /* short */); } @Test public void test07ExclPre_4Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 4 /* numWin */, true /* exclusive */, true /* preAdd */, false /* short */); } @Test public void test08ExclPost_4Win() throws InterruptedException { final GLProfile glp = GLProfile.getGL2ES2(); final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps, 4 /* numWin */, true /* exclusive */, false /* preAdd */, true /* short */); } }