From 20bf031db719f7baa4c6e74734fc999061e08fe2 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Thu, 19 Jul 2012 21:15:10 +0200
Subject: Bug 599 - FBObject / Offscreen Support - Part 1

- New FBObject implementation handling FBO and it's attachments  *** API CHANGE: Util -> Core ***
  while it's size and sample-count can be reconfigured on the fly.
    - com.jogamp.opengl.util.FBObject -> com.jogamp.opengl.FBObject
    - agnostic to texture unit
    - separate attachments using OO hierarchy reflecting FBO
    - handling MSAA and blitting
    - no FBO destruction for reconfig (attach/detach)

- New GLFBODrawableImpl impl. an FBObject based GLDrawable
   - Instantiated by a dummy native surface (onscreen and invisible)
     hooked up to a dummy GLDrawable, which is the delegation for context creation.

   - Utilizies ProxySurface.UpstreamSurfaceHook for dummy surface
     avoiding specialization for native platforms.

   - TODO: Allow to utilize common surface interface as a
     dummy-surface to supporting API seperation of
     windowing/GL. The latter allows impl. of createGLDrawable(NativeSurface)
     with FBO.

- New OffscreenAutoDrawable (extends GLAutoDrawableDelegate)
  for all offscreen drawables. Shall replace GLPbuffer.

- New GLCapabilities*.isFBO() / setFBO(boolean) to request FBO offscreen,
  similar to isPBuffer(). Rule: if both are requested, FBO shall be favored.

- GLContext adds raw FBO availability query (min. FBO avail),
  FBObject contains fine grained queries (TODO: Move parts to GLContext for efficiency).

- Add framebuffer tracking, allowing fast querying:
  - GLBase/GLContext:
      public int getBoundFramebuffer(int target);
      public int getDefaultDrawFramebuffer();
      public int getDefaultReadFramebuffer();

  - GLContextImpl
      public final void setBoundFramebuffer(int target, int framebufferName)
      .. called by GL impl bind framebuffer

- GL: getDefaultDrawFramebuffer(), getDefaultReadFramebuffer()
  Adding default framebuffer queries being issued by
  GL.glBindFramebuffer(target, 0) w/ a default framebuffer, o.e. zero.
  This allows a transparent use of a custom FBO even in case the applications
  attempts to reset FBO to zero.
    Value flow: GL <- GLContext <- GLDrawable,

- GLCapabilities handle fbo/pbuffer seperate, don't disable the other

- GLContext/GL track read/write framebuffer to be queried by FBObject
  to determine whether to bind/unbind  a framebuffer

- Test cases for multiple FBO w/ and w/o MSAA

Other Features:

- New interface ProxySurface.UpstreamSurfaceHook,
  allowing to hook an upstream surface of unknown type
  providing lifecycle and information (size, ..) callbacks.
  Used for all new dummy NativeSurface impl and SWT GLCanvas.

  - GLContext -> GLDrawable propagation context/drawable lifecycle
    via ProxySurface.UpstreamSurfaceHook allowing dynamic resources
    to react (create, init, ..)
    - contextRealized()
    - contextMadeCurrent()

- SurfaceChangeable -> MutableSurface
  currently only contains setting the surface handle.

  TODO: May need to move ProxySurface.UpstreamSurfaceHook -> MutableSurface.UpstreamSurfaceHook,
        allowing other impl. classes (NEWT OffscreenWindow) to utilize the new
        upstream hookup mechanism - will allow FBO/Dummy window to work.

- SWT GLCanvas using ProxySurface.UpstreamSurfaceHook for proper size
  propagation.

- New GLAutoDrawable::getUpstreamWidget(), allowing GLEventListener
  to fetch the owning Java side UI element (NEWT, SWT, AWT, ..).

- GLDrawableFactory: Removed createOffscreenSurface() - unused and not GL related

- EGLDrawableFactory handles device/profile avail. mapping
  while actually creating context/drawable.
  This allows us to learn whether the ES context is software/hardware as well as FBO avail.

- EGLDrawable: Removed secret buckets of EGL configs :)
  Employ native surface (X11, WGL, ..) to EGL 'mapping' in
  EGLDrawableFactory utilizing new EGLUpstreamSurfaceHook (implements ProxySurface.UpstreamSurfaceHook).

Other Bugs:

- Add CTX_OPTION_DEBUG to ctx/extension cache key since only a debug ctx
  may expose the ARB debug capability.
  This bug caused lack of ARB/AMD debug functionality.

- Fix GLProfile deadlock (debug mode, w/ EGL/ES, no X11),
  dump availability information _after_ lock.

- ImmModeSink draw(): Use GL's glDrawElements(..), don't cast for GL2ES1.
  Fixes use for GL2ES2.

- Fix KeyEvent.getKeyChar() comment (-> only stable for keyTyped(..))

Misc:

- Refined alot of API doc

- New GLExtensions holds commonly used GL extension strings,
  allows better referencing and usage lookup.

- Move GL (interface) decl. to GLBase

- GLBuffers: Cleanup API doc (format, types)

- TextureIO: Add PAM and PPM static suffix identifier

- GLCapabilities getNumSamples() returns 0 if sampleBuffers is disabled, this seems to be more natural.

- finalized a lot
---
 .../jogamp/opengl/GLDrawableFactoryImpl.java       | 234 +++++++++++++++------
 1 file changed, 169 insertions(+), 65 deletions(-)

(limited to 'src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java')

diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
index e5c44a8d4..897d3fcaf 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
@@ -1,22 +1,22 @@
 /*
  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
  * Copyright (c) 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:
- * 
+ *
  * - 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 of Sun Microsystems, Inc. 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
@@ -29,11 +29,11 @@
  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- * 
+ *
  * You acknowledge that this software is not designed or intended for use
  * in the design, construction, operation or maintenance of any nuclear
  * facility.
- * 
+ *
  * Sun gratefully acknowledges that this software was originally authored
  * and developed by Kenneth Bradley Russell and Christopher John Kline.
  */
@@ -47,7 +47,8 @@ import javax.media.nativewindow.NativeSurface;
 import javax.media.nativewindow.NativeWindowFactory;
 import javax.media.nativewindow.OffscreenLayerSurface;
 import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.SurfaceChangeable;
+import javax.media.nativewindow.MutableSurface;
+import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
 import javax.media.opengl.GLCapabilities;
 import javax.media.opengl.GLCapabilitiesChooser;
 import javax.media.opengl.GLCapabilitiesImmutable;
@@ -88,7 +89,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
       return null;
   }
   protected abstract GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device);
-  
+
   /**
    * Returns the shared device mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()},
    * either a preexisting or newly created, or <code>null</code> if creation failed or not supported.<br>
@@ -115,7 +116,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
   }
   protected abstract AbstractGraphicsDevice getOrCreateSharedDeviceImpl(AbstractGraphicsDevice device);
 
-  /** 
+  /**
    * Returns the GLDynamicLookupHelper
    * @param profile if EGL/ES, profile <code>1</code> refers to ES1 and <code>2</code> to ES2,
    *        otherwise the profile is ignored.
@@ -125,6 +126,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
   //---------------------------------------------------------------------------
   // Dispatching GLDrawable construction in respect to the NativeSurface Capabilities
   //
+  @Override
   public GLDrawable createGLDrawable(NativeSurface target) {
     if (target == null) {
       throw new IllegalArgumentException("Null target");
@@ -132,23 +134,37 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
     final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration();
     final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
     final AbstractGraphicsDevice adevice = config.getScreen().getDevice();
+    final boolean isFBOAvailable = GLContext.isFBOAvailable(adevice, chosenCaps.getGLProfile());
     GLDrawable result = null;
     adevice.lock();
     try {
         final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true);
         if(null != ols) {
-            // layered surface -> Offscreen/PBuffer
+            // layered surface -> Offscreen/[FBO|PBuffer]
             final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable();
             chosenCapsMod.setOnscreen(false);
-            chosenCapsMod.setPBuffer(canCreateGLPbuffer(adevice));
+            if( isFBOAvailable ) {
+                chosenCapsMod.setFBO(true);
+            } else if(canCreateGLPbuffer(adevice)) {
+                chosenCapsMod.setPBuffer(true);
+            } else {
+                chosenCapsMod.setFBO(false);
+                chosenCapsMod.setPBuffer(false);
+            }
             config.setChosenCapabilities(chosenCapsMod);
             if(DEBUG) {
                 System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target);
             }
-            if( ! ( target instanceof SurfaceChangeable ) ) {
+            if( ! ( target instanceof MutableSurface ) ) {
                 throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target);
+            }            
+            if( ((GLCapabilitiesImmutable)config.getRequestedCapabilities()).isFBO() && isFBOAvailable ) {
+                // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO ..
+                final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target);                
+                result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */);
+            } else {            
+                result = createOffscreenDrawableImpl(target);
             }
-            result = createOffscreenDrawableImpl(target);            
         } else if(chosenCaps.isOnscreen()) {
             // onscreen
             if(DEBUG) {
@@ -158,12 +174,18 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
         } else {
             // offscreen
             if(DEBUG) {
-                System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+chosenCaps.isPBuffer()+"): "+target);
+                System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable, FBO-chosen(-avail)/PBuffer: "+chosenCaps.isFBO()+"("+isFBOAvailable+")/"+chosenCaps.isPBuffer()+": "+target);
             }
-            if( ! ( target instanceof SurfaceChangeable ) ) {
+            if( ! ( target instanceof MutableSurface ) ) {
                 throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target);
             }
-            result = createOffscreenDrawableImpl(target);
+            if( ((GLCapabilitiesImmutable)config.getRequestedCapabilities()).isFBO() && isFBOAvailable ) {
+                // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO ..
+                final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target);                
+                result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */);
+            } else {
+                result = createOffscreenDrawableImpl(target);
+            }
         }
     } finally {
         adevice.unlock();
@@ -176,43 +198,42 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
 
   //---------------------------------------------------------------------------
   //
-  // Onscreen GLDrawable construction 
+  // Onscreen GLDrawable construction
   //
 
   protected abstract GLDrawableImpl createOnscreenDrawableImpl(NativeSurface target);
 
   //---------------------------------------------------------------------------
   //
-  // PBuffer Offscreen GLDrawable construction 
+  // PBuffer Offscreen GLDrawable construction
   //
-
+  
+  @Override
   public abstract boolean canCreateGLPbuffer(AbstractGraphicsDevice device);
 
+  @Override
   public GLPbuffer createGLPbuffer(AbstractGraphicsDevice deviceReq,
                                    GLCapabilitiesImmutable capsRequested,
                                    GLCapabilitiesChooser chooser,
                                    int width,
                                    int height,
                                    GLContext shareWith) {
-    if(height<=0 || height<=0) {
-        throw new GLException("Width and height of pbuffer must be positive (were (" +
-                        width + ", " + height + "))");
+    if(width<=0 || height<=0) {
+        throw new GLException("initial size must be positive (were (" + width + " x " + height + "))");
     }
-
     AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
     if(null == device) {
         throw new GLException("No shared device for requested: "+deviceReq);
     }
-
-    if (!canCreateGLPbuffer(device)) {
-        throw new GLException("Pbuffer support not available with device: "+device);
+    if ( !canCreateGLPbuffer(device) ) {
+        throw new GLException("Pbuffer not available with device: "+device);
     }
-    
-    GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(capsRequested);
+
+    final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(capsRequested);
     GLDrawableImpl drawable = null;
     device.lock();
     try {
-        drawable = (GLDrawableImpl) createGLDrawable( createOffscreenSurfaceImpl(device, capsChosen, capsRequested, chooser, width, height) );
+        drawable = (GLDrawableImpl) createGLDrawable( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) );
         if(null != drawable) {
             drawable.setRealized(true);
         }
@@ -228,75 +249,155 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
 
   //---------------------------------------------------------------------------
   //
-  // Offscreen GLDrawable construction 
+  // Offscreen GLDrawable construction
   //
 
-  protected abstract GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) ;
-
+  @Override
   public GLDrawable createOffscreenDrawable(AbstractGraphicsDevice deviceReq,
                                             GLCapabilitiesImmutable capsRequested,
                                             GLCapabilitiesChooser chooser,
-                                            int width,
-                                            int height) {
+                                            int width, int height) {
     if(width<=0 || height<=0) {
-        throw new GLException("Width and height of pbuffer must be positive (were (" +
-                        width + ", " + height + "))");
+        throw new GLException("initial size must be positive (were (" + width + " x " + height + "))");
     }
-    AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
+    final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
     if(null == device) {
         throw new GLException("No shared device for requested: "+deviceReq);
     }
-    GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffScreenGLCapabilities(capsRequested, canCreateGLPbuffer(deviceReq));
-
+    
+    if( capsRequested.isFBO() && GLContext.isFBOAvailable(device, capsRequested.getGLProfile()) ) {
+        device.lock();
+        try {
+            return createFBODrawableImpl(device, capsRequested, chooser, width, height);
+        } finally {
+            device.unlock();
+        }
+    }
+    
+    final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(capsRequested, false, canCreateGLPbuffer(device));
     device.lock();
     try {
-        return createGLDrawable( createOffscreenSurfaceImpl(device, capsChosen, capsRequested, chooser, width, height) );
+        return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) );
     } finally {
         device.unlock();
     }
   }
 
-  public NativeSurface createOffscreenSurface(AbstractGraphicsDevice deviceReq,
-                                              GLCapabilitiesImmutable capsRequested,
-                                              GLCapabilitiesChooser chooser,
-                                              int width, int height) {
-    AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
+  /** Creates a platform independent offscreen FBO GLDrawable implementation */  
+  protected GLDrawable createFBODrawableImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, 
+                                            int initialWidth, int initialHeight) {    
+    final GLCapabilitiesImmutable dummyCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps);
+    final NativeSurface dummySurface = createDummySurfaceImpl(device, true, dummyCaps, null, 64, 64);
+    final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface);
+    
+    return new GLFBODrawableImpl(this, dummyDrawable, dummySurface, initialWidth, initialHeight, 0 /* textureUnit */);
+  }
+  
+  /** Creates a platform dependent offscreen pbuffer/pixmap GLDrawable implementation */  
+  protected abstract GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) ;
+
+  /**
+   * Creates a mutable {@link ProxySurface} w/o defined surface handle.
+   * <p>
+   * It's {@link AbstractGraphicsConfiguration} is properly set according to the given {@link GLCapabilitiesImmutable}.
+   * </p>
+   * <p>
+   * Lifecycle (destruction) of the TBD surface handle shall be handled by the caller.
+   * </p>
+   * @param device a valid platform dependent target device.
+   * @param createNewDevice if <code>true</code> a new device instance is created using <code>device</code> details,
+   *                        otherwise <code>device</code> instance is used as-is.
+   * @param capsChosen
+   * @param capsRequested
+   * @param chooser the custom chooser, may be null for default
+   * @param width the initial width
+   * @param height the initial height
+   * @param lifecycleHook optional control of the surface's lifecycle 
+   * @return the created {@link MutableSurface} instance w/o defined surface handle
+   */
+  protected abstract ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice, 
+                                                           GLCapabilitiesImmutable capsChosen,
+                                                           GLCapabilitiesImmutable capsRequested,
+                                                           GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook);
+
+  /**
+   * A dummy surface is not visible on screen and will not be used to render directly to,
+   * it maybe on- or offscreen.
+   * <p>
+   * It is used to allow the creation of a {@link GLDrawable} and {@link GLContext} to query information.
+   * It also allows creation of framebuffer objects which are used for rendering.
+   * </p>
+   * @param deviceReq which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device.
+   * @param requestedCaps
+   * @param chooser the custom chooser, may be null for default
+   * @param width the initial width
+   * @param height the initial height
+   *
+   * @return the created {@link MutableSurface} instance w/o defined surface handle
+   */
+  public NativeSurface createDummySurface(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser,
+                                          int width, int height) {
+    final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
     if(null == device) {
         throw new GLException("No shared device for requested: "+deviceReq);
     }
-    GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffScreenGLCapabilities(capsRequested, canCreateGLPbuffer(deviceReq));
-
     device.lock();
     try {
-        return createOffscreenSurfaceImpl(device, capsChosen, capsRequested, chooser, width, height);
+        return createDummySurfaceImpl(device, true, requestedCaps, chooser, width, height);
     } finally {
         device.unlock();
     }
   }
-
+  
   /**
-   * creates an offscreen NativeSurface, which must implement SurfaceChangeable as well,
-   * so the windowing system related implementation is able to set the surface handle.
+   * A dummy surface is not visible on screen and will not be used to render directly to,
+   * it maybe on- or offscreen.
+   * <p>
+   * It is used to allow the creation of a {@link GLDrawable} and {@link GLContext} to query information.
+   * It also allows creation of framebuffer objects which are used for rendering.
+   * </p>
+   * @param device a valid platform dependent target device.
+   * @param createNewDevice if <code>true</code> a new device instance is created using <code>device</code> details,
+   *                        otherwise <code>device</code> instance is used as-is.
+   * @param requestedCaps
+   * @param chooser the custom chooser, may be null for default
+   * @param width the initial width
+   * @param height the initial height
+   * @return the created {@link MutableSurface} instance w/o defined surface handle
    */
-  protected abstract NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device,
-                                                              GLCapabilitiesImmutable capabilities, GLCapabilitiesImmutable capsRequested,
-                                                              GLCapabilitiesChooser chooser,
-                                                              int width, int height);
+  public abstract ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice, 
+                                                      GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height);
 
-  public ProxySurface createProxySurface(AbstractGraphicsDevice device, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser) {
+  //---------------------------------------------------------------------------
+  //
+  // ProxySurface (Wrapped pre-existing native surface) construction
+  //
+  
+  @Override
+  public ProxySurface createProxySurface(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, 
+                                         GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) {
+    final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
     if(null == device) {
-        throw new GLException("No shared device for requested: "+device);
+        throw new GLException("No shared device for requested: "+deviceReq);
     }
 
     device.lock();
     try {
-        return createProxySurfaceImpl(device, windowHandle, capsRequested, chooser);
+        return createProxySurfaceImpl(device, screenIdx, windowHandle, capsRequested, chooser, upstream);
     } finally {
         device.unlock();
     }
-  }  
-  
-  protected abstract ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice device, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser);
+  }
+
+  /**
+   * Creates a {@link ProxySurface} with a set surface handle.
+   * <p>
+   * Implementation is also required to allocate it's own {@link AbstractGraphicsDevice} instance.
+   * </p>
+ * @param upstream TODO
+   */
+  protected abstract ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, 
+                                                         GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream);
 
   //---------------------------------------------------------------------------
   //
@@ -304,7 +405,8 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
   //
 
   protected abstract GLContext createExternalGLContextImpl();
-  
+
+  @Override
   public GLContext createExternalGLContext() {
     NativeWindowFactory.getDefaultToolkitLock().lock();
     try {
@@ -316,6 +418,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
 
   protected abstract GLDrawable createExternalGLDrawableImpl();
 
+  @Override
   public GLDrawable createExternalGLDrawable() {
     NativeWindowFactory.getDefaultToolkitLock().lock();
     try {
@@ -398,7 +501,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
    * normal ahead of time, use resetDisplayGamma(). Throws
    * IllegalArgumentException if any of the parameters were
    * out-of-bounds.
-   * 
+   *
    * @param gamma The gamma value, typically > 1.0 (default value is
    *   1.0)
    * @param brightness The brightness value between -1.0 and 1.0,
@@ -484,7 +587,8 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
       return;
     if (gammaShutdownHook == null) {
       gammaShutdownHook = new Thread(new Runnable() {
-          public void run() {
+          @Override
+        public void run() {
             synchronized (GLDrawableFactoryImpl.this) {
               resetGammaRamp(originalGammaRamp);
             }
-- 
cgit v1.2.3