diff options
Diffstat (limited to 'src/classes/com/sun/opengl')
8 files changed, 423 insertions, 16 deletions
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); + } + } + } } |