From 0f7412855c118cb501d8a001df7a7487354b5029 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Tue, 23 Apr 2013 07:53:31 +0200
Subject: Fix Bug 722: Make GLEventListenerState 'transaction' safe
 Animator.pause[ surface.lock[ modify ] ]

GLEventListenerState:
  New model for GLEventListenerState's transaction safety:
   - Z Decorate-1: Animator.pause [ X ]  Animator.resume
   - X Decorate-2: Surface.lock [ Y ] Surface.unlock

  - Instead of setting AbstractGraphicsDevice, just swap the handle and ownership.

  - Issuing setRealized(..) only if required, i.e. having an upstream-surface (EGL..) depending on used device

  - Utilizing setRealized(..) on the GLAD's delegated 'real' drawable, avoiding optional GLAD locking.

  - Cleanup and above changes shall render impl. easier to read.

GLEventListenerState Unit Tests:
  - If swapping/moving from AWT -> NEWT, use a NEWT dedicated Display
    avoiding ATI driver XCB crash - read comment.
---
 .../com/jogamp/opengl/GLEventListenerState.java    | 332 ++++++++++++---------
 1 file changed, 191 insertions(+), 141 deletions(-)

(limited to 'src/jogl')

diff --git a/src/jogl/classes/com/jogamp/opengl/GLEventListenerState.java b/src/jogl/classes/com/jogamp/opengl/GLEventListenerState.java
index 2914a1bf9..21dafecb1 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLEventListenerState.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLEventListenerState.java
@@ -32,11 +32,9 @@ import java.util.List;
 
 import javax.media.nativewindow.AbstractGraphicsConfiguration;
 import javax.media.nativewindow.AbstractGraphicsDevice;
-import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.DefaultGraphicsDevice;
 import javax.media.nativewindow.NativeSurface;
-import javax.media.nativewindow.NativeWindowFactory;
 import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.VisualIDHolder;
 import javax.media.opengl.GLAnimatorControl;
 import javax.media.opengl.GLAutoDrawable;
 import javax.media.opengl.GLCapabilitiesImmutable;
@@ -57,8 +55,8 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration;
  *   <li>{@link GLContext}</li>
  *   <li>All {@link GLEventListener}, incl. their init state</li>
  *   <li>{@link GLAnimatorControl}</li>
- *   <li>{@link GLCapabilitiesImmutable} for compatibility check</li>
- *   <li>{@link AbstractGraphicsScreen} for compatibility check and preserving the {@link AbstractGraphicsDevice}</li>
+ *   <!--li>{@link GLCapabilitiesImmutable} for compatibility check</li-->
+ *   <li>{@link AbstractGraphicsDevice} for compatibility check and preserving the native device handle incl. ownership</li>
  * </ul>
  * <p>
  * A GLEventListenerState instance can be created while components are {@link #moveFrom(GLAutoDrawable) moved from} a {@link GLAutoDrawable}
@@ -68,16 +66,16 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration;
  * A GLEventListenerState instance's components can be {@link #moveTo(GLAutoDrawable) moved to} a {@link GLAutoDrawable},
  * while loosing {@link #isOwner() ownership} of the moved components.
  * </p>
- * <p>
  */
 public class GLEventListenerState {
-    private static final boolean DEBUG = Debug.debug("GLDrawable");
+    private static final boolean DEBUG = Debug.debug("GLDrawable") || Debug.debug("GLEventListenerState");
     
-    private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, boolean proxyOwnsUpstreamDevice, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, 
+    private GLEventListenerState(AbstractGraphicsDevice upstreamDevice, boolean proxyOwnsUpstreamDevice, AbstractGraphicsDevice device, 
+                                 GLCapabilitiesImmutable caps,
                                  GLContext context, int count, GLAnimatorControl anim, boolean animStarted) {
-        this.upstreamScreen = upstreamScreen;
+        this.upstreamDevice = upstreamDevice;
         this.proxyOwnsUpstreamDevice = proxyOwnsUpstreamDevice;
-        this.screen = screen;
+        this.device = device;
         this.caps = caps;
         this.context = context;
         this.listeners = new GLEventListener[count];
@@ -99,9 +97,9 @@ public class GLEventListenerState {
     
     public final int listenerCount() { return listeners.length; }
 
-    public final AbstractGraphicsScreen upstreamScreen;
+    public final AbstractGraphicsDevice upstreamDevice;
     public final boolean proxyOwnsUpstreamDevice;
-    public final AbstractGraphicsScreen screen;
+    public final AbstractGraphicsDevice device;
     public final GLCapabilitiesImmutable caps;
     public final GLContext context;
     public final GLEventListener[] listeners;
@@ -121,14 +119,13 @@ public class GLEventListenerState {
                 listeners[i] = null;
             }
             // context.destroy(); - NPE (null drawable)
-            screen.getDevice().close();
+            device.close();
             owner = false;
         }
     }
 
-    private static AbstractGraphicsScreen cloneScreen(AbstractGraphicsScreen aScreen) {
-        final AbstractGraphicsDevice aDevice2 = (AbstractGraphicsDevice) aScreen.getDevice().clone();
-        return NativeWindowFactory.createScreen( aDevice2, aScreen.getIndex() );        
+    private static AbstractGraphicsDevice cloneDevice(AbstractGraphicsDevice aDevice) {
+        return (AbstractGraphicsDevice) aDevice.clone();
     }
     
     /**
@@ -152,51 +149,6 @@ public class GLEventListenerState {
      * @see #moveTo(GLAutoDrawable)
      */
     public static GLEventListenerState moveFrom(GLAutoDrawable a) {
-        final int aSz = a.getGLEventListenerCount();
-
-        // Create new AbstractGraphicsScreen w/ cloned AbstractGraphicsDevice for future GLAutoDrawable
-        // allowing this AbstractGraphicsDevice to loose ownership -> not closing display/device!
-        final NativeSurface aSurface = a.getNativeSurface();
-        final AbstractGraphicsConfiguration aCfg = aSurface.getGraphicsConfiguration();
-        final AbstractGraphicsScreen aScreen1 = aCfg.getScreen();
-        final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities();
-        final AbstractGraphicsScreen aScreen2 = cloneScreen(aScreen1);
-        aScreen1.getDevice().clearHandleOwner();  // don't close device handle
-        if( DEBUG ) {            
-            System.err.println("GLEventListenerState.moveFrom.0a: orig 0x"+Integer.toHexString(aScreen1.getDevice().hashCode())+", "+aScreen1.getDevice());
-            System.err.println("GLEventListenerState.moveFrom.0b: pres 0x"+Integer.toHexString(aScreen2.getDevice().hashCode())+", "+aScreen2.getDevice());
-            System.err.println("GLEventListenerState.moveFrom.1: "+aSurface.getClass().getName()+", "+aSurface);
-        }
-        final AbstractGraphicsScreen aUpScreen2;
-        final boolean proxyOwnsUpstreamDevice;
-        {
-            AbstractGraphicsScreen _aUpScreen2=null;
-            if(aSurface instanceof ProxySurface) {
-                final ProxySurface aProxy = (ProxySurface)aSurface;
-                proxyOwnsUpstreamDevice = aProxy.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
-                final NativeSurface aUpSurface = aProxy.getUpstreamSurface();
-                if(DEBUG && null != aUpSurface) {
-                    System.err.println("GLEventListenerState.moveFrom.2: "+aUpSurface.getClass().getName()+", "+aUpSurface);
-                }
-                if(null != aUpSurface) {
-                    final AbstractGraphicsScreen aUpScreen1 = aUpSurface.getGraphicsConfiguration().getScreen();
-                    _aUpScreen2 = cloneScreen(aUpScreen1);
-                    if(null != aUpScreen1) {
-                        aUpScreen1.getDevice().clearHandleOwner(); // don't close device handle
-                    }
-                    if(DEBUG) {
-                        System.err.println("GLEventListenerState.moveFrom.3a: up-orig 0x"+Integer.toHexString(aUpScreen1.getDevice().hashCode())+", "+aUpScreen1.getDevice());
-                        System.err.println("GLEventListenerState.moveFrom.3b: up-pres 0x"+Integer.toHexString(_aUpScreen2.getDevice().hashCode())+", "+_aUpScreen2.getDevice());
-                        System.err.println("GLEventListenerState.moveFrom.3c: "+aSurface.getClass().getName()+", "+aSurface);
-                        System.err.println("GLEventListenerState.moveFrom.3d: "+aUpSurface.getClass().getName()+", "+aUpSurface);
-                    }
-                }
-            } else {
-                proxyOwnsUpstreamDevice = false;
-            }
-            aUpScreen2=_aUpScreen2;
-        }
-        
         final GLAnimatorControl aAnim = a.getAnimator();
         final boolean aAnimStarted;
         if( null != aAnim ) {
@@ -206,23 +158,75 @@ public class GLEventListenerState {
             aAnimStarted = false;
         }
         
-        final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, proxyOwnsUpstreamDevice, aScreen2, caps, a.getContext(), aSz, aAnim, aAnimStarted); 
-
-        //
-        // remove and cache all GLEventListener and their init-state
-        //
-        for(int i=0; i<aSz; i++) {
-            final GLEventListener l = a.getGLEventListener(0);
-            glls.listenersInit[i] = a.getGLEventListenerInitState(l);
-            glls.listeners[i] = a.removeGLEventListener( l );
-        }    
-
-        //
-        // trigger glFinish to sync GL ctx
-        //
-        a.invoke(true, glFinish);
-
-        a.setContext( null, false );
+        final GLEventListenerState glls;
+        final NativeSurface aSurface = a.getNativeSurface();
+        final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
+        try {
+            final int aSz = a.getGLEventListenerCount();
+    
+            // Create new AbstractGraphicsScreen w/ cloned AbstractGraphicsDevice for future GLAutoDrawable
+            // allowing this AbstractGraphicsDevice to loose ownership -> not closing display/device!
+            final AbstractGraphicsConfiguration aCfg = aSurface.getGraphicsConfiguration();
+            final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities();
+            final AbstractGraphicsDevice aDevice1 = aCfg.getScreen().getDevice();
+            final AbstractGraphicsDevice aDevice2 = cloneDevice(aDevice1);
+            aDevice1.clearHandleOwner();  // don't close device handle
+            if( DEBUG ) {            
+                System.err.println("GLEventListenerState.moveFrom.0a: orig 0x"+Integer.toHexString(aDevice1.hashCode())+", "+aDevice1);
+                System.err.println("GLEventListenerState.moveFrom.0b: pres 0x"+Integer.toHexString(aDevice2.hashCode())+", "+aDevice2);
+                System.err.println("GLEventListenerState.moveFrom.1: "+aSurface.getClass().getName()/*+", "+aSurface*/);
+            }
+            final AbstractGraphicsDevice aUpDevice2;
+            final boolean proxyOwnsUpstreamDevice;
+            {
+                AbstractGraphicsDevice _aUpDevice2 = null;
+                if(aSurface instanceof ProxySurface) {
+                    final ProxySurface aProxy = (ProxySurface)aSurface;
+                    proxyOwnsUpstreamDevice = aProxy.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+                    final NativeSurface aUpSurface = aProxy.getUpstreamSurface();
+                    if(DEBUG && null != aUpSurface) {
+                        System.err.println("GLEventListenerState.moveFrom.2: "+aUpSurface.getClass().getName()+", "+aUpSurface);
+                    }
+                    if(null != aUpSurface) {
+                        final AbstractGraphicsDevice aUpDevice1 = aUpSurface.getGraphicsConfiguration().getScreen().getDevice();
+                        _aUpDevice2 = cloneDevice(aUpDevice1);
+                        aUpDevice1.clearHandleOwner(); // don't close device handle
+                        if(DEBUG) {
+                            System.err.println("GLEventListenerState.moveFrom.3a: up-orig 0x"+Integer.toHexString(aUpDevice1.hashCode())+", "+aUpDevice1);
+                            System.err.println("GLEventListenerState.moveFrom.3b: up-pres 0x"+Integer.toHexString(_aUpDevice2.hashCode())+", "+_aUpDevice2);
+                            System.err.println("GLEventListenerState.moveFrom.3c: "+aSurface.getClass().getName()+", "+aSurface);
+                            System.err.println("GLEventListenerState.moveFrom.3d: "+aUpSurface.getClass().getName()/*+", "+aUpSurface+", "*/+aProxy.getUpstreamOptionBits(null).toString());
+                        }
+                    }
+                } else {
+                    proxyOwnsUpstreamDevice = false;
+                }
+                aUpDevice2 = _aUpDevice2;
+            }
+            
+            glls = new GLEventListenerState(aUpDevice2, proxyOwnsUpstreamDevice, aDevice2, caps, a.getContext(), aSz, aAnim, aAnimStarted); 
+    
+            //
+            // remove and cache all GLEventListener and their init-state
+            //
+            for(int i=0; i<aSz; i++) {
+                final GLEventListener l = a.getGLEventListener(0);
+                glls.listenersInit[i] = a.getGLEventListenerInitState(l);
+                glls.listeners[i] = a.removeGLEventListener( l );
+            }    
+    
+            //
+            // trigger glFinish to sync GL ctx
+            //
+            a.invoke(true, glFinish);
+    
+            a.setContext( null, false );
+            
+        } finally {
+            if( surfaceLocked ) {
+                aSurface.unlockSurface();
+            }
+        }        
         
         return glls;
     }
@@ -241,84 +245,123 @@ public class GLEventListenerState {
      * 
      * @param a {@link GLAutoDrawable} destination to move GLEventListenerState components to
      * 
-     * @throws GLException if the {@link GLAutoDrawable}'s configuration is incompatible, i.e. different {@link GLCapabilitiesImmutable}.
+     * <!-- @throws GLException if the {@link GLAutoDrawable}'s configuration is incompatible, i.e. different {@link GLCapabilitiesImmutable}. -->
+     * @throws GLException if this preserved {@link AbstractGraphicsDevice} is incompatible w/ the given destination one.
      * 
      * @see #moveFrom(GLAutoDrawable)
      * @see #isOwner()
      */
     public final void moveTo(GLAutoDrawable a) {
+        final GLAnimatorControl aAnim = a.getAnimator();
+        final boolean hasAnimator = null != aAnim;
+        final boolean aPaused;
+        if( hasAnimator ) {
+            aPaused = aAnim.pause();
+            aAnim.remove(a); // also handles ECT
+            if( aPaused ) {
+                aAnim.resume();
+            }
+        } else {        
+            aPaused = false;
+        }
+        
         final List<GLRunnable> aGLCmds = new ArrayList<GLRunnable>();
         final int aSz = listenerCount();
         
         final NativeSurface aSurface = a.getNativeSurface();
-        final MutableGraphicsConfiguration aCfg = (MutableGraphicsConfiguration) aSurface.getGraphicsConfiguration();
-        final GLCapabilitiesImmutable aCaps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities();
-        if( caps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) != aCaps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) || 
-            caps.getVisualID(VisualIDHolder.VIDType.NATIVE) != aCaps.getVisualID(VisualIDHolder.VIDType.NATIVE) ) {
-            throw new GLException("Incompatible Capabilities - Prev-Holder: "+caps+", New-Holder "+caps);
-        }
-        // Destroy and remove currently associated GLContext, if any (will be replaced)
-        a.setContext( null, true );
-        final boolean aRealized = a.isRealized();
-        if( aRealized ) {
-            a.setRealized(false);
-        }
-        // Set new Screen and close previous one
-        {
-            final AbstractGraphicsScreen aScreen1 = aCfg.getScreen();
-            if( DEBUG ) {
-                System.err.println("GLEventListenerState.moveTo.0a: orig 0x"+Integer.toHexString(aScreen1.getDevice().hashCode())+", "+aScreen1.getDevice());
-                System.err.println("GLEventListenerState.moveTo.0b: pres 0x"+Integer.toHexString(screen.getDevice().hashCode())+", "+screen.getDevice());
+        final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
+        final boolean aRealized;
+        try {
+            
+            final MutableGraphicsConfiguration aCfg = (MutableGraphicsConfiguration) aSurface.getGraphicsConfiguration();
+            /**
+            final GLCapabilitiesImmutable aCaps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities();
+            if( caps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) != aCaps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) || 
+                caps.getVisualID(VisualIDHolder.VIDType.NATIVE) != aCaps.getVisualID(VisualIDHolder.VIDType.NATIVE) ) {
+                throw new GLException("Incompatible Capabilities - Prev-Holder: "+caps+", New-Holder "+caps);
+            } */
+            final DefaultGraphicsDevice aDevice1 = (DefaultGraphicsDevice) aCfg.getScreen().getDevice();
+            final DefaultGraphicsDevice aDevice2 = (DefaultGraphicsDevice) device;
+            if( !aDevice1.getUniqueID().equals( aDevice2.getUniqueID() ) ) {
+                throw new GLException("Incompatible devices: Preserved <"+aDevice2.getUniqueID()+">, target <"+aDevice1.getUniqueID()+">");
+            }
+            
+            // collect optional upstream surface info 
+            final ProxySurface aProxy;
+            final NativeSurface aUpSurface;
+            if(aSurface instanceof ProxySurface) {
+                aProxy = (ProxySurface)aSurface;
+                aUpSurface = aProxy.getUpstreamSurface();
+            } else {
+                aProxy = null;
+                aUpSurface = null;
             }
-            aCfg.setScreen( screen );
-            aScreen1.getDevice().close();
             if( DEBUG ) {
-                System.err.println("GLEventListenerState.moveTo.1a: orig 0x"+Integer.toHexString(aScreen1.getDevice().hashCode())+", "+aScreen1.getDevice());
-                System.err.println("GLEventListenerState.moveTo.1b: pres 0x"+Integer.toHexString(screen.getDevice().hashCode())+", "+screen.getDevice());
+                System.err.println("GLEventListenerState.moveTo.0 : has aProxy "+(null!=aProxy));
+                System.err.println("GLEventListenerState.moveTo.0 : has aUpSurface "+(null!=aUpSurface));
             }
-        }
-        
-        // If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it
-        {
-            boolean upstreamSet = false;
-            if(aSurface instanceof ProxySurface) {
-                final ProxySurface aProxy = (ProxySurface)aSurface;
-                final NativeSurface aUpSurface = aProxy.getUpstreamSurface();            
-                if(null != aUpSurface) {
-                    final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration();
-                    if( null != upstreamScreen ) {
-                        final AbstractGraphicsScreen aUpScreen1 = aUpCfg.getScreen();
-                        if( DEBUG ) {
-                            System.err.println("GLEventListenerState.moveTo.2a: up-orig 0x"+Integer.toHexString(aUpScreen1.getDevice().hashCode())+", "+aUpScreen1.getDevice());
-                            System.err.println("GLEventListenerState.moveTo.2b: up-pres 0x"+Integer.toHexString(upstreamScreen.getDevice().hashCode())+", "+upstreamScreen.getDevice());
-                            System.err.println("GLEventListenerState.moveTo.2c:  "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString());
-                        }
-                        aUpScreen1.getDevice().close();
-                        aUpCfg.setScreen( upstreamScreen );
-                        if( proxyOwnsUpstreamDevice ) {
-                            aProxy.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
-                        }
-                        upstreamSet = true;
-                        if( DEBUG ) {
-                            System.err.println("GLEventListenerState.moveTo.3a: up-orig 0x"+Integer.toHexString(aUpScreen1.getDevice().hashCode())+", "+aUpScreen1.getDevice());
-                            System.err.println("GLEventListenerState.moveTo.3b: up-pres 0x"+Integer.toHexString(upstreamScreen.getDevice().hashCode())+", "+upstreamScreen.getDevice());
-                            System.err.println("GLEventListenerState.moveTo.3c:  "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString());
-                        }
-                    } else {
-                        throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true");
+            if( null==aUpSurface && null != upstreamDevice ) {
+                throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = true, New-Holder = false");
+            }            
+            
+            // Destroy and remove currently associated GLContext, if any (will be replaced)
+            a.setContext( null, true );
+            aRealized = a.isRealized();
+            if( aRealized && null != aUpSurface ) {
+                // Unrealize due to device dependencies of an upstream surface, e.g. EGLUpstreamSurfaceHook
+                a.getDelegatedDrawable().setRealized(false);
+            }
+            
+            // Set new Screen and close previous one
+            {
+                if( DEBUG ) {
+                    System.err.println("GLEventListenerState.moveTo.0a: orig 0x"+Integer.toHexString(aDevice1.hashCode())+", "+aDevice1);
+                    System.err.println("GLEventListenerState.moveTo.0b: pres 0x"+Integer.toHexString(aDevice2.hashCode())+", "+aDevice2);
+                }
+                DefaultGraphicsDevice.swapDeviceHandleAndOwnership(aDevice1, aDevice2);
+                aDevice2.close();                
+                if( DEBUG ) {
+                    System.err.println("GLEventListenerState.moveTo.1a: orig 0x"+Integer.toHexString(aDevice1.hashCode())+", "+aDevice1);
+                    System.err.println("GLEventListenerState.moveTo.1b: pres 0x"+Integer.toHexString(aDevice2.hashCode())+", "+aDevice2);
+                }
+            }
+            
+            // If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it
+            if( null != aUpSurface ) {
+                final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration();
+                if( null != upstreamDevice ) {
+                    final DefaultGraphicsDevice aUpDevice1 = (DefaultGraphicsDevice) aUpCfg.getScreen().getDevice();
+                    final DefaultGraphicsDevice aUpDevice2 = (DefaultGraphicsDevice)upstreamDevice;
+                    if( !aUpDevice1.getUniqueID().equals( aUpDevice2.getUniqueID() ) ) {
+                        throw new GLException("Incompatible updtream devices: Preserved <"+aUpDevice2.getUniqueID()+">, target <"+aUpDevice1.getUniqueID()+">");
+                    }
+                    if( DEBUG ) {
+                        System.err.println("GLEventListenerState.moveTo.2a: up-orig 0x"+Integer.toHexString(aUpDevice1.hashCode())+", "+aUpDevice1);
+                        System.err.println("GLEventListenerState.moveTo.2b: up-pres 0x"+Integer.toHexString(aUpDevice2.hashCode())+", "+aUpDevice2);
+                        System.err.println("GLEventListenerState.moveTo.2c:  "+aUpSurface.getClass().getName()/*+", "+aUpSurface+", "*/+aProxy.getUpstreamOptionBits(null).toString());
+                    }                            
+                    DefaultGraphicsDevice.swapDeviceHandleAndOwnership(aUpDevice1, aUpDevice2);
+                    aUpDevice2.close();                            
+                    if( proxyOwnsUpstreamDevice ) {
+                        aProxy.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+                    }
+                    if( DEBUG ) {
+                        System.err.println("GLEventListenerState.moveTo.3a: up-orig 0x"+Integer.toHexString(aUpDevice1.hashCode())+", "+aUpDevice1);
+                        System.err.println("GLEventListenerState.moveTo.3b: up-pres 0x"+Integer.toHexString(aUpDevice2.hashCode())+", "+aUpDevice2);
+                        System.err.println("GLEventListenerState.moveTo.3c:  "+aUpSurface.getClass().getName()/*+", "+aUpSurface+", "*/+aProxy.getUpstreamOptionBits(null).toString());
                     }
+                } else {
+                    throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true");
                 }
             }
-            if( !upstreamSet && null != upstreamScreen ) {
-                throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = true, New-Holder = false");
+            
+            if( aRealized && null != aUpSurface ) {
+                a.getDelegatedDrawable().setRealized(true);
+            }
+            if( DEBUG ) {
+                System.err.println("GLEventListenerState.moveTo.X : has aProxy "+(null!=aProxy));
+                System.err.println("GLEventListenerState.moveTo.X : has aUpSurface "+(null!=aUpSurface));
             }
-        }
-        
-        if( aRealized ) {
-            a.setRealized(true);
-        }
-        final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
-        try {
             a.setContext( context, false );
         } finally {
             if( surfaceLocked ) {
@@ -347,7 +390,14 @@ public class GLEventListenerState {
             listeners[i] = null;
         }
         
-        if( null != anim && null == a.getAnimator() ) {
+        if( hasAnimator ) {
+            // prefer already bound animator
+            aAnim.add(a);
+            if( aPaused ) {
+                aAnim.resume();
+            }
+        } else if ( null != anim ) {
+            // use previously bound animator
             anim.add(a); // also handles ECT
             if(animStarted) {
                 anim.start();
-- 
cgit v1.2.3