diff options
Diffstat (limited to 'src/jogl')
17 files changed, 701 insertions, 395 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java index 206331ac0..0f0f03ac4 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java +++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java @@ -51,12 +51,12 @@ import jogamp.opengl.GLDrawableImpl; * utilizing already created {@link GLDrawable} and {@link GLContext} instances. * <p> * Since no native windowing system events are being processed, it is recommended - * to handle at least: + * to handle at least the {@link com.jogamp.newt.event.WindowEvent window events}: * <ul> * <li>{@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint} using {@link #windowRepaintOp()}</li> * <li>{@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize} using {@link #windowResizedOp()}</li> - * <li>{@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} using {@link #windowDestroyNotifyOp()}</li> - * </ul> + * </ul> + * and setup a {@link com.jogamp.newt.Window#setWindowDestroyNotifyAction(Runnable) custom toolkit destruction} issuing {@link #windowDestroyNotifyOp()}. * </p> * <p> * See example {@link com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT TestGLAutoDrawableDelegateNEWT}. diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java index 9a13ff904..715511d1b 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java +++ b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java @@ -73,12 +73,20 @@ public class GLRendererQuirks { */ public static final int GLNonCompliant = 6; + /** + * The OpenGL Context needs a <code>glFlush()</code> before releasing it, otherwise driver may freeze: + * <ul> + * <li>OSX < 10.7.3 - NVidia Driver. Bug 533 and Bug 548 @ https://jogamp.org/bugzilla/.</li> + * </ul> + */ + public static final int GLFlushBeforeRelease = 7; + /** Number of quirks known. */ - public static final int COUNT = 7; + public static final int COUNT = 8; private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval", "NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard", - "GLNonCompliant" + "GLNonCompliant", "GLFlushBeforeRelease" }; private final int _bitmask; diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index 53a99b640..aa0e70132 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -537,7 +537,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { remaining -= System.currentTimeMillis() - t1 ; nok = waitCondition.eval(); } - if(DEBUG || nok) { + if(DEBUG || blocking && nok) { // Info only if DEBUG or ( blocking && not-ok ) ; !blocking possible if AWT if( remaining<=0 && nok ) { System.err.println("finishLifecycleAction(" + waitCondition.getClass().getName() + "): ++++++ timeout reached ++++++ " + Thread.currentThread().getName()); } diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 4817add4d..c31b76401 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -442,7 +442,7 @@ public abstract class GLContext { * new GLContext implementations; not for use by end users. */ protected static void setCurrent(GLContext cur) { - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { if(null == cur) { System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - NULL"); } else { diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java index f916ab8b1..25bba1725 100644 --- a/src/jogl/classes/javax/media/opengl/GLProfile.java +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -543,8 +543,20 @@ public class GLProfile { * </ul> * */ - public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2 }; + public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2 }; + /** + * Order of maximum programmable shader <i>core only</i> profiles + * + * <ul> + * <li> GL4 + * <li> GL3 + * <li> GLES2 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER_CORE = new String[] { GL4, GL3, GLES2 }; + /** Returns a default GLProfile object, reflecting the best for the running platform. * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL} * and favors hardware acceleration. @@ -659,6 +671,29 @@ public class GLProfile { return get(GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer); } + /** + * Returns the highest profile, implementing the programmable shader <i>core</i> pipeline <i>only</i>. + * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER_CORE} + * + * @throws GLException if no programmable core profile is available for the device. + * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE + */ + public static GLProfile getMaxProgrammableCore(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer); + } + + /** Uses the default device + * @throws GLException if no programmable core profile is available for the default device. + * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE + */ + public static GLProfile getMaxProgrammableCore(boolean favorHardwareRasterizer) + throws GLException + { + return get(GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer); + } + /** * Returns the GL2ES1 profile implementation, hence compatible w/ GL2ES1.<br/> * It returns: diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 2de86b545..94e123b3e 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -174,9 +174,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing new AWTWindowClosingProtocol(this, new Runnable() { @Override public void run() { - GLCanvas.this.destroy(); + GLCanvas.this.destroyImpl( true ); } - }); + }, null); /** Creates a new GLCanvas component with a default set of OpenGL capabilities, using the default OpenGL capabilities selection @@ -312,6 +312,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing * all platforms since the peer hasn't been created. */ final GraphicsConfiguration gc = super.getGraphicsConfiguration(); + + if( Beans.isDesignTime() ) { + return gc; + } + /* * chosen is only non-null on platforms where the GLDrawableFactory * returns a non-null GraphicsConfiguration (in the GLCanvas @@ -370,10 +375,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing */ chosen = compatible; - awtConfig = config; - if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) { - dispose(true); + // complete destruction! + destroyImpl( true ); + // recreation! + awtConfig = config; + createDrawableAndContext( true ); + validateGLDrawable(); + } else { + awtConfig = config; } } } @@ -447,26 +457,33 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } return; // not yet available .. } - Threading.invoke(true, displayOnEDTAction, getTreeLock()); - awtWindowClosingProtocol.addClosingListenerOneShot(); - } - - private void dispose(boolean regenerate) { - disposeRegenerate=regenerate; - Threading.invoke(true, disposeOnEDTAction, getTreeLock()); + if( isVisible() ) { + Threading.invoke(true, displayOnEDTAction, getTreeLock()); + } } /** * {@inheritDoc} * * <p> - * This impl. calls this class's {@link #removeNotify()} AWT override, - * where the actual implementation resides. + * This impl. only destroys all GL related resources. + * </p> + * <p> + * This impl. does not remove the GLCanvas from it's parent AWT container + * so this class's {@link #removeNotify()} AWT override won't get called. + * To do so, remove this component from it's parent AWT container. * </p> */ @Override public void destroy() { - removeNotify(); + destroyImpl( false ); + } + + protected void destroyImpl(boolean destroyJAWTWindowAndAWTDevice) { + Threading.invoke(true, destroyOnEDTAction, getTreeLock()); + if( destroyJAWTWindowAndAWTDevice ) { + AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, disposeJAWTWindowAndAWTDeviceOnEDT); + } } /** Overridden to cause OpenGL rendering to be performed during @@ -476,7 +493,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing */ @Override public void paint(Graphics g) { - if (Beans.isDesignTime()) { + if( Beans.isDesignTime() ) { // Make GLCanvas behave better in NetBeans GUI builder g.setColor(Color.BLACK); g.fillRect(0, 0, getWidth(), getHeight()); @@ -494,9 +511,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing g.drawString(name, (int) ((getWidth() - bounds.getWidth()) / 2), (int) ((getHeight() + bounds.getHeight()) / 2)); - return; - } - if( ! this.helper.isAnimatorAnimatingOnOtherThread() ) { + } else if( !this.helper.isAnimatorAnimatingOnOtherThread() ) { display(); } } @@ -513,42 +528,47 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing public void addNotify() { final RecursiveLock _lock = lock; _lock.lock(); - try { + try { + final boolean isBeansDesignTime = Beans.isDesignTime(); + if(DEBUG) { - System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()); + System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()+", isBeansDesignTime "+isBeansDesignTime); Thread.dumpStack(); } - /** - * 'super.addNotify()' determines the GraphicsConfiguration, - * while calling this class's overriden 'getGraphicsConfiguration()' method - * after which it creates the native peer. - * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration - * is being used in getGraphicsConfiguration(). - * This code order also allows recreation, ie re-adding the GLCanvas. - */ - awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device); - if(null==awtConfig) { - throw new GLException("Error: NULL AWTGraphicsConfiguration"); - } - - // before native peer is valid: X11 - disableBackgroundErase(); - - // issues getGraphicsConfiguration() and creates the native peer - super.addNotify(); - - // after native peer is valid: Windows - disableBackgroundErase(); - - if (!Beans.isDesignTime()) { - createDrawableAndContext(); + if( isBeansDesignTime ) { + super.addNotify(); + } else { + /** + * 'super.addNotify()' determines the GraphicsConfiguration, + * while calling this class's overriden 'getGraphicsConfiguration()' method + * after which it creates the native peer. + * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration + * is being used in getGraphicsConfiguration(). + * This code order also allows recreation, ie re-adding the GLCanvas. + */ + awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device); + if(null==awtConfig) { + throw new GLException("Error: NULL AWTGraphicsConfiguration"); + } + + // before native peer is valid: X11 + disableBackgroundErase(); + + // issues getGraphicsConfiguration() and creates the native peer + super.addNotify(); + + // after native peer is valid: Windows + disableBackgroundErase(); + + createDrawableAndContext( true ); + + // init drawable by paint/display makes the init sequence more equal + // for all launch flavors (applet/javaws/..) + // validateGLDrawable(); } - - // init drawable by paint/display makes the init sequence more equal - // for all launch flavors (applet/javaws/..) - // validateGLDrawable(); - + awtWindowClosingProtocol.addClosingListener(); + if(DEBUG) { System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer()); } @@ -557,27 +577,33 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } - private void createDrawableAndContext() { - // no lock required, since this resource ain't available yet - jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); - jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); - jawtWindow.lockSurface(); - try { - drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow); - context = (GLContextImpl) drawable.createContext(shareWith); - context.setContextCreationFlags(additionalCtxCreationFlags); - } finally { - jawtWindow.unlockSurface(); + private void createDrawableAndContext(boolean createJAWTWindow) { + if ( !Beans.isDesignTime() ) { + if( createJAWTWindow ) { + jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); + jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); + } + jawtWindow.lockSurface(); + try { + drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setContextCreationFlags(additionalCtxCreationFlags); + } finally { + jawtWindow.unlockSurface(); + } } - } + } private boolean validateGLDrawable() { + if( Beans.isDesignTime() || !isDisplayable() ) { + return false; // early out! + } final GLDrawable _drawable = drawable; if ( null != _drawable ) { if( _drawable.isRealized() ) { return true; } - if( Beans.isDesignTime() || !isDisplayable() || 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { + if( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { return false; // early out! } // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! @@ -627,11 +653,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing awtWindowClosingProtocol.removeClosingListener(); - if (Beans.isDesignTime()) { + if( Beans.isDesignTime() ) { super.removeNotify(); } else { try { - dispose(false); + destroyImpl( true ); } finally { super.removeNotify(); } @@ -676,6 +702,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock + if(null != jawtWindow && jawtWindow.isOffscreenLayerSurfaceEnabled() ) { + jawtWindow.layoutSurfaceLayer(); + } } } } @@ -790,7 +819,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public GL getGL() { - if (Beans.isDesignTime()) { + if( Beans.isDesignTime() ) { return null; } final GLContext _context = context; @@ -844,18 +873,18 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public GLCapabilitiesImmutable getChosenGLCapabilities() { - if (awtConfig == null) { + if( Beans.isDesignTime() ) { + return capsReqUser; + } else if( null == awtConfig ) { throw new GLException("No AWTGraphicsConfiguration: "+this); } - return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(); } public GLCapabilitiesImmutable getRequestedGLCapabilities() { - if (awtConfig == null) { + if( null == awtConfig ) { return capsReqUser; } - return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(); } @@ -897,8 +926,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // Internals only below this point // - private boolean disposeRegenerate; - private final Runnable disposeOnEDTAction = new Runnable() { + private final Runnable destroyOnEDTAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; @@ -907,11 +935,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing final GLAnimatorControl animator = getAnimator(); if(DEBUG) { - System.err.println(getThreadName()+": Info: dispose("+disposeRegenerate+") - START, hasContext " + + System.err.println(getThreadName()+": Info: destroyOnEDTAction() - START, hasContext " + (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator); Thread.dumpStack(); } - + final boolean animatorPaused; if(null!=animator) { // can't remove us from animator for recreational addNotify() @@ -926,50 +954,29 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // so we can continue with the destruction. try { helper.disposeGL(GLCanvas.this, context, true); + if(DEBUG) { + System.err.println(getThreadName()+": destroyOnEDTAction() - post ctx: "+context); + } } catch (GLException gle) { gle.printStackTrace(); } - } - context=null; + } + context = null; } if( null != drawable ) { drawable.setRealized(false); if(DEBUG) { - System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - 1: "+drawable); + System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable); } - drawable=null; + drawable = null; } - if( null != jawtWindow ) { - jawtWindow.destroy(); - if(DEBUG) { - System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - 2: "+jawtWindow); - } - jawtWindow=null; - } - - if(disposeRegenerate) { - // Similar process as in addNotify()! - - // Recreate GLDrawable/GLContext to reflect it's new graphics configuration - createDrawableAndContext(); - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas.dispose(true): new drawable: "+drawable); - } - validateGLDrawable(); // immediate attempt to recreate the drawable - } else { - if(null != awtConfig) { - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, disposeAbstractGraphicsDeviceActionOnEDT); - } - awtConfig=null; - } - if(animatorPaused) { animator.resume(); } if(DEBUG) { - System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - END, animator "+animator); + System.err.println(getThreadName()+": dispose() - END, animator "+animator); } } finally { @@ -979,28 +986,43 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing }; /** - * Disposes the AbstractGraphicsDevice within EDT, + * Disposes the JAWTWindow and AbstractGraphicsDevice within EDT, * since resources created (X11: Display), must be destroyed in the same thread, where they have been created. + * <p> + * The drawable and context handle are null'ed as well, assuming {@link #destroy()} has been called already. + * </p> * * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice) */ - private final Runnable disposeAbstractGraphicsDeviceActionOnEDT = new Runnable() { + private final Runnable disposeJAWTWindowAndAWTDeviceOnEDT = new Runnable() { @Override public void run() { - if(null != awtConfig) { - final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration(); - final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); - final String adeviceMsg; - if(DEBUG) { - adeviceMsg = adevice.toString(); - } else { - adeviceMsg = null; - } - boolean closed = adevice.close(); - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); - } - } + context=null; + drawable=null; + + if( null != jawtWindow ) { + jawtWindow.destroy(); + if(DEBUG) { + System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow); + } + jawtWindow=null; + } + + if(null != awtConfig) { + final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration(); + final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + final String adeviceMsg; + if(DEBUG) { + adeviceMsg = adevice.toString(); + } else { + adeviceMsg = null; + } + boolean closed = adevice.close(); + if(DEBUG) { + System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed); + } + } + awtConfig=null; } }; @@ -1139,14 +1161,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing * @param device * @return the chosen AWTGraphicsConfiguration * - * @see #disposeAbstractGraphicsDeviceActionOnEDT + * @see #disposeJAWTWindowAndAWTDeviceOnEDT */ private AWTGraphicsConfiguration chooseGraphicsConfiguration(final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final GraphicsDevice device) { // Make GLCanvas behave better in NetBeans GUI builder - if (Beans.isDesignTime()) { + if( Beans.isDesignTime() ) { return null; } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 664edb996..6c28c75ab 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -152,9 +152,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Used by all backends either directly or indirectly to hook up callbacks private Updater updater = new Updater(); - // Indicates whether the Java 2D OpenGL pipeline is enabled - private boolean oglPipelineEnabled = - Java2D.isOGLPipelineActive() && + // Indicates whether the Java 2D OpenGL pipeline is enabled and resource-compatible + private boolean oglPipelineUsable = + Java2D.isOGLPipelineResourceCompatible() && !Debug.isPropertyDefined("jogl.gljpanel.noogl", true); // For handling reshape events lazily @@ -174,13 +174,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing public void run() { GLJPanel.this.destroy(); } - }); + }, null); static { // Force eager initialization of part of the Java2D class since // otherwise it's likely it will try to be initialized while on // the Queue Flusher Thread, which is not allowed - if (Java2D.isOGLPipelineActive() && Java2D.isFBOEnabled()) { + if (Java2D.isOGLPipelineResourceCompatible() && Java2D.isFBOEnabled()) { Java2D.getShareContext(GraphicsEnvironment. getLocalGraphicsEnvironment(). getDefaultScreenDevice()); @@ -250,17 +250,19 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public void display() { - if (EventQueue.isDispatchThread()) { - // Want display() to be synchronous, so call paintImmediately() - paintImmediately(0, 0, getWidth(), getHeight()); - } else { - // Multithreaded redrawing of Swing components is not allowed, - // so do everything on the event dispatch thread - try { - EventQueue.invokeAndWait(paintImmediatelyAction); - } catch (Exception e) { - throw new GLException(e); - } + if( isVisible() ) { + if (EventQueue.isDispatchThread()) { + // Want display() to be synchronous, so call paintImmediately() + paintImmediately(0, 0, getWidth(), getHeight()); + } else { + // Multithreaded redrawing of Swing components is not allowed, + // so do everything on the event dispatch thread + try { + EventQueue.invokeAndWait(paintImmediatelyAction); + } catch (Exception e) { + throw new GLException(e); + } + } } } @@ -350,9 +352,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing sendReshape = handleReshape(); } - updater.setGraphics(g); - - backend.doPaintComponent(g); + if( isVisible() ) { + updater.setGraphics(g); + + backend.doPaintComponent(g); + } } @@ -365,6 +369,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public void addNotify() { super.addNotify(); + awtWindowClosingProtocol.addClosingListener(); if (DEBUG) { System.err.println(getThreadName()+": GLJPanel.addNotify()"); } @@ -608,7 +613,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing to perform OpenGL rendering using the GLJPanel into the same OpenGL drawable as the Swing implementation uses. */ public boolean shouldPreserveColorBufferIfTranslucent() { - return oglPipelineEnabled; + return oglPipelineUsable; } @Override @@ -662,7 +667,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } if ( null == backend ) { - if (oglPipelineEnabled) { + if (oglPipelineUsable) { backend = new J2DOGLBackend(); } else { backend = new OffscreenBackend(); @@ -673,8 +678,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (!isInitialized) { backend.initialize(); } - - awtWindowClosingProtocol.addClosingListenerOneShot(); } @Override @@ -1560,7 +1563,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } isInitialized = false; backend = null; - oglPipelineEnabled = false; + oglPipelineUsable = false; handleReshape = true; j2dContext.destroy(); j2dContext = null; diff --git a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java index 27569d210..b74ac9f41 100644 --- a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java +++ b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java @@ -103,6 +103,7 @@ public class FPSCounterImpl implements FPSCounter { fpsLastPeriod = 0; fpsTotalFrames = 0; fpsLast = 0f; fpsTotal = 0f; + fpsLastPeriod = 0; fpsTotalDuration=0; } public final synchronized int getUpdateFPSFrames() { diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index b17fce569..42364dbfd 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -278,14 +278,14 @@ public abstract class GLContextImpl extends GLContext { release(false); } private void release(boolean inDestruction) throws GLException { - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[release.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock); } if ( !lock.isOwner(Thread.currentThread()) ) { final String msg = getThreadName() +": Context not current on current thread, obj " + toHexString(hashCode())+", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock; if( DEBUG_TRACE_SWITCH ) { System.err.println(msg); - if( null != lastCtxReleaseStack) { + if( null != lastCtxReleaseStack ) { System.err.print("Last release call: "); lastCtxReleaseStack.printStackTrace(); } else { @@ -318,7 +318,7 @@ public abstract class GLContextImpl extends GLContext { if( DEBUG_TRACE_SWITCH ) { final String msg = getThreadName() +": GLContext.ContextSwitch[release.X]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+(actualRelease?"switch":"keep ")+" - "+lock; lastCtxReleaseStack = new Throwable(msg); - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { System.err.println(msg); // Thread.dumpStack(); } @@ -334,7 +334,7 @@ public abstract class GLContextImpl extends GLContext { @Override public final void destroy() { - if (DEBUG_TRACE_SWITCH) { + if ( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() + ": GLContextImpl.destroy.0: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + ", surf "+toHexString(drawable.getHandle())+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); } @@ -351,7 +351,7 @@ public abstract class GLContextImpl extends GLContext { lock.lock(); // holdCount++ -> 1 - n (1: not locked, 2-n: destroy while rendering) if ( lock.getHoldCount() > 2 ) { final String msg = getThreadName() + ": GLContextImpl.destroy: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle); - if (DEBUG_TRACE_SWITCH) { + if ( DEBUG_TRACE_SWITCH ) { System.err.println(msg+" - Lock was hold more than once - makeCurrent/release imbalance: "+lock); Thread.dumpStack(); } @@ -388,7 +388,7 @@ public abstract class GLContextImpl extends GLContext { } } finally { lock.unlock(); - if (TRACE_SWITCH) { + if ( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() + ": GLContextImpl.destroy.X: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + ", isShared "+GLContextShareSet.isShared(this)+" - "+lock); } @@ -468,14 +468,14 @@ public abstract class GLContextImpl extends GLContext { */ @Override public int makeCurrent() throws GLException { - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock); } // Note: the surface is locked within [makeCurrent .. swap .. release] final int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - if(DEBUG_TRACE_SWITCH) { + if( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X1]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - Surface Not Ready - CONTEXT_NOT_CURRENT - "+lock); } return CONTEXT_NOT_CURRENT; @@ -503,7 +503,7 @@ public abstract class GLContextImpl extends GLContext { // For Mac OS X, however, we need to update the context to track resizes drawableUpdatedNotify(); unlockContextAndSurface = false; // success - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X2]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - keep - CONTEXT_CURRENT - "+lock); } return CONTEXT_CURRENT; @@ -526,7 +526,7 @@ public abstract class GLContextImpl extends GLContext { throw e; } finally { if (unlockContextAndSurface) { - if(DEBUG_TRACE_SWITCH) { + if( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.1]: Context lock.unlock() due to error, res "+makeCurrentResultToString(res)+", "+lock); } lock.unlock(); @@ -575,7 +575,7 @@ public abstract class GLContextImpl extends GLContext { } */ } - if(TRACE_SWITCH) { + if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X3]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - switch - "+makeCurrentResultToString(res)+" - "+lock); } return res; @@ -611,7 +611,7 @@ public abstract class GLContextImpl extends GLContext { shareWith.getDrawableImpl().unlockSurface(); } } - if (DEBUG_TRACE_SWITCH) { + if ( DEBUG_TRACE_SWITCH ) { if(created) { System.err.println(getThreadName() + ": Create GL context OK: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + ", surf "+toHexString(drawable.getHandle())+" for " + getClass().getName()+" - "+getGLVersion()); // Thread.dumpStack(); @@ -811,7 +811,7 @@ public abstract class GLContextImpl extends GLContext { if(PROFILE_ALIASING) { hasGL3 = true; } - resetStates(); // clean this context states, since creation was temporary + resetStates(); // clean context states, since creation was temporary } } if(!hasGL3) { @@ -1301,7 +1301,7 @@ public abstract class GLContextImpl extends GLContext { // Only validate if a valid int version was fetched, otherwise cont. w/ version-string method -> 3.0 > Version || Version > MAX! if ( GLContext.isValidGLVersion(glIntMajor[0], glIntMinor[0]) ) { if( glIntMajor[0]<major || ( glIntMajor[0]==major && glIntMinor[0]<minor ) || 0 == major ) { - if( strictMatch && 0 < major ) { + if( strictMatch && 2 < major ) { // relaxed match for versions major < 3 requests, last resort! if(DEBUG) { System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (Int): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+glIntMajor[0]+"."+glIntMinor[0]); } @@ -1326,7 +1326,7 @@ public abstract class GLContextImpl extends GLContext { // Only validate if a valid string version was fetched -> MIN > Version || Version > MAX! if( null != strGLVersionNumber ) { if( strGLVersionNumber.compareTo(setGLVersionNumber) < 0 || 0 == major ) { - if( strictMatch && 0 < major ) { + if( strictMatch && 2 < major ) { // relaxed match for versions major < 3 requests, last resort! if(DEBUG) { System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (String): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+strGLVersionNumber); } @@ -1462,29 +1462,55 @@ public abstract class GLContextImpl extends GLContext { final boolean hwAccel = 0 == ( ctp & GLContext.CTX_IMPL_ACCEL_SOFT ); final boolean compatCtx = 0 != ( ctp & GLContext.CTX_PROFILE_COMPAT ); + // // OS related quirks + // if( Platform.getOSType() == Platform.OSType.MACOS ) { - final int quirk1 = GLRendererQuirks.NoOffscreenBitmap; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk1)+": cause: OS "+Platform.getOSType()); + // + // OSX + // + { + final int quirk = GLRendererQuirks.NoOffscreenBitmap; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()); + } + quirks[i++] = quirk; + } + + final VersionNumber OSXVersion173 = new VersionNumber(1,7,3); + if( Platform.getOSVersionNumber().compareTo(OSXVersion173) < 0 && glRendererLowerCase.contains("nvidia") ) { + final int quirk = GLRendererQuirks.GLFlushBeforeRelease; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer); + } + quirks[i++] = quirk; } - quirks[i++] = quirk1; } else if( Platform.getOSType() == Platform.OSType.WINDOWS ) { + // + // WINDOWS + // final int quirk = GLRendererQuirks.NoDoubleBufferedBitmap; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()); } quirks[i++] = quirk; - } - - // Renderer related quirks, may also involve OS - if( Platform.OSType.ANDROID == Platform.getOSType() && glRendererLowerCase.contains("powervr") ) { - final int quirk = GLRendererQuirks.NoSetSwapInterval; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer); + } else if( Platform.OSType.ANDROID == Platform.getOSType() ) { + // + // ANDROID + // + // Renderer related quirks, may also involve OS + if( glRendererLowerCase.contains("powervr") ) { + final int quirk = GLRendererQuirks.NoSetSwapInterval; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer); + } + quirks[i++] = quirk; } - quirks[i++] = quirk; } + + // + // RENDERER related quirks + // if( glRendererLowerCase.contains("mesa") || glRendererLowerCase.contains("gallium") ) { { final int quirk = GLRendererQuirks.NoSetSwapIntervalPostRetarget; diff --git a/src/jogl/classes/jogamp/opengl/GLVersionNumber.java b/src/jogl/classes/jogamp/opengl/GLVersionNumber.java index 1004f04c6..83815f7a4 100644 --- a/src/jogl/classes/jogamp/opengl/GLVersionNumber.java +++ b/src/jogl/classes/jogamp/opengl/GLVersionNumber.java @@ -29,6 +29,9 @@ package jogamp.opengl; import java.util.StringTokenizer; + +import javax.media.opengl.GLContext; + import com.jogamp.common.util.VersionNumber; /** @@ -90,9 +93,11 @@ class GLVersionNumber extends VersionNumber { // Avoid possibly confusing situations by putting some // constraints on the upgrades we do to the major and // minor versions - if ((altMajor == val[0] && altMinor > val[1]) || altMajor == val[0] + 1) { - val[0] = altMajor; - val[1] = altMinor; + if ( (altMajor == val[0] && altMinor > val[1]) || altMajor == val[0] + 1 ) { + if( GLContext.isValidGLVersion(altMajor, altMinor) ) { + val[0] = altMajor; + val[1] = altMinor; + } } } } diff --git a/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java b/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java index 983f11133..ae8969d07 100644 --- a/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java +++ b/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java @@ -94,11 +94,7 @@ public class AWTThreadingPlugin implements ToolkitThreadingPlugin { // QFT which is not allowed. For now, on X11 platforms, // continue to perform this work on the EDT. if (wait && Java2D.isOGLPipelineActive() && !ThreadingImpl.isX11()) { - if(wait) { - Java2D.invokeWithOGLContextCurrent(null, r); - } else { - - } + Java2D.invokeWithOGLContextCurrent(null, r); } else { AWTEDTExecutor.singleton.invoke(wait, r); } diff --git a/src/jogl/classes/jogamp/opengl/awt/Java2D.java b/src/jogl/classes/jogamp/opengl/awt/Java2D.java index 3dbfefb19..edf9e89f8 100644 --- a/src/jogl/classes/jogamp/opengl/awt/Java2D.java +++ b/src/jogl/classes/jogamp/opengl/awt/Java2D.java @@ -69,6 +69,7 @@ public class Java2D { private static boolean DEBUG = Debug.debug("Java2D"); private static boolean isHeadless; private static boolean isOGLPipelineActive; + private static boolean isOGLPipelineResourceCompatible; private static Method invokeWithOGLContextCurrentMethod; private static Method isQueueFlusherThreadMethod; private static Method getOGLViewportMethod; @@ -124,19 +125,37 @@ public class Java2D { isHeadless = true; // Figure out whether the default graphics configuration is an // OpenGL graphics configuration - GraphicsConfiguration cfg = - GraphicsEnvironment.getLocalGraphicsEnvironment(). - getDefaultScreenDevice(). - getDefaultConfiguration(); + final GraphicsConfiguration cfg; + final String cfgName; + final boolean java2dOGLDisabledByOS = Platform.OS_TYPE == Platform.OSType.MACOS; + final boolean java2dOGLDisabledByProp; + { + boolean enabled = true; + final String sVal = System.getProperty("sun.java2d.opengl"); + if( null != sVal ) { + enabled = Boolean.valueOf(sVal); + } + java2dOGLDisabledByProp = !enabled; + } + if( !java2dOGLDisabledByProp && !java2dOGLDisabledByOS ) { + cfg = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + cfgName = cfg.getClass().getName(); + } else { + if (DEBUG) { + System.err.println("Java2D support disabled: by Property "+java2dOGLDisabledByProp+", by OS "+java2dOGLDisabledByOS); + } + cfg = null; + cfgName = "nil"; + } // If we get here, we aren't running in headless mode isHeadless = false; - String name = cfg.getClass().getName(); if (DEBUG) { - System.err.println("Java2D support: default GraphicsConfiguration = " + name); + System.err.println("Java2D support: default GraphicsConfiguration = " + cfgName); } - isOGLPipelineActive = Platform.OS_TYPE != Platform.OSType.MACOS && - (name.startsWith("sun.java2d.opengl")); - + isOGLPipelineActive = cfgName.startsWith("sun.java2d.opengl"); + isOGLPipelineResourceCompatible = isOGLPipelineActive; + if (isOGLPipelineActive) { try { // Try to get methods we need to integrate @@ -152,99 +171,101 @@ public class Java2D { new Class[] {}); isQueueFlusherThreadMethod.setAccessible(true); - getOGLViewportMethod = utils.getDeclaredMethod("getOGLViewport", - new Class[] { - Graphics.class, - Integer.TYPE, - Integer.TYPE - }); - getOGLViewportMethod.setAccessible(true); - - getOGLScissorBoxMethod = utils.getDeclaredMethod("getOGLScissorBox", - new Class[] { - Graphics.class - }); - getOGLScissorBoxMethod.setAccessible(true); - - getOGLSurfaceIdentifierMethod = utils.getDeclaredMethod("getOGLSurfaceIdentifier", + if( isOGLPipelineResourceCompatible ) { + getOGLViewportMethod = utils.getDeclaredMethod("getOGLViewport", + new Class[] { + Graphics.class, + Integer.TYPE, + Integer.TYPE + }); + getOGLViewportMethod.setAccessible(true); + + getOGLScissorBoxMethod = utils.getDeclaredMethod("getOGLScissorBox", + new Class[] { + Graphics.class + }); + getOGLScissorBoxMethod.setAccessible(true); + + getOGLSurfaceIdentifierMethod = utils.getDeclaredMethod("getOGLSurfaceIdentifier", + new Class[] { + Graphics.class + }); + getOGLSurfaceIdentifierMethod.setAccessible(true); + + // Try to get additional methods required for proper FBO support + fbObjectSupportInitialized = true; + try { + invokeWithOGLSharedContextCurrentMethod = utils.getDeclaredMethod("invokeWithOGLSharedContextCurrent", + new Class[] { + GraphicsConfiguration.class, + Runnable.class + }); + invokeWithOGLSharedContextCurrentMethod.setAccessible(true); + + getOGLSurfaceTypeMethod = utils.getDeclaredMethod("getOGLSurfaceType", new Class[] { Graphics.class }); - getOGLSurfaceIdentifierMethod.setAccessible(true); - - // Try to get additional methods required for proper FBO support - fbObjectSupportInitialized = true; - try { - invokeWithOGLSharedContextCurrentMethod = utils.getDeclaredMethod("invokeWithOGLSharedContextCurrent", - new Class[] { - GraphicsConfiguration.class, - Runnable.class - }); - invokeWithOGLSharedContextCurrentMethod.setAccessible(true); - - getOGLSurfaceTypeMethod = utils.getDeclaredMethod("getOGLSurfaceType", - new Class[] { - Graphics.class - }); - getOGLSurfaceTypeMethod.setAccessible(true); - } catch (Exception e) { - fbObjectSupportInitialized = false; - if (DEBUG) { - e.printStackTrace(); - System.err.println("Info: Disabling Java2D/JOGL FBO support"); - } - } - - // Try to get an additional method for FBO support in recent Mustang builds - try { - getOGLTextureTypeMethod = utils.getDeclaredMethod("getOGLTextureType", - new Class[] { - Graphics.class - }); - getOGLTextureTypeMethod.setAccessible(true); - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - System.err.println("Info: GL_ARB_texture_rectangle FBO support disabled"); - } - } - - // Try to set up APIs for enabling the bridge on OS X, - // where it isn't possible to create generalized - // external GLDrawables - Class<?> cglSurfaceData = null; - try { - cglSurfaceData = Class.forName("sun.java2d.opengl.CGLSurfaceData"); - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - System.err.println("Info: Unable to find class sun.java2d.opengl.CGLSurfaceData for OS X"); - } - } - if (cglSurfaceData != null) { - // FIXME: for now, assume that FBO support is not enabled on OS X - fbObjectSupportInitialized = false; - - // We need to find these methods in order to make the bridge work on OS X - createOGLContextOnSurfaceMethod = cglSurfaceData.getDeclaredMethod("createOGLContextOnSurface", - new Class[] { - Graphics.class, - Long.TYPE - }); - createOGLContextOnSurfaceMethod.setAccessible(true); - - makeOGLContextCurrentOnSurfaceMethod = cglSurfaceData.getDeclaredMethod("makeOGLContextCurrentOnSurface", - new Class[] { - Graphics.class, - Long.TYPE - }); - makeOGLContextCurrentOnSurfaceMethod.setAccessible(true); - - destroyOGLContextMethod = cglSurfaceData.getDeclaredMethod("destroyOGLContext", - new Class[] { - Long.TYPE - }); - destroyOGLContextMethod.setAccessible(true); + getOGLSurfaceTypeMethod.setAccessible(true); + } catch (Exception e) { + fbObjectSupportInitialized = false; + if (DEBUG) { + e.printStackTrace(); + System.err.println("Info: Disabling Java2D/JOGL FBO support"); + } + } + + // Try to get an additional method for FBO support in recent Mustang builds + try { + getOGLTextureTypeMethod = utils.getDeclaredMethod("getOGLTextureType", + new Class[] { + Graphics.class + }); + getOGLTextureTypeMethod.setAccessible(true); + } catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + System.err.println("Info: GL_ARB_texture_rectangle FBO support disabled"); + } + } + + // Try to set up APIs for enabling the bridge on OS X, + // where it isn't possible to create generalized + // external GLDrawables + Class<?> cglSurfaceData = null; + try { + cglSurfaceData = Class.forName("sun.java2d.opengl.CGLSurfaceData"); + } catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + System.err.println("Info: Unable to find class sun.java2d.opengl.CGLSurfaceData for OS X"); + } + } + if (cglSurfaceData != null) { + // FIXME: for now, assume that FBO support is not enabled on OS X + fbObjectSupportInitialized = false; + + // We need to find these methods in order to make the bridge work on OS X + createOGLContextOnSurfaceMethod = cglSurfaceData.getDeclaredMethod("createOGLContextOnSurface", + new Class[] { + Graphics.class, + Long.TYPE + }); + createOGLContextOnSurfaceMethod.setAccessible(true); + + makeOGLContextCurrentOnSurfaceMethod = cglSurfaceData.getDeclaredMethod("makeOGLContextCurrentOnSurface", + new Class[] { + Graphics.class, + Long.TYPE + }); + makeOGLContextCurrentOnSurfaceMethod.setAccessible(true); + + destroyOGLContextMethod = cglSurfaceData.getDeclaredMethod("destroyOGLContext", + new Class[] { + Long.TYPE + }); + destroyOGLContextMethod.setAccessible(true); + } } } catch (Exception e) { catched = e; @@ -252,6 +273,7 @@ public class Java2D { System.err.println("Info: Disabling Java2D/JOGL integration"); } isOGLPipelineActive = false; + isOGLPipelineResourceCompatible = false; } } } catch (HeadlessException e) { @@ -265,7 +287,7 @@ public class Java2D { if(null != catched) { catched.printStackTrace(); } - System.err.println("JOGL/Java2D integration " + (isOGLPipelineActive ? "enabled" : "disabled")); + System.err.println("JOGL/Java2D OGL Pipeline active " + isOGLPipelineActive + ", resourceCompatible "+isOGLPipelineResourceCompatible); } return null; } @@ -275,6 +297,10 @@ public class Java2D { public static boolean isOGLPipelineActive() { return isOGLPipelineActive; } + + public static boolean isOGLPipelineResourceCompatible() { + return isOGLPipelineResourceCompatible; + } public static boolean isFBOEnabled() { return fbObjectSupportInitialized; @@ -330,7 +356,7 @@ public class Java2D { false if the passed GraphicsConfiguration was not an OpenGL GraphicsConfiguration. */ public static boolean invokeWithOGLSharedContextCurrent(GraphicsConfiguration g, Runnable r) throws GLException { - checkActive(); + checkCompatible(); try { AWTUtil.lockToolkit(); @@ -355,7 +381,7 @@ public class Java2D { public static Rectangle getOGLViewport(Graphics g, int componentWidth, int componentHeight) { - checkActive(); + checkCompatible(); try { return (Rectangle) getOGLViewportMethod.invoke(null, new Object[] {g, @@ -375,7 +401,7 @@ public class Java2D { passed to a call to glScissor(). Should only be called from the Queue Flusher Thread. */ public static Rectangle getOGLScissorBox(Graphics g) { - checkActive(); + checkCompatible(); try { return (Rectangle) getOGLScissorBoxMethod.invoke(null, new Object[] {g}); @@ -393,7 +419,7 @@ public class Java2D { created (and the old ones destroyed). Should only be called from the Queue Flusher Thread.*/ public static Object getOGLSurfaceIdentifier(Graphics g) { - checkActive(); + checkCompatible(); try { return getOGLSurfaceIdentifierMethod.invoke(null, new Object[] {g}); @@ -408,7 +434,7 @@ public class Java2D { object. This indicates, in particular, whether Java2D is currently rendering into a pbuffer or FBO. */ public static int getOGLSurfaceType(Graphics g) { - checkActive(); + checkCompatible(); try { // FIXME: fallback path for pre-b73 (?) Mustang builds -- remove @@ -429,7 +455,7 @@ public class Java2D { object assuming it is rendering to an FBO. Returns either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB. */ public static int getOGLTextureType(Graphics g) { - checkActive(); + checkCompatible(); if (getOGLTextureTypeMethod == null) { return GL.GL_TEXTURE_2D; @@ -483,7 +509,7 @@ public class Java2D { associated with the given Graphics object, sharing textures and display lists with the specified (CGLContextObj) share context. */ public static long createOGLContextOnSurface(Graphics g, long shareCtx) { - checkActive(); + checkCompatible(); try { return ((Long) createOGLContextOnSurfaceMethod.invoke(null, new Object[] { g, new Long(shareCtx) })).longValue(); @@ -497,7 +523,7 @@ public class Java2D { /** (Mac OS X-specific) Makes the given OpenGL context current on the surface associated with the given Graphics object. */ public static boolean makeOGLContextCurrentOnSurface(Graphics g, long ctx) { - checkActive(); + checkCompatible(); try { return ((Boolean) makeOGLContextCurrentOnSurfaceMethod.invoke(null, new Object[] { g, new Long(ctx) })).booleanValue(); @@ -510,7 +536,7 @@ public class Java2D { /** (Mac OS X-specific) Destroys the given OpenGL context. */ public static void destroyOGLContext(long ctx) { - checkActive(); + checkCompatible(); try { destroyOGLContextMethod.invoke(null, new Object[] { new Long(ctx) }); @@ -527,7 +553,13 @@ public class Java2D { private static void checkActive() { if (!isOGLPipelineActive()) { - throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); + throw new GLException("Java2D OpenGL pipeline not active"); + } + } + + private static void checkCompatible() { + if ( !isOGLPipelineResourceCompatible() ) { + throw new GLException("Java2D OpenGL pipeline not resource compatible"); } } @@ -562,7 +594,7 @@ public class Java2D { // Note 2: the first execution of this method must not be from the // Java2D Queue Flusher Thread. - if (isOGLPipelineActive() && + if (isOGLPipelineResourceCompatible() && isFBOEnabled() && !initializedJ2DFBOShareContext) { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 838a0387d..3825f855c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -74,6 +74,7 @@ import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.util.PMVMatrix; import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; @@ -687,13 +688,33 @@ public abstract class MacOSXCGLContext extends GLContextImpl } else { gl3ShaderProgramName = 0; } - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, nsOpenGLLayerPFmt, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); - nsOpenGLLayerPFmt = 0; // NSOpenGLLayer will release pfmt - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); + + /** + * Perform NSOpenGLLayer creation and attaching on main-thread, + * hence release the lock on our context - which will be used to + * create a shared context within NSOpenGLLayer. + */ + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + final boolean ctxUnlocked = CGL.kCGLNoError == CGL.CGLUnlockContext(cglCtx); + try { + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, nsOpenGLLayerPFmt, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); + nsOpenGLLayerPFmt = 0; // NSOpenGLLayer will release pfmt + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + setSwapInterval(1); // enabled per default in layered surface + } finally { + if( ctxUnlocked ) { + if( CGL.kCGLNoError != CGL.CGLLockContext(cglCtx) ) { + throw new InternalError("Could not re-lock CGLContext for: "+this); + } + } } - backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); - setSwapInterval(1); // enabled per default in layered surface + backingLayerHost.layoutSurfaceLayer(); } else { lastWidth = drawable.getWidth(); lastHeight = drawable.getHeight(); @@ -773,7 +794,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean release(long ctx) { try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + if( hasRendererQuirk(GLRendererQuirks.GLFlushBeforeRelease) && null != MacOSXCGLContext.this.getGLProcAddressTable() ) { + gl.glFlush(); + } } catch (GLException gle) { if(DEBUG) { System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:"); @@ -953,7 +976,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean release(long ctx) { try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + if( hasRendererQuirk(GLRendererQuirks.GLFlushBeforeRelease) && null != MacOSXCGLContext.this.getGLProcAddressTable() ) { + gl.glFlush(); + } } catch (GLException gle) { if(DEBUG) { System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:"); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index e76c39805..9f034adb1 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -346,7 +346,7 @@ public class WindowsWGLContext extends GLContextImpl { if(glCaps.getGLProfile().isGL3()) { WGL.wglMakeCurrent(0, 0); WGL.wglDeleteContext(temp_ctx); - throw new GLException("WindowsWGLContext.createContext ctx !ARB, context > GL2 requested "+getGLVersion()); + throw new GLException(getThreadName()+": WindowsWGLContex.createContextImpl ctx !ARB, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glCaps.getGLProfile()+", current: "+getGLVersion()); } if(DEBUG) { System.err.println("WindowsWGLContext.createContext failed, fall back to !ARB context "+getGLVersion()); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index feda64f30..575ff51b8 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -166,7 +166,7 @@ public abstract class X11GLXContext extends GLContextImpl { throw new InternalError("Given readDrawable but no driver support"); } } catch (RuntimeException re) { - if(DEBUG_TRACE_SWITCH) { + if( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName()+": Warning: X11GLXContext.glXMakeContextCurrent failed: "+re+", with "+ "dpy "+toHexString(dpy)+ ", write "+toHexString(writeDrawable)+ @@ -374,7 +374,7 @@ public abstract class X11GLXContext extends GLContextImpl { if(glp.isGL3()) { glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, temp_ctx); - throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ctx !ARB, context > GL2 requested - requested: "+glp+", current: "+getGLVersion()+", "); + throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ctx !ARB, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glp+", current: "+getGLVersion()); } if(DEBUG) { System.err.println(getThreadName()+": X11GLXContext.createContextImpl failed, fall back to !ARB context "+getGLVersion()); diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m index b37930587..2cf74380c 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m @@ -1,6 +1,7 @@ #import "MacOSXWindowSystemInterface.h" #import <QuartzCore/QuartzCore.h> #import <pthread.h> +#import "NativeWindowProtocols.h" #include "timespec.h" #import <OpenGL/glext.h> @@ -41,6 +42,8 @@ extern GLboolean glIsVertexArray (GLuint array); // // #define DBG_PERF 1 +// #define DBG_LIFECYCLE 1 + /** * Capture setView(NULL), which produces a 'invalid drawable' message * @@ -52,6 +55,10 @@ extern GLboolean glIsVertexArray (GLuint array); - (id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share; - (void)setView:(NSView *)view; - (void)update; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +#endif - (void)dealloc; @end @@ -69,8 +76,11 @@ extern GLboolean glIsVertexArray (GLuint array); - (void)setView:(NSView *)view { DBG_PRINT("MyNSOpenGLContext.setView: this.0 %p, view %p\n", self, view); + // NSLog(@"MyNSOpenGLContext::setView: %@",[NSThread callStackSymbols]); if(NULL != view) { [super setView:view]; + } else { + [self clearDrawable]; } DBG_PRINT("MyNSOpenGLContext.setView.X\n"); } @@ -82,19 +92,47 @@ extern GLboolean glIsVertexArray (GLuint array); DBG_PRINT("MyNSOpenGLContext.update.X\n"); } +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyNSOpenGLContext::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLContext::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyNSOpenGLContext::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyNSOpenGLContext::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT("MyNSOpenGLContext::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +#endif + - (void)dealloc { - DBG_PRINT("MyNSOpenGLContext.dealloc: this.0 %p\n", self); + CGLContextObj cglCtx = [self CGLContextObj]; + + DBG_PRINT("MyNSOpenGLContext::dealloc.0 %p (refcnt %d) - CGL-Ctx %p\n", self, (int)[self retainCount], cglCtx); + [self clearDrawable]; + if( NULL != cglCtx ) { + CGLDestroyContext( cglCtx ); + } [super dealloc]; - DBG_PRINT("MyNSOpenGLContext.dealloc.X: %p\n", self); + // DBG_PRINT("MyNSOpenGLContext.dealloc.X: %p\n", self); } @end -@interface MyNSOpenGLLayer: NSOpenGLLayer +@interface MyNSOpenGLLayer: NSOpenGLLayer <NWDedicatedSize> { @private GLfloat gl_texCoords[8]; + NSOpenGLContext* myCtx; + Bool isGLEnabled; @protected NSOpenGLContext* parentCtx; @@ -106,8 +144,8 @@ extern GLboolean glIsVertexArray (GLuint array); NSOpenGLPixelFormat* parentPixelFmt; int texWidth; int texHeight; - int newTexWidth; - int newTexHeight; + int dedicatedWidth; + int dedicatedHeight; volatile NSOpenGLPixelBuffer* pbuffer; volatile GLuint textureID; volatile NSOpenGLPixelBuffer* newPBuffer; @@ -136,7 +174,17 @@ extern GLboolean glIsVertexArray (GLuint array); texWidth: (int) texWidth texHeight: (int) texHeight; -- (Bool) validateTexSizeWithNewSize; +- (void)releaseLayer; +- (void)deallocPBuffer; +- (void)disableAnimation; +- (void)pauseAnimation:(Bool)pause; +- (void)setSwapInterval:(int)interval; +- (void)tick; +- (void)waitUntilRenderSignal: (long) to_micros; +- (Bool)isGLSourceValid; + +- (void) setGLEnabled: (Bool) enable; +- (Bool) validateTexSizeWithDedicatedSize; - (Bool) validateTexSize: (int) _texWidth texHeight: (int) _texHeight; - (void) setTextureID: (int) _texID; @@ -144,17 +192,22 @@ extern GLboolean glIsVertexArray (GLuint array); - (void) setNewPBuffer: (NSOpenGLPixelBuffer*)p; - (void) applyNewPBuffer; +- (void)setDedicatedSize:(CGSize)size; // @NWDedicatedSize +- (CGRect)fixMyFrame; +- (CGRect)fixSuperPosition; +- (id<CAAction>)actionForKey:(NSString *)key ; - (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask; - (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat; -- (void)disableAnimation; -- (void)pauseAnimation:(Bool)pause; -- (void)deallocPBuffer; -- (void)releaseLayer; +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp; +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp; + +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +#endif - (void)dealloc; -- (void)setSwapInterval:(int)interval; -- (void)tick; -- (void)waitUntilRenderSignal: (long) to_micros; -- (Bool)isGLSourceValid; @end @@ -209,6 +262,7 @@ static const GLfloat gl_verts[] = { pthread_mutex_init(&renderLock, &renderLockAttr); // recursive pthread_cond_init(&renderSignal, NULL); // no attribute + myCtx = NULL; { int i; for(i=0; i<8; i++) { @@ -226,9 +280,10 @@ static const GLfloat gl_verts[] = { swapIntervalCounter = 0; timespec_now(&lastWaitTime); shallDraw = NO; - newTexWidth = _texWidth; - newTexHeight = _texHeight; - [self validateTexSizeWithNewSize]; + isGLEnabled = YES; + dedicatedWidth = _texWidth; + dedicatedHeight = _texHeight; + [self validateTexSizeWithDedicatedSize]; [self setTextureID: texID]; newPBuffer = NULL; @@ -265,13 +320,6 @@ static const GLfloat gl_verts[] = { } } if(NULL != displayLink) { - cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [parentCtx CGLContextObj], [parentPixelFmt CGLPixelFormatObj]); - if(kCVReturnSuccess != cvres) { - DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); - displayLink = NULL; - } - } - if(NULL != displayLink) { cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); if(kCVReturnSuccess != cvres) { DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); @@ -302,9 +350,15 @@ static const GLfloat gl_verts[] = { return self; } -- (Bool) validateTexSizeWithNewSize +- (void) setGLEnabled: (Bool) enable { - return [self validateTexSize: newTexWidth texHeight: newTexHeight]; + DBG_PRINT("MyNSOpenGLLayer::setGLEnabled: %p, %d -> %d\n", self, (int)isGLEnabled, (int)enable); + isGLEnabled = enable; +} + +- (Bool) validateTexSizeWithDedicatedSize +{ + return [self validateTexSize: dedicatedWidth texHeight: dedicatedHeight]; } - (Bool) validateTexSize: (int) _texWidth texHeight: (int) _texHeight @@ -312,12 +366,14 @@ static const GLfloat gl_verts[] = { if(_texHeight != texHeight || _texWidth != texWidth) { texWidth = _texWidth; texHeight = _texHeight; + /** CGRect lRect = [self bounds]; lRect.origin.x = 0; lRect.origin.y = 0; lRect.size.width = texWidth; lRect.size.height = texHeight; - [self setFrame: lRect]; + [self setFrame: lRect]; */ + CGRect lRect = [self fixMyFrame]; GLfloat texCoordWidth, texCoordHeight; if(NULL != pbuffer) { @@ -339,8 +395,14 @@ static const GLfloat gl_verts[] = { gl_texCoords[5] = texCoordHeight; gl_texCoords[4] = texCoordWidth; gl_texCoords[6] = texCoordWidth; +#ifdef VERBOSE_ON + DBG_PRINT("MyNSOpenGLLayer::validateTexSize %p -> tex %dx%d, bounds: %lf/%lf %lfx%lf\n", + self, texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); +#endif return YES; } else { + [self fixMyFrame]; return NO; } } @@ -407,26 +469,9 @@ static const GLfloat gl_verts[] = { } } -- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask -{ - DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask: %p (refcnt %d) - parent-pfmt %p -> new-pfmt %p\n", - self, (int)[self retainCount], parentPixelFmt, parentPixelFmt); - return parentPixelFmt; -} - -- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat -{ - DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, parent %p\n", - self, (int)[self retainCount], pixelFormat, parentCtx); - NSOpenGLContext * nctx = [[MyNSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx]; - DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.X: new-ctx %p\n", nctx); - return nctx; -} - - (void)disableAnimation { - DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); - pthread_mutex_lock(&renderLock); + DBG_PRINT("MyNSOpenGLLayer::disableAnimation.0: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); [self setAsynchronous: NO]; if(NULL != displayLink) { #ifdef HAS_CADisplayLink @@ -438,35 +483,60 @@ static const GLfloat gl_verts[] = { #endif displayLink = NULL; } - pthread_mutex_unlock(&renderLock); + DBG_PRINT("MyNSOpenGLLayer::disableAnimation.X: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); } - (void)releaseLayer { DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]); - pthread_mutex_lock(&renderLock); [self disableAnimation]; + pthread_mutex_lock(&renderLock); [self deallocPBuffer]; - [[self openGLContext] release]; + // [[self openGLContext] release]; + if( NULL != myCtx ) { + [myCtx release]; + myCtx = NULL; + } + parentCtx = NULL; [parentPixelFmt release]; - [self release]; - DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]); pthread_mutex_unlock(&renderLock); + [self release]; + DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p\n", self); +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyNSOpenGLLayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyNSOpenGLLayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; } +- (oneway void)release +{ + DBG_PRINT("MyNSOpenGLLayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyNSOpenGLLayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +#endif + - (void)dealloc { DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]); - - pthread_mutex_lock(&renderLock); [self disableAnimation]; + pthread_mutex_lock(&renderLock); [self deallocPBuffer]; pthread_mutex_unlock(&renderLock); pthread_cond_destroy(&renderSignal); pthread_mutex_destroy(&renderLock); [super dealloc]; - DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); + // DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); } - (Bool)isGLSourceValid @@ -474,26 +544,114 @@ static const GLfloat gl_verts[] = { return NULL != pbuffer || NULL != newPBuffer || 0 != textureID ; } -- (void)resizeWithOldSuperlayerSize:(CGSize)size - { - CGRect lRectS = [[self superlayer] bounds]; +// @NWDedicatedSize +- (void)setDedicatedSize:(CGSize)size { + DBG_PRINT("MyNSOpenGLLayer::setDedicatedSize: %p, texSize %dx%d <- %lfx%lf\n", + self, texWidth, texHeight, size.width, size.height); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + dedicatedWidth = size.width; + dedicatedHeight = size.height; - DBG_PRINT("MyNSOpenGLLayer::resizeWithOldSuperlayerSize: %p, texSize %dx%d, bounds: %lfx%lf -> %lfx%lf (refcnt %d)\n", - self, texWidth, texHeight, size.width, size.height, lRectS.size.width, lRectS.size.height, (int)[self retainCount]); + CGRect rect = CGRectMake(0, 0, dedicatedWidth, dedicatedHeight); + [self setFrame: rect]; - newTexWidth = lRectS.size.width; - newTexHeight = lRectS.size.height; - shallDraw = [self isGLSourceValid]; - SYNC_PRINT("<SZ %dx%d>", newTexWidth, newTexHeight); + [CATransaction commit]; +} - [super resizeWithOldSuperlayerSize: size]; +- (void) setFrame:(CGRect) frame { + CGRect rect = CGRectMake(0, 0, dedicatedWidth, dedicatedHeight); + [super setFrame: rect]; +} + +- (CGRect)fixMyFrame +{ + CGRect lRect = [self frame]; + + // With Java7 our root CALayer's frame gets off-limit -> force 0/0 origin! + if( lRect.origin.x!=0 || lRect.origin.y!=0 || lRect.size.width!=texWidth || lRect.size.height!=texHeight) { + DBG_PRINT("MyNSOpenGLLayer::fixMyFrame: %p, 0/0 texSize %dx%d -> Frame[%lf/%lf %lfx%lf]\n", + self, texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + lRect.origin.x = 0; + lRect.origin.y = 0; + lRect.size.width=texWidth; + lRect.size.height=texHeight; + [self setFrame: lRect]; + + [CATransaction commit]; + } + return lRect; +} + +- (CGRect)fixSuperPosition +{ + CALayer * superL = [self superlayer]; + CGRect lRect = [superL frame]; + + // With Java7 our root CALayer's frame gets off-limit -> force 0/0 origin! + if( lRect.origin.x!=0 || lRect.origin.y!=0 ) { + DBG_PRINT("MyNSOpenGLLayer::fixSuperPosition: %p, 0/0 -> Super Frame[%lf/%lf %lfx%lf]\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + lRect.origin.x = 0; + lRect.origin.y = 0; + [superL setPosition: lRect.origin]; + + [CATransaction commit]; + } + return lRect; +} + +- (id<CAAction>)actionForKey:(NSString *)key +{ + DBG_PRINT("MyNSOpenGLLayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]); + return nil; + // return [super actionForKey: key]; +} + +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask +{ + DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask: %p (refcnt %d) - parent-pfmt %p -> new-pfmt %p\n", + self, (int)[self retainCount], parentPixelFmt, parentPixelFmt); + // We simply take over ownership of parent PixelFormat .. + return parentPixelFmt; +} + +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat +{ + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.0: %p (refcnt %d) - pfmt %p, parent %p, DisplayLink %p\n", + self, (int)[self retainCount], pixelFormat, parentCtx, displayLink); + // NSLog(@"MyNSOpenGLLayer::openGLContextForPixelFormat: %@",[NSThread callStackSymbols]); + myCtx = [[MyNSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx]; +#ifndef HAS_CADisplayLink + if(NULL != displayLink) { + CVReturn cvres; + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.1: setup DisplayLink %p\n", displayLink); + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [myCtx CGLContextObj], [pixelFormat CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + } + } +#endif + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat.X: new-ctx %p\n", myCtx); + return myCtx; } - (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - SYNC_PRINT("<? %d>", (int)shallDraw); - return shallDraw; + SYNC_PRINT("<? %d, %d>", (int)shallDraw, (int)isGLEnabled); + return shallDraw && isGLEnabled; } - (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat @@ -503,7 +661,7 @@ static const GLfloat gl_verts[] = { SYNC_PRINT("<* "); // NSLog(@"MyNSOpenGLLayer::DRAW: %@",[NSThread callStackSymbols]); - if( shallDraw && ( NULL != pbuffer || NULL != newPBuffer || 0 != textureID ) ) { + if( isGLEnabled && shallDraw && ( NULL != pbuffer || NULL != newPBuffer || 0 != textureID ) ) { [context makeCurrentContext]; if( NULL != newPBuffer ) { // volatile OK @@ -512,7 +670,7 @@ static const GLfloat gl_verts[] = { GLenum textureTarget; - Bool texSizeChanged = [self validateTexSizeWithNewSize]; + Bool texSizeChanged = [self validateTexSizeWithDedicatedSize]; if( NULL != pbuffer ) { if( texSizeChanged && 0 != textureID ) { @@ -752,32 +910,34 @@ static const GLfloat gl_verts[] = { @end NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, int gl3ShaderProgramName, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, uint32_t texID, Bool opaque, int texWidth, int texHeight) { - // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ? - // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO. - // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID - // opaque: opaque texWidth: texWidth texHeight: texHeight]; - return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx gl3ShaderProgramName: (GLuint)gl3ShaderProgramName pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID opaque: opaque texWidth: texWidth texHeight: texHeight]; } + +void setNSOpenGLLayerEnabled(NSOpenGLLayer* layer, Bool enable) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + [l setGLEnabled: enable]; + [pool release]; +} void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; [l setSwapInterval: interval]; [pool release]; } void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; [l waitUntilRenderSignal: to_micros]; [pool release]; } void setNSOpenGLLayerNeedsDisplayFBO(NSOpenGLLayer* layer, uint32_t texID) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; Bool shallDraw; // volatile OK @@ -799,8 +959,8 @@ void setNSOpenGLLayerNeedsDisplayFBO(NSOpenGLLayer* layer, uint32_t texID) { } void setNSOpenGLLayerNeedsDisplayPBuffer(NSOpenGLLayer* layer, NSOpenGLPixelBuffer* p) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; Bool shallDraw; if( NO == [l isSamePBuffer: p] ) { @@ -825,16 +985,10 @@ void setNSOpenGLLayerNeedsDisplayPBuffer(NSOpenGLLayer* layer, NSOpenGLPixelBuff } void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { - MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l); - - if ( [NSThread isMainThread] == YES ) { - [l releaseLayer]; - } else { - [l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO]; - } - + [l releaseLayer]; DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l); [pool release]; } diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m index e8925f8e8..f8faeb8d0 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -575,7 +575,6 @@ void setContextView(NSOpenGLContext* ctx, NSView* view) { [ctx setView:view]; } [pool release]; - return ctx; } Bool makeCurrentContext(NSOpenGLContext* ctx) { |