From 63be4a40aa6ecfe9fbc6585acccbc6f6f6689377 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 10 Sep 2010 05:33:17 +0200 Subject: NEWT: Changed Lifecycle of Display/Screen Display/Screen: - Removed Display reusage by unique TLS key: type + name, instead use user-responsibility or Destroy-When-Unused (usage reference count). - Removed X11 Display TLS pool usage - Display creation means i, incl the later native one (X11). - Added reference counting as follows: - Display's refCount: number it is referenced by Screen: display.addReference()/display.removeReference() - Screen's refCount: number it is referenced by Window: screen.addReference()/screen.removeReference() - Lazy creation using refcount 0 -> 1 All resources are created when they are needed. This also removes redundant native Display/Screen objects, ie in case of [AWT] reparenting. - Default lifecycle is user-responsibility, ie no Destroy-When-Unused, where Window may be destroyed unrecoverable, which removes the Screen reference only. - If using optional Destroy-When-Unused a Window may be destroyed unrecoverable, which removes the Screen reference: Screen.removeReference(); IF Screen.refCount == 0 THEN Screen.destroy(); Display.removeReference(); IF Display.refCount == 0 THEN Display.destroy(); - Use Destroy-When-Unused lifecycle for all automatic created Display/Screen instances (GLWindow, NewtCanvasAWT,..) - Display/Screen destroy/create cycles valid, ie you can reuse destroyed Display/Screen's - EDTUtil: - Created right away. - Started always via invoke, if not running. - DefaultEDTUtil: - Simplified locking a bit locking on: - edtLock for start/stop - edtTasks for tasks queue - invoke-wait doubles check shouldStop - invoke-wait 'waiting' outside of edtLock +++ NEWT: Cleanup - Window.destroy/invalidate: deep -> unrecoverable - Window.isNativeWindowValid() -> Window.isNativeValid() to unify with Display/Screen - Window.isDestroyed() -> Window.isValid() to unify and simplify logic. Returns false if destroy(true) has been called. - NewtFactory.wrapDisplay(.. handle) -> NewtFactory.createDisplay(.. handle), since it actually creates a compatible display. +++ NativeWindow X11Util: Added non TLS createDisplay()/closeDisplay() +++ TODO: - Stabilize (many tests fail) - OSX --- .../junit/newt/TestDisplayLifecycle01NEWT.java | 316 +++++++++++++++++++++ .../test/junit/newt/TestGLWindows01NEWT.java | 26 +- .../junit/newt/TestGLWindows02NEWTAnimated.java | 4 +- .../jogamp/test/junit/newt/TestWindows01NEWT.java | 8 +- .../junit/newt/parenting/TestParenting01NEWT.java | 54 ++-- .../junit/newt/parenting/TestParenting01aAWT.java | 26 +- .../junit/newt/parenting/TestParenting01cAWT.java | 14 +- .../newt/parenting/TestParenting01cSwingAWT.java | 24 +- .../junit/newt/parenting/TestParenting02AWT.java | 10 +- 9 files changed, 399 insertions(+), 83 deletions(-) create mode 100644 src/junit/com/jogamp/test/junit/newt/TestDisplayLifecycle01NEWT.java (limited to 'src/junit/com/jogamp') diff --git a/src/junit/com/jogamp/test/junit/newt/TestDisplayLifecycle01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestDisplayLifecycle01NEWT.java new file mode 100644 index 000000000..f0ceba606 --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestDisplayLifecycle01NEWT.java @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2010 Sven Gothel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name Sven Gothel or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.test.junit.newt; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; + +import javax.media.nativewindow.*; +import javax.media.opengl.*; + +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.opengl.*; +import java.io.IOException; + +import com.jogamp.test.junit.util.MiscUtils; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; + +public class TestDisplayLifecycle01NEWT { + static { + GLProfile.initSingleton(); + } + + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + static long durationPerTest = 100; // ms + + @BeforeClass + public static void initClass() { + width = 640; + height = 480; + glp = GLProfile.getDefault(); + caps = new GLCapabilities(glp); + } + + static GLWindow createWindow(Screen screen, GLCapabilities caps, int width, int height) + throws InterruptedException + { + Assert.assertNotNull(caps); + + // + // Create native windowing resources .. X11/Win/OSX + // + GLWindow glWindow; + if(null!=screen) { + Window window = NewtFactory.createWindow(screen, caps, false); + Assert.assertNotNull(window); + glWindow = GLWindow.create(window); + } else { + glWindow = GLWindow.create(caps, false); + } + + GLEventListener demo = new Gears(); + setDemoFields(demo, glWindow); + glWindow.addGLEventListener(demo); + glWindow.addWindowListener(new TraceWindowAdapter()); + glWindow.setSize(width, height); + return glWindow; + } + + private void testDisplayCreate01(Display display, Screen screen, boolean destroyWhenUnused) throws InterruptedException { + // start-state == end-state + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + Assert.assertEquals(0,display.getReferenceCount()); + Assert.assertEquals(false,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(false,display.getEDTUtil().isRunning()); + Assert.assertEquals(0,screen.getReferenceCount()); + Assert.assertEquals(false,screen.isNativeValid()); + + // Setup/Verify default DestroyWhenUnused behavior + if(destroyWhenUnused) { + screen.setDestroyWhenUnused(true); + } + Assert.assertEquals(destroyWhenUnused,display.getDestroyWhenUnused()); + Assert.assertEquals(destroyWhenUnused,screen.getDestroyWhenUnused()); + + // Create Window, pending lazy native creation + GLWindow window = createWindow(screen, caps, width, height); + Assert.assertEquals(screen,window.getScreen()); + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + Assert.assertEquals(0,display.getReferenceCount()); + Assert.assertEquals(false,display.isNativeValid()); + Assert.assertEquals(false,display.getEDTUtil().isRunning()); + Assert.assertEquals(0,screen.getReferenceCount()); + Assert.assertEquals(false,screen.isNativeValid()); + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + // lazy native creation sequence: Display, Screen and Window + window.setVisible(true); + window.display(); + int wait=0; + while(wait<10 && window.getTotalFrames()<1) { Thread.sleep(100); wait++; } + System.out.println("Frames for setVisible(true) 1: "+window.getTotalFrames()); + + Assert.assertEquals(screen,window.getScreen()); + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + Assert.assertEquals(1,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(1,screen.getReferenceCount()); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + while(window.getDuration()<1*durationPerTest) { + window.display(); + Thread.sleep(100); + } + System.out.println("duration: "+window.getDuration()); + + // just make the Window invisible + window.setVisible(false); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + // just make the Window visible again + window.setVisible(true); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + while(window.getDuration()<2*durationPerTest) { + window.display(); + Thread.sleep(100); + } + System.out.println("duration: "+window.getDuration()); + + // recoverable destruction, ie Display/Screen untouched + window.destroy(false); + Assert.assertEquals(screen,window.getScreen()); + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + Assert.assertEquals(1,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(1,screen.getReferenceCount()); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + // a display call shall not change a thing + window.display(); + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + // recover Window + window.setVisible(true); + window.display(); + wait=0; + while(wait<10 && window.getTotalFrames()<1) { Thread.sleep(100); wait++; } + System.out.println("Frames for setVisible(true) 2: "+window.getTotalFrames()); + + Assert.assertEquals(screen,window.getScreen()); + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + Assert.assertEquals(1,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(1,screen.getReferenceCount()); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + while(window.getDuration()<1*durationPerTest) { + window.display(); + Thread.sleep(100); + } + System.out.println("duration: "+window.getDuration()); + + // unrecoverable destruction, ie Display/Screen will be unreferenced + window.destroy(true); + Assert.assertEquals(null,window.getScreen()); + Display.dumpDisplayList("Post destroy(true)"); + if(!destroyWhenUnused) { + // display/screen untouched when unused, default + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + Assert.assertEquals(1,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(0,screen.getReferenceCount()); + Assert.assertEquals(true,screen.isNativeValid()); + + // manual destruction: Screen + screen.destroy(); + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + Assert.assertEquals(0,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(0,screen.getReferenceCount()); + Assert.assertEquals(false,screen.isNativeValid()); + + // manual destruction: Display + display.destroy(); + } else { + // display/screen destroyed when unused + } + + // end-state == start-state + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + Assert.assertEquals(0,display.getReferenceCount()); + Assert.assertEquals(false,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(false,display.getEDTUtil().isRunning()); + Assert.assertEquals(0,screen.getReferenceCount()); + Assert.assertEquals(false,screen.isNativeValid()); + + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + } + + @Test + public void testDisplayCreate01_DestroyWhenUnused_False() throws InterruptedException { + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + + // Create Display/Screen, pending lazy native creation + Display display = NewtFactory.createDisplay(null); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + testDisplayCreate01(display, screen, false); + testDisplayCreate01(display, screen, false); + + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + } + + @Test + public void testDisplayCreate01_DestroyWhenUnused_True() throws InterruptedException { + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + + // Create Display/Screen, pending lazy native creation + Display display = NewtFactory.createDisplay(null); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + testDisplayCreate01(display, screen, true); + testDisplayCreate01(display, screen, true); + + Assert.assertEquals(0,Display.getActiveDisplayNumber()); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getInnerWindow())) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i