From e552d800ee9df3761108c044342612c8bda1f304 Mon Sep 17 00:00:00 2001
From: Kenneth Russel <kbrussel@alum.mit.edu>
Date: Fri, 21 Jul 2006 22:34:00 +0000
Subject: Added support for sharing of textures, etc. between GLPbuffers and
 GLJPanels when the Java2D/JOGL bridge is active on Mac OS X. This required
 adding an alternate implementation for pbuffer drawables and contexts on OS X
 which uses CGL rather than the NextStep OpenGL APIs. Tested with advance
 Mustang bits on Mac OS X; Water and HWShadowmapsSimple demos (which use
 pbuffers) are now working within the JRefract harness when the Java2D/JOGL
 bridge is active.

git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@855 232f8b59-042b-4e1e-8c03-345bb8c30851
---
 .../impl/macosx/MacOSXExternalGLContext.java       |   9 +
 .../sun/opengl/impl/macosx/MacOSXGLContext.java    |   6 +-
 .../sun/opengl/impl/macosx/MacOSXGLDrawable.java   |  41 +++-
 .../opengl/impl/macosx/MacOSXJava2DGLContext.java  |   9 +
 .../impl/macosx/MacOSXOnscreenGLContext.java       |   9 +
 .../impl/macosx/MacOSXOnscreenGLDrawable.java      |  14 ++
 .../opengl/impl/macosx/MacOSXPbufferGLContext.java | 253 ++++++++++++++++++++-
 .../impl/macosx/MacOSXPbufferGLDrawable.java       |  98 +++++++-
 8 files changed, 423 insertions(+), 16 deletions(-)

(limited to 'src/classes/com/sun/opengl')

diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXExternalGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXExternalGLContext.java
index ceda14f3b..c9b6e432e 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXExternalGLContext.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXExternalGLContext.java
@@ -111,4 +111,13 @@ public class MacOSXExternalGLContext extends MacOSXGLContext {
   public boolean isCreated() {
     return created;
   }
+
+  public void setOpenGLMode(int mode) {
+    if (mode != MacOSXGLDrawable.NSOPENGL_MODE)
+      throw new GLException("OpenGL mode switching not supported for external GLContexts");
+  }
+    
+  public int  getOpenGLMode() {
+    return MacOSXGLDrawable.NSOPENGL_MODE;
+  }
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java
index d7890e369..e41ad856d 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java
@@ -142,7 +142,7 @@ public abstract class MacOSXGLContext extends GLContextImpl
         return CONTEXT_NOT_CURRENT;
       }
       if (DEBUG) {
-        System.err.println("!!! Created GL nsContext for " + getClass().getName());
+        System.err.println("!!! Created OpenGL context " + toHexString(nsContext) + " for " + getClass().getName());
       }
       created = true;
     }
@@ -249,6 +249,10 @@ public abstract class MacOSXGLContext extends GLContextImpl
     throw new GLException("Should not call this");
   }
     
+  // Support for "mode switching" as described in MacOSXGLDrawable
+  public abstract void setOpenGLMode(int mode);
+  public abstract int  getOpenGLMode();
+
   //----------------------------------------------------------------------
   // Internals only below this point
   //
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLDrawable.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLDrawable.java
index 16f2410de..8a31d4b18 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLDrawable.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLDrawable.java
@@ -45,10 +45,42 @@ import com.sun.opengl.impl.*;
 public abstract class MacOSXGLDrawable extends GLDrawableImpl {
   protected static final boolean DEBUG = Debug.debug("MacOSXGLDrawable");
 
-  protected long nsView; // NSView
   protected GLCapabilities capabilities;
   protected GLCapabilitiesChooser chooser;
   
+  // The Java2D/OpenGL pipeline on OS X uses low-level CGLContextObjs
+  // to represent the contexts for e.g. the Java2D back buffer. When
+  // the Java2D/JOGL bridge is active, this means that if we want to
+  // be able to share textures and display lists with the Java2D
+  // contexts, we need to use the CGL APIs rather than the NSOpenGL
+  // APIs on the JOGL side. For example, if we create a pbuffer using
+  // the NSOpenGL APIs and want to share textures and display lists
+  // between it and the Java2D back buffer, there is no way to do so,
+  // because the Java2D context is actually a CGLContextObj and the
+  // NSOpenGLContext's initWithFormat:shareContext: only accepts an
+  // NSOpenGLContext as its second argument. Of course there is no way
+  // to wrap an NSOpenGLContext around an arbitrary CGLContextObj.
+  //
+  // The situation we care most about is allowing a GLPbuffer to share
+  // textures, etc. with a GLJPanel when the Java2D/JOGL bridge is
+  // active; several of the demos rely on this functionality. We aim
+  // to get there by allowing a GLPBuffer to switch its implementation
+  // between using an NSOpenGLPixelBuffer and a CGLPBufferObj. In
+  // order to track whether this has been done we need to have the
+  // notion of a "mode" of both the MacOSXGLDrawable and the
+  // MacOSXGLContext. Initially the mode is "unspecified", meaning it
+  // leans toward the default (NSOpenGL). If sharing is requested
+  // between either a GLJPanel and a GLPbuffer or a GLCanvas and a
+  // GLPbuffer, the GLPbuffer will be switched into the appropriate
+  // mode: CGL mode for a GLJPanel and NSOpenGL mode for a GLCanvas.
+  // To avoid thrashing we support exactly one such switch during the
+  // lifetime of a given GLPbuffer. This is not a fully general
+  // solution (for example, you can't share textures among a
+  // GLPbuffer, a GLJPanel and a GLCanvas simultaneously) but should
+  // be enough to get things off the ground.
+  public static final int NSOPENGL_MODE = 1;
+  public static final int CGL_MODE      = 2;
+
   public MacOSXGLDrawable(GLCapabilities capabilities,
                           GLCapabilitiesChooser chooser) {
     this.capabilities = (GLCapabilities) capabilities.clone();
@@ -83,11 +115,16 @@ public abstract class MacOSXGLDrawable extends GLDrawableImpl {
     return availableCaps[pixelFormat];
   }
 
+  // Only used for on-screen contexts
   public long getView() {
-    return nsView;
+    return 0;
   }
   
   protected static String getThreadName() {
     return Thread.currentThread().getName();
   }
+
+  // Support for "mode switching" as per above
+  public abstract void setOpenGLMode(int mode);
+  public abstract int  getOpenGLMode();
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXJava2DGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXJava2DGLContext.java
index c9e4013c3..3082dd200 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXJava2DGLContext.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXJava2DGLContext.java
@@ -120,4 +120,13 @@ public class MacOSXJava2DGLContext extends MacOSXGLContext implements Java2DGLCo
   public void setSwapInterval(int interval) {
     // Not supported in this context implementation
   }
+
+  public void setOpenGLMode(int mode) {
+    if (mode != MacOSXGLDrawable.CGL_MODE)
+      throw new GLException("OpenGL mode switching not supported for Java2D GLContexts");
+  }
+
+  public int  getOpenGLMode() {
+    return MacOSXGLDrawable.CGL_MODE;
+  }
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLContext.java
index 1e6a263de..9486f7c7b 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLContext.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLContext.java
@@ -116,4 +116,13 @@ public class MacOSXOnscreenGLContext extends MacOSXGLContext {
   protected boolean create() {
     return create(false, false);
   }
+
+  public void setOpenGLMode(int mode) {
+    if (mode != MacOSXGLDrawable.NSOPENGL_MODE)
+      throw new GLException("OpenGL mode switching not supported for on-screen GLContexts");
+  }
+    
+  public int  getOpenGLMode() {
+    return MacOSXGLDrawable.NSOPENGL_MODE;
+  }
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java
index c9e993237..2cb501020 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java
@@ -53,6 +53,7 @@ public class MacOSXOnscreenGLDrawable extends MacOSXGLDrawable {
   public static final int LOCK_SUCCESS = 3;
 
   protected Component component;
+  protected long nsView; // NSView
 
   private List/*<WeakReference<GLContext>>*/ createdContexts =
     new ArrayList();
@@ -126,6 +127,10 @@ public class MacOSXOnscreenGLDrawable extends MacOSXGLDrawable {
     }
   }
   
+  public long getView() {
+    return nsView;
+  }
+
   public int lockSurface() throws GLException {
     if (!realized) {
       return LOCK_SURFACE_NOT_READY;
@@ -205,4 +210,13 @@ public class MacOSXOnscreenGLDrawable extends MacOSXGLDrawable {
     macosxdsi = null;
     nsView = 0;
   }
+
+  public void setOpenGLMode(int mode) {
+    if (mode != NSOPENGL_MODE)
+      throw new GLException("OpenGL mode switching not supported for on-screen GLDrawables");
+  }
+
+  public int  getOpenGLMode() {
+    return NSOPENGL_MODE;
+  }
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLContext.java
index a1251bd70..c4e3058da 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLContext.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLContext.java
@@ -32,6 +32,7 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
                                 GLContext shareWith) {
     super(drawable, shareWith);
     this.drawable = drawable;
+    initOpenGLImpl();
   }
 
   public void bindPbufferToTexture() {
@@ -55,8 +56,28 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
       return CONTEXT_NOT_CURRENT;
     }
 
-    int res = super.makeCurrentImpl();
-    if (res == CONTEXT_CURRENT_NEW) {
+    if (getOpenGLMode() != drawable.getOpenGLMode()) {
+      setOpenGLMode(drawable.getOpenGLMode());
+    }
+
+    boolean created = false;
+    if (nsContext == 0) {
+      if (!create()) {
+        return CONTEXT_NOT_CURRENT;
+      }
+      if (DEBUG) {
+        System.err.println("!!! Created OpenGL context " + toHexString(nsContext) + " for " + getClass().getName());
+      }
+      created = true;
+    }
+    
+    if (!impl.makeCurrent(nsContext)) {
+      throw new GLException("Error making nsContext current");
+    }
+            
+    if (created) {
+      resetGLFunctionAvailability();
+
       // Initialize render-to-texture support if requested
       boolean rect = drawable.getCapabilities().getPbufferRenderToTextureRectangle();
       GL gl = getGL();
@@ -77,8 +98,36 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
       gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
       gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
       gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, drawable.getWidth(), drawable.getHeight(), 0);
+
+      return CONTEXT_CURRENT_NEW;
+    }
+    return CONTEXT_CURRENT;
+  }
+
+  protected void releaseImpl() throws GLException {
+    if (!impl.release(nsContext)) {
+      throw new GLException("Error releasing OpenGL nsContext");
+    }
+  }
+
+  protected void destroyImpl() throws GLException {
+    if (nsContext != 0) {
+      if (!impl.destroy(nsContext)) {
+        throw new GLException("Unable to delete OpenGL context");
+      }
+      if (DEBUG) {
+        System.err.println("!!! Destroyed OpenGL context " + nsContext);
+      }
+      nsContext = 0;
+      GLContextShareSet.contextDestroyed(this);
     }
-    return res;
+  }
+
+  public void setSwapInterval(int interval) {
+    if (nsContext == 0) {
+      throw new GLException("OpenGL context not current");
+    }
+    impl.setSwapInterval(nsContext, interval);
   }
 
   public int getFloatingPointMode() {
@@ -91,11 +140,201 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
 	!isTigerOrLater) {
       throw new GLException("Floating-point pbuffers supported only on OS X 10.4 or later");
     }
-    if (!super.create(true, capabilities.getPbufferFloatingPointBuffers())) {
-      return false;
+    // Change our OpenGL mode to match that of any share context before we create ourselves
+    MacOSXGLContext other = (MacOSXGLContext) GLContextShareSet.getShareContext(this);
+    if (other != null) {
+      setOpenGLMode(other.getOpenGLMode());
     }
-    // Must now associate the pbuffer with our newly-created context
-    CGL.setContextPBuffer(nsContext, drawable.getPbuffer());
+    // Will throw exception upon error
+    nsContext = impl.create();
     return true;
   }
+
+  //---------------------------------------------------------------------------
+  // OpenGL "mode switching" functionality
+  //
+  private boolean haveSetOpenGLMode = false;
+  // FIXME: should consider switching the default mode based on
+  // whether the Java2D/JOGL bridge is active -- need to ask ourselves
+  // whether it's more likely that we will share with a GLCanvas or a
+  // GLJPanel when the bridge is turned on
+  private int     openGLMode = MacOSXGLDrawable.NSOPENGL_MODE;
+  // Implementation object (either NSOpenGL-based or CGL-based)
+  protected Impl impl;
+
+  public void setOpenGLMode(int mode) {
+    if (mode == openGLMode) {
+      return;
+    }
+    if (haveSetOpenGLMode) {
+      throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once");
+    }
+    destroyImpl();
+    drawable.setOpenGLMode(mode);
+    openGLMode = mode;
+    haveSetOpenGLMode = true;
+    if (DEBUG) {
+      System.err.println("Switching PBuffer context mode to " +
+                         ((mode == MacOSXGLDrawable.NSOPENGL_MODE) ? "NSOPENGL_MODE" : "CGL_MODE"));
+    }
+    initOpenGLImpl();
+  }
+
+  public int  getOpenGLMode() {
+    return openGLMode;
+  }
+
+  private void initOpenGLImpl() {
+    switch (openGLMode) {
+      case MacOSXGLDrawable.NSOPENGL_MODE:
+        impl = new NSOpenGLImpl();
+        break;
+      case MacOSXGLDrawable.CGL_MODE:
+        impl = new CGLImpl();
+        break;
+      default:
+        throw new InternalError("Illegal implementation mode " + openGLMode);
+    }
+  }
+
+  // Abstract interface for implementation of this context (either
+  // NSOpenGL-based or CGL-based)
+  interface Impl {
+    public long    create();
+    public boolean destroy(long ctx);
+    public boolean makeCurrent(long ctx);
+    public boolean release(long ctx);
+    public void    setSwapInterval(long ctx, int interval);
+  }
+
+  // NSOpenGLContext-based implementation
+  class NSOpenGLImpl implements Impl {
+    public long create() {
+      GLCapabilities capabilities = drawable.getCapabilities();
+      if (capabilities.getPbufferFloatingPointBuffers() &&
+          !isTigerOrLater) {
+        throw new GLException("Floating-point pbuffers supported only on OS X 10.4 or later");
+      }
+      if (!MacOSXPbufferGLContext.this.create(true, capabilities.getPbufferFloatingPointBuffers())) {
+        throw new GLException("Error creating context for pbuffer");
+      }
+      // Must now associate the pbuffer with our newly-created context
+      CGL.setContextPBuffer(nsContext, drawable.getPbuffer());
+      return nsContext;
+    }
+
+    public boolean destroy(long ctx) {
+      return CGL.deleteContext(ctx);
+    }
+
+    public boolean makeCurrent(long ctx) {
+      return CGL.makeCurrentContext(ctx);
+    }
+
+    public boolean release(long ctx) {
+      return CGL.clearCurrentContext(ctx);
+    }
+
+    public void setSwapInterval(long ctx, int interval) {
+      CGL.setSwapInterval(ctx, interval);      
+    }
+  }
+
+  class CGLImpl implements Impl {
+    public long create() {
+      // Find and configure share context
+      MacOSXGLContext other = (MacOSXGLContext) GLContextShareSet.getShareContext(MacOSXPbufferGLContext.this);
+      long share = 0;
+      if (other != null) {
+        // Reconfigure pbuffer-based GLContexts
+        if (other instanceof MacOSXPbufferGLContext) {
+          MacOSXPbufferGLContext ctx = (MacOSXPbufferGLContext) other;
+          ctx.setOpenGLMode(MacOSXGLDrawable.CGL_MODE);
+        } else {
+          if (other.getOpenGLMode() != MacOSXGLDrawable.CGL_MODE) {
+            throw new GLException("Can't share between NSOpenGLContexts and CGLContextObjs");
+          }
+        }
+        share = other.getNSContext();
+        // Note we don't check for a 0 return value, since switching
+        // the context's mode causes it to be destroyed and not
+        // re-initialized until the next makeCurrent
+      }
+
+      // Set up pixel format attributes
+      int[] attrs = new int[256];
+      int i = 0;
+      attrs[i++] = CGL.kCGLPFAPBuffer;
+      GLCapabilities capabilities = drawable.getCapabilities();
+      if (capabilities.getPbufferFloatingPointBuffers())
+        attrs[i++] = CGL.kCGLPFAColorFloat;
+      if (capabilities.getDoubleBuffered())
+        attrs[i++] = CGL.kCGLPFADoubleBuffer;
+      if (capabilities.getStereo())
+        attrs[i++] = CGL.kCGLPFAStereo;
+      attrs[i++] = CGL.kCGLPFAColorSize;
+      attrs[i++] = (capabilities.getRedBits() +
+                    capabilities.getGreenBits() +
+                    capabilities.getBlueBits());
+      attrs[i++] = CGL.kCGLPFAAlphaSize;
+      attrs[i++] = capabilities.getAlphaBits();
+      attrs[i++] = CGL.kCGLPFADepthSize;
+      attrs[i++] = capabilities.getDepthBits();
+      // FIXME: should validate stencil size as is done in MacOSXWindowSystemInterface.m
+      attrs[i++] = CGL.kCGLPFAStencilSize;
+      attrs[i++] = capabilities.getStencilBits();
+      attrs[i++] = CGL.kCGLPFAAccumSize;
+      attrs[i++] = (capabilities.getAccumRedBits() +
+                    capabilities.getAccumGreenBits() +
+                    capabilities.getAccumBlueBits() +
+                    capabilities.getAccumAlphaBits());
+      if (capabilities.getSampleBuffers()) {
+        attrs[i++] = CGL.kCGLPFASampleBuffers;
+        attrs[i++] = 1;
+        attrs[i++] = CGL.kCGLPFASamples;
+        attrs[i++] = capabilities.getNumSamples();
+      }
+
+      // Use attribute array to select pixel format
+      long[] fmt = new long[1];
+      long[] numScreens = new long[1];
+      int res = CGL.CGLChoosePixelFormat(attrs, 0, fmt, 0, numScreens, 0);
+      if (res != CGL.kCGLNoError) {
+        throw new GLException("Error code " + res + " while choosing pixel format");
+      }
+      
+      // Create new context
+      long[] ctx = new long[1];
+      if (DEBUG) {
+        System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share));
+      }
+      res = CGL.CGLCreateContext(fmt[0], share, ctx, 0);
+      CGL.CGLDestroyPixelFormat(fmt[0]);
+      if (res != CGL.kCGLNoError) {
+        throw new GLException("Error code " + res + " while creating context");
+      }
+      // Attach newly-created context to the pbuffer
+      res = CGL.CGLSetPBuffer(ctx[0], drawable.getPbuffer(), 0, 0, 0);
+      if (res != CGL.kCGLNoError) {
+        throw new GLException("Error code " + res + " while attaching context to pbuffer");
+      }
+      return ctx[0];
+    }
+    
+    public boolean destroy(long ctx) {
+      return (CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError);
+    }
+
+    public boolean makeCurrent(long ctx) {
+      return CGL.CGLSetCurrentContext(ctx) == CGL.kCGLNoError;
+    }
+
+    public boolean release(long ctx) {
+      return (CGL.CGLSetCurrentContext(0) == CGL.kCGLNoError);
+    }
+
+    public void setSwapInterval(long ctx, int interval) {
+      // For now not supported (not really relevant for off-screen contexts anyway)
+    }
+  }
 }
diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLDrawable.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLDrawable.java
index a28d945f7..5a4967f5c 100644
--- a/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLDrawable.java
+++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXPbufferGLDrawable.java
@@ -43,13 +43,15 @@ import javax.media.opengl.*;
 import com.sun.opengl.impl.*;
 
 public class MacOSXPbufferGLDrawable extends MacOSXGLDrawable {
-  private static final boolean DEBUG = Debug.debug("MacOSXPbufferGLContext");
+  private static final boolean DEBUG = Debug.debug("MacOSXPbufferGLDrawable");
   
   protected int  initWidth;
   protected int  initHeight;
 
+  // NSOpenGLPbuffer (for normal mode)
+  // CGLPbufferObj (for CGL_MODE situation, i.e., when Java2D/JOGL bridge is active)
   protected long pBuffer;
-  
+
   protected int  width;
   protected int  height;
 
@@ -61,7 +63,7 @@ public class MacOSXPbufferGLDrawable extends MacOSXGLDrawable {
     super(capabilities, null);
     this.initWidth  = initialWidth;
     this.initHeight = initialHeight;
-
+    initOpenGLImpl();
     createPbuffer();
   }
 
@@ -71,7 +73,7 @@ public class MacOSXPbufferGLDrawable extends MacOSXGLDrawable {
 
   public void destroy() {
     if (this.pBuffer != 0) {
-      CGL.destroyPBuffer(0, pBuffer);
+      impl.destroy(pBuffer);
       this.pBuffer = 0;
     
       if (DEBUG) {
@@ -135,13 +137,13 @@ public class MacOSXPbufferGLDrawable extends MacOSXGLDrawable {
       }
     }
 		
-    pBuffer = CGL.createPBuffer(renderTarget, internalFormat, width, height);
+    pBuffer = impl.create(renderTarget, internalFormat, width, height);
     if (pBuffer == 0) {
       throw new GLException("pbuffer creation error: CGL.createPBuffer() failed");
     }
 	
     if (DEBUG) {
-      System.err.println("Created pbuffer 0x" + toHexString(pBuffer) + ", " + width + " x " + height + " for " + this);
+      System.err.println("Created pbuffer " + toHexString(pBuffer) + ", " + width + " x " + height + " for " + this);
     }
   }
 
@@ -157,4 +159,88 @@ public class MacOSXPbufferGLDrawable extends MacOSXGLDrawable {
     }
     return (1<<power);
   }
+
+  //---------------------------------------------------------------------------
+  // OpenGL "mode switching" functionality
+  //
+  private boolean haveSetOpenGLMode = false;
+  // FIXME: should consider switching the default mode based on
+  // whether the Java2D/JOGL bridge is active -- need to ask ourselves
+  // whether it's more likely that we will share with a GLCanvas or a
+  // GLJPanel when the bridge is turned on
+  private int     openGLMode = NSOPENGL_MODE;
+  // Implementation object (either NSOpenGL-based or CGL-based)
+  protected Impl impl;
+
+  public void setOpenGLMode(int mode) {
+    if (mode == openGLMode) {
+      return;
+    }
+    if (haveSetOpenGLMode) {
+      throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once");
+    }
+    destroy();
+    openGLMode = mode;
+    haveSetOpenGLMode = true;
+    if (DEBUG) {
+      System.err.println("Switching PBuffer drawable mode to " +
+                         ((mode == MacOSXGLDrawable.NSOPENGL_MODE) ? "NSOPENGL_MODE" : "CGL_MODE"));
+    }
+    initOpenGLImpl();
+    createPbuffer();
+  }
+
+  public int getOpenGLMode() {
+    return openGLMode;
+  }
+
+  private void initOpenGLImpl() {
+    switch (openGLMode) {
+      case NSOPENGL_MODE:
+        impl = new NSOpenGLImpl();
+        break;
+      case CGL_MODE:
+        impl = new CGLImpl();
+        break;
+      default:
+        throw new InternalError("Illegal implementation mode " + openGLMode);
+    }
+  }
+
+  // Abstract interface for implementation of this drawable (either
+  // NSOpenGL-based or CGL-based)
+  interface Impl {
+    public long create(int renderTarget, int internalFormat, int width, int height);
+    public void destroy(long pbuffer);
+  }
+
+  // NSOpenGLPixelBuffer implementation
+  class NSOpenGLImpl implements Impl {
+    public long create(int renderTarget, int internalFormat, int width, int height) {
+      return CGL.createPBuffer(renderTarget, internalFormat, width, height);
+    }
+
+    public void destroy(long pbuffer) {
+      CGL.destroyPBuffer(0, pbuffer);
+    }
+  }
+
+  // CGL implementation
+  class CGLImpl implements Impl {
+    public long create(int renderTarget, int internalFormat, int width, int height) {
+      long[] pbuffer = new long[1];
+      int res = CGL.CGLCreatePBuffer(width, height, renderTarget, internalFormat, 0, pbuffer, 0);
+      if (res != CGL.kCGLNoError) {
+        throw new GLException("Error creating CGL-based pbuffer: error code " + res);
+      }
+      return pbuffer[0];
+    }
+
+    public void destroy(long pbuffer) {
+      int res = CGL.CGLDestroyPBuffer(pbuffer);
+      if (res != CGL.kCGLNoError) {
+        throw new GLException("Error destroying CGL-based pbuffer: error code " + res);
+      }
+    }
+  }
 }
-- 
cgit v1.2.3