diff options
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java')
-rw-r--r-- | src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java | 488 |
1 files changed, 354 insertions, 134 deletions
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 383594d87..45c8b9304 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -40,19 +40,62 @@ package jogamp.opengl.macosx.cgl; -import java.nio.*; -import java.util.*; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.util.Map; +import java.util.StringTokenizer; -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import jogamp.opengl.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.DefaultGraphicsConfiguration; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import jogamp.opengl.Debug; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLContextShareSet; +import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLGraphicsConfigurationUtil; +import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; + +import com.jogamp.common.nio.PointerBuffer; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; + public abstract class MacOSXCGLContext extends GLContextImpl { - protected boolean isNSContext; + // Abstract interface for implementation of this context (either + // NSOpenGL-based or CGL-based) + protected interface GLBackendImpl { + boolean isNSContext(); + boolean create(long share); + boolean destroy(); + boolean copyImpl(long src, int mask); + boolean makeCurrent(); + boolean release(); + boolean setSwapInterval(int interval); + boolean swapBuffers(boolean isOnscreen); + } + + private static boolean isTigerOrLater; + + static { + String osVersion = Debug.getProperty("os.version", false, AccessController.getContext()); + StringTokenizer tok = new StringTokenizer(osVersion, ". "); + int major = Integer.parseInt(tok.nextToken()); + int minor = Integer.parseInt(tok.nextToken()); + isTigerOrLater = ((major > 10) || (minor > 3)); + } + + private boolean haveSetOpenGLMode = false; + private GLBackendType openGLMode = GLBackendType.NSOPENGL; + + // Implementation object (either NSOpenGL-based or CGL-based) + protected GLBackendImpl impl; + private CGLExt _cglExt; // Table that holds the addresses of the native C-language entry points for // CGL extension functions. @@ -61,11 +104,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl protected MacOSXCGLContext(GLDrawableImpl drawable, GLContext shareWith) { super(drawable, shareWith); + initOpenGLImpl(getOpenGLMode()); } @Override protected void resetStates() { - isNSContext = false; // no inner state _cglExt = null; super.resetStates(); } @@ -74,7 +117,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl return getCGLExt(); } - protected boolean isNSContext() { return isNSContext; } + protected boolean isNSContext() { + return (null != impl) ? impl.isNSContext() : this.openGLMode == GLBackendType.NSOPENGL; + } public CGLExt getCGLExt() { if (_cglExt == null) { @@ -107,125 +152,108 @@ public abstract class MacOSXCGLContext extends GLContextImpl return false; } - /** - * Creates and initializes an appropriate OpenGl Context (NS). Should only be - * called by {@link makeCurrentImpl()}. - */ - protected boolean create(boolean pbuffer, boolean floatingPoint) { + protected long createImplPreset() throws GLException { MacOSXCGLContext other = (MacOSXCGLContext) GLContextShareSet.getShareContext(this); long share = 0; if (other != null) { - if (!other.isNSContext()) { - throw new GLException("GLContextShareSet is not a NS Context"); - } + // Change our OpenGL mode to match that of any share context before we create ourselves + setOpenGLMode(other.getOpenGLMode()); share = other.getHandle(); if (share == 0) { throw new GLException("GLContextShareSet returned a NULL OpenGL context"); } } MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilitiesRequested = (GLCapabilitiesImmutable) config.getRequestedCapabilities(); - GLProfile glProfile = capabilitiesRequested.getGLProfile(); + GLCapabilitiesImmutable capabilitiesChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + if (capabilitiesChosen.getPbufferFloatingPointBuffers() && + !isTigerOrLater) { + throw new GLException("Floating-point pbuffers supported only on OS X 10.4 or later"); + } + GLProfile glProfile = capabilitiesChosen.getGLProfile(); if(glProfile.isGL3()) { throw new GLException("GL3 profile currently not supported on MacOSX, due to the lack of a OpenGL 3.1 implementation"); } - // HACK .. bring in OnScreen/PBuffer selection to the DrawableFactory !! - GLCapabilities capabilities = (GLCapabilities) capabilitiesRequested.cloneMutable(); - capabilities.setPBuffer(pbuffer); - capabilities.setPbufferFloatingPointBuffers(floatingPoint); - - long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(capabilities); - if (pixelFormat == 0) { - throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); - } - config.setChosenPixelFormat(pixelFormat); - try { - int[] viewNotReady = new int[1]; - // Try to allocate a context with this - contextHandle = CGL.createContext(share, - drawable.getHandle(), - pixelFormat, - capabilities.isBackgroundOpaque(), - viewNotReady, 0); - if (contextHandle == 0) { - if (viewNotReady[0] == 1) { - if (DEBUG) { - System.err.println("!!! View not ready for " + getClass().getName()); - } - // View not ready at the window system level -- this is OK - return false; - } - throw new GLException("Error creating NSOpenGLContext with requested pixel format"); - } - - if (!pbuffer && !capabilities.isBackgroundOpaque()) { - // Set the context opacity - CGL.setContextOpacity(contextHandle, 0); - } - - GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(glProfile, pixelFormat); - caps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(caps, capabilities.isBackgroundOpaque()); - config.setChosenCapabilities(caps); - } finally { - CGL.deletePixelFormat(pixelFormat); + if (DEBUG) { + System.err.println("!!! Share context is " + toHexString(share) + " for " + this); } - if (!CGL.makeCurrentContext(contextHandle)) { - throw new GLException("Error making Context (NS) current"); + return share; + } + + protected boolean createImpl() throws GLException { + long share = createImplPreset(); + + // Will throw exception upon error + if(!impl.create(share)) { + return false; + } + if (!impl.makeCurrent()) { + throw new GLException("Error making Context (NS:"+isNSContext()+") current"); } - isNSContext = true; setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); - GLContextShareSet.contextCreated(this); + if (DEBUG) { + System.err.println("!!! Created " + this); + } return true; } - + protected void makeCurrentImpl(boolean newCreated) throws GLException { - if ( isNSContext ) { - if (!CGL.makeCurrentContext(contextHandle)) { - throw new GLException("Error making Context (NS) current"); - } - } else { - if (CGL.kCGLNoError != CGL.CGLSetCurrentContext(contextHandle)) { - throw new GLException("Error making Context (CGL) current"); - } + if (getOpenGLMode() != ((MacOSXCGLDrawable)drawable).getOpenGLMode()) { + setOpenGLMode(((MacOSXCGLDrawable)drawable).getOpenGLMode()); } + + if (!impl.makeCurrent()) { + throw new GLException("Error making Context current: "+this); + } } protected void releaseImpl() throws GLException { - if ( isNSContext ) { - if (!CGL.clearCurrentContext(contextHandle)) { - throw new GLException("Error freeing OpenGL Context (NS)"); - } - } else { - CGL.CGLReleaseContext(contextHandle); + if (!impl.release()) { + throw new GLException("Error releasing OpenGL Context: "+this); } } - + protected void destroyImpl() throws GLException { - if ( !isNSContext ) { - if (CGL.kCGLNoError != CGL.CGLDestroyContext(contextHandle)) { - throw new GLException("Unable to delete OpenGL Context (CGL)"); - } - } else { - if (!CGL.deleteContext(contextHandle, true)) { - throw new GLException("Unable to delete OpenGL Context (NS) "+toHexString(contextHandle)); - } + if(!impl.destroy()) { + throw new GLException("Error destroying OpenGL Context: "+this); } } protected void copyImpl(GLContext source, int mask) throws GLException { - long dst = getHandle(); - long src = source.getHandle(); - if( !isNSContext() ) { - if ( ((MacOSXCGLContext)source).isNSContext() ) { - throw new GLException("Source OpenGL Context is NS ; Destination Context is CGL."); - } - CGL.CGLCopyContext(src, dst, mask); + if( isNSContext() != ((MacOSXCGLContext)source).isNSContext() ) { + throw new GLException("Source/Destination OpenGL Context tyoe mismatch: source "+source+", dest: "+this); + } + if(!impl.copyImpl(source.getHandle(), mask)) { + throw new GLException("Error copying OpenGL Context: source "+source+", dest: "+this); + } + } + + protected void swapBuffers() { + DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + if(!impl.swapBuffers(caps.isOnscreen())) { + throw new GLException("Error swapping buffers: "+this); + } + } + + protected void setSwapIntervalImpl(int interval) { + if( ! isCreated() ) { + throw new GLException("OpenGL context not created"); + } + if(!impl.setSwapInterval(interval)) { + throw new GLException("Error set swap-interval: "+this); + } + if ( isNSContext() ) { + CGL.setSwapInterval(contextHandle, interval); } else { - if ( !((MacOSXCGLContext)source).isNSContext() ) { - throw new GLException("Source OpenGL Context is CGL ; Destination Context is NS."); - } - CGL.copyContext(dst, src, mask); + int[] lval = new int[] { (int) interval } ; + CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); } + currentSwapInterval = interval ; + } + + public ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3) { + // FIXME: apparently the Apple extension doesn't require a custom memory allocator + throw new GLException("Not yet implemented"); } protected final void updateGLXProcAddressTable() { @@ -246,8 +274,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl } } else { if (cglExtProcAddressTable == null) { - // FIXME: cache ProcAddressTables by capability bits so we can - // share them among contexts with the same capabilities cglExtProcAddressTable = new CGLExtProcAddressTable(new GLProcAddressResolver()); } resetProcAddressTable(getCGLExtProcAddressTable()); @@ -264,40 +290,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl return new StringBuffer(); } - protected void swapBuffers() { - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - if(caps.isOnscreen()) { - if(isNSContext) { - if (!CGL.flushBuffer(contextHandle)) { - throw new GLException("Error swapping buffers (NS)"); - } - } else { - if (CGL.kCGLNoError != CGL.CGLFlushDrawable(contextHandle)) { - throw new GLException("Error swapping buffers (CGL)"); - } - } - } - } - - protected void setSwapIntervalImpl(int interval) { - if( ! isCreated() ) { - throw new GLException("OpenGL context not created"); - } - if ( isNSContext ) { - CGL.setSwapInterval(contextHandle, interval); - } else { - int[] lval = new int[] { (int) interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - } - currentSwapInterval = interval ; - } - - public ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3) { - // FIXME: apparently the Apple extension doesn't require a custom memory allocator - throw new GLException("Not yet implemented"); - } - public boolean isExtensionAvailable(String glExtensionName) { if (glExtensionName.equals("GL_ARB_pbuffer") || glExtensionName.equals("GL_ARB_pixel_format")) { @@ -327,6 +319,234 @@ public abstract class MacOSXCGLContext extends GLContextImpl } // Support for "mode switching" as described in MacOSXCGLDrawable - public abstract void setOpenGLMode(int mode); - public abstract int getOpenGLMode(); + public void setOpenGLMode(GLBackendType mode) { + if (mode == openGLMode) { + return; + } + if (haveSetOpenGLMode) { + throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once"); + } + destroyImpl(); + ((MacOSXCGLDrawable)drawable).setOpenGLMode(mode); + if (DEBUG) { + System.err.println("Switching context mode " + openGLMode + " -> " + mode); + } + initOpenGLImpl(mode); + openGLMode = mode; + haveSetOpenGLMode = true; + } + public final GLBackendType getOpenGLMode() { return openGLMode; } + + protected void initOpenGLImpl(GLBackendType backend) { + switch (backend) { + case NSOPENGL: + impl = new NSOpenGLImpl(); + break; + case CGL: + impl = new CGLImpl(); + break; + default: + throw new InternalError("Illegal implementation mode " + backend); + } + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + super.append(sb); + sb.append(", mode "); + sb.append(openGLMode); + sb.append("] "); + return sb.toString(); + } + + // NSOpenGLContext-based implementation + class NSOpenGLImpl implements GLBackendImpl { + public boolean isNSContext() { return true; } + + public boolean create(long share) { + MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps); + if (pixelFormat == 0) { + throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); + } + config.setChosenPixelFormat(pixelFormat); + try { + int[] viewNotReady = new int[1]; + // Try to allocate a context with this + contextHandle = CGL.createContext(share, + drawable.getHandle(), + pixelFormat, + chosenCaps.isBackgroundOpaque(), + viewNotReady, 0); + if (0 == contextHandle) { + if (viewNotReady[0] == 1) { + if (DEBUG) { + System.err.println("!!! View not ready for " + getClass().getName()); + } + // View not ready at the window system level -- this is OK + return false; + } + throw new GLException("Error creating NSOpenGLContext with requested pixel format"); + } + + if (!chosenCaps.isPBuffer() && !chosenCaps.isBackgroundOpaque()) { + // Set the context opacity + CGL.setContextOpacity(contextHandle, 0); + } + + GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + caps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(caps, chosenCaps.isBackgroundOpaque()); + config.setChosenCapabilities(caps); + if(caps.isPBuffer()) { + // Must now associate the pbuffer with our newly-created context + CGL.setContextPBuffer(contextHandle, drawable.getHandle()); + } + } finally { + CGL.deletePixelFormat(pixelFormat); + } + if (!CGL.makeCurrentContext(contextHandle)) { + throw new GLException("Error making Context (NS) current"); + } + setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); + GLContextShareSet.contextCreated(MacOSXCGLContext.this); + return true; + } + + public boolean destroy() { + return CGL.deleteContext(contextHandle, true); + } + + public boolean copyImpl(long src, int mask) { + CGL.copyContext(contextHandle, src, mask); + return true; + } + + public boolean makeCurrent() { + return CGL.makeCurrentContext(contextHandle); + } + + public boolean release() { + return CGL.clearCurrentContext(contextHandle); + } + + public boolean setSwapInterval(int interval) { + CGL.setSwapInterval(contextHandle, interval); + return true; + } + public boolean swapBuffers(boolean isOnscreen) { + if(isOnscreen) { + return CGL.flushBuffer(contextHandle); + } + return true; + } + } + + class CGLImpl implements GLBackendImpl { + public boolean isNSContext() { return false; } + + public boolean create(long share) { + DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + + // Set up pixel format attributes + int[] attrs = new int[256]; + int i = 0; + if(chosenCaps.isPBuffer()) { + attrs[i++] = CGL.kCGLPFAPBuffer; + } + if (chosenCaps.getPbufferFloatingPointBuffers()) { + attrs[i++] = CGL.kCGLPFAColorFloat; + } + if (chosenCaps.getDoubleBuffered()) { + attrs[i++] = CGL.kCGLPFADoubleBuffer; + } + if (chosenCaps.getStereo()) { + attrs[i++] = CGL.kCGLPFAStereo; + } + attrs[i++] = CGL.kCGLPFAColorSize; + attrs[i++] = (chosenCaps.getRedBits() + + chosenCaps.getGreenBits() + + chosenCaps.getBlueBits()); + attrs[i++] = CGL.kCGLPFAAlphaSize; + attrs[i++] = chosenCaps.getAlphaBits(); + attrs[i++] = CGL.kCGLPFADepthSize; + attrs[i++] = chosenCaps.getDepthBits(); + // FIXME: should validate stencil size as is done in MacOSXWindowSystemInterface.m + attrs[i++] = CGL.kCGLPFAStencilSize; + attrs[i++] = chosenCaps.getStencilBits(); + attrs[i++] = CGL.kCGLPFAAccumSize; + attrs[i++] = (chosenCaps.getAccumRedBits() + + chosenCaps.getAccumGreenBits() + + chosenCaps.getAccumBlueBits() + + chosenCaps.getAccumAlphaBits()); + if (chosenCaps.getSampleBuffers()) { + attrs[i++] = CGL.kCGLPFASampleBuffers; + attrs[i++] = 1; + attrs[i++] = CGL.kCGLPFASamples; + attrs[i++] = chosenCaps.getNumSamples(); + } + + // Use attribute array to select pixel format + PointerBuffer fmt = PointerBuffer.allocateDirect(1); + long[] numScreens = new long[1]; + int res = CGL.CGLChoosePixelFormat(attrs, 0, fmt, numScreens, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while choosing pixel format"); + } + try { + // Create new context + PointerBuffer ctx = PointerBuffer.allocateDirect(1); + if (DEBUG) { + System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share)); + } + res = CGL.CGLCreateContext(fmt.get(0), share, ctx); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while creating context"); + } + if(chosenCaps.isPBuffer()) { + // Attach newly-created context to the pbuffer + res = CGL.CGLSetPBuffer(ctx.get(0), drawable.getHandle(), 0, 0, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while attaching context to pbuffer"); + } + } + contextHandle = ctx.get(0); + } finally { + CGL.CGLDestroyPixelFormat(fmt.get(0)); + } + return true; + } + + public boolean destroy() { + return CGL.CGLDestroyContext(contextHandle) == CGL.kCGLNoError; + } + + public boolean copyImpl(long src, int mask) { + CGL.CGLCopyContext(src, contextHandle, mask); + return true; + } + + public boolean makeCurrent() { + return CGL.CGLSetCurrentContext(contextHandle) == CGL.kCGLNoError; + } + + public boolean release() { + return (CGL.CGLSetCurrentContext(0) == CGL.kCGLNoError); + } + + public boolean setSwapInterval(int interval) { + int[] lval = new int[] { interval } ; + CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); + return true; + } + public boolean swapBuffers(boolean isOnscreen) { + if(isOnscreen) { + return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); + } + return true; + } + } } |