diff options
12 files changed, 538 insertions, 17 deletions
diff --git a/make/build.xml b/make/build.xml index f6e7f9910..726cadf11 100644 --- a/make/build.xml +++ b/make/build.xml @@ -584,6 +584,7 @@ <!-- Generate WGL/GLX/CGL implementation class --> <echo message="Generating WGL/GLX/CGL implementation class" /> + <dirset id="stub.includes.fileset.platform" dir="." includes="${stub.includes.fileset.platform.params}" /> <gluegen src="${stub.includes.platform}/window-system.c" config="${window.cfg}" includeRefid="stub.includes.fileset.platform" @@ -597,7 +598,6 @@ - handle different drives in an effective manner. --> <echo message="Generating JAWT interface class" /> <echo message="java.home.dir=${java.home.dir}" /> - <dirset id="stub.includes.fileset.platform" dir="." includes="${stub.includes.fileset.platform.params}" /> <gluegen src="${java.includes.dir.platform}/jawt_md.h" config="${jawt.cfg}" literalInclude="${java.includes.dir}" diff --git a/make/cgl-macosx.cfg b/make/cgl-macosx.cfg index 97a3bbeff..7c31f7338 100644 --- a/make/cgl-macosx.cfg +++ b/make/cgl-macosx.cfg @@ -9,6 +9,11 @@ Include gl-common-macosx.cfg Opaque long void * +# Opaque directives for low-level CGL binding (for Java2D/JOGL bridge) +Opaque long CGLContextObj +Opaque long CGLPBufferObj +Opaque long CGLPixelFormatObj + CustomCCode #include </usr/include/machine/types.h> CustomCCode #include "macosx-window-system.h" diff --git a/make/stub_includes/macosx/OpenGL/OpenGL.h b/make/stub_includes/macosx/OpenGL/OpenGL.h new file mode 100644 index 000000000..16225b46b --- /dev/null +++ b/make/stub_includes/macosx/OpenGL/OpenGL.h @@ -0,0 +1,101 @@ +/* Typedefs, enums and function prototypes extracted from Apple's + OpenGL.h to expose portions of the low-level CGL API to Java */ + +/* Typedefs to get things working */ +typedef struct _cglObj* CGLContextObj; +typedef struct _cglObj* CGLPBufferObj; +typedef struct _cglObj* CGLPixelFormatObj; + +/* +** Attribute names for CGLChoosePixelFormat and CGLDescribePixelFormat. +*/ +typedef enum _CGLPixelFormatAttribute { + kCGLPFAAllRenderers = 1, /* choose from all available renderers */ + kCGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */ + kCGLPFAStereo = 6, /* stereo buffering supported */ + kCGLPFAAuxBuffers = 7, /* number of aux buffers */ + kCGLPFAColorSize = 8, /* number of color buffer bits */ + kCGLPFAAlphaSize = 11, /* number of alpha component bits */ + kCGLPFADepthSize = 12, /* number of depth buffer bits */ + kCGLPFAStencilSize = 13, /* number of stencil buffer bits */ + kCGLPFAAccumSize = 14, /* number of accum buffer bits */ + kCGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */ + kCGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */ + kCGLPFAOffScreen = 53, /* choose an off-screen capable renderer */ + kCGLPFAFullScreen = 54, /* choose a full-screen capable renderer */ + kCGLPFASampleBuffers = 55, /* number of multi sample buffers */ + kCGLPFASamples = 56, /* number of samples per multi sample buffer */ + kCGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */ + kCGLPFAColorFloat = 58, /* color buffers store floating point pixels */ + kCGLPFAMultisample = 59, /* choose multisampling */ + kCGLPFASupersample = 60, /* choose supersampling */ + kCGLPFASampleAlpha = 61, /* request alpha filtering */ + + kCGLPFARendererID = 70, /* request renderer by ID */ + kCGLPFASingleRenderer = 71, /* choose a single renderer for all screens */ + kCGLPFANoRecovery = 72, /* disable all failure recovery systems */ + kCGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */ + kCGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */ + kCGLPFARobust = 75, /* renderer does not need failure recovery */ + kCGLPFABackingStore = 76, /* back buffer contents are valid after swap */ + kCGLPFAMPSafe = 78, /* renderer is multi-processor safe */ + kCGLPFAWindow = 80, /* can be used to render to an onscreen window */ + kCGLPFAMultiScreen = 81, /* single window can span multiple screens */ + kCGLPFACompliant = 83, /* renderer is opengl compliant */ + kCGLPFADisplayMask = 84, /* mask limiting supported displays */ + kCGLPFAPBuffer = 90, /* can be used to render to a pbuffer */ + kCGLPFARemotePBuffer = 91, /* can be used to render offline to a pbuffer */ + kCGLPFAVirtualScreenCount = 128 /* number of virtual screens in this format */ +} CGLPixelFormatAttribute; + +/* +** Error return values from CGLGetError. +*/ +typedef enum _CGLError { + kCGLNoError = 0, /* no error */ + kCGLBadAttribute = 10000, /* invalid pixel format attribute */ + kCGLBadProperty = 10001, /* invalid renderer property */ + kCGLBadPixelFormat = 10002, /* invalid pixel format */ + kCGLBadRendererInfo = 10003, /* invalid renderer info */ + kCGLBadContext = 10004, /* invalid context */ + kCGLBadDrawable = 10005, /* invalid drawable */ + kCGLBadDisplay = 10006, /* invalid graphics device */ + kCGLBadState = 10007, /* invalid context state */ + kCGLBadValue = 10008, /* invalid numerical value */ + kCGLBadMatch = 10009, /* invalid share context */ + kCGLBadEnumeration = 10010, /* invalid enumerant */ + kCGLBadOffScreen = 10011, /* invalid offscreen drawable */ + kCGLBadFullScreen = 10012, /* invalid offscreen drawable */ + kCGLBadWindow = 10013, /* invalid window */ + kCGLBadAddress = 10014, /* invalid pointer */ + kCGLBadCodeModule = 10015, /* invalid code module */ + kCGLBadAlloc = 10016, /* invalid memory allocation */ + kCGLBadConnection = 10017 /* invalid CoreGraphics connection */ +} CGLError; + +/* Pixel format manipulation */ +CGLError CGLChoosePixelFormat(const CGLPixelFormatAttribute *attribs, + CGLPixelFormatObj *pix, + long *npix); +CGLError CGLDestroyPixelFormat(CGLPixelFormatObj pix); + +/* Context manipulation */ +CGLError CGLCreateContext(CGLPixelFormatObj pix, + CGLContextObj share, + CGLContextObj* ctx); +CGLError CGLDestroyContext(CGLContextObj ctx); +CGLError CGLSetCurrentContext(CGLContextObj ctx); + +/* PBuffer manipulation */ +CGLError CGLCreatePBuffer(long width, + long height, + unsigned long target, + unsigned long internalFormat, + long max_level, + CGLPBufferObj* pbuffer); +CGLError CGLDestroyPBuffer(CGLPBufferObj pbuffer); +CGLError CGLSetPBuffer(CGLContextObj ctx, + CGLPBufferObj pbuffer, + unsigned long face, + long level, + long screen); diff --git a/make/stub_includes/opengl/macosx-window-system.h b/make/stub_includes/opengl/macosx-window-system.h index 959c2352e..1d3df1a08 100644 --- a/make/stub_includes/opengl/macosx-window-system.h +++ b/make/stub_includes/opengl/macosx-window-system.h @@ -48,3 +48,11 @@ void setSwapInterval(void* nsContext, int interval); /* Gamma-related functionality */ Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp); void resetGammaRamp(); + +/****************************************************************************************/ +/* Java2D/JOGL bridge support; need to be able to create pbuffers and + contexts using the CGL APIs to be able to share textures, etc. with + contexts created by Java2D/JOGL bridge, which are CGLContextObjs */ + +/* Pick up copies of CGL signatures from Mac OS X stub_includes/window-system-build directory */ +#include <OpenGL/OpenGL.h> 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); + } + } + } } |