diff options
author | Sven Gothel <[email protected]> | 2012-09-15 16:54:52 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-09-15 16:54:52 +0200 |
commit | 4dd44b985fe0541be3a3bcd9045d201ed3ca2cc5 (patch) | |
tree | e14c927a1da9f089297aa291dcd69f2f39b4f15e /src/jogl/classes/jogamp/opengl/macosx | |
parent | 9036376b7806a5fc61590bf49404eb71830de92f (diff) |
Seamless Integration of an FBObject based GLFBODrawable as GLOffscreenAutoDrawable.FBO and as an OffscreenLayerSurface's drawable (OSX) - Fix Bugs 569 and 599
Summary:
=========
The new FBObject based GLFBODrawable implementation allows the seamless utilization of
FBO offscreen rendering in single buffer, double buffer and MSAA mode.
The GLFBODrawable uses a parent drawable based on a
dummy surface to allow a GLOffscreenAutoDrawable.FBO creation
or a mutable surface supporting an existing offscreen layer surface (OSX CALayer).
Offscreen GLDrawable's and GLOffscreenAutoDrawable's can be selected via the
GLCapabilities. If simply !onscreen is selected in the caps instance w/o enabling FBO, PBuffer or Bitmap,
the factory will automatically choose regarding availability:
FBO > PBuffer > Bitmap
Double buffering is supported in MSAA more (intrinsic) and explicit in non MSAA.
It is preferred when delivering resources (texture id's or framebuffer names)
to a shared GLContext.
This is demonstrated in (emulates our OSX CALayer implementation):
TestFBOOffThreadSharedContextMix2DemosES2NEWT,
TestFBOOnThreadSharedContext1DemoES2NEWT
and with the OSX JAWT OffscreenLayerSurface itself. FBO is the preferred choice.
+++
Offscreen drawables can be resized while maintaining a bound GLContext (e.g. w/ GLAutoDrawable).
Previously both, drawable and context, needed to be destroyed and recreated at offscreen resize.
Common implementation in GLDrawableHelper is used in the implementations
(NEWT's GLWindow, AWT GLCanvas, SWT GLCanvas).
+++
Tested:
=======
Manually run all unit tests on:
- Linux x86_64 NVidia/AMD/Mesa3d(ES)
- OSX x86_64 NVidia
- Windows x86_64 NVidia
- Android arm Mali-400/Tegra-2
No regressions.
Disclaimer:
===========
This feature is committed almost in one patch.
Both previous commits were introducing / fixing the capabilities behavior:
90d45928186f2be99999461cfe45f76a783cc961
9036376b7806a5fc61590bf49404eb71830de92f
I have to appologize for the huge size and impact (files and platforms) of this commit
however, I could not find a better way to inject this feature in one sane piece.
NativeWindow Details:
=====================
Complete decoupling of platform impl. detail of surfaces
implementing ProxySurface. Used to generalize dummy surfaces and EGL surfaces
on top of a native platform surface.
- ProxySurface.UpstreamSurfaceHook -> UpstreamSurfaceHook
- abstract class ProxySurface -> interface ProxySurface + ProxySurfaceImpl
- Misc. implementations
JOGL Details:
=====================
FBOObject: API Change / Simplification & Usability
- Removed reference counter to remove complexity, allow user to choose.
- Add 'dispose' flag for detachColorbuffer(..), allowing to keep attachment alive
- Fix equals operation of Attachment
- Check pre-exising GL errors
- Interface Colobuffer gets lifecycle methods
- Add static factory methods to create Attachments w/o FBObject instance
- Reset:
- Clip min size to 1
- Keep alive samplingSink, i.e. don't issue resetMSAATexture2DSink(..).
It gets called at syncFramebuffer()/use(..) later on before actual usage.
This allows the consumer to utilize the GL_FRONT buffer until (e.g.) swap.
- misc bugfixes
GLOffscreenAutoDrawable: API Change
- Reloc and interfacing
- class com.jogamp.opengl.OffscreenAutoDrawable -> javax.media.opengl.*
interfaces GLOffscreenAutoDrawable extends GLAutoDrawable
GLOffscreenAutoDrawable.FBO extends GLOffscreenAutoDrawable, GLFBODrawable
- Added general implementation and FBO specialization
- Replacing GLPBuffer (deprecated) .. usable for any offscreen GLDrawable via factory
GLAutoDrawable:
- Add 'GLDrawable getDelegatedDrawable()'
- Refine documentation of setContext(..), remove disclaimer and fixme tags
GLDrawableFactory:
- Refine API doc and it's selection mechanism for offscreen.
- Add createOffscreenDrawable(..)
- Add createOffscreenAutoDrawable(..)
- Add canCreateFBO(..)
- Mark createGLPbuffer(..) deprectated
Mark GLPBuffer deprecated
New: GLFBODrawable extends GLDrawable
GLCanvas (AWT and SWT): Add offscreen resize support w/o GLContext recreation
GLAutoDrawableBase .. GLWindow:
- Add offscreen resize support w/o GLContext recreation
- Remove double swapBuffer call
-
GLBase/GLContext:
- Add:
- boolean hasBasicFBOSupport()
- boolean hasFullFBOSupport()
- int getMaxRenderbufferSamples()
- boolean isTextureFormatBGRA8888Available()
GLContext: Fix version detection and hasGLSL()
- Version detection in setGLFunctionAvailability(..)
- Query GL_VERSION ASAP and parse it and compare w/ given major/minor
- Use parsed version if valid and lower than given _or_ given is invalid.
- Use validated version for caching (procaddr, ..), version number, etc.
- Fix hasGLSL()
Since 'isGL2ES2()' is true if 'isGL2()'
and the latter simply alows GL 1.*, we confine the result to a GL >= 2.0
on desktops. FIXME: May consider GL 1.5 w/ extensions.
- return isGL2ES2();
+ return isGLES2() ||
+ isGL3() ||
+ isGL2() && ctxMajorVersion>1 ;
GLDrawableImpl:
- Add 'associateContext(GLContext, boolean)' allowing impl.
to have a (weak) reference list of bound context.
This is was pulled up from the OSX specific drawable impl.
- swapBuffersImpl() -> swapBuffersImpl(boolean doubleBuffered)
and call it regardless of single buffering.
This is required to propagate this event to impl. properly,
i.e. FBODrawable requires a swap notification.
- Clarify 'contextMadeCurrent(..)' protocol
GLDrawableHelper:
- Add resize and recreate offscreen drawable util method
- Simplify required init/reshape calls for GLEventListener
-
GLGraphicsConfigurationUtil:
- fixWinAttribBitsAndHwAccel: Reflect sharede context hw-accel bits
- OSX has no offscreen bitmap, use pbuffer
- use proper offscreen auto selection if offscreen and no modes are set
EGL Context/Drawable/DrawableFactory: Abstract native platform code out of base classes
- Use EGLWrappedSurface w/ UpstreamSurfaceHook to handle upstream (X11, WGL, ..)
lifecycle - in case the EGL resource is hooked up on it.
Invisible dummy surfaces: All platforms
- size is now reduced to 64x64 and decoupled of actual generic mutable size
- fix device lifecycle, no more leaks
+++
OSX
====
Enable support for GLFBODrawableImpl in offscreen CALayer mode
- NSOpenGLImpl: hooks to calayer native code
- calayer code:
- allows pbuffer and texures (FBO)
- decouple size and draw calls avoiding flickering
- enable auto resize of calayer tree
MacOSXCGLContext:
- NSOpenGLImpl:
- Fix false pbuffer 'usage', validate the pointer
- If !pbuffer, copy other window mode bits of caps
-
MacOSXCGLGraphicsConfiguration:
- Only assume pbuffer if !onscreen
- Remove reference of native pixelformat pointer
Native code:
- use 'respondsToSelector:' query before calling 'new' methods
avoiding an error message where unsuported (prev. OSX versions)
- if monitor refresh-rate is queried 0, set to default 60hz
- add missing NSAutoreleasePool decoration
+++
Android / NEWT:
===============
Issue setVisible(..) w/o wait, i.e. queue on EDT,
@Android surfaceChanged() callback. Otherwise we could deadlock:
setVisible(..) -> EDT -> setVisibleImpl(..) -> 'GL-display'.
the latter may may cause havoc while Android-EDT is blocked [until it's return].
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/macosx')
9 files changed, 529 insertions, 383 deletions
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 55aea3a98..ec29558d1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -49,6 +49,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.ProxySurface; +import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; @@ -58,6 +59,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLFBODrawableImpl; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -76,9 +78,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl boolean isNSContext(); long create(long share, int ctp, int major, int minor); boolean destroy(long ctx); + boolean contextRealized(boolean realized); boolean copyImpl(long src, int mask); boolean makeCurrent(long ctx); boolean release(long ctx); + boolean detachPBuffer(); boolean setSwapInterval(int interval); boolean swapBuffers(); } @@ -279,7 +283,24 @@ public abstract class MacOSXCGLContext extends GLContextImpl throw new GLException("Error destroying OpenGL Context: "+this); } } + + @Override + protected void contextRealized(boolean realized) { + // context stuff depends on drawable stuff + if(realized) { + super.contextRealized(true); // 1) init drawable stuff + impl.contextRealized(true); // 2) init context stuff + } else { + impl.contextRealized(false); // 1) free context stuff + super.contextRealized(false); // 2) free drawable stuff + } + } + + /* pp */ void detachPBuffer() { + impl.detachPBuffer(); + } + @Override protected void copyImpl(GLContext source, int mask) throws GLException { if( isNSContext() != ((MacOSXCGLContext)source).isNSContext() ) { @@ -365,16 +386,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl throw new GLException("Should not call this"); } - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - // Support for "mode switching" as described in MacOSXCGLDrawable public void setOpenGLMode(GLBackendType mode) { if (mode == openGLMode) { @@ -421,323 +432,486 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { - long nsOpenGLLayer = 0; - long nsOpenGLLayerPFmt = 0; - float screenVSyncTimeout; // microSec - int vsyncTimeout; // microSec - for nsOpenGLLayer mode - - @Override - public boolean isNSContext() { return true; } - - @Override - public long create(long share, int ctp, int major, int minor) { - long ctx = 0; - final long nsViewHandle; - if(drawable instanceof MacOSXCGLDrawable) { - // we allow null here! (special pbuffer case) - nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle(); - } else { - // we only allow a valid NSView here - final long aHandle = drawable.getHandle(); - if( OSXUtil.isNSView(aHandle) ) { - nsViewHandle = aHandle; - } else { - throw new RuntimeException("Anonymous drawable instance's handle not of type NSView: "+drawable.getClass().getName()+", "+drawable); - } - } - final NativeSurface surface = drawable.getNativeSurface(); - final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - - boolean allowIncompleteView = null != backingLayerHost; - if( !allowIncompleteView && surface instanceof ProxySurface ) { - allowIncompleteView = 0 != ( ProxySurface.INVISIBLE_WINDOW & ((ProxySurface)surface).getImplBitfield() ) ; - } - final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); - if (pixelFormat == 0) { - if(DEBUG) { - System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps); - } - return 0; - } - config.setChosenPixelFormat(pixelFormat); - int sRefreshRate = CGL.getScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex()); - screenVSyncTimeout = 1000000f / sRefreshRate; - if(DEBUG) { - System.err.println("NS create OSX>=lion "+isLionOrLater); - System.err.println("NS create allowIncompleteView: "+allowIncompleteView); - System.err.println("NS create backingLayerHost: "+backingLayerHost); - System.err.println("NS create share: "+share); - System.err.println("NS create chosenCaps: "+chosenCaps); - System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); - System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); - System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle)); - System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros"); - // Thread.dumpStack(); - } - try { - int[] viewNotReady = new int[1]; - // Try to allocate a context with this - ctx = CGL.createContext(share, - nsViewHandle, allowIncompleteView, - pixelFormat, - chosenCaps.isBackgroundOpaque(), - viewNotReady, 0); - if (0 == ctx) { - if(DEBUG) { - System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); - } - return 0; - } + private OffscreenLayerSurface backingLayerHost = null; + private long nsOpenGLLayer = 0; + private long nsOpenGLLayerPFmt = 0; + private float screenVSyncTimeout; // microSec + private int vsyncTimeout; // microSec - for nsOpenGLLayer mode + private int lastWidth=0, lastHeight=0; // allowing to detect size change + private long lastPBufferHandle = 0; // allowing to detect pbuffer recreation + + @Override + public boolean isNSContext() { return true; } + + @Override + public long create(long share, int ctp, int major, int minor) { + long ctx = 0; + final NativeSurface surface = drawable.getNativeSurface(); + final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration(); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final long nsViewHandle; + final boolean isPBuffer; + final boolean isFBO; + if(drawable instanceof GLFBODrawableImpl) { + nsViewHandle = 0; + isPBuffer = false; + isFBO = true; + if(DEBUG) { + System.err.println("NS create GLFBODrawableImpl drawable: isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } else if(drawable instanceof MacOSXCGLDrawable) { + // we allow null here! (special pbuffer case) + nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle(); + isPBuffer = CGL.isNSOpenGLPixelBuffer(drawable.getHandle()); + isFBO = false; + if(DEBUG) { + System.err.println("NS create MacOSXCGLDrawable drawable handle isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } else { + // we only allow a valid NSView here + final long drawableHandle = drawable.getHandle(); + final boolean isNSView = OSXUtil.isNSView(drawableHandle); + final boolean isNSWindow = OSXUtil.isNSWindow(drawableHandle); + isPBuffer = CGL.isNSOpenGLPixelBuffer(drawableHandle); + isFBO = false; - if (!chosenCaps.isPBuffer() && !chosenCaps.isBackgroundOpaque()) { - // Set the context opacity - CGL.setContextOpacity(ctx, 0); + if(DEBUG) { + System.err.println("NS create Anonymous drawable handle "+toHexString(drawableHandle)+": isNSView "+isNSView+", isNSWindow "+isNSWindow+", isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + if( isNSView ) { + nsViewHandle = drawableHandle; + } else if( isNSWindow ) { + nsViewHandle = OSXUtil.GetNSView(drawableHandle); + } else if( isPBuffer ) { + nsViewHandle = 0; + } else { + throw new RuntimeException("Anonymous drawable instance's handle neither NSView, NSWindow nor PBuffer: "+toHexString(drawableHandle)+", "+drawable.getClass().getName()+",\n\t"+drawable); + } } + backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + boolean allowIncompleteView = null != backingLayerHost; + if( !allowIncompleteView && surface instanceof ProxySurface ) { + allowIncompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); + } + long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); + if (pixelFormat == 0) { + if(DEBUG) { + System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps); + } + return 0; + } GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); - fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); - if(!fixedCaps.isPBuffer()) { + if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) { // not handled, so copy them fixedCaps.setFBO(chosenCaps.isFBO()); + fixedCaps.setPBuffer(chosenCaps.isPBuffer()); fixedCaps.setBitmap(chosenCaps.isBitmap()); fixedCaps.setOnscreen(chosenCaps.isOnscreen()); } - config.setChosenCapabilities(fixedCaps); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + int sRefreshRate = OSXUtil.GetScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex()); + screenVSyncTimeout = 1000000f / sRefreshRate; if(DEBUG) { + System.err.println("NS create OSX>=lion "+isLionOrLater); + System.err.println("NS create allowIncompleteView: "+allowIncompleteView); + System.err.println("NS create backingLayerHost: "+backingLayerHost); + System.err.println("NS create share: "+share); + System.err.println("NS create drawable type: "+drawable.getClass().getName()); + System.err.println("NS create drawable handle: isPBuffer "+isPBuffer+", isFBO "+isFBO); + System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); + System.err.println("NS create chosenCaps: "+chosenCaps); System.err.println("NS create fixedCaps: "+fixedCaps); + System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); + System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle)); + System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros"); + // Thread.dumpStack(); } if(fixedCaps.isPBuffer()) { - // Must now associate the pbuffer with our newly-created context - CGL.setContextPBuffer(ctx, drawable.getHandle()); + if(!isPBuffer) { + throw new InternalError("fixedCaps is PBuffer, handle not: "+drawable); + } + } else { + if(isPBuffer) { + throw new InternalError("handle is PBuffer, fixedCaps not: "+drawable); + } } - // - // handled layered surface - // + config.setChosenCapabilities(fixedCaps); + /** if(null != backingLayerHost) { - nsOpenGLLayerPFmt = pixelFormat; - pixelFormat = 0; - final int texWidth, texHeight; - if(drawable instanceof MacOSXPbufferCGLDrawable) { - final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; - texWidth = osxPDrawable.getTextureWidth(); - texHeight = osxPDrawable.getTextureHeight(); - } else { - texWidth = drawable.getWidth(); - texHeight = drawable.getHeight(); + backingLayerHost.setChosenCapabilities(fixedCaps); + } */ + + try { + int[] viewNotReady = new int[1]; + // Try to allocate a context with this + ctx = CGL.createContext(share, + nsViewHandle, allowIncompleteView, + pixelFormat, + chosenCaps.isBackgroundOpaque(), + viewNotReady, 0); + if (0 == ctx) { + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); + } + return 0; } - if(0>=texWidth || 0>=texHeight || !drawable.isRealized()) { - throw new GLException("Drawable not realized yet or invalid texture size, texSize "+texWidth+"x"+texHeight+", "+drawable); + + if(null != backingLayerHost) { + nsOpenGLLayerPFmt = pixelFormat; + pixelFormat = 0; } - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight); - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", texSize "+texWidth+"x"+texHeight+", "+drawable); + + if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { + // Set the context opacity + CGL.setContextOpacity(ctx, 0); + } + } finally { + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + pixelFormat = 0; } - backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); - setSwapInterval(1); // enabled per default in layered surface - } - } finally { - if(0!=pixelFormat) { - CGL.deletePixelFormat(pixelFormat); - } - } - return ctx; - } - - @Override - public boolean destroy(long ctx) { - if(0 != nsOpenGLLayer) { - final NativeSurface surface = drawable.getNativeSurface(); - if (DEBUG) { - System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)); - } - final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - if(null != ols && ols.isSurfaceLayerAttached()) { - // still having a valid OLS attached to surface (parent OLS could have been removed) - ols.detachSurfaceLayer(); } - CGL.releaseNSOpenGLLayer(nsOpenGLLayer); - CGL.deletePixelFormat(nsOpenGLLayerPFmt); - nsOpenGLLayerPFmt = 0; - nsOpenGLLayer = 0; + return ctx; } - return CGL.deleteContext(ctx, true); - } - - @Override - public boolean copyImpl(long src, int mask) { - CGL.copyContext(contextHandle, src, mask); - return true; - } - @Override - public boolean makeCurrent(long ctx) { - final long cglCtx = CGL.getCGLContext(ctx); - if(0 == cglCtx) { - throw new InternalError("Null CGLContext for: "+this); + @Override + public boolean destroy(long ctx) { + lastPBufferHandle = 0; + return CGL.deleteContext(ctx, true); } - int err = CGL.CGLLockContext(cglCtx); - if(CGL.kCGLNoError == err) { - return CGL.makeCurrentContext(ctx); - } else if(DEBUG) { - System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean contextRealized(boolean realized) { + if( realized ) { + if( null != backingLayerHost ) { + // + // handled layered surface + // + final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities(); + final long ctx = MacOSXCGLContext.this.getHandle(); + final int texID; + final long drawableHandle = drawable.getHandle(); + if(drawable instanceof GLFBODrawableImpl) { + final GLFBODrawableImpl fbod = (GLFBODrawableImpl)drawable; + texID = fbod.getTextureBuffer(GL.GL_FRONT).getName(); + fbod.setSwapBufferContext(new GLFBODrawableImpl.SwapBufferContext() { + public void swapBuffers(boolean doubleBuffered) { + MacOSXCGLContext.NSOpenGLImpl.this.swapBuffers(); + } } ) ; + lastPBufferHandle = 0; + } else if( chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) ) { + texID = 0; + lastPBufferHandle = drawableHandle; + } else { + throw new GLException("BackingLayerHost w/ unknown handle (!FBO, !PBuffer): "+drawable); + } + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + if(0>=lastWidth || 0>=lastHeight || !drawable.isRealized()) { + throw new GLException("Drawable not realized yet or invalid texture size, texSize "+lastWidth+"x"+lastHeight+", "+drawable); + } + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, lastPBufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(lastPBufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + setSwapInterval(1); // enabled per default in layered surface + } else { + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + } + } else { + if( 0 != nsOpenGLLayer ) { + final NativeSurface surface = drawable.getNativeSurface(); + if (DEBUG) { + System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable); + } + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + if(null != ols && ols.isSurfaceLayerAttached()) { + // still having a valid OLS attached to surface (parent OLS could have been removed) + ols.detachSurfaceLayer(); + } + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); + nsOpenGLLayer = 0; + } + if(0 != nsOpenGLLayerPFmt) { + CGL.deletePixelFormat(nsOpenGLLayerPFmt); + nsOpenGLLayerPFmt = 0; + } + lastPBufferHandle = 0; + } + backingLayerHost = null; + return true; } - return false; - } - @Override - public boolean release(long ctx) { - try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze - } catch (GLException gle) { - if(DEBUG) { - System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:"); - gle.printStackTrace(); + private final void validatePBufferConfig(long ctx) { + final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities(); + final long drawableHandle = drawable.getHandle(); + if(chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) && lastPBufferHandle != drawableHandle) { + // Must associate the pbuffer with our newly-created context + lastPBufferHandle = drawableHandle; + if(0 != drawableHandle) { + CGL.setContextPBuffer(ctx, drawableHandle); + } + if(DEBUG) { + System.err.println("NS.validateDrawableConfig bind pbuffer "+toHexString(drawableHandle)+" -> ctx "+toHexString(ctx)); + } } } - final boolean res = CGL.clearCurrentContext(ctx); - final long cglCtx = CGL.getCGLContext(ctx); - if(0 == cglCtx) { - throw new InternalError("Null CGLContext for: "+this); + + /** Returns true if size has been updated, otherwise false (same size). */ + private final boolean validateDrawableSizeConfig(long ctx) { + final int width = drawable.getWidth(); + final int height = drawable.getHeight(); + if( lastWidth != width || lastHeight != height ) { + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + if(DEBUG) { + System.err.println("NS.validateDrawableConfig size changed"); + } + return true; + } + return false; } - final int err = CGL.CGLUnlockContext(cglCtx); - if(DEBUG && CGL.kCGLNoError != err) { - System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean copyImpl(long src, int mask) { + CGL.copyContext(contextHandle, src, mask); + return true; } - return res && CGL.kCGLNoError == err; - } - @Override - public boolean setSwapInterval(int interval) { - if(0 != nsOpenGLLayer) { - CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); - vsyncTimeout = interval * (int)screenVSyncTimeout; - if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); } + @Override + public boolean makeCurrent(long ctx) { + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + int err = CGL.CGLLockContext(cglCtx); + if(CGL.kCGLNoError == err) { + validatePBufferConfig(ctx); // required to handle pbuffer change ASAP + return CGL.makeCurrentContext(ctx); + } else if(DEBUG) { + System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return false; + } + + @Override + public boolean release(long ctx) { + try { + gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + } catch (GLException gle) { + if(DEBUG) { + System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:"); + gle.printStackTrace(); + } + } + final boolean res = CGL.clearCurrentContext(ctx); + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + final int err = CGL.CGLUnlockContext(cglCtx); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return res && CGL.kCGLNoError == err; } - CGL.setSwapInterval(contextHandle, interval); - return true; - } - @Override - public boolean swapBuffers() { - if( 0 != nsOpenGLLayer ) { - // If v-sync is disabled, frames will be drawn as quickly as possible - // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync). - CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout); + @Override + public boolean detachPBuffer() { + if(0 != lastPBufferHandle) { + lastPBufferHandle = 0; + if(0 != nsOpenGLLayer) { + CGL.flushNSOpenGLLayerPBuffer(nsOpenGLLayer); // notify invalid pbuffer + } + // CGL.setContextPBuffer(contextHandle, 0); // doesn't work, i.e. not taking nil + } + return true; } - if(CGL.flushBuffer(contextHandle)) { + + @Override + public boolean setSwapInterval(int interval) { if(0 != nsOpenGLLayer) { - // trigger CALayer to update - CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer); + CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + vsyncTimeout = interval * (int)screenVSyncTimeout + 1000; // +1ms + if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); } } + CGL.setSwapInterval(contextHandle, interval); return true; } - return false; - } + + private int skipSync=0; + + @Override + public boolean swapBuffers() { + final boolean res; + if( 0 != nsOpenGLLayer ) { + if( validateDrawableSizeConfig(contextHandle) ) { + // skip wait-for-vsync for a few frames if size has changed, + // allowing to update the texture IDs ASAP. + skipSync = 10; + } + + final int texID; + final boolean valid; + if(drawable instanceof GLFBODrawableImpl) { + texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName(); + valid = 0 != texID; + } else { + texID = 0; + valid = 0 != lastPBufferHandle; + } + if(valid) { + if(0 == skipSync) { + // If v-sync is disabled, frames will be drawn as quickly as possible + // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync). + CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout); + } else { + skipSync--; + } + res = CGL.flushBuffer(contextHandle); + if(res) { + // trigger CALayer to update incl. possible surface change + CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer, lastPBufferHandle, texID, lastWidth, lastHeight); + } + } else { + res = true; + } + } else { + res = CGL.flushBuffer(contextHandle); + } + return res; + } + } class CGLImpl implements GLBackendImpl { - @Override - public boolean isNSContext() { return false; } - - @Override - public long create(long share, int ctp, int major, int minor) { - long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor); - if (pixelFormat == 0) { - throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); - } - config.setChosenPixelFormat(pixelFormat); - try { - // Create new context - PointerBuffer ctxPB = PointerBuffer.allocateDirect(1); - if (DEBUG) { - System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share)); + @Override + public boolean isNSContext() { return false; } + + @Override + public long create(long share, int ctp, int major, int minor) { + long ctx = 0; + MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor); + if (pixelFormat == 0) { + throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } - int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB); - 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(ctxPB.get(0), drawable.getHandle(), 0, 0, 0); + try { + // Create new context + PointerBuffer ctxPB = PointerBuffer.allocateDirect(1); + if (DEBUG) { + System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share)); + } + int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB); if (res != CGL.kCGLNoError) { - throw new GLException("Error code " + res + " while attaching context to pbuffer"); + throw new GLException("Error code " + res + " while creating context"); } - } - ctx = ctxPB.get(0); - if(0!=ctx) { - if(DEBUG) { - GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat); - System.err.println("NS created: "+caps0); + ctx = ctxPB.get(0); + + if (0 != ctx) { + GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) { + // not handled, so copy them + fixedCaps.setFBO(chosenCaps.isFBO()); + fixedCaps.setPBuffer(chosenCaps.isPBuffer()); + fixedCaps.setBitmap(chosenCaps.isBitmap()); + fixedCaps.setOnscreen(chosenCaps.isOnscreen()); + } + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("CGL create fixedCaps: "+fixedCaps); + } + if(fixedCaps.isPBuffer()) { + // Must now associate the pbuffer with our newly-created context + res = CGL.CGLSetPBuffer(ctx, drawable.getHandle(), 0, 0, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while attaching context to pbuffer"); + } + } } + } finally { + CGL.CGLDestroyPixelFormat(pixelFormat); } - } finally { - CGL.CGLDestroyPixelFormat(pixelFormat); + return ctx; } - return ctx; - } - @Override - public boolean destroy(long ctx) { - return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError; - } + @Override + public boolean destroy(long ctx) { + return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError; + } - @Override - public boolean copyImpl(long src, int mask) { - CGL.CGLCopyContext(src, contextHandle, mask); - return true; - } + @Override + public boolean contextRealized(boolean realized) { + return true; + } + + @Override + public boolean copyImpl(long src, int mask) { + CGL.CGLCopyContext(src, contextHandle, mask); + return true; + } - @Override - public boolean makeCurrent(long ctx) { - int err = CGL.CGLLockContext(ctx); - if(CGL.kCGLNoError == err) { - err = CGL.CGLSetCurrentContext(ctx); + @Override + public boolean makeCurrent(long ctx) { + int err = CGL.CGLLockContext(ctx); if(CGL.kCGLNoError == err) { - return true; + err = CGL.CGLSetCurrentContext(ctx); + if(CGL.kCGLNoError == err) { + return true; + } else if(DEBUG) { + System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this); + } } else if(DEBUG) { - System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this); + System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); } - } else if(DEBUG) { - System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + return false; } - return false; - } - @Override - public boolean release(long ctx) { - try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze - } catch (GLException gle) { - if(DEBUG) { - System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:"); - gle.printStackTrace(); + @Override + public boolean release(long ctx) { + try { + gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + } catch (GLException gle) { + if(DEBUG) { + System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:"); + gle.printStackTrace(); + } } + int err = CGL.CGLSetCurrentContext(0); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this); + } + int err2 = CGL.CGLUnlockContext(ctx); + if(DEBUG && CGL.kCGLNoError != err2) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this); + } + return CGL.kCGLNoError == err && CGL.kCGLNoError == err2; + } + + @Override + public boolean detachPBuffer() { + /* Doesn't work, i.e. not taking NULL + final int res = CGL.CGLSetPBuffer(contextHandle, 0, 0, 0, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while detaching context from pbuffer"); + } */ + return true; } - int err = CGL.CGLSetCurrentContext(0); - if(DEBUG && CGL.kCGLNoError != err) { - System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean setSwapInterval(int interval) { + int[] lval = new int[] { interval } ; + CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); + return true; } - int err2 = CGL.CGLUnlockContext(ctx); - if(DEBUG && CGL.kCGLNoError != err2) { - System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this); + @Override + public boolean swapBuffers() { + return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); } - return CGL.kCGLNoError == err && CGL.kCGLNoError == err2; - } - - @Override - public boolean setSwapInterval(int interval) { - int[] lval = new int[] { interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - return true; - } - @Override - public boolean swapBuffers() { - return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); - } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index af767f0c3..cc727c8e1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -42,10 +42,10 @@ package jogamp.opengl.macosx.cgl; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -92,7 +92,7 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { this.id = id; } } - private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); + /* pp */ List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); private boolean haveSetOpenGLMode = false; private GLBackendType openGLMode = GLBackendType.NSOPENGL; @@ -110,26 +110,42 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { return GLBackendType.NSOPENGL == openGLMode ? getHandle() : 0; } - protected void registerContext(MacOSXCGLContext ctx) { + @Override + protected void associateContext(GLContext ctx, boolean bound) { // NOTE: we need to keep track of the created contexts in order to // implement swapBuffers() because of how Mac OS X implements its // OpenGL window interface synchronized (createdContexts) { - createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); - } + if(bound) { + createdContexts.add(new WeakReference<MacOSXCGLContext>((MacOSXCGLContext)ctx)); + } else { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext _ctx = ref.get(); + if( _ctx == null || _ctx == ctx) { + createdContexts.remove(i); + } else { + i++; + } + } + } + } } + @Override - protected final void swapBuffersImpl() { - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - synchronized (createdContexts) { - for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { - WeakReference<MacOSXCGLContext> ref = iter.next(); - MacOSXCGLContext ctx = ref.get(); - if (ctx != null) { - ctx.swapBuffers(); - } else { - iter.remove(); - } + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + synchronized (createdContexts) { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.swapBuffers(); + i++; + } else { + createdContexts.remove(i); + } + } } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 591fafc68..e174d38f4 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -51,7 +51,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; @@ -61,7 +61,8 @@ import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.macosx.OSXDummyUpstreamSurfaceHook; import jogamp.opengl.DesktopGLDynamicLookupHelper; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -71,7 +72,7 @@ import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.nativewindow.WrappedSurface; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.opengl.GLExtensions; @@ -320,9 +321,14 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) { - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration(); + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!caps.isPBuffer()) { + // Actual implementation is using PBuffer ... + final GLCapabilities modCaps = (GLCapabilities) caps.cloneMutable(); + modCaps.setPBuffer(true); + modCaps.setBitmap(false); + config.setChosenCapabilities(modCaps); return new MacOSXOffscreenCGLDrawable(this, target); } return new MacOSXPbufferCGLDrawable(this, target); @@ -336,7 +342,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final MacOSXGraphicsDevice device; if(createNewDevice) { device = new MacOSXGraphicsDevice(deviceReq.getUnitID()); @@ -348,68 +354,23 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface(config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, createNewDevice); } @Override public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps); - return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, + new OSXDummyUpstreamSurfaceHook(width, height)); } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - long nsWindow = 0; - @Override - public final void create(ProxySurface s) { - if(0 == nsWindow && 0 == s.getSurfaceHandle()) { - nsWindow = OSXUtil.CreateNSWindow(0, 0, s.getWidth(), s.getHeight()); - if(0 == nsWindow) { - throw new GLException("Error NS window 0"); - } - long nsView = OSXUtil.GetNSView(nsWindow); - if(0 == nsView) { - throw new GLException("Error NS view 0"); - } - s.setSurfaceHandle(nsView); - s.setImplBitfield(ProxySurface.INVISIBLE_WINDOW); - if(DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final void destroy(ProxySurface s) { - if(0 != nsWindow && 0 != s.getSurfaceHandle()) { - OSXUtil.DestroyNSWindow(nsWindow); - nsWindow = 0; - s.setSurfaceHandle(0); - if(DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.destroy: "+s); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - - @Override - public String toString() { - return "MacOSXLSurfaceLifecycleHook[]"; - } - - }; @Override protected ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { final MacOSXGraphicsDevice device = new MacOSXGraphicsDevice(deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final MacOSXCGLGraphicsConfiguration config = MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, true); - return new WrappedSurface(config, windowHandle, 0, 0, upstream); + return new WrappedSurface(config, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java index 149927160..8866c7ce6 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java @@ -51,23 +51,16 @@ import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.MutableGraphicsConfiguration; public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { - long pixelformat; MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen, - GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - long pixelformat) { + GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested) { super(screen, capsChosen, capsRequested); - this.pixelformat=pixelformat; } public Object clone() { return super.clone(); } - void setChosenPixelFormat(long pixelformat) { - this.pixelformat=pixelformat; - } - protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) { MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device); if(null == sharedResource) { @@ -114,11 +107,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration break; case CGL.kCGLPFAColorFloat: - ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0; + ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() && caps.getPbufferFloatingPointBuffers() ) ? 1 : 0; break; case CGL.NSOpenGLPFAPixelBuffer: - ivalues[idx] = caps.isPBuffer() ? 1 : 0; + ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() ) ? 1 : 0; break; case CGL.NSOpenGLPFADoubleBuffer: @@ -188,11 +181,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration attrs[i++] = CGL.kCGLPFAOpenGLProfile; attrs[i++] = MacOSXCGLContext.GLProfile2CGLOGLProfileValue(ctp, major, minor); } - if(caps.isPBuffer()) { + if(!caps.isOnscreen() && caps.isPBuffer()) { attrs[i++] = CGL.kCGLPFAPBuffer; - } - if (caps.getPbufferFloatingPointBuffers()) { - attrs[i++] = CGL.kCGLPFAColorFloat; + if (caps.getPbufferFloatingPointBuffers()) { + attrs[i++] = CGL.kCGLPFAColorFloat; + } } if (caps.getDoubleBuffered()) { attrs[i++] = CGL.kCGLPFADoubleBuffer; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java index 13faf7090..43a9d0d1a 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java @@ -96,6 +96,6 @@ public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurati capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(device, capsChosen.getGLProfile()), factory.canCreateGLPbuffer(device) ); - return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, 0); + return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java index 6be9e386d..65ed5fc15 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java @@ -49,8 +49,8 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; -import com.jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLContextShareSet; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -62,7 +62,6 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) { super(drawable, null); setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL ); - drawable.registerContext(this); this.contextHandle = handle; GLContextShareSet.contextCreated(this); setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT); @@ -108,13 +107,13 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { } AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX); - MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps, pixelFormat); + MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps); if(0 == currentDrawable) { // set a fake marker stating a valid drawable currentDrawable = 1; } - WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, null); + WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, true); return new MacOSXExternalCGLContext(new Drawable(factory, ns), isNSContext, contextHandle); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java index b1e283ebc..ec9628004 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java @@ -52,9 +52,7 @@ public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable { @Override public GLContext createContext(GLContext shareWith) { - final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); - registerContext(ctx); - return ctx; + return new MacOSXOnscreenCGLContext(this, shareWith); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java index 88886ddd2..7e2d8cf10 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java @@ -39,6 +39,7 @@ import javax.media.opengl.GLPbuffer; import jogamp.opengl.GLContextImpl; +@SuppressWarnings("deprecation") public class MacOSXPbufferCGLContext extends MacOSXCGLContext { // State for render-to-texture and render-to-texture-rectangle support diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index 8f2f386af..668e463a2 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -40,6 +40,8 @@ package jogamp.opengl.macosx.cgl; +import java.lang.ref.WeakReference; + import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.MutableSurface; @@ -70,9 +72,6 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV // private int texture; // actual texture object - // Note that we can not store this in the NativeSurface because the - // semantic is that contains an NSView - protected long pBuffer; protected int pBufferTexTarget, pBufferTexWidth, pBufferTexHeight; public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target) { @@ -90,9 +89,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { @Override public GLContext createContext(GLContext shareWith) { - final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith); - registerContext(ctx); - return ctx; + return new MacOSXPbufferCGLContext(this, shareWith); } @Override @@ -101,27 +98,34 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { return 0; } - @Override - public long getHandle() { - return pBuffer; - } - protected int getTextureTarget() { return pBufferTexTarget; } protected int getTextureWidth() { return pBufferTexWidth; } protected int getTextureHeight() { return pBufferTexHeight; } protected void destroyPbuffer() { - if (this.pBuffer != 0) { - NativeSurface ns = getNativeSurface(); + final MutableSurface ms = (MutableSurface) getNativeSurface(); + final long pBuffer = ms.getSurfaceHandle(); + if (0 != pBuffer) { + synchronized (createdContexts) { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.detachPBuffer(); + i++; + } else { + createdContexts.remove(i); + } + } + } impl.destroy(pBuffer); - this.pBuffer = 0; - ((MutableSurface)ns).setSurfaceHandle(0); + ms.setSurfaceHandle(0); } } private void createPbuffer() { - final NativeSurface ns = getNativeSurface(); - final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration(); + final MutableSurface ms = (MutableSurface) getNativeSurface(); + final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ms.getGraphicsConfiguration(); final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); final GLProfile glProfile = capabilities.getGLProfile(); MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice()); @@ -161,7 +165,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } } - pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); + final long pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); if(DEBUG) { System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+ ", pbufferSize "+getWidth()+"x"+getHeight()+ @@ -174,7 +178,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } - ((MutableSurface)ns).setSurfaceHandle(pBuffer); + ms.setSurfaceHandle(pBuffer); } @Override |