diff options
author | Sven Gothel <[email protected]> | 2015-02-02 02:38:55 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-02-02 02:38:55 +0100 |
commit | 78b4918b207e16b967e8335fb8ec1b31c706c507 (patch) | |
tree | 736cf80d089eb5e9df7f349035936daaa78f230d /src/jogl/classes/javax/media/opengl/awt | |
parent | 1ec82447e464d5308442581f14d32f9775928454 (diff) |
Bug 682 - Relocating javax.media.opengl.* -> com.jogamp.opengl.* (Part 2)
Relocation javax.media.nativewindow.* -> com.jogamp.nativewindow.*
Relocation javax.media.opengl.* -> com.jogamp.opengl.*
Diffstat (limited to 'src/jogl/classes/javax/media/opengl/awt')
4 files changed, 0 insertions, 4458 deletions
diff --git a/src/jogl/classes/javax/media/opengl/awt/AWTGLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/awt/AWTGLAutoDrawable.java deleted file mode 100644 index 6e273e4e6..000000000 --- a/src/jogl/classes/javax/media/opengl/awt/AWTGLAutoDrawable.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package com.jogamp.opengl.awt; - -import com.jogamp.opengl.GLAutoDrawable; - -public interface AWTGLAutoDrawable extends GLAutoDrawable, ComponentEvents { - /** Requests a new width and height for this AWTGLAutoDrawable. */ - public void setSize(int width, int height); - - /** Schedules a repaint of the component at some point in the - future. */ - public void repaint(); -} diff --git a/src/jogl/classes/javax/media/opengl/awt/ComponentEvents.java b/src/jogl/classes/javax/media/opengl/awt/ComponentEvents.java deleted file mode 100644 index 996776c9b..000000000 --- a/src/jogl/classes/javax/media/opengl/awt/ComponentEvents.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package com.jogamp.opengl.awt; - -import com.jogamp.opengl.*; -import java.awt.event.*; -import java.beans.PropertyChangeListener; - -/** Factors out the listener manipulation for the events supported by - all of the {@link GLDrawable} implementations. Provided to reduce - clutter in the documentation for GLDrawable. */ - -public interface ComponentEvents { - public void addComponentListener(ComponentListener l); - public void removeComponentListener(ComponentListener l); - public void addFocusListener(FocusListener l); - public void removeFocusListener(FocusListener l); - public void addHierarchyBoundsListener(HierarchyBoundsListener l); - public void removeHierarchyBoundsListener(HierarchyBoundsListener l); - public void addHierarchyListener(HierarchyListener l); - public void removeHierarchyListener(HierarchyListener l); - public void addInputMethodListener(InputMethodListener l); - public void removeInputMethodListener(InputMethodListener l); - public void addKeyListener(KeyListener l); - public void removeKeyListener(KeyListener l); - public void addMouseListener(MouseListener l); - public void removeMouseListener(MouseListener l); - public void addMouseMotionListener(MouseMotionListener l); - public void removeMouseMotionListener(MouseMotionListener l); - public void addMouseWheelListener(MouseWheelListener l); - public void removeMouseWheelListener(MouseWheelListener l); - public void addPropertyChangeListener(PropertyChangeListener listener); - public void removePropertyChangeListener(PropertyChangeListener listener); - public void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener); - public void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener); -} diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java deleted file mode 100644 index 11d217535..000000000 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ /dev/null @@ -1,1643 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package com.jogamp.opengl.awt; - -import java.beans.Beans; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.awt.Canvas; -import java.awt.Color; -import java.awt.FontMetrics; -import java.awt.Frame; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.awt.EventQueue; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; - -import com.jogamp.nativewindow.AbstractGraphicsConfiguration; -import com.jogamp.nativewindow.OffscreenLayerOption; -import com.jogamp.nativewindow.ScalableSurface; -import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.WindowClosingProtocol; -import com.jogamp.nativewindow.AbstractGraphicsDevice; -import com.jogamp.nativewindow.AbstractGraphicsScreen; -import com.jogamp.nativewindow.GraphicsConfigurationFactory; -import com.jogamp.nativewindow.NativeSurface; -import com.jogamp.nativewindow.NativeWindowFactory; -import com.jogamp.opengl.GL; -import com.jogamp.opengl.GLAnimatorControl; -import com.jogamp.opengl.GLAutoDrawable; -import com.jogamp.opengl.GLCapabilities; -import com.jogamp.opengl.GLCapabilitiesChooser; -import com.jogamp.opengl.GLCapabilitiesImmutable; -import com.jogamp.opengl.GLContext; -import com.jogamp.opengl.GLDrawable; -import com.jogamp.opengl.GLDrawableFactory; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLException; -import com.jogamp.opengl.GLOffscreenAutoDrawable; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.GLRunnable; -import com.jogamp.opengl.GLSharedContextSetter; -import com.jogamp.opengl.Threading; - -import com.jogamp.common.GlueGenVersion; -import com.jogamp.common.util.VersionUtil; -import com.jogamp.common.util.awt.AWTEDTExecutor; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; -import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; -import com.jogamp.nativewindow.awt.AWTGraphicsDevice; -import com.jogamp.nativewindow.awt.AWTGraphicsScreen; -import com.jogamp.nativewindow.awt.AWTPrintLifecycle; -import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; -import com.jogamp.nativewindow.awt.JAWTWindow; -import com.jogamp.opengl.JoglVersion; -import com.jogamp.opengl.util.GLDrawableUtil; -import com.jogamp.opengl.util.TileRenderer; - -import jogamp.nativewindow.SurfaceScaleUtils; -import jogamp.opengl.Debug; -import jogamp.opengl.GLContextImpl; -import jogamp.opengl.GLDrawableHelper; -import jogamp.opengl.GLDrawableImpl; -import jogamp.opengl.awt.AWTTilePainter; - -// FIXME: Subclasses need to call resetGLFunctionAvailability() on their -// context whenever the displayChanged() function is called on our -// GLEventListeners - -/** A heavyweight AWT component which provides OpenGL rendering - support. This is the primary implementation of an AWT {@link GLDrawable}; - {@link GLJPanel} is provided for compatibility with Swing user - interfaces when adding a heavyweight doesn't work either because - of Z-ordering or LayoutManager problems. - * - * <h5><a name="offscreenlayer">Offscreen Layer Remarks</a></h5> - * - * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} - * maybe called to use an offscreen drawable (FBO or PBuffer) allowing - * the underlying JAWT mechanism to composite the image, if supported. - * <p> - * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} - * is being called if {@link GLCapabilitiesImmutable#isOnscreen()} is <code>false</code>. - * </p> - * - * <h5><a name="java2dgl">Java2D OpenGL Remarks</a></h5> - * - * To avoid any conflicts with a potential Java2D OpenGL context,<br> - * you shall consider setting the following JVM properties:<br> - * <ul> - * <li><pre>sun.java2d.opengl=false</pre></li> - * <li><pre>sun.java2d.noddraw=true</pre></li> - * </ul> - * This is especially true in case you want to utilize a GLProfile other than - * {@link GLProfile#GL2}, eg. using {@link GLProfile#getMaxFixedFunc()}.<br> - * On the other hand, if you like to experiment with GLJPanel's utilization - * of Java2D's OpenGL pipeline, you have to set them to - * <ul> - * <li><pre>sun.java2d.opengl=true</pre></li> - * <li><pre>sun.java2d.noddraw=true</pre></li> - * </ul> - * - * <h5><a name="backgrounderase">Disable Background Erase</a></h5> - * - * GLCanvas tries to disable background erase for the AWT Canvas - * before native peer creation (X11) and after it (Windows), <br> - * utilizing the optional {@link java.awt.Toolkit} method <code>disableBeackgroundErase(java.awt.Canvas)</code>.<br> - * However if this does not give you the desired results, you may want to disable AWT background erase in general: - * <ul> - * <li><pre>sun.awt.noerasebackground=true</pre></li> - * </ul> - * - * <p> - * <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a> - * To share a {@link GLContext} see the following note in the documentation overview: - * <a href="../../../../overview-summary.html#SHARING">context sharing</a> - * as well as {@link GLSharedContextSetter}. - * </p> - */ - -@SuppressWarnings("serial") -public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol, OffscreenLayerOption, - AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface { - - private static final boolean DEBUG = Debug.debug("GLCanvas"); - - private final RecursiveLock lock = LockFactory.createRecursiveLock(); - private final GLDrawableHelper helper = new GLDrawableHelper(); - private AWTGraphicsConfiguration awtConfig; - private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access - private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle - private volatile GLContextImpl context; // volatile: avoid locking for read-only access - private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking - private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; - - // copy of the cstr args, mainly for recreation - private final GLCapabilitiesImmutable capsReqUser; - private final GLCapabilitiesChooser chooser; - private int additionalCtxCreationFlags = 0; - private final GraphicsDevice device; - private boolean shallUseOffscreenLayer = false; - - private volatile boolean isShowing; - private final HierarchyListener hierarchyListener = new HierarchyListener() { - @Override - public void hierarchyChanged(final HierarchyEvent e) { - isShowing = GLCanvas.this.isShowing(); - } - }; - - private final AWTWindowClosingProtocol awtWindowClosingProtocol = - new AWTWindowClosingProtocol(this, new Runnable() { - @Override - public void run() { - GLCanvas.this.destroyImpl( true ); - } - }, null); - - /** Creates a new GLCanvas component with a default set of OpenGL - capabilities, using the default OpenGL capabilities selection - mechanism, on the default screen device. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no default profile is available for the default desktop device. - */ - public GLCanvas() throws GLException { - this(null); - } - - /** Creates a new GLCanvas component with the requested set of - OpenGL capabilities, using the default OpenGL capabilities - selection mechanism, on the default screen device. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device. - * @see GLCanvas#GLCanvas(com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesChooser, com.jogamp.opengl.GLContext, java.awt.GraphicsDevice) - */ - public GLCanvas(final GLCapabilitiesImmutable capsReqUser) throws GLException { - this(capsReqUser, null, null); - } - - /** Creates a new GLCanvas component. The passed GLCapabilities - specifies the OpenGL capabilities for the component; if null, a - default set of capabilities is used. The GLCapabilitiesChooser - specifies the algorithm for selecting one of the available - GLCapabilities for the component; a DefaultGLCapabilitesChooser - is used if null is passed for this argument. - The passed GraphicsDevice indicates the screen on - which to create the GLCanvas; the GLDrawableFactory uses the - default screen device of the local GraphicsEnvironment if null - is passed for this argument. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device. - */ - public GLCanvas(final GLCapabilitiesImmutable capsReqUser, - final GLCapabilitiesChooser chooser, - final GraphicsDevice device) - throws GLException - { - /* - * Determination of the native window is made in 'super.addNotify()', - * which creates the native peer using AWT's GraphicsConfiguration. - * GraphicsConfiguration is returned by this class overwritten - * 'getGraphicsConfiguration()', which returns our OpenGL compatible - * 'chosen' GraphicsConfiguration. - */ - super(); - - if(null==capsReqUser) { - this.capsReqUser = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice())); - } else { - // don't allow the user to change data - this.capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable(); - } - if( !this.capsReqUser.isOnscreen() ) { - setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported - } - - if(null==device) { - final GraphicsConfiguration gc = super.getGraphicsConfiguration(); - if(null!=gc) { - this.device = gc.getDevice(); - } else { - this.device = null; - } - } else { - this.device = device; - } - - // instantiation will be issued in addNotify() - this.chooser = chooser; - - this.addHierarchyListener(hierarchyListener); - this.isShowing = isShowing(); - } - - @Override - public final void setSharedContext(final GLContext sharedContext) throws IllegalStateException { - helper.setSharedContext(this.context, sharedContext); - } - - @Override - public final void setSharedAutoDrawable(final GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { - helper.setSharedAutoDrawable(this, sharedAutoDrawable); - } - - @Override - public final Object getUpstreamWidget() { - return this; - } - - @Override - public final RecursiveLock getUpstreamLock() { return lock; } - - @Override - public final boolean isThreadGLCapable() { return Threading.isOpenGLThread(); } - - @Override - public void setShallUseOffscreenLayer(final boolean v) { - shallUseOffscreenLayer = v; - } - - @Override - public final boolean getShallUseOffscreenLayer() { - return shallUseOffscreenLayer; - } - - @Override - public final boolean isOffscreenLayerSurfaceEnabled() { - final JAWTWindow _jawtWindow = jawtWindow; - if(null != _jawtWindow) { - return _jawtWindow.isOffscreenLayerSurfaceEnabled(); - } - return false; - } - - - /** - * Overridden to choose a GraphicsConfiguration on a parent container's - * GraphicsDevice because both devices - */ - @Override - public GraphicsConfiguration getGraphicsConfiguration() { - /* - * Workaround for problems with Xinerama and java.awt.Component.checkGD - * when adding to a container on a different graphics device than the - * one that this Canvas is associated with. - * - * GC will be null unless: - * - A native peer has assigned it. This means we have a native - * peer, and are already comitted to a graphics configuration. - * - This canvas has been added to a component hierarchy and has - * an ancestor with a non-null GC, but the native peer has not - * yet been created. This means we can still choose the GC on - * 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 - * constructor). - * - * if gc is from this Canvas' native peer then it should equal chosen, - * otherwise it is from an ancestor component that this Canvas is being - * added to, and we go into this block. - */ - GraphicsConfiguration chosen = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null; - - if (gc != null && chosen != null && !chosen.equals(gc)) { - /* - * Check for compatibility with gc. If they differ by only the - * device then return a new GCconfig with the super-class' GDevice - * (and presumably the same visual ID in Xinerama). - * - */ - if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) { - /* - * Here we select a GraphicsConfiguration on the alternate - * device that is presumably identical to the chosen - * configuration, but on the other device. - * - * Should really check to ensure that we select a configuration - * with the same X visual ID for Xinerama screens, otherwise the - * GLDrawable may have the wrong visual ID (I don't think this - * ever gets updated). May need to add a method to - * X11GLDrawableFactory to do this in a platform specific - * manner. - * - * However, on platforms where we can actually get into this - * block, both devices should have the same visual list, and the - * same configuration should be selected here. - */ - final AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(), - (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(), - chooser, gc.getDevice()); - final GraphicsConfiguration compatible = config.getAWTGraphicsConfiguration(); - final boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()); - if(DEBUG) { - System.err.println(getThreadName()+": Info:"); - System.err.println("Created Config (n): HAVE GC "+chosen); - System.err.println("Created Config (n): THIS GC "+gc); - System.err.println("Created Config (n): Choosen GC "+compatible); - System.err.println("Created Config (n): HAVE CF "+awtConfig); - System.err.println("Created Config (n): Choosen CF "+config); - System.err.println("Created Config (n): EQUALS CAPS "+equalCaps); - // Thread.dumpStack(); - } - - if (compatible != null) { - /* - * Save the new GC for equals test above, and to return to - * any outside callers of this method. - */ - chosen = compatible; - - if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) { - // complete destruction! - destroyImpl( true ); - // recreation! - awtConfig = config; - createJAWTDrawableAndContext(); - validateGLDrawable(); - } else { - awtConfig = config; - } - } - } - - /* - * If a compatible GC was not found in the block above, this will - * return the GC that was selected in the constructor (and might - * cause an exception in Component.checkGD when adding to a - * container, but in this case that would be the desired behavior). - * - */ - return chosen; - } else if (gc == null) { - /* - * The GC is null, which means we have no native peer, and are not - * part of a (realized) component hierarchy. So we return the - * desired visual that was selected in the constructor (possibly - * null). - */ - return chosen; - } - - /* - * Otherwise we have not explicitly selected a GC in the constructor, so - * just return what Canvas would have. - */ - return gc; - } - - @Override - public GLContext createContext(final GLContext shareWith) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if(drawable != null) { - final GLContext _ctx = drawable.createContext(shareWith); - _ctx.setContextCreationFlags(additionalCtxCreationFlags); - return _ctx; - } - return null; - } finally { - _lock.unlock(); - } - } - - private final void setRealizedImpl(final boolean realized) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLDrawable _drawable = drawable; - if( null == _drawable || realized == _drawable.isRealized() || - realized && ( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) ) { - return; - } - _drawable.setRealized(realized); - if( realized && _drawable.isRealized() ) { - sendReshape=true; // ensure a reshape is being send .. - } - } finally { - _lock.unlock(); - } - } - private final Runnable realizeOnEDTAction = new Runnable() { - @Override - public void run() { setRealizedImpl(true); } - }; - private final Runnable unrealizeOnEDTAction = new Runnable() { - @Override - public void run() { setRealizedImpl(false); } - }; - - @Override - public final void setRealized(final boolean realized) { - // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! - AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, realized ? realizeOnEDTAction : unrealizeOnEDTAction); - } - - @Override - public boolean isRealized() { - final GLDrawable _drawable = drawable; - return ( null != _drawable ) ? _drawable.isRealized() : false; - } - - @Override - public WindowClosingMode getDefaultCloseOperation() { - return awtWindowClosingProtocol.getDefaultCloseOperation(); - } - - @Override - public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { - return awtWindowClosingProtocol.setDefaultCloseOperation(op); - } - - @Override - public void display() { - if( !validateGLDrawable() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet"); - } - return; // not yet available .. - } - if( isShowing && !printActive ) { - Threading.invoke(true, displayOnEDTAction, getTreeLock()); - } - } - - /** - * {@inheritDoc} - * - * <p> - * 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() { - destroyImpl( false ); - } - - protected void destroyImpl(final 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 - repaint cycles. Subclasses which override this method must call - super.paint() in their paint() method in order to function - properly. - */ - @Override - public void paint(final Graphics g) { - if( Beans.isDesignTime() ) { - // Make GLCanvas behave better in NetBeans GUI builder - g.setColor(Color.BLACK); - g.fillRect(0, 0, getWidth(), getHeight()); - final FontMetrics fm = g.getFontMetrics(); - String name = getName(); - if (name == null) { - name = getClass().getName(); - final int idx = name.lastIndexOf('.'); - if (idx >= 0) { - name = name.substring(idx + 1); - } - } - final Rectangle2D bounds = fm.getStringBounds(name, g); - g.setColor(Color.WHITE); - g.drawString(name, - (int) ((getWidth() - bounds.getWidth()) / 2), - (int) ((getHeight() + bounds.getHeight()) / 2)); - } else if( !this.helper.isAnimatorAnimatingOnOtherThread() ) { - display(); - } - } - - /** Overridden to track when this component is added to a container. - Subclasses which override this method must call - super.addNotify() in their addNotify() method in order to - function properly. <P> - - <B>Overrides:</B> - <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - @SuppressWarnings("deprecation") - @Override - public void addNotify() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final boolean isBeansDesignTime = Beans.isDesignTime(); - - if(DEBUG) { - System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()+", isBeansDesignTime "+isBeansDesignTime); - // Thread.dumpStack(); - } - - 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(); - - createJAWTDrawableAndContext(); - - // 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()); - } - } finally { - _lock.unlock(); - } - } - - @Override - public final boolean setSurfaceScale(final float[] pixelScale) { - System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2); - if( isRealized() && isShowing ) { - Threading.invoke(true, setSurfaceScaleOnEDTAction, getTreeLock()); - return true; - } else { - return false; - } - } - private final Runnable setSurfaceScaleOnEDTAction = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( null != drawable && drawable.isRealized() ) { - if( setSurfaceScaleImpl(jawtWindow) ) { - reshapeImpl(getWidth(), getHeight()); - if( !helper.isAnimatorAnimatingOnOtherThread() ) { - helper.invokeGL(drawable, context, displayAction, initAction); // display - } - } - } - } finally { - _lock.unlock(); - } - } }; - private final boolean setSurfaceScaleImpl(final ScalableSurface ns) { - if( ns.setSurfaceScale(reqPixelScale) ) { - ns.getCurrentSurfaceScale(hasPixelScale); - return true; - } else { - return false; - } - } - - private final boolean updatePixelScale() { - if( jawtWindow.hasPixelScaleChanged() ) { - jawtWindow.getMaximumSurfaceScale(maxPixelScale); - jawtWindow.getMinimumSurfaceScale(minPixelScale); - return setSurfaceScaleImpl(jawtWindow); - } else { - return false; - } - } - - @Override - public final float[] getRequestedSurfaceScale(final float[] result) { - System.arraycopy(reqPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public final float[] getCurrentSurfaceScale(final float[] result) { - System.arraycopy(hasPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public float[] getMinimumSurfaceScale(final float[] result) { - System.arraycopy(minPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public float[] getMaximumSurfaceScale(final float[] result) { - System.arraycopy(maxPixelScale, 0, result, 0, 2); - return result; - } - - private void createJAWTDrawableAndContext() { - if ( !Beans.isDesignTime() ) { - jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); - jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); - jawtWindow.lockSurface(); - try { - jawtWindow.setSurfaceScale(reqPixelScale); - drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow); - createContextImpl(drawable); - jawtWindow.getCurrentSurfaceScale(hasPixelScale); - jawtWindow.getMinimumSurfaceScale(minPixelScale); - jawtWindow.getMaximumSurfaceScale(maxPixelScale); - } finally { - jawtWindow.unlockSurface(); - } - } - } - private boolean createContextImpl(final GLDrawable drawable) { - final GLContext[] shareWith = { null }; - if( !helper.isSharedGLContextPending(shareWith) ) { - context = (GLContextImpl) drawable.createContext(shareWith[0]); - context.setContextCreationFlags(additionalCtxCreationFlags); - if(DEBUG) { - System.err.println(getThreadName()+": Context created: has shared "+(null != shareWith[0])); - } - return true; - } else { - if(DEBUG) { - System.err.println(getThreadName()+": Context !created: pending share"); - } - return false; - } - } - - private boolean validateGLDrawable() { - if( Beans.isDesignTime() || !isDisplayable() ) { - return false; // early out! - } - final GLDrawable _drawable = drawable; - if ( null != _drawable ) { - boolean res = _drawable.isRealized(); - if( !res ) { - // re-try drawable creation - if( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) { - return false; // early out! - } - setRealized(true); - res = _drawable.isRealized(); - if(DEBUG) { - System.err.println(getThreadName()+": Realized Drawable: isRealized "+res+", "+_drawable.toString()); - // Thread.dumpStack(); - } - } - if( res && null == context ) { - // re-try context creation - res = createContextImpl(_drawable); // pending creation. - } - return res; - } - return false; - } - - /** <p>Overridden to track when this component is removed from a - container. Subclasses which override this method must call - super.removeNotify() in their removeNotify() method in order to - function properly. </p> - <p>User shall not call this method outside of EDT, read the AWT/Swing specs - about this.</p> - <B>Overrides:</B> - <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - @SuppressWarnings("deprecation") - @Override - public void removeNotify() { - if(DEBUG) { - System.err.println(getThreadName()+": Info: removeNotify - start"); - // Thread.dumpStack(); - } - - awtWindowClosingProtocol.removeClosingListener(); - - if( Beans.isDesignTime() ) { - super.removeNotify(); - } else { - try { - destroyImpl( true ); - } finally { - super.removeNotify(); - } - } - if(DEBUG) { - System.err.println(getThreadName()+": Info: removeNotify - end, peer: "+getPeer()); - } - } - - /** Overridden to cause {@link GLDrawableHelper#reshape} to be - called on all registered {@link GLEventListener}s. Subclasses - which override this method must call super.reshape() in - their reshape() method in order to function properly. <P> - - <B>Overrides:</B> - <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - @SuppressWarnings("deprecation") - @Override - public void reshape(final int x, final int y, final int width, final int height) { - synchronized (getTreeLock()) { // super.reshape(..) claims tree lock, so we do extend it's lock over reshape - super.reshape(x, y, width, height); - reshapeImpl(width, height); - } - } - private void reshapeImpl(final int width, final int height) { - final int scaledWidth = SurfaceScaleUtils.scale(width, hasPixelScale[0]); - final int scaledHeight = SurfaceScaleUtils.scale(height, hasPixelScale[1]); - - if(DEBUG) { - final NativeSurface ns = getNativeSurface(); - final long nsH = null != ns ? ns.getSurfaceHandle() : 0; - System.err.println(getThreadName()+": GLCanvas.reshape.0 "+this.getName()+" resize"+(printActive?"WithinPrint":"")+ - " [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+ - "] -> "+(printActive?"[skipped] ":"") + width+"x"+height+" * "+getPixelScaleStr()+" -> "+scaledWidth+"x"+scaledHeight+ - " - surfaceHandle 0x"+Long.toHexString(nsH)); - // Thread.dumpStack(); - } - if( validateGLDrawable() && !printActive ) { - final GLDrawableImpl _drawable = drawable; - if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, scaledWidth, scaledHeight); - if(_drawable != _drawableNew) { - // write back - drawable = _drawableNew; - } - } finally { - _lock.unlock(); - } - } - sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock - } - } - - /** - * Overridden from Canvas to prevent the AWT's clearing of the - * canvas from interfering with the OpenGL rendering. - */ - @Override - public void update(final Graphics g) { - paint(g); - } - - private volatile boolean printActive = false; - private GLAnimatorControl printAnimator = null; - private GLAutoDrawable printGLAD = null; - private AWTTilePainter printAWTTiles = null; - - @Override - public void setupPrint(final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final int tileHeight) { - printActive = true; - final int componentCount = isOpaque() ? 3 : 4; - final TileRenderer printRenderer = new TileRenderer(); - printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG); - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT); - } - private final Runnable setupPrintOnEDT = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( !validateGLDrawable() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet"); - } - printActive = false; - return; // not yet available .. - } - if( !isVisible() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible"); - } - printActive = false; - return; // not yet available .. - } - sendReshape = false; // clear reshape flag - printAnimator = helper.getAnimator(); - if( null != printAnimator ) { - printAnimator.remove(GLCanvas.this); - } - printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD - final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); - final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); - GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); - final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); - final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || - printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); - final boolean reqNewGLADOnscrn = gladCaps.isOnscreen(); - - final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); - newGLADCaps.setDoubleBuffered(false); - newGLADCaps.setOnscreen(false); - if( printNumSamples != newGLADCaps.getNumSamples() ) { - newGLADCaps.setSampleBuffers(0 < printNumSamples); - newGLADCaps.setNumSamples(printNumSamples); - } - final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); - - final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; - - if( DEBUG ) { - System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ - ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ - ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ - ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ - ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); - } - if( reqNewGLAD ) { - final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); - GLOffscreenAutoDrawable offGLAD = null; - try { - offGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, - printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, - printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); - } catch (final GLException gle) { - if( DEBUG ) { - System.err.println("Caught: "+gle.getMessage()); - gle.printStackTrace(); - } - } - if( null != offGLAD ) { - printGLAD = offGLAD; - GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD); - printDrawable = printGLAD.getDelegatedDrawable(); - } - } - printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented()); - printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); - printAWTTiles.renderer.attachAutoDrawable(printGLAD); - if( DEBUG ) { - System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); - System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); - System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); - } - } finally { - _lock.unlock(); - } - } - }; - - @Override - public void releasePrint() { - if( !printActive || null == printGLAD ) { - throw new IllegalStateException("setupPrint() not called"); - } - sendReshape = false; // clear reshape flag - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT); - } - private final Runnable releasePrintOnEDT = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( DEBUG ) { - System.err.println("AWT print.release "+printAWTTiles); - } - printAWTTiles.dispose(); - printAWTTiles= null; - if( printGLAD != GLCanvas.this ) { - GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this); - printGLAD.destroy(); - } - printGLAD = null; - if( null != printAnimator ) { - printAnimator.add(GLCanvas.this); - printAnimator = null; - } - sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! - printActive = false; - display(); - } finally { - _lock.unlock(); - } - } - }; - - @Override - public void print(final Graphics graphics) { - if( !printActive || null == printGLAD ) { - throw new IllegalStateException("setupPrint() not called"); - } - if(DEBUG && !EventQueue.isDispatchThread()) { - System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT"); - // we cannot dispatch print on AWT-EDT due to printing internal locking .. - } - sendReshape = false; // clear reshape flag - - final Graphics2D g2d = (Graphics2D)graphics; - try { - printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight()); - final TileRenderer tileRenderer = printAWTTiles.renderer; - if( DEBUG ) { - System.err.println("AWT print.0: "+tileRenderer); - } - if( !tileRenderer.eot() ) { - try { - do { - if( printGLAD != GLCanvas.this ) { - tileRenderer.display(); - } else { - Threading.invoke(true, displayOnEDTAction, getTreeLock()); - } - } while ( !tileRenderer.eot() ); - if( DEBUG ) { - System.err.println("AWT print.1: "+printAWTTiles); - } - } finally { - tileRenderer.reset(); - printAWTTiles.resetGraphics2D(); - } - } - } catch (final NoninvertibleTransformException nte) { - System.err.println("Caught: Inversion failed of: "+g2d.getTransform()); - nte.printStackTrace(); - } - if( DEBUG ) { - System.err.println("AWT print.X: "+printAWTTiles); - } - } - - @Override - public void addGLEventListener(final GLEventListener listener) { - helper.addGLEventListener(listener); - } - - @Override - public void addGLEventListener(final int index, final GLEventListener listener) throws IndexOutOfBoundsException { - helper.addGLEventListener(index, listener); - } - - @Override - public int getGLEventListenerCount() { - return helper.getGLEventListenerCount(); - } - - @Override - public GLEventListener getGLEventListener(final int index) throws IndexOutOfBoundsException { - return helper.getGLEventListener(index); - } - - @Override - public boolean areAllGLEventListenerInitialized() { - return helper.areAllGLEventListenerInitialized(); - } - - @Override - public boolean getGLEventListenerInitState(final GLEventListener listener) { - return helper.getGLEventListenerInitState(listener); - } - - @Override - public void setGLEventListenerInitState(final GLEventListener listener, final boolean initialized) { - helper.setGLEventListenerInitState(listener, initialized); - } - - @Override - public GLEventListener disposeGLEventListener(final GLEventListener listener, final boolean remove) { - final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove); - Threading.invoke(true, r, getTreeLock()); - return r.listener; - } - - @Override - public GLEventListener removeGLEventListener(final GLEventListener listener) { - return helper.removeGLEventListener(listener); - } - - @Override - public void setAnimator(final GLAnimatorControl animatorControl) { - helper.setAnimator(animatorControl); - } - - @Override - public GLAnimatorControl getAnimator() { - return helper.getAnimator(); - } - - @Override - public final Thread setExclusiveContextThread(final Thread t) throws GLException { - return helper.setExclusiveContextThread(t, context); - } - - @Override - public final Thread getExclusiveContextThread() { - return helper.getExclusiveContextThread(); - } - - @Override - public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException { - return helper.invoke(this, wait, glRunnable); - } - - @Override - public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException { - return helper.invoke(this, wait, glRunnables); - } - - @Override - public void flushGLRunnables() { - helper.flushGLRunnables(); - } - - @Override - public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLContext oldCtx = context; - GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); - context=(GLContextImpl)newCtx; - return oldCtx; - } finally { - _lock.unlock(); - } - } - - @Override - public final GLDrawable getDelegatedDrawable() { - return drawable; - } - - @Override - public GLContext getContext() { - return context; - } - - @Override - public GL getGL() { - if( Beans.isDesignTime() ) { - return null; - } - final GLContext _context = context; - return (_context == null) ? null : _context.getGL(); - } - - @Override - public GL setGL(final GL gl) { - final GLContext _context = context; - if (_context != null) { - _context.setGL(gl); - return gl; - } - return null; - } - - - @Override - public void setAutoSwapBufferMode(final boolean onOrOff) { - helper.setAutoSwapBufferMode(onOrOff); - } - - @Override - public boolean getAutoSwapBufferMode() { - return helper.getAutoSwapBufferMode(); - } - - @Override - public void swapBuffers() { - Threading.invoke(true, swapBuffersOnEDTAction, getTreeLock()); - } - - @Override - public void setContextCreationFlags(final int flags) { - additionalCtxCreationFlags = flags; - final GLContext _context = context; - if(null != _context) { - _context.setContextCreationFlags(additionalCtxCreationFlags); - } - } - - @Override - public int getContextCreationFlags() { - return additionalCtxCreationFlags; - } - - @Override - public GLProfile getGLProfile() { - return capsReqUser.getGLProfile(); - } - - @Override - public GLCapabilitiesImmutable getChosenGLCapabilities() { - if( Beans.isDesignTime() ) { - return capsReqUser; - } else if( null == awtConfig ) { - throw new GLException("No AWTGraphicsConfiguration: "+this); - } - return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(); - } - - @Override - public GLCapabilitiesImmutable getRequestedGLCapabilities() { - if( null == awtConfig ) { - return capsReqUser; - } - return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(); - } - - @Override - public int getSurfaceWidth() { - return SurfaceScaleUtils.scale(getWidth(), hasPixelScale[0]); - } - - @Override - public int getSurfaceHeight() { - return SurfaceScaleUtils.scale(getHeight(), hasPixelScale[1]); - } - - @Override - public boolean isGLOriented() { - final GLDrawable _drawable = drawable; - return null != _drawable ? _drawable.isGLOriented() : true; - } - - @Override - public NativeSurface getNativeSurface() { - final GLDrawable _drawable = drawable; - return (null != _drawable) ? _drawable.getNativeSurface() : null; - } - - @Override - public long getHandle() { - final GLDrawable _drawable = drawable; - return (null != _drawable) ? _drawable.getHandle() : 0; - } - - @Override - public GLDrawableFactory getFactory() { - final GLDrawable _drawable = drawable; - return (null != _drawable) ? _drawable.getFactory() : null; - } - - @Override - public String toString() { - final GLDrawable _drawable = drawable; - final int dw = (null!=_drawable) ? _drawable.getSurfaceWidth() : -1; - final int dh = (null!=_drawable) ? _drawable.getSurfaceHeight() : -1; - - return "AWT-GLCanvas[Realized "+isRealized()+ - ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ - ",\n\tFactory "+getFactory()+ - ",\n\thandle 0x"+Long.toHexString(getHandle())+ - ",\n\tDrawable size "+dw+"x"+dh+" surface["+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ - ",\n\tAWT[pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ - ",\n\tvisible "+isVisible()+", displayable "+isDisplayable()+", showing "+isShowing+ - ",\n\t"+awtConfig+"]]"; - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private final String getPixelScaleStr() { return "["+hasPixelScale[0]+", "+hasPixelScale[1]+"]"; } - - private final Runnable destroyOnEDTAction = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLAnimatorControl animator = getAnimator(); - - if(DEBUG) { - 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() - animatorPaused = animator.pause(); - } else { - animatorPaused = false; - } - - GLException exceptionOnDisposeGL = null; - - // OLS will be detached by disposeGL's context destruction below - if( null != context ) { - if( context.isCreated() ) { - try { - helper.disposeGL(GLCanvas.this, context, true); - if(DEBUG) { - System.err.println(getThreadName()+": destroyOnEDTAction() - post ctx: "+context); - } - } catch (final GLException gle) { - exceptionOnDisposeGL = gle; - } - } - context = null; - } - - Throwable exceptionOnUnrealize = null; - if( null != drawable ) { - try { - drawable.setRealized(false); - if(DEBUG) { - System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable); - } - } catch( final Throwable re ) { - exceptionOnUnrealize = re; - } - drawable = null; - } - - if(animatorPaused) { - animator.resume(); - } - - // throw exception in order of occurrence .. - if( null != exceptionOnDisposeGL ) { - throw exceptionOnDisposeGL; - } - if( null != exceptionOnUnrealize ) { - throw GLException.newGLException(exceptionOnUnrealize); - } - - if(DEBUG) { - System.err.println(getThreadName()+": dispose() - END, animator "+animator); - } - - } finally { - _lock.unlock(); - } - } - }; - - /** - * 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(com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice) - */ - private final Runnable disposeJAWTWindowAndAWTDeviceOnEDT = new Runnable() { - @Override - public void run() { - context=null; - drawable=null; - - if( null != jawtWindow ) { - jawtWindow.destroy(); - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow); - } - jawtWindow=null; - } - hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - - 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; - } - final boolean closed = adevice.close(); - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed); - } - } - awtConfig=null; - } - }; - - private final Runnable initAction = new Runnable() { - @Override - public void run() { - helper.init(GLCanvas.this, !sendReshape); - } - }; - - private final Runnable displayAction = new Runnable() { - @Override - public void run() { - if (sendReshape) { - if(DEBUG) { - System.err.println(getThreadName()+": Reshape: "+getSurfaceWidth()+"x"+getSurfaceHeight()); - } - // Note: we ignore the given x and y within the parent component - // since we are drawing directly into this heavyweight component. - helper.reshape(GLCanvas.this, 0, 0, getSurfaceWidth(), getSurfaceHeight()); - sendReshape = false; - } - - helper.display(GLCanvas.this); - } - }; - - private final Runnable displayOnEDTAction = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( null != drawable && drawable.isRealized() ) { - if( GLCanvas.this.updatePixelScale() ) { - GLCanvas.this.reshapeImpl(getWidth(), getHeight()); - } - helper.invokeGL(drawable, context, displayAction, initAction); - } - } finally { - _lock.unlock(); - } - } - }; - - private final Runnable swapBuffersOnEDTAction = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( null != drawable && drawable.isRealized() ) { - drawable.swapBuffers(); - } - } finally { - _lock.unlock(); - } - } - }; - - private class DisposeGLEventListenerAction implements Runnable { - GLEventListener listener; - private final boolean remove; - private DisposeGLEventListenerAction(final GLEventListener listener, final boolean remove) { - this.listener = listener; - this.remove = remove; - } - - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove); - } finally { - _lock.unlock(); - } - } - }; - - // Disables the AWT's erasing of this Canvas's background on Windows - // in Java SE 6. This internal API is not available in previous - // releases, but the system property - // -Dsun.awt.noerasebackground=true can be specified to get similar - // results globally in previous releases. - private static boolean disableBackgroundEraseInitialized; - private static Method disableBackgroundEraseMethod; - private void disableBackgroundErase() { - if (!disableBackgroundEraseInitialized) { - try { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - try { - Class<?> clazz = getToolkit().getClass(); - while (clazz != null && disableBackgroundEraseMethod == null) { - try { - disableBackgroundEraseMethod = - clazz.getDeclaredMethod("disableBackgroundErase", - new Class[] { Canvas.class }); - disableBackgroundEraseMethod.setAccessible(true); - } catch (final Exception e) { - clazz = clazz.getSuperclass(); - } - } - } catch (final Exception e) { - } - return null; - } - }); - } catch (final Exception e) { - } - disableBackgroundEraseInitialized = true; - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase method found: "+ - (null!=disableBackgroundEraseMethod)); - } - } - if (disableBackgroundEraseMethod != null) { - Throwable t=null; - try { - disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this }); - } catch (final Exception e) { - t = e; - } - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase error: "+t); - } - } - } - - /** - * Issues the GraphicsConfigurationFactory's choosing facility within EDT, - * since resources created (X11: Display), must be destroyed in the same thread, where they have been created. - * - * @param capsChosen - * @param capsRequested - * @param chooser - * @param device - * @return the chosen AWTGraphicsConfiguration - * - * @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() ) { - return null; - } - - final AbstractGraphicsScreen aScreen = null != device ? - AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT): - AWTGraphicsScreen.createDefault(); - AWTGraphicsConfiguration config = null; - - if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { - config = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, - capsRequested, - chooser, aScreen, VisualIDHolder.VID_UNDEFINED); - } else { - try { - final ArrayList<AWTGraphicsConfiguration> bucket = new ArrayList<AWTGraphicsConfiguration>(1); - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - final AWTGraphicsConfiguration c = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, - capsRequested, - chooser, aScreen, VisualIDHolder.VID_UNDEFINED); - bucket.add(c); - } - }); - config = ( bucket.size() > 0 ) ? bucket.get(0) : null ; - } catch (final InvocationTargetException e) { - throw new GLException(e.getTargetException()); - } catch (final InterruptedException e) { - throw new GLException(e); - } - } - - if ( null == config ) { - throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration"); - } - - return config; - } - - protected static String getThreadName() { return Thread.currentThread().getName(); } - - /** - * A most simple JOGL AWT test entry - */ - public static void main(final String args[]) { - System.err.println(VersionUtil.getPlatformInfo()); - System.err.println(GlueGenVersion.getInstance()); - // System.err.println(NativeWindowVersion.getInstance()); - System.err.println(JoglVersion.getInstance()); - - System.err.println(JoglVersion.getDefaultOpenGLInfo(null, null, true).toString()); - - final GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDevice()) ); - final Frame frame = new Frame("JOGL AWT Test"); - - final GLCanvas glCanvas = new GLCanvas(caps); - frame.add(glCanvas); - frame.setSize(128, 128); - - glCanvas.addGLEventListener(new GLEventListener() { - @Override - public void init(final GLAutoDrawable drawable) { - final GL gl = drawable.getGL(); - System.err.println(JoglVersion.getGLInfo(gl, null)); - } - @Override - public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } - @Override - public void display(final GLAutoDrawable drawable) { } - @Override - public void dispose(final GLAutoDrawable drawable) { } - }); - - try { - javax.swing.SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - frame.setVisible(true); - }}); - } catch (final Throwable t) { - t.printStackTrace(); - } - glCanvas.display(); - try { - javax.swing.SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - frame.dispose(); - }}); - } catch (final Throwable t) { - t.printStackTrace(); - } - } - -} diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java deleted file mode 100644 index 91b2f5e0c..000000000 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ /dev/null @@ -1,2689 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package com.jogamp.opengl.awt; - -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsEnvironment; -import java.awt.Rectangle; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.beans.Beans; -import java.nio.IntBuffer; -import java.util.List; - -import com.jogamp.nativewindow.AbstractGraphicsDevice; -import com.jogamp.nativewindow.NativeSurface; -import com.jogamp.nativewindow.ScalableSurface; -import com.jogamp.nativewindow.SurfaceUpdatedListener; -import com.jogamp.nativewindow.WindowClosingProtocol; -import com.jogamp.nativewindow.util.PixelFormat; -import com.jogamp.opengl.GL; -import com.jogamp.opengl.GL2; -import com.jogamp.opengl.GL2ES3; -import com.jogamp.opengl.GL2GL3; -import com.jogamp.opengl.GLAnimatorControl; -import com.jogamp.opengl.GLAutoDrawable; -import com.jogamp.opengl.GLCapabilities; -import com.jogamp.opengl.GLCapabilitiesChooser; -import com.jogamp.opengl.GLCapabilitiesImmutable; -import com.jogamp.opengl.GLContext; -import com.jogamp.opengl.GLDrawable; -import com.jogamp.opengl.GLDrawableFactory; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLException; -import com.jogamp.opengl.GLFBODrawable; -import com.jogamp.opengl.GLOffscreenAutoDrawable; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.GLRunnable; -import com.jogamp.opengl.GLSharedContextSetter; -import com.jogamp.opengl.Threading; -import javax.swing.JPanel; - -import jogamp.nativewindow.SurfaceScaleUtils; -import jogamp.nativewindow.WrappedSurface; -import jogamp.nativewindow.jawt.JAWTUtil; -import jogamp.opengl.Debug; -import jogamp.opengl.GLContextImpl; -import jogamp.opengl.GLDrawableFactoryImpl; -import jogamp.opengl.GLDrawableHelper; -import jogamp.opengl.GLDrawableImpl; -import jogamp.opengl.awt.AWTTilePainter; -import jogamp.opengl.awt.Java2D; -import jogamp.opengl.util.glsl.GLSLTextureRaster; - -import com.jogamp.common.util.PropertyAccess; -import com.jogamp.common.util.awt.AWTEDTExecutor; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; -import com.jogamp.nativewindow.awt.AWTPrintLifecycle; -import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; -import com.jogamp.opengl.FBObject; -import com.jogamp.opengl.GLRendererQuirks; -import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; -import com.jogamp.opengl.util.GLPixelBuffer.SingletonGLPixelBufferProvider; -import com.jogamp.opengl.util.GLDrawableUtil; -import com.jogamp.opengl.util.GLPixelStorageModes; -import com.jogamp.opengl.util.TileRenderer; -import com.jogamp.opengl.util.awt.AWTGLPixelBuffer; -import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider; -import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvider; -import com.jogamp.opengl.util.texture.TextureState; - -/** A lightweight Swing component which provides OpenGL rendering - support. Provided for compatibility with Swing user interfaces - when adding a heavyweight doesn't work either because of - Z-ordering or LayoutManager problems. - <p> - The GLJPanel can be made transparent by creating it with a - GLCapabilities object with alpha bits specified and calling {@link - #setOpaque}(false). Pixels with resulting OpenGL alpha values less - than 1.0 will be overlaid on any underlying Swing rendering. - </p> - <p> - This component attempts to use hardware-accelerated rendering via FBO or pbuffers and - falls back on to software rendering if none of the former are available - using {@link GLDrawableFactory#createOffscreenDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int) GLDrawableFactory.createOffscreenDrawable(..)}.<br/> - </p> - <p> - <a name="verticalFlip">A vertical-flip is required</a>, if the drawable {@link #isGLOriented()} and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}.<br> - In this case this component performs the required vertical flip to bring the content from OpenGL's orientation into AWT's orientation.<br> - In case <a href="#fboGLSLVerticalFlip">GLSL based vertical-flip</a> is not available, - the CPU intensive {@link System#arraycopy(Object, int, Object, int, int) System.arraycopy(..)} is used line by line. - See details about <a href="#fboGLSLVerticalFlip">FBO and GLSL vertical flipping</a>. - </p> - <p> - For performance reasons, as well as for <a href="#bug842">GL state sideeffects</a>, - <b>{@link #setSkipGLOrientationVerticalFlip(boolean) skipping vertical flip} is highly recommended</b>! - </p> - <p> - The OpenGL path is concluded by copying the rendered pixels an {@link BufferedImage} via {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)} - for later Java2D composition. - </p> - <p> - Finally the Java2D compositioning takes place via via {@link Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver) Graphics.drawImage(...)} - on the prepared {@link BufferedImage} as described above. - </p> - <P> - * Please read <a href="GLCanvas.html#java2dgl">Java2D OpenGL Remarks</a>. - * </P> - * - <a name="fboGLSLVerticalFlip"><h5>FBO / GLSL Vertical Flip</h5></a> - If <a href="#verticalFlip">vertical flip is required</a>, - FBO is used, GLSL is available and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}, a fragment shader is utilized - to flip the FBO texture vertically. This hardware-accelerated step can be disabled via system property <code>jogl.gljpanel.noglsl</code>. - <p> - The FBO / GLSL code path uses one texture-unit and binds the FBO texture to it's active texture-target, - see {@link #setTextureUnit(int)} and {@link #getTextureUnit()}. - </p> - <p> - The active and dedicated texture-unit's {@link GL#GL_TEXTURE_2D} state is preserved via {@link TextureState}. - See also {@link Texture#textureCallOrder Order of Texture Commands}. - </p> - <p> - The current gl-viewport is preserved. - </p> - <p> - <a name="bug842"><i>Warning (Bug 842)</i></a>: Certain GL states other than viewport and texture (see above) - influencing rendering, will also influence the GLSL vertical flip, e.g. {@link GL#glFrontFace(int) glFrontFace}({@link GL#GL_CCW}). - It is recommended to reset those states to default when leaving the {@link GLEventListener#display(GLAutoDrawable)} method! - We may change this behavior in the future, i.e. preserve all influencing states. - </p> - <p> - <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a> - To share a {@link GLContext} see the following note in the documentation overview: - <a href="../../../../overview-summary.html#SHARING">context sharing</a> - as well as {@link GLSharedContextSetter}. - </p> -*/ - -@SuppressWarnings("serial") -public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol, AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface { - private static final boolean DEBUG; - private static final boolean DEBUG_FRAMES; - private static final boolean DEBUG_VIEWPORT; - private static final boolean USE_GLSL_TEXTURE_RASTERIZER; - private static final boolean SKIP_VERTICAL_FLIP_DEFAULT; - - /** Indicates whether the Java 2D OpenGL pipeline is requested by user. */ - private static final boolean java2dOGLEnabledByProp; - - /** Indicates whether the Java 2D OpenGL pipeline is enabled, resource-compatible and requested by user. */ - private static final boolean useJava2DGLPipeline; - - /** Indicates whether the Java 2D OpenGL pipeline's usage is error free. */ - private static boolean java2DGLPipelineOK; - - static { - Debug.initSingleton(); - DEBUG = Debug.debug("GLJPanel"); - DEBUG_FRAMES = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Frames", true); - DEBUG_VIEWPORT = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true); - USE_GLSL_TEXTURE_RASTERIZER = !PropertyAccess.isPropertyDefined("jogl.gljpanel.noglsl", true); - SKIP_VERTICAL_FLIP_DEFAULT = PropertyAccess.isPropertyDefined("jogl.gljpanel.noverticalflip", true); - boolean enabled = PropertyAccess.getBooleanProperty("sun.java2d.opengl", false); - java2dOGLEnabledByProp = enabled && !PropertyAccess.isPropertyDefined("jogl.gljpanel.noogl", true); - - enabled = false; - if( java2dOGLEnabledByProp ) { - // 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.isOGLPipelineResourceCompatible() && Java2D.isFBOEnabled()) { - if( null != Java2D.getShareContext(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()) ) { - enabled = true; - } - } - } - useJava2DGLPipeline = enabled; - java2DGLPipelineOK = enabled; - if( DEBUG ) { - System.err.println("GLJPanel: DEBUG_VIEWPORT "+DEBUG_VIEWPORT); - System.err.println("GLJPanel: USE_GLSL_TEXTURE_RASTERIZER "+USE_GLSL_TEXTURE_RASTERIZER); - System.err.println("GLJPanel: SKIP_VERTICAL_FLIP_DEFAULT "+SKIP_VERTICAL_FLIP_DEFAULT); - System.err.println("GLJPanel: java2dOGLEnabledByProp "+java2dOGLEnabledByProp); - System.err.println("GLJPanel: useJava2DGLPipeline "+useJava2DGLPipeline); - System.err.println("GLJPanel: java2DGLPipelineOK "+java2DGLPipelineOK); - } - } - - private static SingleAWTGLPixelBufferProvider singleAWTGLPixelBufferProvider = null; - private static synchronized SingleAWTGLPixelBufferProvider getSingleAWTGLPixelBufferProvider() { - if( null == singleAWTGLPixelBufferProvider ) { - singleAWTGLPixelBufferProvider = new SingleAWTGLPixelBufferProvider( true /* allowRowStride */ ); - } - return singleAWTGLPixelBufferProvider; - } - - private final RecursiveLock lock = LockFactory.createRecursiveLock(); - - private final GLDrawableHelper helper; - private boolean autoSwapBufferMode; - - private volatile boolean isInitialized; - - // - // Data used for either pbuffers or pixmap-based offscreen surfaces - // - private AWTGLPixelBufferProvider customPixelBufferProvider = null; - /** Requested single buffered offscreen caps */ - private volatile GLCapabilitiesImmutable reqOffscreenCaps; - private volatile GLDrawableFactoryImpl factory; - private final GLCapabilitiesChooser chooser; - private int additionalCtxCreationFlags = 0; - - // Lazy reshape notification: reshapeWidth -> panelWidth -> backend.width - private boolean handleReshape = false; - private boolean sendReshape = true; - - private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - private final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; - - /** For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width in pixel units (scaled) */ - private int reshapeWidth; - /** For handling reshape events lazily: reshapeHeight -> panelHeight -> backend.height in pixel units (scaled) */ - private int reshapeHeight; - - /** Scaled pixel width of the actual GLJPanel: reshapeWidth -> panelWidth -> backend.width */ - private int panelWidth = 0; - /** Scaled pixel height of the actual GLJPanel: reshapeHeight -> panelHeight -> backend.height */ - private int panelHeight = 0; - - // These are always set to (0, 0) except when the Java2D / OpenGL - // pipeline is active - private int viewportX; - private int viewportY; - - private int requestedTextureUnit = 0; // default - - // The backend in use - private volatile Backend backend; - - private boolean skipGLOrientationVerticalFlip = SKIP_VERTICAL_FLIP_DEFAULT; - - // Used by all backends either directly or indirectly to hook up callbacks - private final Updater updater = new Updater(); - - private boolean oglPipelineUsable() { - return null == customPixelBufferProvider && useJava2DGLPipeline && java2DGLPipelineOK; - } - - private volatile boolean isShowing; - private final HierarchyListener hierarchyListener = new HierarchyListener() { - @Override - public void hierarchyChanged(final HierarchyEvent e) { - isShowing = GLJPanel.this.isShowing(); - } - }; - - private final AWTWindowClosingProtocol awtWindowClosingProtocol = - new AWTWindowClosingProtocol(this, new Runnable() { - @Override - public void run() { - GLJPanel.this.destroy(); - } - }, null); - - /** Creates a new GLJPanel component with a default set of OpenGL - capabilities and using the default OpenGL capabilities selection - mechanism. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no default profile is available for the default desktop device. - */ - public GLJPanel() throws GLException { - this(null); - } - - /** Creates a new GLJPanel component with the requested set of - OpenGL capabilities, using the default OpenGL capabilities - selection mechanism. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device. - */ - public GLJPanel(final GLCapabilitiesImmutable userCapsRequest) throws GLException { - this(userCapsRequest, null); - } - - /** Creates a new GLJPanel component. The passed GLCapabilities - specifies the OpenGL capabilities for the component; if null, a - default set of capabilities is used. The GLCapabilitiesChooser - specifies the algorithm for selecting one of the available - GLCapabilities for the component; a DefaultGLCapabilitesChooser - is used if null is passed for this argument. - <p> - See details about <a href="#contextSharing">OpenGL context sharing</a>. - </p> - * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device. - */ - public GLJPanel(final GLCapabilitiesImmutable userCapsRequest, final GLCapabilitiesChooser chooser) - throws GLException - { - super(); - - // Works around problems on many vendors' cards; we don't need a - // back buffer for the offscreen surface anyway - { - GLCapabilities caps; - if (userCapsRequest != null) { - caps = (GLCapabilities) userCapsRequest.cloneMutable(); - } else { - caps = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice())); - } - caps.setDoubleBuffered(false); - reqOffscreenCaps = caps; - } - this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // pre-fetch, reqOffscreenCaps may changed - this.chooser = chooser; - - helper = new GLDrawableHelper(); - autoSwapBufferMode = helper.getAutoSwapBufferMode(); - - this.setFocusable(true); // allow keyboard input! - this.addHierarchyListener(hierarchyListener); - this.isShowing = isShowing(); - } - - /** - * Attempts to initialize the backend, if not initialized yet. - * <p> - * If backend is already initialized method returns <code>true</code>. - * </p> - * <p> - * If <code>offthread</code> is <code>true</code>, initialization will kicked off - * on a <i>short lived</i> arbitrary thread and method returns immediately.<br/> - * If platform supports such <i>arbitrary thread</i> initialization method returns - * <code>true</code>, otherwise <code>false</code>. - * </p> - * <p> - * If <code>offthread</code> is <code>false</code>, initialization be performed - * on the current thread and method returns after initialization.<br/> - * Method returns <code>true</code> if initialization was successful, otherwise <code>false</code>. - * <p> - * @param offthread - */ - public final boolean initializeBackend(final boolean offthread) { - if( offthread ) { - new Thread(getThreadName()+"-GLJPanel_Init") { - public void run() { - if( !isInitialized ) { - initializeBackendImpl(); - } - } }.start(); - return true; - } else { - if( !isInitialized ) { - return initializeBackendImpl(); - } else { - return true; - } - } - } - - @Override - public final void setSharedContext(final GLContext sharedContext) throws IllegalStateException { - helper.setSharedContext(this.getContext(), sharedContext); - } - - @Override - public final void setSharedAutoDrawable(final GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { - helper.setSharedAutoDrawable(this, sharedAutoDrawable); - } - - public AWTGLPixelBufferProvider getCustomPixelBufferProvider() { return customPixelBufferProvider; } - - /** - * @param custom custom {@link AWTGLPixelBufferProvider} - * @throws IllegalArgumentException if <code>custom</code> is <code>null</code> - * @throws IllegalStateException if backend is already realized, i.e. this instanced already painted once. - */ - public void setPixelBufferProvider(final AWTGLPixelBufferProvider custom) throws IllegalArgumentException, IllegalStateException { - if( null == custom ) { - throw new IllegalArgumentException("Null PixelBufferProvider"); - } - if( null != backend ) { - throw new IllegalStateException("Backend already realized."); - } - customPixelBufferProvider = custom; - } - - @Override - public final Object getUpstreamWidget() { - return this; - } - - @Override - public final RecursiveLock getUpstreamLock() { return lock; } - - @Override - public final boolean isThreadGLCapable() { return EventQueue.isDispatchThread(); } - - @Override - public void display() { - if( isShowing || ( printActive && isVisible() ) ) { - if (EventQueue.isDispatchThread()) { - // Want display() to be synchronous, so call paintImmediately() - paintImmediatelyAction.run(); - } else { - // Multithreaded redrawing of Swing components is not allowed, - // so do everything on the event dispatch thread - try { - EventQueue.invokeAndWait(paintImmediatelyAction); - } catch (final Exception e) { - throw new GLException(e); - } - } - } - } - - protected void dispose(final Runnable post) { - if(DEBUG) { - System.err.println(getThreadName()+": GLJPanel.dispose() - start"); - // Thread.dumpStack(); - } - - if (backend != null && backend.getContext() != null) { - final boolean animatorPaused; - final GLAnimatorControl animator = getAnimator(); - if(null!=animator) { - animatorPaused = animator.pause(); - } else { - animatorPaused = false; - } - - if(backend.getContext().isCreated()) { - Threading.invoke(true, disposeAction, getTreeLock()); - } - if(null != backend) { - // not yet destroyed due to backend.isUsingOwnThreadManagment() == true - backend.destroy(); - isInitialized = false; - } - if( null != post ) { - post.run(); - } - - if( animatorPaused ) { - animator.resume(); - } - } - - if(DEBUG) { - System.err.println(getThreadName()+": GLJPanel.dispose() - stop"); - } - } - - /** - * Just an alias for removeNotify - */ - @Override - public void destroy() { - removeNotify(); - } - - /** Overridden to cause OpenGL rendering to be performed during - repaint cycles. Subclasses which override this method must call - super.paintComponent() in their paintComponent() method in order - to function properly. <P> - - <DL><DD><CODE>paintComponent</CODE> in class <CODE>javax.swing.JComponent</CODE></DD></DL> */ - @Override - protected void paintComponent(final Graphics g) { - if (Beans.isDesignTime()) { - // Make GLJPanel behave better in NetBeans GUI builder - g.setColor(Color.BLACK); - g.fillRect(0, 0, getWidth(), getHeight()); - final FontMetrics fm = g.getFontMetrics(); - String name = getName(); - if (name == null) { - name = getClass().getName(); - final int idx = name.lastIndexOf('.'); - if (idx >= 0) { - name = name.substring(idx + 1); - } - } - final Rectangle2D bounds = fm.getStringBounds(name, g); - g.setColor(Color.WHITE); - g.drawString(name, - (int) ((getWidth() - bounds.getWidth()) / 2), - (int) ((getHeight() + bounds.getHeight()) / 2)); - return; - } - - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( !isInitialized ) { - initializeBackendImpl(); - } - - if (!isInitialized || printActive) { - return; - } - - // NOTE: must do this when the context is not current as it may - // involve destroying the pbuffer (current context) and - // re-creating it -- tricky to do properly while the context is - // current - if( !printActive ) { - updatePixelScale(backend); - if ( handleReshape ) { - handleReshape = false; - sendReshape = handleReshape(); - } - - if( isShowing ) { - updater.setGraphics(g); - backend.doPaintComponent(g); - } - } - } finally { - _lock.unlock(); - } - } - - private final void updateWrappedSurfaceScale(final GLDrawable d) { - final NativeSurface s = d.getNativeSurface(); - if( s instanceof WrappedSurface ) { - ((WrappedSurface)s).setSurfaceScale(hasPixelScale); - } - } - - @Override - public final boolean setSurfaceScale(final float[] pixelScale) { // HiDPI support - System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2); - final Backend b = backend; - if ( isInitialized && null != b && isShowing ) { - if( isShowing || ( printActive && isVisible() ) ) { - if (EventQueue.isDispatchThread()) { - setSurfaceScaleAction.run(); - } else { - try { - EventQueue.invokeAndWait(setSurfaceScaleAction); - } catch (final Exception e) { - throw new GLException(e); - } - } - } - return true; - } else { - return false; - } - } - private final Runnable setSurfaceScaleAction = new Runnable() { - @Override - public void run() { - final Backend b = backend; - if( null != b && setSurfaceScaleImpl(b) ) { - if( !helper.isAnimatorAnimatingOnOtherThread() ) { - paintImmediatelyAction.run(); // display - } - } - } - }; - - private final boolean setSurfaceScaleImpl(final Backend b) { - if( SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null) ) { - reshapeImpl(getWidth(), getHeight()); - updateWrappedSurfaceScale(b.getDrawable()); - return true; - } - return false; - } - - private final boolean updatePixelScale(final Backend b) { - if( JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale) ) { - return setSurfaceScaleImpl(b); - } else { - return false; - } - } - - @Override - public final float[] getRequestedSurfaceScale(final float[] result) { - System.arraycopy(reqPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public final float[] getCurrentSurfaceScale(final float[] result) { - System.arraycopy(hasPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public float[] getMinimumSurfaceScale(final float[] result) { - System.arraycopy(minPixelScale, 0, result, 0, 2); - return result; - } - - @Override - public float[] getMaximumSurfaceScale(final float[] result) { - System.arraycopy(maxPixelScale, 0, result, 0, 2); - return result; - } - - /** Overridden to track when this component is added to a container. - Subclasses which override this method must call - super.addNotify() in their addNotify() method in order to - function properly. <P> - - <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - @Override - public void addNotify() { - super.addNotify(); - awtWindowClosingProtocol.addClosingListener(); - - // HiDPI support - JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale); - SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null); - - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.addNotify()"); - } - } - - /** Overridden to track when this component is removed from a - container. Subclasses which override this method must call - super.removeNotify() in their removeNotify() method in order to - function properly. <P> - - <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - @Override - public void removeNotify() { - awtWindowClosingProtocol.removeClosingListener(); - - dispose(null); - hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; - maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; - - super.removeNotify(); - } - - /** Overridden to cause {@link GLDrawableHelper#reshape} to be - called on all registered {@link GLEventListener}s. Subclasses - which override this method must call super.reshape() in - their reshape() method in order to function properly. <P> - * - * {@inheritDoc} - */ - @SuppressWarnings("deprecation") - @Override - public void reshape(final int x, final int y, final int width, final int height) { - super.reshape(x, y, width, height); - reshapeImpl(width, height); - } - - private void reshapeImpl(final int width, final int height) { - final int scaledWidth = SurfaceScaleUtils.scale(width, hasPixelScale[0]); - final int scaledHeight = SurfaceScaleUtils.scale(height, hasPixelScale[1]); - if( !printActive && ( handleReshape || scaledWidth != panelWidth || scaledHeight != panelHeight ) ) { - reshapeWidth = scaledWidth; - reshapeHeight = scaledHeight; - handleReshape = true; - } - if( DEBUG ) { - System.err.println(getThreadName()+": GLJPanel.reshape.0 "+this.getName()+" resize ["+(printActive?"printing":"paint")+ - "] [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+ - ", panel "+panelWidth+"x"+panelHeight + - "] -> "+(handleReshape?"":"[skipped] ") + width+"x"+height+" * "+getPixelScaleStr()+ - " -> "+scaledWidth+"x"+scaledHeight+", reshapeSize "+reshapeWidth+"x"+reshapeHeight); - } - } - - private volatile boolean printActive = false; - private GLAnimatorControl printAnimator = null; - private GLAutoDrawable printGLAD = null; - private AWTTilePainter printAWTTiles = null; - - @Override - public void setupPrint(final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final int tileHeight) { - printActive = true; - if( DEBUG ) { - System.err.printf(getThreadName()+": GLJPanel.setupPrint: scale %f / %f, samples %d, tileSz %d x %d%n", scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight); - } - final int componentCount = isOpaque() ? 3 : 4; - final TileRenderer printRenderer = new TileRenderer(); - printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG); - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT); - } - private final Runnable setupPrintOnEDT = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( !isInitialized ) { - initializeBackendImpl(); - } - if (!isInitialized) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet"); - } - printActive = false; - return; // not yet available .. - } - if( !isVisible() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible"); - } - printActive = false; - return; // not yet available .. - } - sendReshape = false; // clear reshape flag - handleReshape = false; // ditto - printAnimator = helper.getAnimator(); - if( null != printAnimator ) { - printAnimator.remove(GLJPanel.this); - } - - printGLAD = GLJPanel.this; // default: re-use - final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); - final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); - GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); - final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); - final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || - printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); - - final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); - newGLADCaps.setDoubleBuffered(false); - newGLADCaps.setOnscreen(false); - if( printNumSamples != newGLADCaps.getNumSamples() ) { - newGLADCaps.setSampleBuffers(0 < printNumSamples); - newGLADCaps.setNumSamples(printNumSamples); - } - final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); - - final boolean reqNewGLAD = ( reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; - - if( DEBUG ) { - System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ - ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ - ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ - ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ - ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); - } - if( reqNewGLAD ) { - final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); - GLOffscreenAutoDrawable offGLAD = null; - try { - offGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, - printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, - printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); - } catch (final GLException gle) { - if( DEBUG ) { - System.err.println("Caught: "+gle.getMessage()); - gle.printStackTrace(); - } - } - if( null != offGLAD ) { - printGLAD = offGLAD; - GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD); - printDrawable = printGLAD.getDelegatedDrawable(); - } - } - printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() ); - printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); - printAWTTiles.renderer.attachAutoDrawable(printGLAD); - if( DEBUG ) { - System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); - System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); - System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); - } - } finally { - _lock.unlock(); - } - } - }; - - @Override - public void releasePrint() { - if( !printActive ) { - throw new IllegalStateException("setupPrint() not called"); - } - sendReshape = false; // clear reshape flag - handleReshape = false; // ditto - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT); - } - - private final Runnable releasePrintOnEDT = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if( DEBUG ) { - System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles); - } - printAWTTiles.dispose(); - printAWTTiles= null; - if( printGLAD != GLJPanel.this ) { - GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this); - printGLAD.destroy(); - } - printGLAD = null; - if( null != printAnimator ) { - printAnimator.add(GLJPanel.this); - printAnimator = null; - } - - // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! - final int awtWidth = GLJPanel.this.getWidth(); - final int awtHeight= GLJPanel.this.getHeight(); - final int scaledAWTWidth = SurfaceScaleUtils.scale(awtWidth, hasPixelScale[0]); - final int scaledAWTHeight= SurfaceScaleUtils.scale(awtHeight, hasPixelScale[1]); - final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable(); - if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight || - drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) { - // -> !( awtSize == panelSize == drawableSize ) - if ( DEBUG ) { - System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resize [printing] panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+ - ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+ - " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight); - } - reshapeWidth = scaledAWTWidth; - reshapeHeight = scaledAWTHeight; - sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape - } else { - sendReshape = true; // only GL reshape - } - printActive = false; - display(); - } finally { - _lock.unlock(); - } - } - }; - - @Override - public void print(final Graphics graphics) { - if( !printActive ) { - throw new IllegalStateException("setupPrint() not called"); - } - if(DEBUG && !EventQueue.isDispatchThread()) { - System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT"); - // we cannot dispatch print on AWT-EDT due to printing internal locking .. - } - sendReshape = false; // clear reshape flag - handleReshape = false; // ditto - - final Graphics2D g2d = (Graphics2D)graphics; - try { - printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight()); - final TileRenderer tileRenderer = printAWTTiles.renderer; - if( DEBUG ) { - System.err.println("AWT print.0: "+tileRenderer); - } - if( !tileRenderer.eot() ) { - try { - do { - if( printGLAD != GLJPanel.this ) { - tileRenderer.display(); - } else { - backend.doPlainPaint(); - } - } while ( !tileRenderer.eot() ); - if( DEBUG ) { - System.err.println("AWT print.1: "+printAWTTiles); - } - } finally { - tileRenderer.reset(); - printAWTTiles.resetGraphics2D(); - } - } - } catch (final NoninvertibleTransformException nte) { - System.err.println("Caught: Inversion failed of: "+g2d.getTransform()); - nte.printStackTrace(); - } - if( DEBUG ) { - System.err.println("AWT print.X: "+printAWTTiles); - } - } - @Override - protected void printComponent(final Graphics g) { - if( DEBUG ) { - System.err.println("AWT printComponent.X: "+printAWTTiles); - } - print(g); - } - - @Override - public void setOpaque(final boolean opaque) { - if (backend != null) { - backend.setOpaque(opaque); - } - super.setOpaque(opaque); - } - - @Override - public void addGLEventListener(final GLEventListener listener) { - helper.addGLEventListener(listener); - } - - @Override - public void addGLEventListener(final int index, final GLEventListener listener) { - helper.addGLEventListener(index, listener); - } - - @Override - public int getGLEventListenerCount() { - return helper.getGLEventListenerCount(); - } - - @Override - public GLEventListener getGLEventListener(final int index) throws IndexOutOfBoundsException { - return helper.getGLEventListener(index); - } - - @Override - public boolean areAllGLEventListenerInitialized() { - return helper.areAllGLEventListenerInitialized(); - } - - @Override - public boolean getGLEventListenerInitState(final GLEventListener listener) { - return helper.getGLEventListenerInitState(listener); - } - - @Override - public void setGLEventListenerInitState(final GLEventListener listener, final boolean initialized) { - helper.setGLEventListenerInitState(listener, initialized); - } - - @Override - public GLEventListener disposeGLEventListener(final GLEventListener listener, final boolean remove) { - final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove); - if (EventQueue.isDispatchThread()) { - r.run(); - } else { - // Multithreaded redrawing of Swing components is not allowed, - // so do everything on the event dispatch thread - try { - EventQueue.invokeAndWait(r); - } catch (final Exception e) { - throw new GLException(e); - } - } - return r.listener; - } - - @Override - public GLEventListener removeGLEventListener(final GLEventListener listener) { - return helper.removeGLEventListener(listener); - } - - @Override - public void setAnimator(final GLAnimatorControl animatorControl) { - helper.setAnimator(animatorControl); - } - - @Override - public GLAnimatorControl getAnimator() { - return helper.getAnimator(); - } - - @Override - public final Thread setExclusiveContextThread(final Thread t) throws GLException { - return helper.setExclusiveContextThread(t, getContext()); - } - - @Override - public final Thread getExclusiveContextThread() { - return helper.getExclusiveContextThread(); - } - - @Override - public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException { - return helper.invoke(this, wait, glRunnable); - } - - @Override - public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException { - return helper.invoke(this, wait, glRunnables); - } - - @Override - public void flushGLRunnables() { - helper.flushGLRunnables(); - } - - @Override - public GLContext createContext(final GLContext shareWith) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final Backend b = backend; - if ( null == b ) { - return null; - } - return b.createContext(shareWith); - } finally { - _lock.unlock(); - } - } - - @Override - public void setRealized(final boolean realized) { - } - - @Override - public boolean isRealized() { - return isInitialized; - } - - @Override - public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final Backend b = backend; - if ( null == b ) { - return null; - } - final GLContext oldCtx = b.getContext(); - GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); - b.setContext(newCtx); - return oldCtx; - } finally { - _lock.unlock(); - } - } - - - @Override - public final GLDrawable getDelegatedDrawable() { - final Backend b = backend; - if ( null == b ) { - return null; - } - return b.getDrawable(); - } - - @Override - public GLContext getContext() { - final Backend b = backend; - if ( null == b ) { - return null; - } - return b.getContext(); - } - - @Override - public GL getGL() { - if (Beans.isDesignTime()) { - return null; - } - final GLContext context = getContext(); - return (context == null) ? null : context.getGL(); - } - - @Override - public GL setGL(final GL gl) { - final GLContext context = getContext(); - if (context != null) { - context.setGL(gl); - return gl; - } - return null; - } - - @Override - public void setAutoSwapBufferMode(final boolean enable) { - this.autoSwapBufferMode = enable; - boolean backendHandlesSwapBuffer = false; - if( isInitialized ) { - final Backend b = backend; - if ( null != b ) { - backendHandlesSwapBuffer= b.handlesSwapBuffer(); - } - } - if( !backendHandlesSwapBuffer ) { - helper.setAutoSwapBufferMode(enable); - } - } - - @Override - public boolean getAutoSwapBufferMode() { - return autoSwapBufferMode; - } - - @Override - public void swapBuffers() { - if( isInitialized ) { - final Backend b = backend; - if ( null != b ) { - b.swapBuffers(); - } - } - } - - @Override - public void setContextCreationFlags(final int flags) { - additionalCtxCreationFlags = flags; - } - - @Override - public int getContextCreationFlags() { - return additionalCtxCreationFlags; - } - - /** For a translucent GLJPanel (one for which {@link #setOpaque - setOpaque}(false) has been called), indicates whether the - application should preserve the OpenGL color buffer - (GL_COLOR_BUFFER_BIT) for correct rendering of the GLJPanel and - underlying widgets which may show through portions of the - GLJPanel with alpha values less than 1. Most Swing - implementations currently expect the GLJPanel to be completely - cleared (e.g., by <code>glClear(GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT)</code>), but for certain optimized Swing - implementations which use OpenGL internally, it may be possible - to perform OpenGL rendering using the GLJPanel into the same - OpenGL drawable as the Swing implementation uses. */ - public boolean shouldPreserveColorBufferIfTranslucent() { - return oglPipelineUsable(); - } - - @Override - public int getSurfaceWidth() { - return panelWidth; // scaled surface width in pixel units, current as-from reshape - } - - @Override - public int getSurfaceHeight() { - return panelHeight; // scaled surface height in pixel units, current as-from reshape - } - - /** - * {@inheritDoc} - * <p> - * Method returns a valid value only <i>after</i> - * the backend has been initialized, either {@link #initializeBackend(boolean) eagerly} - * or manually via the first display call.<br/> - * Method always returns a valid value when called from within a {@link GLEventListener}. - * </p> - */ - @Override - public boolean isGLOriented() { - final Backend b = backend; - if ( null == b ) { - return true; - } - return b.getDrawable().isGLOriented(); - } - - /** - * Skip {@link #isGLOriented()} based vertical flip, - * which usually is required by the offscreen backend, - * see details about <a href="#verticalFlip">vertical flip</a> - * and <a href="#fboGLSLVerticalFlip">FBO / GLSL vertical flip</a>. - * <p> - * If set to <code>true</code>, user needs to flip the OpenGL rendered scene - * <i>if {@link #isGLOriented()} == true</i>, e.g. via the projection matrix.<br/> - * See constraints of {@link #isGLOriented()}. - * </p> - */ - public final void setSkipGLOrientationVerticalFlip(final boolean v) { - skipGLOrientationVerticalFlip = v; - } - /** See {@link #setSkipGLOrientationVerticalFlip(boolean)}. */ - public final boolean getSkipGLOrientationVerticalFlip() { - return skipGLOrientationVerticalFlip; - } - - @Override - public GLCapabilitiesImmutable getChosenGLCapabilities() { - final Backend b = backend; - if ( null == b ) { - return null; - } - return b.getChosenGLCapabilities(); - } - - @Override - public final GLCapabilitiesImmutable getRequestedGLCapabilities() { - return reqOffscreenCaps; - } - - /** - * Set a new requested {@link GLCapabilitiesImmutable} for this GLJPanel - * allowing reconfiguration. - * <p> - * Method shall be invoked from the {@link #isThreadGLCapable() AWT-EDT thread}. - * In case it is not invoked on the AWT-EDT thread, an attempt is made to do so. - * </p> - * <p> - * Method will dispose a previous {@link #isRealized() realized} GLContext and offscreen backend! - * </p> - * @param caps new capabilities. - */ - public final void setRequestedGLCapabilities(final GLCapabilitiesImmutable caps) { - if( null == caps ) { - throw new IllegalArgumentException("null caps"); - } - Threading.invoke(true, - new Runnable() { - @Override - public void run() { - dispose( new Runnable() { - @Override - public void run() { - // switch to new caps and re-init backend - // after actual dispose, but before resume animator - reqOffscreenCaps = caps; - initializeBackendImpl(); - } } ); - } - }, getTreeLock()); - } - - @Override - public final GLProfile getGLProfile() { - return reqOffscreenCaps.getGLProfile(); - } - - @Override - public NativeSurface getNativeSurface() { - final Backend b = backend; - if ( null == b ) { - return null; - } - return b.getDrawable().getNativeSurface(); - } - - @Override - public long getHandle() { - final Backend b = backend; - if ( null == b ) { - return 0; - } - return b.getDrawable().getNativeSurface().getSurfaceHandle(); - } - - @Override - public final GLDrawableFactory getFactory() { - return factory; - } - - /** - * Returns the used texture unit, i.e. a value of [0..n], or -1 if non used. - * <p> - * If implementation uses a texture-unit, it will be known only after the first initialization, i.e. display call. - * </p> - * <p> - * See <a href="#fboGLSLVerticalFlip">FBO / GLSL Vertical Flip</a>. - * </p> - */ - public final int getTextureUnit() { - final Backend b = backend; - if ( null == b ) { - return -1; - } - return b.getTextureUnit(); - } - - /** - * Allows user to request a texture unit to be used, - * must be called before the first initialization, i.e. {@link #display()} call. - * <p> - * Defaults to <code>0</code>. - * </p> - * <p> - * See <a href="#fboGLSLVerticalFlip">FBO / GLSL Vertical Flip</a>. - * </p> - * - * @param v requested texture unit - * @see #getTextureUnit() - */ - public final void setTextureUnit(final int v) { - requestedTextureUnit = v; - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private final Object initSync = new Object(); - private boolean initializeBackendImpl() { - synchronized(initSync) { - if( !isInitialized ) { - if( handleReshape ) { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.1: ["+(printActive?"printing":"paint")+"] "+ - panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr() + " -> " + - reshapeWidth+"x"+reshapeHeight+" @ scale "+getPixelScaleStr()); - } - panelWidth = reshapeWidth; - panelHeight = reshapeHeight; - handleReshape = false; - } else { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.0: ["+(printActive?"printing":"paint")+"] "+ - panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr()); - } - } - - if ( 0 >= panelWidth || 0 >= panelHeight ) { - return false; - } - - if ( null == backend ) { - if ( oglPipelineUsable() ) { - backend = new J2DOGLBackend(); - } else { - backend = new OffscreenBackend(customPixelBufferProvider); - } - isInitialized = false; - } - - if (!isInitialized) { - this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // reqOffscreenCaps may have changed - backend.initialize(); - } - return isInitialized; - } else { - return true; - } - } - } - - private final String getPixelScaleStr() { return "["+hasPixelScale[0]+", "+hasPixelScale[1]+"]"; } - - @Override - public WindowClosingMode getDefaultCloseOperation() { - return awtWindowClosingProtocol.getDefaultCloseOperation(); - } - - @Override - public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { - return awtWindowClosingProtocol.setDefaultCloseOperation(op); - } - - private boolean handleReshape() { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.handleReshape: "+ - panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr() + " -> " + - reshapeWidth+"x"+reshapeHeight+" @ scale "+getPixelScaleStr()); - } - panelWidth = reshapeWidth; - panelHeight = reshapeHeight; - - return backend.handleReshape(); - } - - // This is used as the GLEventListener for the pbuffer-based backend - // as well as the callback mechanism for the other backends - class Updater implements GLEventListener { - private Graphics g; - - public void setGraphics(final Graphics g) { - this.g = g; - } - - @Override - public void init(final GLAutoDrawable drawable) { - if (!backend.preGL(g)) { - return; - } - helper.init(GLJPanel.this, !sendReshape); - backend.postGL(g, false); - } - - @Override - public void dispose(final GLAutoDrawable drawable) { - helper.disposeAllGLEventListener(GLJPanel.this, false); - } - - @Override - public void display(final GLAutoDrawable drawable) { - if (!backend.preGL(g)) { - return; - } - if (sendReshape) { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + " @ scale "+getPixelScaleStr()+")"); - } - helper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight); - sendReshape = false; - } - - helper.display(GLJPanel.this); - backend.postGL(g, true); - } - - public void plainPaint(final GLAutoDrawable drawable) { - helper.display(GLJPanel.this); - } - - @Override - public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { - // This is handled above and dispatched directly to the appropriate context - } - } - - @Override - public String toString() { - final GLDrawable d = ( null != backend ) ? backend.getDrawable() : null; - return "AWT-GLJPanel[ drawableType "+ ( ( null != d ) ? d.getClass().getName() : "null" ) + - ", chosenCaps " + getChosenGLCapabilities() + - "]"; - } - - private final Runnable disposeAction = new Runnable() { - @Override - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - if ( null != backend ) { - final GLContext _context = backend.getContext(); - final boolean backendDestroy = !backend.isUsingOwnLifecycle(); - - GLException exceptionOnDisposeGL = null; - if( null != _context && _context.isCreated() ) { - try { - helper.disposeGL(GLJPanel.this, _context, !backendDestroy); - } catch (final GLException gle) { - exceptionOnDisposeGL = gle; - } - } - Throwable exceptionBackendDestroy = null; - if ( backendDestroy ) { - try { - backend.destroy(); - } catch( final Throwable re ) { - exceptionBackendDestroy = re; - } - backend = null; - isInitialized = false; - } - - // throw exception in order of occurrence .. - if( null != exceptionOnDisposeGL ) { - throw exceptionOnDisposeGL; - } - if( null != exceptionBackendDestroy ) { - throw GLException.newGLException(exceptionBackendDestroy); - } - } - } finally { - _lock.unlock(); - } - } - }; - - private final Runnable updaterInitAction = new Runnable() { - @Override - public void run() { - updater.init(GLJPanel.this); - } - }; - - private final Runnable updaterDisplayAction = new Runnable() { - @Override - public void run() { - updater.display(GLJPanel.this); - } - }; - - private final Runnable updaterPlainDisplayAction = new Runnable() { - @Override - public void run() { - updater.plainPaint(GLJPanel.this); - } - }; - - private final Runnable paintImmediatelyAction = new Runnable() { - @Override - public void run() { - paintImmediately(0, 0, getWidth(), getHeight()); - } - }; - - private class DisposeGLEventListenerAction implements Runnable { - GLEventListener listener; - private final boolean remove; - private DisposeGLEventListenerAction(final GLEventListener listener, final boolean remove) { - this.listener = listener; - this.remove = remove; - } - - @Override - public void run() { - final Backend b = backend; - if ( null != b ) { - listener = helper.disposeGLEventListener(GLJPanel.this, b.getDrawable(), b.getContext(), listener, remove); - } - } - }; - - private int getGLInteger(final GL gl, final int which) { - final int[] tmp = new int[1]; - gl.glGetIntegerv(which, tmp, 0); - return tmp[0]; - } - - protected static String getThreadName() { return Thread.currentThread().getName(); } - - //---------------------------------------------------------------------- - // Implementations of the various backends - // - - /** - * Abstraction of the different rendering backends: i.e., pure - * software / pixmap rendering, pbuffer-based acceleration, Java 2D - * JOGL bridge - */ - static interface Backend { - /** Create, Destroy, .. */ - public boolean isUsingOwnLifecycle(); - - /** Called each time the backend needs to initialize itself */ - public void initialize(); - - /** Called when the backend should clean up its resources */ - public void destroy(); - - /** Called when the opacity of the GLJPanel is changed */ - public void setOpaque(boolean opaque); - - /** - * Called to manually create an additional OpenGL context against - * this GLJPanel - */ - public GLContext createContext(GLContext shareWith); - - /** Called to set the current backend's GLContext */ - public void setContext(GLContext ctx); - - /** Called to get the current backend's GLContext */ - public GLContext getContext(); - - /** Called to get the current backend's GLDrawable */ - public GLDrawable getDrawable(); - - /** Returns the used texture unit, i.e. a value of [0..n], or -1 if non used. */ - public int getTextureUnit(); - - /** Called to fetch the "real" GLCapabilities for the backend */ - public GLCapabilitiesImmutable getChosenGLCapabilities(); - - /** Called to fetch the "real" GLProfile for the backend */ - public GLProfile getGLProfile(); - - /** - * Called to handle a reshape event. When this is called, the - * OpenGL context associated with the backend is not current, to - * make it easier to destroy and re-create pbuffers if necessary. - */ - public boolean handleReshape(); - - /** - * Called before the OpenGL work is done in init() and display(). - * If false is returned, this render is aborted. - */ - public boolean preGL(Graphics g); - - /** - * Return true if backend handles 'swap buffer' itself - * and hence the helper's setAutoSwapBuffer(enable) shall not be called. - * In this case {@link GLJPanel#autoSwapBufferMode} is being used - * in the backend to determine whether to swap buffers or not. - */ - public boolean handlesSwapBuffer(); - - /** - * Shall invoke underlying drawable's swapBuffer. - */ - public void swapBuffers(); - - /** - * Called after the OpenGL work is done in init() and display(). - * The isDisplay argument indicates whether this was called on - * behalf of a call to display() rather than init(). - */ - public void postGL(Graphics g, boolean isDisplay); - - /** Called from within paintComponent() to initiate the render */ - public void doPaintComponent(Graphics g); - - /** Called from print .. no backend update desired onscreen */ - public void doPlainPaint(); - } - - // Base class used by both the software (pixmap) and pbuffer - // backends, both of which rely on reading back the OpenGL frame - // buffer and drawing it with a BufferedImage - class OffscreenBackend implements Backend { - private final AWTGLPixelBufferProvider pixelBufferProvider; - private final boolean useSingletonBuffer; - private AWTGLPixelBuffer pixelBuffer; - private BufferedImage alignedImage; - - // One of these is used to store the read back pixels before storing - // in the BufferedImage - protected IntBuffer readBackIntsForCPUVFlip; - - // Implementation using software rendering - private volatile GLDrawable offscreenDrawable; // volatile: avoid locking for read-only access - private boolean offscreenIsFBO; - private FBObject fboFlipped; - private GLSLTextureRaster glslTextureRaster; - - private volatile GLContextImpl offscreenContext; // volatile: avoid locking for read-only access - private boolean flipVertical; - private int frameCount = 0; - - // For saving/restoring of OpenGL state during ReadPixels - private final GLPixelStorageModes psm = new GLPixelStorageModes(); - - OffscreenBackend(final AWTGLPixelBufferProvider custom) { - if(null == custom) { - pixelBufferProvider = getSingleAWTGLPixelBufferProvider(); - } else { - pixelBufferProvider = custom; - } - if( pixelBufferProvider instanceof SingletonGLPixelBufferProvider ) { - useSingletonBuffer = true; - } else { - useSingletonBuffer = false; - } - } - - @Override - public final boolean isUsingOwnLifecycle() { return false; } - - @Override - public final void initialize() { - if(DEBUG) { - System.err.println(getThreadName()+": OffscreenBackend: initialize() - frameCount "+frameCount); - } - GLException glException = null; - try { - final GLContext[] shareWith = { null }; - if( helper.isSharedGLContextPending(shareWith) ) { - return; // pending .. - } - offscreenDrawable = factory.createOffscreenDrawable( - null /* default platform device */, - reqOffscreenCaps, - chooser, - panelWidth, panelHeight); - updateWrappedSurfaceScale(offscreenDrawable); - offscreenDrawable.setRealized(true); - if( DEBUG_FRAMES ) { - offscreenDrawable.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() { - @Override - public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { - System.err.println(getThreadName()+": OffscreenBackend.swapBuffers - frameCount "+frameCount); - } } ); - } - - // - // Pre context configuration - // - flipVertical = !GLJPanel.this.skipGLOrientationVerticalFlip && offscreenDrawable.isGLOriented(); - offscreenIsFBO = offscreenDrawable.getRequestedGLCapabilities().isFBO(); - final boolean useGLSLFlip_pre = flipVertical && offscreenIsFBO && reqOffscreenCaps.getGLProfile().isGL2ES2() && USE_GLSL_TEXTURE_RASTERIZER; - if( offscreenIsFBO && !useGLSLFlip_pre ) { - // Texture attachment only required for GLSL vertical flip, hence simply use a color-renderbuffer attachment. - ((GLFBODrawable)offscreenDrawable).setFBOMode(0); - } - - offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith[0]); - offscreenContext.setContextCreationFlags(additionalCtxCreationFlags); - if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) { - isInitialized = true; - helper.setAutoSwapBufferMode(false); // we handle swap-buffers, see handlesSwapBuffer() - - final GL gl = offscreenContext.getGL(); - // Remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting, - // otherwise first MSAA frame lacks antialiasing. - // Clearing of FBO is performed within GLFBODrawableImpl.initialize(..): - // gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - - final GLCapabilitiesImmutable chosenCaps = offscreenDrawable.getChosenGLCapabilities(); - final boolean glslCompliant = !offscreenContext.hasRendererQuirk(GLRendererQuirks.GLSLNonCompliant); - final boolean useGLSLFlip = useGLSLFlip_pre && gl.isGL2ES2() && glslCompliant; - if( DEBUG ) { - System.err.println(getThreadName()+": OffscreenBackend.initialize: useGLSLFlip "+useGLSLFlip+ - " [flip "+flipVertical+", isFBO "+offscreenIsFBO+", isGL2ES2 "+gl.isGL2ES2()+ - ", noglsl "+!USE_GLSL_TEXTURE_RASTERIZER+", glslNonCompliant "+!glslCompliant+ - ", isGL2ES2 " + gl.isGL2ES2()+"\n "+offscreenDrawable+"]"); - } - if( useGLSLFlip ) { - final GLFBODrawable fboDrawable = (GLFBODrawable) offscreenDrawable; - fboDrawable.setTextureUnit( GLJPanel.this.requestedTextureUnit ); - try { - fboFlipped = new FBObject(); - fboFlipped.init(gl, panelWidth, panelHeight, 0); - fboFlipped.attachColorbuffer(gl, 0, chosenCaps.getAlphaBits()>0); - // fboFlipped.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); - gl.glClear(GL.GL_COLOR_BUFFER_BIT); // Bug 1020 (see above), cannot do in FBObject due to unknown 'first bind' state. - glslTextureRaster = new GLSLTextureRaster(fboDrawable.getTextureUnit(), true); - glslTextureRaster.init(gl.getGL2ES2()); - glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight); - } catch (final Exception ex) { - ex.printStackTrace(); - if(null != glslTextureRaster) { - glslTextureRaster.dispose(gl.getGL2ES2()); - glslTextureRaster = null; - } - if(null != fboFlipped) { - fboFlipped.destroy(gl); - fboFlipped = null; - } - } - } else { - fboFlipped = null; - glslTextureRaster = null; - } - offscreenContext.release(); - } else { - isInitialized = false; - } - } catch( final GLException gle ) { - glException = gle; - } finally { - if( !isInitialized ) { - if(null != offscreenContext) { - offscreenContext.destroy(); - offscreenContext = null; - } - if(null != offscreenDrawable) { - offscreenDrawable.setRealized(false); - offscreenDrawable = null; - } - } - if( null != glException ) { - throw new GLException("Caught GLException: "+glException.getMessage(), glException); - } - } - } - - @Override - public final void destroy() { - if(DEBUG) { - System.err.println(getThreadName()+": OffscreenBackend: destroy() - offscreenContext: "+(null!=offscreenContext)+" - offscreenDrawable: "+(null!=offscreenDrawable)+" - frameCount "+frameCount); - } - if ( null != offscreenContext && offscreenContext.isCreated() ) { - if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) { - try { - final GL gl = offscreenContext.getGL(); - if(null != glslTextureRaster) { - glslTextureRaster.dispose(gl.getGL2ES2()); - } - if(null != fboFlipped) { - fboFlipped.destroy(gl); - } - } finally { - offscreenContext.destroy(); - } - } - } - offscreenContext = null; - glslTextureRaster = null; - fboFlipped = null; - offscreenContext = null; - - if (offscreenDrawable != null) { - final AbstractGraphicsDevice adevice = offscreenDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); - offscreenDrawable.setRealized(false); - offscreenDrawable = null; - if(null != adevice) { - adevice.close(); - } - } - offscreenIsFBO = false; - - if( null != readBackIntsForCPUVFlip ) { - readBackIntsForCPUVFlip.clear(); - readBackIntsForCPUVFlip = null; - } - if( null != pixelBuffer ) { - if( !useSingletonBuffer ) { - pixelBuffer.dispose(); - } - pixelBuffer = null; - } - alignedImage = null; - } - - @Override - public final void setOpaque(final boolean opaque) { - if ( opaque != isOpaque() && !useSingletonBuffer ) { - pixelBuffer.dispose(); - pixelBuffer = null; - alignedImage = null; - } - } - - @Override - public final boolean preGL(final Graphics g) { - // Empty in this implementation - return true; - } - - @Override - public final boolean handlesSwapBuffer() { - return true; - } - - @Override - public final void swapBuffers() { - final GLDrawable d = offscreenDrawable; - if( null != d ) { - d.swapBuffers(); - } - } - - @Override - public final void postGL(final Graphics g, final boolean isDisplay) { - if (isDisplay) { - if( DEBUG_FRAMES ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: - frameCount "+frameCount); - } - - final GL gl = offscreenContext.getGL(); - - // - // Save TextureState ASAP, i.e. the user values for the used FBO texture-unit - // and the current active texture-unit (if not same) - // - final TextureState usrTexState, fboTexState; - final int fboTexUnit; - - if( offscreenIsFBO ) { - fboTexUnit = GL.GL_TEXTURE0 + ((GLFBODrawable)offscreenDrawable).getTextureUnit(); - usrTexState = new TextureState(gl, GL.GL_TEXTURE_2D); - if( fboTexUnit != usrTexState.getUnit() ) { - // glActiveTexture(..) + glBindTexture(..) are implicit performed in GLFBODrawableImpl's - // swapBuffers/contextMadeCurent -> swapFBOImpl. - // We need to cache the texture unit's bound texture-id before it's overwritten. - gl.glActiveTexture(fboTexUnit); - fboTexState = new TextureState(gl, fboTexUnit, GL.GL_TEXTURE_2D); - } else { - fboTexState = usrTexState; - } - } else { - fboTexUnit = 0; - usrTexState = null; - fboTexState = null; - } - - - if( autoSwapBufferMode ) { - // Since we only use a single-buffer non-MSAA or double-buffered MSAA offscreenDrawable, - // we can always swap! - offscreenDrawable.swapBuffers(); - } - - final int componentCount; - final int alignment; - if( isOpaque() ) { - // w/o alpha - componentCount = 3; - alignment = 1; - } else { - // with alpha - componentCount = 4; - alignment = 4; - } - - final PixelFormat awtPixelFormat = pixelBufferProvider.getAWTPixelFormat(gl.getGLProfile(), componentCount); - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount, true); - - if( useSingletonBuffer ) { // attempt to fetch the latest AWTGLPixelBuffer - pixelBuffer = (AWTGLPixelBuffer) ((SingletonGLPixelBufferProvider)pixelBufferProvider).getSingleBuffer(awtPixelFormat.comp, pixelAttribs, true); - } - if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, panelWidth, panelHeight, 0) ) { - pixelBuffer.dispose(); - pixelBuffer = null; - alignedImage = null; - } - final boolean DEBUG_INIT; - if ( null == pixelBuffer ) { - if (0 >= panelWidth || 0 >= panelHeight ) { - return; - } - pixelBuffer = pixelBufferProvider.allocate(gl, awtPixelFormat.comp, pixelAttribs, true, panelWidth, panelHeight, 1, 0); - if(DEBUG) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBufferProvider isSingletonBufferProvider "+useSingletonBuffer+", 0x"+Integer.toHexString(pixelBufferProvider.hashCode())+", "+pixelBufferProvider.getClass().getSimpleName()); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBuffer 0x"+Integer.toHexString(pixelBuffer.hashCode())+", "+pixelBuffer+", alignment "+alignment); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" flippedVertical "+flipVertical+", glslTextureRaster "+(null!=glslTextureRaster)+", isGL2ES3 "+gl.isGL2ES3()); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" panelSize "+panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr()); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" awtPixelFormat "+awtPixelFormat); - DEBUG_INIT = true; - } else { - DEBUG_INIT = false; - } - } else { - DEBUG_INIT = false; - } - if( offscreenDrawable.getSurfaceWidth() != panelWidth || offscreenDrawable.getSurfaceHeight() != panelHeight ) { - throw new InternalError("OffscreenDrawable panelSize mismatch (reshape missed): panelSize "+panelWidth+"x"+panelHeight+" != drawable "+offscreenDrawable.getSurfaceWidth()+"x"+offscreenDrawable.getSurfaceHeight()+", on thread "+getThreadName()); - } - if( null == alignedImage || - panelWidth != alignedImage.getWidth() || panelHeight != alignedImage.getHeight() || - !pixelBuffer.isDataBufferSource(alignedImage) ) { - alignedImage = pixelBuffer.getAlignedImage(panelWidth, panelHeight); - if(DEBUG) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" new alignedImage "+alignedImage.getWidth()+"x"+alignedImage.getHeight()+" @ scale "+getPixelScaleStr()+", "+alignedImage+", pixelBuffer "+pixelBuffer.width+"x"+pixelBuffer.height+", "+pixelBuffer); - } - } - final IntBuffer readBackInts; - - if( !flipVertical || null != glslTextureRaster ) { - readBackInts = (IntBuffer) pixelBuffer.buffer; - } else { - if( null == readBackIntsForCPUVFlip || pixelBuffer.width * pixelBuffer.height > readBackIntsForCPUVFlip.remaining() ) { - readBackIntsForCPUVFlip = IntBuffer.allocate(pixelBuffer.width * pixelBuffer.height); - } - readBackInts = readBackIntsForCPUVFlip; - } - - // Must now copy pixels from offscreen context into surface - if( DEBUG_FRAMES ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.readPixels: - frameCount "+frameCount); - } - - // Save PACK modes, reset them to defaults and set alignment - psm.setPackAlignment(gl, alignment); - if( gl.isGL2ES3() ) { - final GL2ES3 gl2es3 = gl.getGL2ES3(); - psm.setPackRowLength(gl2es3, panelWidth); - gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer()); - if( DEBUG_INIT ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: fboDrawable "+offscreenDrawable); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readFBO 0x"+Integer.toHexString(gl2es3.getDefaultReadFramebuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: bound-readFBO 0x"+Integer.toHexString(gl2es3.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); - } - } - - if(null != glslTextureRaster) { // implies flippedVertical - final boolean viewportChange; - final int[] usrViewport = new int[] { 0, 0, 0, 0 }; - gl.glGetIntegerv(GL.GL_VIEWPORT, usrViewport, 0); - viewportChange = 0 != usrViewport[0] || 0 != usrViewport[1] || - panelWidth != usrViewport[2] || panelHeight != usrViewport[3]; - if( DEBUG_VIEWPORT ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL: "+GLJPanel.this.getName()+" Viewport: change "+viewportChange+ - ", "+usrViewport[0]+"/"+usrViewport[1]+" "+usrViewport[2]+"x"+usrViewport[3]+ - " -> 0/0 "+panelWidth+"x"+panelHeight); - } - if( viewportChange ) { - gl.glViewport(0, 0, panelWidth, panelHeight); - } - - // perform vert-flipping via OpenGL/FBO - final GLFBODrawable fboDrawable = (GLFBODrawable)offscreenDrawable; - final FBObject.TextureAttachment fboTex = fboDrawable.getColorbuffer(GL.GL_FRONT).getTextureAttachment(); - - fboFlipped.bind(gl); - - // gl.glActiveTexture(GL.GL_TEXTURE0 + fboDrawable.getTextureUnit()); // implicit by GLFBODrawableImpl: swapBuffers/contextMadeCurent -> swapFBOImpl - gl.glBindTexture(GL.GL_TEXTURE_2D, fboTex.getName()); - // gl.glClear(GL.GL_DEPTH_BUFFER_BIT); // fboFlipped runs w/o DEPTH! - - glslTextureRaster.display(gl.getGL2ES2()); - if( DEBUG_INIT ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: fboDrawable "+fboDrawable); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs); - } - gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts); - - fboFlipped.unbind(gl); - if( DEBUG_INIT ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: fboDrawable "+fboDrawable); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer())); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); - } - if( viewportChange ) { - gl.glViewport(usrViewport[0], usrViewport[1], usrViewport[2], usrViewport[3]); - } - } else { - gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts); - - if ( flipVertical ) { - // Copy temporary data into raster of BufferedImage for faster - // blitting Note that we could avoid this copy in the cases - // where !offscreenDrawable.isGLOriented(), - // but that's the software rendering path which is very slow anyway. - final BufferedImage image = alignedImage; - final int[] src = readBackInts.array(); - final int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); - final int incr = panelWidth; - int srcPos = 0; - int destPos = (panelHeight - 1) * panelWidth; - for (; destPos >= 0; srcPos += incr, destPos -= incr) { - System.arraycopy(src, srcPos, dest, destPos, incr); - } - } - } - if( 0 != fboTexUnit ) { // implies offscreenIsFBO - fboTexState.restore(gl); - if( fboTexUnit != usrTexState.getUnit() ) { - usrTexState.restore(gl); - } - } - - // Restore saved modes. - psm.restore(gl); - - // Note: image will be drawn back in paintComponent() for - // correctness on all platforms - } - } - - @Override - public final int getTextureUnit() { - if(null != glslTextureRaster && null != offscreenDrawable) { // implies flippedVertical - return ((GLFBODrawable)offscreenDrawable).getTextureUnit(); - } - return -1; - } - - @Override - public final void doPaintComponent(final Graphics g) { - helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction); - - if ( null != alignedImage ) { - if( DEBUG_FRAMES ) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.doPaintComponent.drawImage: - frameCount "+frameCount); - } - // Draw resulting image in one shot - g.drawImage(alignedImage, 0, 0, - SurfaceScaleUtils.scaleInv(alignedImage.getWidth(), hasPixelScale[0]), - SurfaceScaleUtils.scaleInv(alignedImage.getHeight(), hasPixelScale[1]), null); // Null ImageObserver since image data is ready. - } - frameCount++; - } - - @Override - public final void doPlainPaint() { - helper.invokeGL(offscreenDrawable, offscreenContext, updaterPlainDisplayAction, updaterInitAction); - } - - @Override - public final boolean handleReshape() { - GLDrawableImpl _drawable = (GLDrawableImpl)offscreenDrawable; - { - final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, offscreenContext, panelWidth, panelHeight); - if(_drawable != _drawableNew) { - // write back - _drawable = _drawableNew; - offscreenDrawable = _drawableNew; - updateWrappedSurfaceScale(offscreenDrawable); - } - } - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.handleReshape: " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr() + " -> " + _drawable.getSurfaceWidth()+"x"+_drawable.getSurfaceHeight()); - } - panelWidth = _drawable.getSurfaceWidth(); - panelHeight = _drawable.getSurfaceHeight(); - - if( null != glslTextureRaster ) { - if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) { - try { - final GL gl = offscreenContext.getGL(); - fboFlipped.reset(gl, panelWidth, panelHeight, 0); - glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight); - } finally { - offscreenContext.release(); - } - } - } - return _drawable.isRealized(); - } - - @Override - public final GLContext createContext(final GLContext shareWith) { - return (null != offscreenDrawable) ? offscreenDrawable.createContext(shareWith) : null; - } - - @Override - public final void setContext(final GLContext ctx) { - offscreenContext=(GLContextImpl)ctx; - } - - @Override - public final GLContext getContext() { - return offscreenContext; - } - - @Override - public final GLDrawable getDrawable() { - return offscreenDrawable; - } - - @Override - public final GLCapabilitiesImmutable getChosenGLCapabilities() { - if (offscreenDrawable == null) { - return null; - } - return offscreenDrawable.getChosenGLCapabilities(); - } - - @Override - public final GLProfile getGLProfile() { - if (offscreenDrawable == null) { - return null; - } - return offscreenDrawable.getGLProfile(); - } - } - - class J2DOGLBackend implements Backend { - // Opaque Object identifier representing the Java2D surface we are - // drawing to; used to determine when to destroy and recreate JOGL - // context - private Object j2dSurface; - // Graphics object being used during Java2D update action - // (absolutely essential to cache this) - // No-op context representing the Java2D OpenGL context - private GLContext j2dContext; - // Context associated with no-op drawable representing the JOGL - // OpenGL context - private GLDrawable joglDrawable; - // The real OpenGL context JOGL uses to render - private GLContext joglContext; - // State captured from Java2D OpenGL context necessary in order to - // properly render into Java2D back buffer - private final int[] drawBuffer = new int[1]; - private final int[] readBuffer = new int[1]; - // This is required when the FBO option of the Java2D / OpenGL - // pipeline is active - private final int[] frameBuffer = new int[1]; - // Current (as of this writing) NVidia drivers have a couple of bugs - // relating to the sharing of framebuffer and renderbuffer objects - // between contexts. It appears we have to (a) reattach the color - // attachment and (b) actually create new depth buffer storage and - // attach it in order for the FBO to behave properly in our context. - private boolean checkedForFBObjectWorkarounds; - private boolean fbObjectWorkarounds; - private int[] frameBufferDepthBuffer; - private int[] frameBufferTexture; - private boolean createNewDepthBuffer; - // Current (as of this writing) ATI drivers have problems when the - // same FBO is bound in two different contexts. Here we check for - // this case and explicitly release the FBO from Java2D's context - // before switching to ours. Java2D will re-bind the FBO when it - // makes its context current the next time. Interestingly, if we run - // this code path on NVidia hardware, it breaks the rendering - // results -- no output is generated. This doesn't appear to be an - // interaction with the abovementioned NVidia-specific workarounds, - // as even if we disable that code the FBO is still reported as - // incomplete in our context. - private boolean checkedGLVendor; - private boolean vendorIsATI; - - // Holding on to this GraphicsConfiguration is a workaround for a - // problem in the Java 2D / JOGL bridge when FBOs are enabled; see - // comment related to Issue 274 below - private GraphicsConfiguration workaroundConfig; - - @Override - public final boolean isUsingOwnLifecycle() { return true; } - - @Override - public final void initialize() { - if(DEBUG) { - System.err.println(getThreadName()+": J2DOGL: initialize()"); - } - // No-op in this implementation; everything is done lazily - isInitialized = true; - } - - @Override - public final void destroy() { - Java2D.invokeWithOGLContextCurrent(null, new Runnable() { - @Override - public void run() { - if(DEBUG) { - System.err.println(getThreadName()+": J2DOGL: destroy() - joglContext: "+(null!=joglContext)+" - joglDrawable: "+(null!=joglDrawable)); - } - if (joglContext != null) { - joglContext.destroy(); - joglContext = null; - } - joglDrawable = null; - if (j2dContext != null) { - j2dContext.destroy(); - j2dContext = null; - } - } - }); - } - - @Override - public final void setOpaque(final boolean opaque) { - // Empty in this implementation - } - - @Override - public final GLContext createContext(final GLContext shareWith) { - if(null != shareWith) { - throw new GLException("J2DOGLBackend cannot create context w/ additional shared context, since it already needs to share the context w/ J2D."); - } - return (null != joglDrawable && null != j2dContext) ? joglDrawable.createContext(j2dContext) : null; - } - - @Override - public final void setContext(final GLContext ctx) { - joglContext=ctx; - } - - @Override - public final GLContext getContext() { - return joglContext; - } - - @Override - public final GLDrawable getDrawable() { - return joglDrawable; - } - - @Override - public final int getTextureUnit() { return -1; } - - @Override - public final GLCapabilitiesImmutable getChosenGLCapabilities() { - // FIXME: should do better than this; is it possible to query J2D Caps ? - return new GLCapabilities(null); - } - - @Override - public final GLProfile getGLProfile() { - // FIXME: should do better than this; is it possible to query J2D's Profile ? - return GLProfile.getDefault(GLProfile.getDefaultDevice()); - } - - @Override - public final boolean handleReshape() { - // Empty in this implementation - return true; - } - - @Override - public final boolean preGL(final Graphics g) { - final GL2 gl = joglContext.getGL().getGL2(); - // Set up needed state in JOGL context from Java2D context - gl.glEnable(GL.GL_SCISSOR_TEST); - final Rectangle r = Java2D.getOGLScissorBox(g); - - if (r == null) { - if (DEBUG) { - System.err.println(getThreadName()+": Java2D.getOGLScissorBox() returned null"); - } - return false; - } - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: gl.glScissor(" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + ")"); - } - - gl.glScissor(r.x, r.y, r.width, r.height); - final Rectangle oglViewport = Java2D.getOGLViewport(g, panelWidth, panelHeight); - // If the viewport X or Y changes, in addition to the panel's - // width or height, we need to send a reshape operation to the - // client - if ((viewportX != oglViewport.x) || - (viewportY != oglViewport.y)) { - sendReshape = true; - if (DEBUG) { - System.err.println(getThreadName()+": Sending reshape because viewport changed"); - System.err.println(" viewportX (" + viewportX + ") ?= oglViewport.x (" + oglViewport.x + ")"); - System.err.println(" viewportY (" + viewportY + ") ?= oglViewport.y (" + oglViewport.y + ")"); - } - } - viewportX = oglViewport.x; - viewportY = oglViewport.y; - - // If the FBO option is active, bind to the FBO from the Java2D - // context. - // Note that all of the plumbing in the context sharing stuff will - // allow us to bind to this object since it's in our namespace. - if (Java2D.isFBOEnabled() && - Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) { - - // The texture target for Java2D's OpenGL pipeline when using FBOs - // -- either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB - final int fboTextureTarget = Java2D.getOGLTextureType(g); - - if (!checkedForFBObjectWorkarounds) { - checkedForFBObjectWorkarounds = true; - gl.glBindTexture(fboTextureTarget, 0); - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]); - final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); - if (status != GL.GL_FRAMEBUFFER_COMPLETE) { - // Need to do workarounds - fbObjectWorkarounds = true; - createNewDepthBuffer = true; - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: ERR GL_FRAMEBUFFER_BINDING: Discovered Invalid J2D FBO("+frameBuffer[0]+"): "+FBObject.getStatusString(status) + - ", frame_buffer_object workarounds to be necessary"); - } - } else { - // Don't need the frameBufferTexture temporary any more - frameBufferTexture = null; - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: OK GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]); - } - } - } - - if (fbObjectWorkarounds && createNewDepthBuffer) { - if (frameBufferDepthBuffer == null) - frameBufferDepthBuffer = new int[1]; - - // Create our own depth renderbuffer and associated storage - // If we have an old one, delete it - if (frameBufferDepthBuffer[0] != 0) { - gl.glDeleteRenderbuffers(1, frameBufferDepthBuffer, 0); - frameBufferDepthBuffer[0] = 0; - } - - gl.glBindTexture(fboTextureTarget, frameBufferTexture[0]); - final int[] width = new int[1]; - final int[] height = new int[1]; - gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2GL3.GL_TEXTURE_WIDTH, width, 0); - gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2GL3.GL_TEXTURE_HEIGHT, height, 0); - - gl.glGenRenderbuffers(1, frameBufferDepthBuffer, 0); - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: Generated frameBufferDepthBuffer " + frameBufferDepthBuffer[0] + - " with width " + width[0] + ", height " + height[0]); - } - - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, frameBufferDepthBuffer[0]); - // FIXME: may need a loop here like in Java2D - gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT24, width[0], height[0]); - - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0); - createNewDepthBuffer = false; - } - - gl.glBindTexture(fboTextureTarget, 0); - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]); - - if (fbObjectWorkarounds) { - // Hook up the color and depth buffer attachment points for this framebuffer - gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, - GL.GL_COLOR_ATTACHMENT0, - fboTextureTarget, - frameBufferTexture[0], - 0); - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: frameBufferDepthBuffer: " + frameBufferDepthBuffer[0]); - } - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, - frameBufferDepthBuffer[0]); - } - - if (DEBUG) { - final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); - if (status != GL.GL_FRAMEBUFFER_COMPLETE) { - throw new GLException("Error: framebuffer was incomplete: status = 0x" + - Integer.toHexString(status)); - } - } - } else { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: Setting up drawBuffer " + drawBuffer[0] + - " and readBuffer " + readBuffer[0]); - } - - gl.glDrawBuffer(drawBuffer[0]); - gl.glReadBuffer(readBuffer[0]); - } - - return true; - } - - @Override - public final boolean handlesSwapBuffer() { - return false; - } - - @Override - public final void swapBuffers() { - final GLDrawable d = joglDrawable; - if( null != d ) { - d.swapBuffers(); - } - } - - @Override - public final void postGL(final Graphics g, final boolean isDisplay) { - // Cause OpenGL pipeline to flush its results because - // otherwise it's possible we will buffer up multiple frames' - // rendering results, resulting in apparent mouse lag - final GL gl = joglContext.getGL(); - gl.glFinish(); - - if (Java2D.isFBOEnabled() && - Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) { - // Unbind the framebuffer from our context to work around - // apparent driver bugs or at least unspecified behavior causing - // OpenGL to run out of memory with certain cards and drivers - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); - } - } - - @Override - public final void doPaintComponent(final Graphics g) { - // This is a workaround for an issue in the Java 2D / JOGL - // bridge (reported by an end user as JOGL Issue 274) where Java - // 2D can occasionally leave its internal OpenGL context current - // to the on-screen window rather than its internal "scratch" - // pbuffer surface to which the FBO is attached. JOGL expects to - // find a stable OpenGL drawable (on Windows, an HDC) upon which - // it can create another OpenGL context. It turns out that, on - // Windows, when Java 2D makes its internal OpenGL context - // current against the window in order to put pixels on the - // screen, it gets the device context for the window, makes its - // context current, and releases the device context. This means - // that when JOGL's Runnable gets to run below, the HDC is - // already invalid. The workaround for this is to force Java 2D - // to make its context current to the scratch surface, which we - // can do by executing an empty Runnable with the "shared" - // context current. This will be fixed in a Java SE 6 update - // release, hopefully 6u2. - if (Java2D.isFBOEnabled()) { - if (workaroundConfig == null) { - workaroundConfig = GraphicsEnvironment. - getLocalGraphicsEnvironment(). - getDefaultScreenDevice(). - getDefaultConfiguration(); - } - Java2D.invokeWithOGLSharedContextCurrent(workaroundConfig, new Runnable() { @Override - public void run() {}}); - } - - Java2D.invokeWithOGLContextCurrent(g, new Runnable() { - @Override - public void run() { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.invokeWithOGLContextCurrent"); - } - - // Create no-op context representing Java2D context - if (j2dContext == null) { - j2dContext = factory.createExternalGLContext(); - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel.Created External Context: "+j2dContext); - } - if (DEBUG) { -// j2dContext.setGL(new DebugGL2(j2dContext.getGL().getGL2())); - } - - // Check to see whether we can support the requested - // capabilities or need to fall back to a pbuffer - // FIXME: add more checks? - - j2dContext.makeCurrent(); - final GL gl = j2dContext.getGL(); - if ((getGLInteger(gl, GL.GL_RED_BITS) < reqOffscreenCaps.getRedBits()) || - (getGLInteger(gl, GL.GL_GREEN_BITS) < reqOffscreenCaps.getGreenBits()) || - (getGLInteger(gl, GL.GL_BLUE_BITS) < reqOffscreenCaps.getBlueBits()) || - // (getGLInteger(gl, GL.GL_ALPHA_BITS) < offscreenCaps.getAlphaBits()) || - (getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) < reqOffscreenCaps.getAccumRedBits()) || - (getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) < reqOffscreenCaps.getAccumGreenBits()) || - (getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) < reqOffscreenCaps.getAccumBlueBits()) || - (getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) < reqOffscreenCaps.getAccumAlphaBits()) || - // (getGLInteger(gl, GL2.GL_DEPTH_BITS) < offscreenCaps.getDepthBits()) || - (getGLInteger(gl, GL.GL_STENCIL_BITS) < reqOffscreenCaps.getStencilBits())) { - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: Falling back to pbuffer-based support because Java2D context insufficient"); - System.err.println(" Available Required"); - System.err.println("GL_RED_BITS " + getGLInteger(gl, GL.GL_RED_BITS) + " " + reqOffscreenCaps.getRedBits()); - System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + reqOffscreenCaps.getGreenBits()); - System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + reqOffscreenCaps.getBlueBits()); - System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + reqOffscreenCaps.getAlphaBits()); - System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) + " " + reqOffscreenCaps.getAccumRedBits()); - System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) + " " + reqOffscreenCaps.getAccumGreenBits()); - System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) + " " + reqOffscreenCaps.getAccumBlueBits()); - System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) + " " + reqOffscreenCaps.getAccumAlphaBits()); - System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + reqOffscreenCaps.getDepthBits()); - System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + reqOffscreenCaps.getStencilBits()); - } - isInitialized = false; - backend = null; - java2DGLPipelineOK = false; - handleReshape = true; - j2dContext.destroy(); - j2dContext = null; - return; - } - } else { - j2dContext.makeCurrent(); - } - try { - captureJ2DState(j2dContext.getGL(), g); - final Object curSurface = Java2D.getOGLSurfaceIdentifier(g); - if (curSurface != null) { - if (j2dSurface != curSurface) { - if (joglContext != null) { - joglContext.destroy(); - joglContext = null; - joglDrawable = null; - sendReshape = true; - if (DEBUG) { - System.err.println(getThreadName()+": Sending reshape because surface changed"); - System.err.println("New surface = " + curSurface); - } - } - j2dSurface = curSurface; - if (DEBUG) { - System.err.print(getThreadName()+": Surface type: "); - final int surfaceType = Java2D.getOGLSurfaceType(g); - if (surfaceType == Java2D.UNDEFINED) { - System.err.println("UNDEFINED"); - } else if (surfaceType == Java2D.WINDOW) { - System.err.println("WINDOW"); - } else if (surfaceType == Java2D.PBUFFER) { - System.err.println("PBUFFER"); - } else if (surfaceType == Java2D.TEXTURE) { - System.err.println("TEXTURE"); - } else if (surfaceType == Java2D.FLIP_BACKBUFFER) { - System.err.println("FLIP_BACKBUFFER"); - } else if (surfaceType == Java2D.FBOBJECT) { - System.err.println("FBOBJECT"); - } else { - System.err.println("(Unknown surface type " + surfaceType + ")"); - } - } - } - if (joglContext == null) { - final AbstractGraphicsDevice device = j2dContext.getGLDrawable().getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); - if (factory.canCreateExternalGLDrawable(device)) { - joglDrawable = factory.createExternalGLDrawable(); - joglContext = joglDrawable.createContext(j2dContext); - if (DEBUG) { - System.err.println("-- Created External Drawable: "+joglDrawable); - System.err.println("-- Created Context: "+joglContext); - } - } - if (Java2D.isFBOEnabled() && - Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT && - fbObjectWorkarounds) { - createNewDepthBuffer = true; - } - } - helper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction); - } - } finally { - j2dContext.release(); - } - } - }); - } - - @Override - public final void doPlainPaint() { - helper.invokeGL(joglDrawable, joglContext, updaterPlainDisplayAction, updaterInitAction); - } - - private final void captureJ2DState(final GL gl, final Graphics g) { - gl.glGetIntegerv(GL2GL3.GL_DRAW_BUFFER, drawBuffer, 0); - gl.glGetIntegerv(GL2ES3.GL_READ_BUFFER, readBuffer, 0); - if (Java2D.isFBOEnabled() && - Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) { - gl.glGetIntegerv(GL.GL_FRAMEBUFFER_BINDING, frameBuffer, 0); - if(!gl.glIsFramebuffer(frameBuffer[0])) { - checkedForFBObjectWorkarounds=true; - fbObjectWorkarounds = true; - createNewDepthBuffer = true; - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: Fetched ERR GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]+" - NOT A FBO"+ - ", frame_buffer_object workarounds to be necessary"); - } - } else if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: Fetched OK GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]); - } - - if(fbObjectWorkarounds || !checkedForFBObjectWorkarounds) { - // See above for description of what we are doing here - if (frameBufferTexture == null) - frameBufferTexture = new int[1]; - - // Query the framebuffer for its color buffer so we can hook - // it back up in our context (should not be necessary) - gl.glGetFramebufferAttachmentParameteriv(GL.GL_FRAMEBUFFER, - GL.GL_COLOR_ATTACHMENT0, - GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - frameBufferTexture, 0); - if (DEBUG) { - System.err.println(getThreadName()+": GLJPanel: FBO COLOR_ATTACHMENT0: " + frameBufferTexture[0]); - } - } - - if (!checkedGLVendor) { - checkedGLVendor = true; - final String vendor = gl.glGetString(GL.GL_VENDOR); - - if ((vendor != null) && - vendor.startsWith("ATI")) { - vendorIsATI = true; - } - } - - if (vendorIsATI) { - // Unbind the FBO from Java2D's context as it appears that - // driver bugs on ATI's side are causing problems if the FBO is - // simultaneously bound to more than one context. Java2D will - // re-bind the FBO during the next validation of its context. - // Note: this breaks rendering at least on NVidia hardware - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); - } - } - } - } -} |