diff options
Diffstat (limited to 'src/jogl/classes/javax/media/opengl')
11 files changed, 517 insertions, 320 deletions
diff --git a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java index b57b85e5c..5fa8ce32d 100644 --- a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java +++ b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java @@ -117,6 +117,7 @@ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { final int availnum = available.size(); if (DEBUG) { + Thread.dumpStack(); System.err.println("Desired: " + gldes); System.err.println("Available: " + availnum); for (int i = 0; i < available.size(); i++) { @@ -141,7 +142,7 @@ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { for (int i = 0; i < scores.length; i++) { scores[i] = NO_SCORE; } - final int gldes_samples = gldes.getSampleBuffers() ? gldes.getNumSamples() : 0; + final int gldes_samples = gldes.getNumSamples(); // Compute score for each for (int i = 0; i < availnum; i++) { @@ -158,8 +159,7 @@ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { if (gldes.getStereo() != cur.getStereo()) { continue; } - final int cur_samples = - cur.getSampleBuffers() ? cur.getNumSamples() : 0; + final int cur_samples = cur.getNumSamples() ; int score = 0; // Compute difference in color depth @@ -242,7 +242,7 @@ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { if (i > 0) { System.err.print(","); } - System.err.print(" " + scores[i]); + System.err.print(" " + i +": " + scores[i]); } System.err.println(" ]"); } diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index 80d4f796c..0b2c664fe 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -51,8 +51,8 @@ import jogamp.opengl.Debug; calls to {@link GLContext#makeCurrent makeCurrent} will block if the context is current on another thread. This allows the internal GLContext for the GLAutoDrawable to be used both by the event - based rendering mechanism as well by end users directly.<P> - + based rendering mechanism as well by end users directly. + <p> The implementation shall initialize itself as soon as possible, ie if the attached {@link javax.media.nativewindow.NativeSurface NativeSurface} becomes visible/realized. The following protocol shall be satisfied: @@ -64,18 +64,18 @@ import jogamp.opengl.Debug; registered {@link GLEventListener}s. This can be done immediatly, or with the followup {@link #display display(..)} call.</li> <li> Send a reshape event by calling {@link GLEventListener#reshape reshape(..)} for all registered {@link GLEventListener}s. This shall be done after the {@link GLEventListener#init init(..)} calls.</li> - </ul><P> - + </ul></P> + <p> Another implementation detail is the drawable reconfiguration. One use case is where a window is being dragged to another screen with a different pixel configuration, ie {@link GLCapabilities}. The implementation - shall be able to detect such cases in conjunction with the associated {@link javax.media.nativewindow.NativeSurface NativeSurface}.<br> + shall be able to detect such cases in conjunction with the associated {@link javax.media.nativewindow.NativeSurface NativeSurface}.<br/> For example, AWT's {@link java.awt.Canvas} 's {@link java.awt.Canvas#getGraphicsConfiguration getGraphicsConfiguration()} is capable to determine a display device change. This is demonstrated within {@link javax.media.opengl.awt.GLCanvas}'s and NEWT's <code>AWTCanvas</code> {@link javax.media.opengl.awt.GLCanvas#getGraphicsConfiguration getGraphicsConfiguration()} specialization. Another demonstration is NEWT's {@link javax.media.nativewindow.NativeWindow NativeWindow} - implementation on the Windows platform, which utilizes the native platform's <i>MonitorFromWindow(HWND)</i> function.<br> + implementation on the Windows platform, which utilizes the native platform's <i>MonitorFromWindow(HWND)</i> function.<br/> All OpenGL resources shall be regenerated, while the drawable's {@link GLCapabilities} has - to be choosen again. The following protocol shall be satisfied. + to be chosen again. The following protocol shall be satisfied. <ul> <li> Controlled disposal:</li> <ul> @@ -97,16 +97,16 @@ import jogamp.opengl.Debug; </ul> Note: Current graphics driver keep the surface configuration for a given window, even if the window is moved to a monitor with a different pixel configuration, ie 32bpp to 16bpp. However, it is best to not assume such behavior - and make your application comply with the above protocol.<P> - - However, to not introduce to much breakage with older applications and because of the situation + and make your application comply with the above protocol. + <p> + Avoiding breakage with older applications and because of the situation mentioned above, the <code>boolean</code> system property <code>jogl.screenchange.action</code> will control the - screen change action as follows:<br> - + screen change action as follows:<br/> <PRE> -Djogl.screenchange.action=false Disable the drawable reconfiguration (the default) -Djogl.screenchange.action=true Enable the drawable reconfiguration </PRE> + </p> */ public interface GLAutoDrawable extends GLDrawable { /** Flag reflecting wheather the drawable reconfiguration will be issued in @@ -362,5 +362,29 @@ public interface GLAutoDrawable extends GLDrawable { demos for examples. @return the set GL pipeline or null if not successful */ public GL setGL(GL gl); + + /** + * Method <i>may</i> return the upstream UI toolkit object + * holding this {@link GLAutoDrawable} instance, if exist. + * <p> + * Currently known Java UI toolkits and it's known return types are: + * + * <table border="1"> + * <tr><td>Toolkit</td> <td>GLAutoDrawable Implementation</td> <td>~</td> <td>Return Type of getUpstreamWidget()</td</tr> + * <tr><td>NEWT</td> <td>{@link com.jogamp.newt.opengl.GLWindow}</td> <td>has a</td> <td>{@link com.jogamp.newt.Window}</td</tr> + * <tr><td>SWT</td> <td>{@link com.jogamp.opengl.swt.GLCanvas}</td> <td>is a</td> <td>{@link org.eclipse.swt.widgets.Canvas}</td</tr> + * <tr><td>AWT</td> <td>{@link javax.media.opengl.awt.GLCanvas}</td> <td>is a</td> <td>{@link java.awt.Canvas}</td</tr> + * <tr><td>AWT</td> <td>{@link javax.media.opengl.awt.GLJPanel}</td> <td>is a</td> <td>{@link javax.swing.JPanel}</td</tr> + * </table> + * However, the result may be other object types than the listed above + * due to new supported toolkits. + * </p> + * <p> + * This method may also return <code>null</code> if no UI toolkit is being used, + * as common for offscreen rendering. + * </p> + * @return + */ + public Object getUpstreamWidget(); } diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java index 89d5cc4cb..67e81270d 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java @@ -28,6 +28,8 @@ package javax.media.opengl; +import javax.media.nativewindow.AbstractGraphicsDevice; + import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; @@ -56,23 +58,33 @@ import jogamp.opengl.GLDrawableImpl; public class GLAutoDrawableDelegate extends GLAutoDrawableBase { public static final boolean DEBUG = Debug.debug("GLAutoDrawableDelegate"); - public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context) { - super((GLDrawableImpl)drawable, (GLContextImpl)context); + /** + * @param drawable a valid {@link GLDrawable}, may not be realized yet. + * @param context a valid {@link GLContext}, may not be made current (created) yet. + * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}. + * @param ownDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued, + * otherwise pass <code>false</code>. Closing the device is required in case + * the drawable is created w/ it's own new instance, e.g. offscreen drawables, + * and no further lifecycle handling is applied. + */ + public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context, Object upstreamWidget, boolean ownDevice) { + super((GLDrawableImpl)drawable, (GLContextImpl)context, ownDevice); + this.upstreamWidget = null; } // - // make protected methods accessible + // expose default methods // - public void defaultWindowRepaintOp() { + public final void windowRepaintOp() { super.defaultWindowRepaintOp(); } - public void defaultWindowResizedOp() { + public final void windowResizedOp() { super.defaultWindowResizedOp(); } - public void defaultWindowDestroyNotifyOp() { + public final void windowDestroyNotifyOp() { super.defaultWindowDestroyNotifyOp(); } @@ -80,44 +92,35 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase { // Complete GLAutoDrawable // - private RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock - + private final RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock + private final Object upstreamWidget; + + @Override + protected final RecursiveLock getLock() { return lock; } + + @Override + public final Object getUpstreamWidget() { + return upstreamWidget; + } + /** * {@inheritDoc} * <p> - * This implementation calls {@link #defaultDestroyOp()}. + * This implementation calls {@link #defaultDestroy()}. * </p> * <p> * User still needs to destroy the upstream window, which details are hidden from this aspect. + * This can be performed by overriding {@link #destroyImplInLock()}. * </p> */ @Override - public void destroy() { - lock.lock(); - try { - defaultDestroyOp(); - } finally { - lock.unlock(); - } + public final void destroy() { + defaultDestroy(); } @Override public void display() { - if( sendDestroy ) { - sendDestroy=false; - destroy(); - return; - } - - lock.lock(); // sync: context/drawable could been recreated/destroyed while animating - try { - if( null != drawable && drawable.isRealized() && null != context ) { - // surface is locked/unlocked implicit by context's makeCurrent/release - helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction); - } - } finally { - lock.unlock(); - } + defaultDisplay(); } // @@ -133,4 +136,9 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase { public final void setRealized(boolean realized) { } + @Override + public final void swapBuffers() throws GLException { + defaultSwapBuffers(); + } + } diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index bd24b15bc..f5831a72d 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -340,5 +340,60 @@ public interface GLBase { * completeness. */ public Object getExtension(String extensionName); + + /** Aliased entrypoint of <code> void {@native glClearDepth}(GLclampd depth); </code> and <code> void {@native glClearDepthf}(GLclampf depth); </code>. */ + public void glClearDepth( double depth ); + + /** Aliased entrypoint of <code> void {@native glDepthRange}(GLclampd depth); </code> and <code> void {@native glDepthRangef}(GLclampf depth); </code>. */ + public void glDepthRange(double zNear, double zFar); + + /** + * @param target a GL buffer (VBO) target as used in {@link GL#glBindBuffer(int, int)}, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}, {@link GL#GL_ARRAY_BUFFER}, .. + * @return the GL buffer (VBO) name bound to a target via {@link GL#glBindBuffer(int, int)} or 0 if unbound. + */ + public int glGetBoundBuffer(int target); + + /** + * @param buffer a GL buffer name, generated with {@link GL#glGenBuffers(int, int[], int)} and used in {@link GL#glBindBuffer(int, int)}, {@link GL#glBufferData(int, long, java.nio.Buffer, int)} or {@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} for example. + * @return the size of the given GL buffer + */ + public long glGetBufferSize(int buffer); + + /** + * @return true if a VBO is bound to {@link GL.GL_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + */ + public boolean glIsVBOArrayEnabled(); + + /** + * @return true if a VBO is bound to {@link GL.GL_ELEMENT_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + */ + public boolean glIsVBOElementArrayEnabled(); + + /** + * Return the framebuffer name bound to this context, + * see {@link GL#glBindFramebuffer(int, int)}. + */ + public int getBoundFramebuffer(int target); + + /** + * Return the default draw framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link FBObject}) based drawable + * is being used. + * </p> + */ + public int getDefaultDrawFramebuffer(); + + /** + * Return the default read framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link FBObject}) based drawable + * is being used. + * </p> + */ + public int getDefaultReadFramebuffer(); + } diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilities.java b/src/jogl/classes/javax/media/opengl/GLCapabilities.java index 61ab2e58d..8845ec665 100644 --- a/src/jogl/classes/javax/media/opengl/GLCapabilities.java +++ b/src/jogl/classes/javax/media/opengl/GLCapabilities.java @@ -55,8 +55,9 @@ import javax.media.nativewindow.CapabilitiesImmutable; It currently contains the minimal number of routines which allow configuration on all supported window systems. */ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabilitiesImmutable { - private GLProfile glProfile = null; - private boolean pbuffer = false; + private GLProfile glProfile = null; + private boolean isPBuffer = false; + private boolean isFBO = false; private boolean doubleBuffered = true; private boolean stereo = false; private boolean hardwareAccelerated = true; @@ -105,7 +106,8 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil public int hashCode() { // 31 * x == (x << 5) - x int hash = 31 + this.glProfile.hashCode() ; - hash = ((hash << 5) - hash) + ( this.pbuffer ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.isFBO ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.isPBuffer ? 1 : 0 ); hash = ((hash << 5) - hash) + ( this.stereo ? 1 : 0 ); hash = ((hash << 5) - hash) + ( this.hardwareAccelerated ? 1 : 0 ); hash = ((hash << 5) - hash) + this.depthBits; @@ -132,7 +134,8 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil GLCapabilitiesImmutable other = (GLCapabilitiesImmutable)obj; boolean res = super.equals(obj) && other.getGLProfile()==glProfile && - other.isPBuffer()==pbuffer && + other.isPBuffer()==isPBuffer && + other.isFBO()==isFBO && other.getStereo()==stereo && other.getHardwareAccelerated()==hardwareAccelerated && other.getDepthBits()==depthBits && @@ -180,8 +183,8 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil return -1; } - final int ms = sampleBuffers ? numSamples : 0; - final int xms = caps.getSampleBuffers() ? caps.getNumSamples() : 0; + final int ms = getNumSamples(); + final int xms = caps.getNumSamples() ; if(ms > xms) { return 1; @@ -222,30 +225,53 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil @Override public final boolean isPBuffer() { - return pbuffer; + return isPBuffer; } /** - * Enables or disables pbuffer usage.<br> - * If enabled this method also invokes {@link #setOnscreen(int) setOnscreen(false)}<br> + * Enables or disables pbuffer usage. + * <p> + * If enabled this method also invokes {@link #setOnscreen(int) setOnscreen(false)}. + * </p> * Defaults to false. */ public void setPBuffer(boolean enable) { if(enable) { setOnscreen(false); } - pbuffer = enable; + isPBuffer = enable; + } + + @Override + public final boolean isFBO() { + return isFBO; + } + + /** + * Enables or disables FBO usage. + * <p> + * If enabled this method also invokes {@link #setOnscreen(int) setOnscreen(false)}. + * </p> + * Defaults to false. + */ + public void setFBO(boolean enable) { + if(enable) { + setOnscreen(false); + } + isFBO = enable; } /** * Sets whether the drawable surface supports onscreen.<br> - * If enabled this method also invokes {@link #setPBuffer(int) setPBuffer(false)}<br> + * If enabled this method also invokes {@link #setPBuffer(int) setPBuffer(false)} + * and {@link #setFBO(int) setFBO(false)}<br> * Defaults to true. */ @Override public void setOnscreen(boolean onscreen) { if(onscreen) { setPBuffer(false); + setFBO(false); } super.setOnscreen(onscreen); } @@ -385,15 +411,18 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil return sampleBuffers; } - /** If sample buffers are enabled, indicates the number of buffers - to be allocated. Defaults to 2. */ + /** + * If sample buffers are enabled, indicates the number of buffers + * to be allocated. Defaults to 2. + * @see #getNumSamples() + */ public void setNumSamples(int numSamples) { this.numSamples = numSamples; } @Override public final int getNumSamples() { - return numSamples; + return sampleBuffers ? numSamples : 0; } /** For pbuffers only, indicates whether floating-point buffers @@ -462,12 +491,16 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil } sink.append(glProfile); if(!isOnscreen()) { - if(pbuffer) { + if(isFBO) { + sink.append(", fbo"); + } + if(isPBuffer) { sink.append(", pbuffer [r2t ").append(pbufferRenderToTexture?1:0) .append(", r2tr ").append(pbufferRenderToTextureRectangle?1:0) .append(", float ").append(pbufferFloatingPointBuffers?1:0) .append("]"); - } else { + } + if(!isFBO && !isPBuffer) { sink.append(", pixmap"); } } diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java b/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java index 5f8795edc..7e0459b2d 100644 --- a/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java +++ b/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java @@ -111,7 +111,7 @@ public interface GLCapabilitiesImmutable extends CapabilitiesImmutable { /** * Returns the number of sample buffers to be allocated if sample - * buffers are enabled. Defaults to 2. + * buffers are enabled, otherwise returns 0. Defaults to 2. */ int getNumSamples(); @@ -144,10 +144,15 @@ public interface GLCapabilitiesImmutable extends CapabilitiesImmutable { boolean getStereo(); /** - * Indicates whether pbuffer is used/requested. + * Indicates whether pbuffer offscreen is used/requested. */ boolean isPBuffer(); + /** + * Indicates whether FBO offscreen is used/requested. + */ + boolean isFBO(); + @Override boolean equals(Object obj); diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 351f90027..63a02ad9c 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -55,6 +55,7 @@ import com.jogamp.common.os.Platform; import com.jogamp.common.util.IntObjectHashMap; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.opengl.GLExtensions; /** Abstraction for an OpenGL rendering context. In order to perform OpenGL rendering, a context must be "made current" on the current @@ -69,6 +70,7 @@ import com.jogamp.common.util.locks.RecursiveLock; abstraction provides a stable object which clients can use to refer to a given context. */ public abstract class GLContext { + /** * If <code>true</code> (default), bootstrapping the available GL profiles * will use the highest compatible GL context for each profile, @@ -120,13 +122,13 @@ public abstract class GLContext { protected static final int CTX_PROFILE_ES = 1 << 3; /** <code>ARB_create_context</code> related: flag forward compatible. Cache key value. See {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_OPTION_FORWARD = 1 << 4; - /** <code>ARB_create_context</code> related: flag debug. Not a cache key. See {@link #setContextCreationFlags(int)}, {@link GLAutoDrawable#setContextCreationFlags(int)}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + /** <code>ARB_create_context</code> related: flag debug. Cache key value. See {@link #setContextCreationFlags(int)}, {@link GLAutoDrawable#setContextCreationFlags(int)}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ public static final int CTX_OPTION_DEBUG = 1 << 5; /** <code>GL_ARB_ES2_compatibility</code> implementation related: Context is compatible w/ ES2. Not a cache key. See {@link #isGLES2Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_IMPL_ES2_COMPAT = 1 << 8; - /** Context supports FBO, details see {@link #hasFBO()}. + /** Context supports basic FBO, details see {@link #hasFBO()}. * Not a cache key. * @see #hasFBO() * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile) @@ -136,16 +138,6 @@ public abstract class GLContext { /** Context uses software rasterizer, otherwise hardware rasterizer. Cache key value. See {@link #isHardwareRasterizer()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 15; - protected static final String GL_ARB_ES2_compatibility = "GL_ARB_ES2_compatibility"; - protected static final String GL_ARB_framebuffer_object = "GL_ARB_framebuffer_object"; - protected static final String GL_EXT_framebuffer_object = "GL_EXT_framebuffer_object"; - protected static final String GL_EXT_framebuffer_blit = "GL_EXT_framebuffer_blit"; - protected static final String GL_EXT_framebuffer_multisample = "GL_EXT_framebuffer_multisample"; - protected static final String GL_EXT_packed_depth_stencil = "GL_EXT_packed_depth_stencil"; - protected static final String GL_ARB_texture_non_power_of_two = "GL_ARB_texture_non_power_of_two"; - protected static final String GL_EXT_texture_format_BGRA8888 = "GL_EXT_texture_format_BGRA8888"; - protected static final String GL_IMG_texture_format_BGRA8888 = "GL_IMG_texture_format_BGRA8888"; - private static final ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>(); private final HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>(); @@ -639,11 +631,19 @@ public abstract class GLContext { return 0 == ( ctxOptions & CTX_IMPL_ACCEL_SOFT ) ; } - /** Returns whether the context supports FBO, hence is either GL-ES >= 2.0, >= core GL 3.0 or implements the extensions - * <code>GL_ARB_ES2_compatibility</code>, <code>ARB_framebuffer_object</code> or all of - * <code>EXT_framebuffer_object</code>, <code>EXT_framebuffer_multisample</code>, - * <code>EXT_framebuffer_blit</code>, <code>GL_EXT_packed_depth_stencil</code>. + /** + * Returns <code>true</code> if basic FBO support is available, otherwise <code>false</code>. + * <p> + * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= core 3.0 or implements the extensions + * <code>GL_ARB_ES2_compatibility</code>, <code>GL_ARB_framebuffer_object</code>, <code>GL_EXT_framebuffer_object</code> or <code>GL_OES_framebuffer_object</code>. + * </p> + * <p> + * Basic FBO support may only include one color attachment and no multisampling, + * as well as limited internal formats for renderbuffer. + * </p> * @see #CTX_IMPL_FBO + * @see com.jogamp.opengl.FBObject#supportsBasicFBO(GL) + * @see com.jogamp.opengl.FBObject#supportsFullFBO(GL) */ public final boolean hasFBO() { return 0 != ( ctxOptions & CTX_IMPL_FBO ) ; @@ -659,13 +659,13 @@ public abstract class GLContext { /** Note: The GL impl. may return a const value, ie {@link GLES2#isNPOTTextureAvailable()} always returns <code>true</code>. */ public boolean isNPOTTextureAvailable() { - return isGL3() || isGLES2Compatible() || isExtensionAvailable(GL_ARB_texture_non_power_of_two); + return isGL3() || isGLES2Compatible() || isExtensionAvailable(GLExtensions.ARB_texture_non_power_of_two); } public boolean isTextureFormatBGRA8888Available() { return isGL2GL3() || - isExtensionAvailable(GL_EXT_texture_format_BGRA8888) || - isExtensionAvailable(GL_IMG_texture_format_BGRA8888) ; + isExtensionAvailable(GLExtensions.EXT_texture_format_BGRA8888) || + isExtensionAvailable(GLExtensions.IMG_texture_format_BGRA8888) ; } /** @see GLProfile#isGL4bc() */ @@ -798,7 +798,32 @@ public abstract class GLContext { } protected boolean bindSwapBarrierImpl(int group, int barrier) { /** nop per default .. **/ return false; } - + /** + * Return the framebuffer name bound to this context, + * see {@link GL#glBindFramebuffer(int, int)}. + */ + public abstract int getBoundFramebuffer(int target); + + /** + * Return the default draw framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link FBObject}) based drawable + * is being used. + * </p> + */ + public abstract int getDefaultDrawFramebuffer(); + + /** + * Return the default read framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link FBObject}) based drawable + * is being used. + * </p> + */ + public abstract int getDefaultReadFramebuffer(); + /** * @return The extension implementing the GLDebugOutput feature, * either <i>GL_ARB_debug_output</i> or <i>GL_AMD_debug_output</i>. @@ -984,6 +1009,7 @@ public abstract class GLContext { deviceVersionsAvailableSet.add(devKey); if (DEBUG) { System.err.println(getThreadName() + ": createContextARB: SET mappedVersionsAvailableSet "+devKey); + System.err.println(GLContext.dumpAvailableGLVersions(null).toString()); } } } @@ -1010,6 +1036,10 @@ public abstract class GLContext { validateProfileBits(profile, "profile"); validateProfileBits(resCtp, "resCtp"); + if(DEBUG) { + System.err.println("GLContext.mapAvailableGLVersion: "+device+": "+getGLVersion(reqMajor, 0, profile, null)+" -> "+getGLVersion(resMajor, resMinor, resCtp, null)); + // Thread.dumpStack(); + } final String key = getDeviceVersionAvailableKey(device, reqMajor, profile); final Integer val = new Integer(composeBits(resMajor, resMinor, resCtp)); synchronized(deviceVersionAvailable) { @@ -1122,7 +1152,9 @@ public abstract class GLContext { } else /* if (glpImpl.isGL2()) */ { reqMajorCTP[0]=2; } - if( glpImpl.isGL2() ) { // incl GL3bc and GL4bc + if( glpImpl.isGLES() ) { + reqMajorCTP[1]=CTX_PROFILE_ES; + } else if( glpImpl.isGL2() ) { // incl GL3bc and GL4bc reqMajorCTP[1]=CTX_PROFILE_COMPAT; } else { reqMajorCTP[1]=CTX_PROFILE_CORE; @@ -1141,8 +1173,7 @@ public abstract class GLContext { int _major[] = { 0 }; int _minor[] = { 0 }; int _ctp[] = { 0 }; - if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1], - _major, _minor, _ctp)) { + if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1], _major, _minor, _ctp)) { return _ctp[0]; } return 0; // n/a @@ -1181,6 +1212,23 @@ public abstract class GLContext { } /** + * Returns true if it is possible to create an <i>framebuffer object</i> (FBO). + * <p> + * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent. + * </p> + * <p> + * FBO support is queried as described in {@link #hasFBO()}. + * </p> + * + * @param device the device to request whether FBO is available for + * @param glp {@link GLProfile} to check for FBO capabilities + * @see GLContext#hasFBO() + */ + public static final boolean isFBOAvailable(AbstractGraphicsDevice device, GLProfile glp) { + return 0 != ( CTX_IMPL_FBO & getAvailableContextProperties(device, glp) ); + } + + /** * @param device the device to request whether the profile is available for * @param reqMajor Key Value either 1, 2, 3 or 4 * @param reqProfile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index d6480e7aa..9a0d2cb99 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -50,9 +50,11 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.ReflectionUtil; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; import javax.media.opengl.GLProfile.ShutdownType; import jogamp.opengl.Debug; @@ -398,9 +400,18 @@ public abstract class GLDrawableFactory { /** * Creates a Offscreen GLDrawable incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions. * <p> - * A Pbuffer drawable/surface is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()} - * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.<br> - * Otherwise a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated.<br> + * It's {@link AbstractGraphicsConfiguration} is properly set according to the given {@link GLCapabilitiesImmutable}, see below. + * </p> + * <p> + * A FBO drawable is created if both {@link javax.media.opengl.GLCapabilities#isFBO() caps.isFBO()} + * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true. + * </p> + * <p> + * A Pbuffer drawable is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()} + * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true. + * </p> + * <p> + * If neither FBO nor Pbuffer is available, a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated. * </p> * * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. @@ -421,42 +432,32 @@ public abstract class GLDrawableFactory { throws GLException; /** - * Creates an offscreen NativeSurface.<br> - * A Pbuffer surface is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()} - * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.<br> - * Otherwise a simple pixmap/bitmap surface is created. The latter is unlikely to be hardware accelerated.<br> - * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. - * @param caps the requested GLCapabilties - * @param chooser the custom chooser, may be null for default - * @param width the requested offscreen width - * @param height the requested offscreen height - * @return the created offscreen native surface - * - * @throws GLException if any window system-specific errors caused - * the creation of the GLDrawable to fail. - */ - public abstract NativeSurface createOffscreenSurface(AbstractGraphicsDevice device, - GLCapabilitiesImmutable caps, - GLCapabilitiesChooser chooser, - int width, int height); - - /** - * Highly experimental API entry, allowing developer of new windowing system bindings - * to leverage the native window handle to produce a NativeSurface implementation (ProxySurface), having the required GLCapabilities.<br> - * Such surface can be used to instantiate a GLDrawable and hence test your new binding w/o the - * costs of providing a full set of abstraction like the AWT GLCanvas or even the native NEWT bindings. + * Creates a proxy {@link NativeSurface} w/ defined surface handle, i.e. a {@link WrappedSurface} or {@link GDISurface} instance. + * <p> + * It's {@link AbstractGraphicsConfiguration} is properly set according to the given + * <code>windowHandle</code>'s native visualID if set or the given {@link GLCapabilitiesImmutable}. + * </p> + * <p> + * Lifecycle (destruction) of the given surface handle shall be handled by the caller. + * </p> + * <p> + * Such surface can be used to instantiate a GLDrawable. With the help of {@link GLAutoDrawableDelegate} + * you will be able to implement a new native windowing system binding almost on-the-fly, see {@link com.jogamp.opengl.swt.GLCanvas}. + * </p> * - * @param device the platform's target device, shall not be <code>null</code> + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * Caller has to ensure it is compatible w/ the given <code>windowHandle</code> + * @param screenIdx matching screen index of given <code>windowHandle</code> * @param windowHandle the native window handle * @param caps the requested GLCapabilties * @param chooser the custom chooser, may be null for default - * @return The proxy surface wrapping the windowHandle on the device + * @param upstream optional {@link ProxySurface.UpstreamSurfaceHook} allowing control of the {@link ProxySurface}'s lifecycle and data it presents. + * @return the created {@link ProxySurface} instance w/ defined surface handle. */ - public abstract ProxySurface createProxySurface(AbstractGraphicsDevice device, + public abstract ProxySurface createProxySurface(AbstractGraphicsDevice device, + int screenIdx, long windowHandle, - GLCapabilitiesImmutable caps, - GLCapabilitiesChooser chooser); + GLCapabilitiesImmutable caps, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream); /** * Returns true if it is possible to create a GLPbuffer. Some older @@ -492,23 +493,7 @@ public abstract class GLDrawableFactory { GLContext shareWith) throws GLException; - /** - * Returns true if it is possible to create an <i>framebuffer object</i> (FBO). - * <p> - * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent. - * </p> - * <p> - * FBO support is queried as described in {@link GLContext#hasFBO()}. - * </p> - * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. - * @param glp {@link GLProfile} to check for FBO capabilities - * @see GLContext#hasFBO() - */ - public final boolean canCreateFBO(AbstractGraphicsDevice device, GLProfile glp) { - return 0 != ( GLContext.CTX_IMPL_FBO & GLContext.getAvailableContextProperties(device, glp) ); - } - + //---------------------------------------------------------------------- // Methods for interacting with third-party OpenGL libraries diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java index a7200b560..1e10dc9a6 100644 --- a/src/jogl/classes/javax/media/opengl/GLProfile.java +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -86,7 +86,14 @@ public class GLProfile { * </p> */ private static final boolean enableANGLE = Debug.isPropertyDefined("jogl.enable.ANGLE", true); - + + /** + * In case no OpenGL ES implementation is required + * and if the running platform may have a buggy implementation, + * setting the property <code>jogl.disable.opengles</code> disables querying a possible existing OpenGL ES implementation. + */ + private static final boolean disableOpenGLES = Debug.isPropertyDefined("jogl.disable.opengles", true); + static { // Also initializes TempJarCache if shall be used. Platform.initSingleton(); @@ -117,10 +124,12 @@ public class GLProfile { * @deprecated Use {@link #initSingleton()}. This method is subject to be removed in future versions of JOGL. */ public static void initSingleton(final boolean firstUIActionOnProcess) { + final boolean justInitialized; initLock.lock(); try { if(!initialized) { // volatile: ok initialized = true; + justInitialized = true; if(DEBUG) { System.err.println("GLProfile.initSingleton(firstUIActionOnProcess: "+firstUIActionOnProcess+") - thread "+Thread.currentThread().getName()); Thread.dumpStack(); @@ -166,10 +175,17 @@ public class GLProfile { return null; } }); + } else { + justInitialized = false; } } finally { initLock.unlock(); } + if(DEBUG) { + if( justInitialized && ( hasGL234Impl || hasGLES1Impl || hasGLES2Impl ) ) { + System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true)); + } + } } /** @@ -1466,7 +1482,7 @@ public class GLProfile { } } - if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) { + if ( !disableOpenGLES && ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) { t=null; try { eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); @@ -1532,18 +1548,17 @@ public class GLProfile { if(DEBUG) { // System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", egl "+addedEGLProfile+")"); - System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile); - System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); - System.err.println("GLProfile.init hasDesktopGLFactory "+hasDesktopGLFactory); - System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); - System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory); - System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); - System.err.println("GLProfile.init hasGLES2Impl "+hasGLES2Impl); - System.err.println("GLProfile.init defaultDevice "+defaultDevice); - System.err.println("GLProfile.init profile order "+array2String(GL_PROFILE_LIST_ALL)); - if(hasGL234Impl || hasGLES1Impl || hasGLES2Impl) { // avoid deadlock - System.err.println(JoglVersion.getDefaultOpenGLInfo(null, true)); - } + System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile); + System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); + System.err.println("GLProfile.init hasDesktopGLFactory "+hasDesktopGLFactory); + System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); + System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory); + System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); + System.err.println("GLProfile.init hasGLES2Impl "+hasGLES2Impl); + System.err.println("GLProfile.init defaultDevice "+defaultDevice); + System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice); + System.err.println("GLProfile.init defaultDevice EGL "+defaultEGLDevice); + System.err.println("GLProfile.init profile order "+array2String(GL_PROFILE_LIST_ALL)); } } @@ -1642,24 +1657,6 @@ public class GLProfile { if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail); } - if( hasGLES2Impl ) { - // The native ES2 impl. overwrites a previous mapping using 'ES2 compatibility' by a desktop profile - GLContext.mapAvailableGLVersion(device, - 2, GLContext.CTX_PROFILE_ES, - 2, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_IMPL_ES2_COMPAT); - if (DEBUG) { - System.err.println(GLContext.getThreadName() + ": initProfilesForDeviceCritical-MapVersionsAvailable HAVE: ES2 -> ES 2.0"); - } - } - if( hasGLES1Impl ) { - // Always favor the native ES1 impl. - GLContext.mapAvailableGLVersion(device, - 1, GLContext.CTX_PROFILE_ES, - 1, 0, GLContext.CTX_PROFILE_ES); - if (DEBUG) { - System.err.println(GLContext.getThreadName() + ": initProfilesForDeviceCritical-MapVersionsAvailable HAVE: ES1 -> ES 1.0"); - } - } addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); } @@ -1767,7 +1764,7 @@ public class GLProfile { } _mappedProfiles.put(profile, glProfile); if (DEBUG) { - System.err.println("GLProfile.init map "+glProfile+" on devide "+device.getConnection()); + System.err.println("GLProfile.init map "+glProfile+" on device "+device.getConnection()); } if(null==defaultGLProfileHW && isHardwareRasterizer[0]) { defaultGLProfileHW=glProfile; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 48f7ea24a..03fd78ac7 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -60,6 +60,7 @@ import java.util.ArrayList; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; @@ -84,6 +85,8 @@ import javax.media.opengl.Threading; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.util.VersionUtil; +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; @@ -132,20 +135,6 @@ import jogamp.opengl.GLDrawableHelper; * <ul> * <li><pre>sun.awt.noerasebackground=true</pre></li> * </ul> - * <p> - * FIXME: If this instance runs in multithreading mode, see {@link Threading#isSingleThreaded()} (default: single-thread), - * proper recursive locking is required for drawable/context @ destroy and display. - * Recreation etc could pull those instances while animating! - * Simply locking before using drawable/context offthread - * would allow a deadlock situation! - * </p> - * <p> - * NOTE: [MT-0] Methods utilizing [volatile] drawable/context are not synchronized. - In case any of the methods are called outside of a locked state - extra care should be added. Maybe we shall expose locking facilities to the user. - However, since the user shall stick to the GLEventListener model while utilizing - GLAutoDrawable implementations, she is safe due to the implicit locked state. - * </p> */ @SuppressWarnings("serial") @@ -153,11 +142,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing 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 GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display + private volatile GLDrawable drawable; // volatile: avoid locking for read-only access private GLContextImpl context; - private boolean sendReshape = false; + private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking // copy of the cstr args, mainly for recreation private GLCapabilitiesImmutable capsReqUser; @@ -262,6 +252,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } @Override + public final Object getUpstreamWidget() { + return this; + } + + @Override public void setShallUseOffscreenLayer(boolean v) { shallUseOffscreenLayer = v; } @@ -273,8 +268,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public final boolean isOffscreenLayerSurfaceEnabled() { - if(null != drawable) { - return ((JAWTWindow)drawable.getNativeSurface()).isOffscreenLayerSurfaceEnabled(); + final GLDrawable _drawable = drawable; + if(null != _drawable) { + return ((JAWTWindow)_drawable.getNativeSurface()).isOffscreenLayerSurfaceEnabled(); } return false; } @@ -393,12 +389,18 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public GLContext createContext(final GLContext shareWith) { - if(drawable != null) { - final GLContext _ctx = drawable.createContext(shareWith); - _ctx.setContextCreationFlags(additionalCtxCreationFlags); - return _ctx; + 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(); } - return null; } @Override @@ -407,7 +409,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public boolean isRealized() { - return (null != drawable) ? drawable.isRealized() : false; + final GLDrawable _drawable = drawable; + return ( null != _drawable ) ? _drawable.isRealized() : false; } @Override @@ -422,50 +425,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @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 .. - } Threading.invoke(true, displayOnEDTAction, getTreeLock()); - awtWindowClosingProtocol.addClosingListenerOneShot(); } private void dispose(boolean regenerate) { - final GLAnimatorControl animator = getAnimator(); - if(DEBUG) { - System.err.println(getThreadName()+": Info: dispose("+regenerate+") - START, hasContext " + - (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator); - Thread.dumpStack(); - } - - if(null!=drawable && null!=context) { // drawable is volatile! - boolean animatorPaused = false; - if(null!=animator) { - // can't remove us from animator for recreational addNotify() - animatorPaused = animator.pause(); - } - - disposeRegenerate=regenerate; - - if(context.isCreated()) { - Threading.invoke(true, disposeOnEDTAction, getTreeLock()); - } - - if(animatorPaused) { - animator.resume(); - } - } - - if(!regenerate) { - disposeAbstractGraphicsDevice(); - } - - if(DEBUG) { - System.err.println(getThreadName()+": dispose("+regenerate+") - END, "+animator); - } + disposeRegenerate=regenerate; + Threading.invoke(true, disposeOnEDTAction, getTreeLock()); } /** @@ -525,43 +491,49 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @SuppressWarnings("deprecation") @Override public void addNotify() { - if(DEBUG) { - System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()); - Thread.dumpStack(); - } - - /** - * 'super.addNotify()' determines the GraphicsConfiguration, - * while calling this class's overriden 'getGraphicsConfiguration()' method - * after which it creates the native peer. - * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration - * is being used in getGraphicsConfiguration(). - * This code order also allows recreation, ie re-adding the GLCanvas. - */ - awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device); - if(null==awtConfig) { - throw new GLException("Error: NULL AWTGraphicsConfiguration"); - } - - // before native peer is valid: X11 - disableBackgroundErase(); - - // issues getGraphicsConfiguration() and creates the native peer - super.addNotify(); - - // after native peer is valid: Windows - disableBackgroundErase(); - - if (!Beans.isDesignTime()) { - createDrawableAndContext(); - } - - // init drawable by paint/display makes the init sequence more equal - // for all launch flavors (applet/javaws/..) - // validateGLDrawable(); - - if(DEBUG) { - System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer()); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if(DEBUG) { + System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()); + Thread.dumpStack(); + } + + /** + * 'super.addNotify()' determines the GraphicsConfiguration, + * while calling this class's overriden 'getGraphicsConfiguration()' method + * after which it creates the native peer. + * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration + * is being used in getGraphicsConfiguration(). + * This code order also allows recreation, ie re-adding the GLCanvas. + */ + awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device); + if(null==awtConfig) { + throw new GLException("Error: NULL AWTGraphicsConfiguration"); + } + + // before native peer is valid: X11 + disableBackgroundErase(); + + // issues getGraphicsConfiguration() and creates the native peer + super.addNotify(); + + // after native peer is valid: Windows + disableBackgroundErase(); + + if (!Beans.isDesignTime()) { + createDrawableAndContext(); + } + + // init drawable by paint/display makes the init sequence more equal + // for all launch flavors (applet/javaws/..) + // validateGLDrawable(); + + if(DEBUG) { + System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer()); + } + } finally { + _lock.unlock(); } } @@ -580,23 +552,24 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } private boolean validateGLDrawable() { - boolean realized = false; - if (!Beans.isDesignTime()) { - if ( null != drawable ) { // OK: drawable is volatile - realized = drawable.isRealized(); - if ( !realized && 0 < drawable.getWidth() * drawable.getHeight() ) { - // make sure drawable realization happens on AWT EDT, due to AWTTree lock - AWTEDTExecutor.singleton.invoke(true, setRealizedOnEDTAction); - realized = true; - sendReshape=true; // ensure a reshape is being send .. - if(DEBUG) { - System.err.println(getThreadName()+": Realized Drawable: "+drawable.toString()); - Thread.dumpStack(); - } + final GLDrawable _drawable = drawable; + if ( null != _drawable ) { + if( _drawable.isRealized() ) { + return true; + } + if (!Beans.isDesignTime() && + 0 < _drawable.getWidth() * _drawable.getHeight() ) { + // make sure drawable realization happens on AWT EDT, due to AWTTree lock + AWTEDTExecutor.singleton.invoke(true, setRealizedOnEDTAction); + sendReshape=true; // ensure a reshape is being send .. + if(DEBUG) { + System.err.println(getThreadName()+": Realized Drawable: "+_drawable.toString()); + Thread.dumpStack(); } + return true; } } - return realized; + return false; } private Runnable setRealizedOnEDTAction = new Runnable() { @Override @@ -628,9 +601,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing try { dispose(false); } finally { - context=null; - drawable=null; - awtConfig=null; super.removeNotify(); } } @@ -650,7 +620,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void reshape(int x, int y, int width, int height) { super.reshape(x, y, width, height); - if(null != drawable && drawable.isRealized() && !drawable.getChosenGLCapabilities().isOnscreen()) { + final GLDrawable _drawable = drawable; + if(null != _drawable && _drawable.isRealized() && !_drawable.getChosenGLCapabilities().isOnscreen()) { dispose(true); } else { sendReshape = true; @@ -705,13 +676,19 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public GLContext setContext(GLContext newCtx) { - final GLContext oldCtx = context; - final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); - context=(GLContextImpl)newCtx; - if(newCtxCurrent) { - context.makeCurrent(); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final GLContext oldCtx = context; + final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + context=(GLContextImpl)newCtx; + if(newCtxCurrent) { + context.makeCurrent(); + } + return oldCtx; + } finally { + _lock.unlock(); } - return oldCtx; } @Override @@ -724,15 +701,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if (Beans.isDesignTime()) { return null; } - GLContext ctx = getContext(); - return (ctx == null) ? null : ctx.getGL(); + final GLContext _context = context; + return (_context == null) ? null : _context.getGL(); } @Override public GL setGL(GL gl) { - GLContext ctx = getContext(); - if (ctx != null) { - ctx.setGL(gl); + final GLContext _context = context; + if (_context != null) { + _context.setGL(gl); return gl; } return null; @@ -757,8 +734,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void setContextCreationFlags(int flags) { additionalCtxCreationFlags = flags; - if(null != context) { - context.setContextCreationFlags(additionalCtxCreationFlags); + final GLContext _context = context; + if(null != _context) { + _context.setContextCreationFlags(additionalCtxCreationFlags); } } @@ -791,26 +769,30 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public NativeSurface getNativeSurface() { - return (null != drawable) ? drawable.getNativeSurface() : null; + final GLDrawable _drawable = drawable; + return (null != _drawable) ? _drawable.getNativeSurface() : null; } @Override public long getHandle() { - return (null != drawable) ? drawable.getHandle() : 0; + final GLDrawable _drawable = drawable; + return (null != _drawable) ? _drawable.getHandle() : 0; } @Override public GLDrawableFactory getFactory() { - return (null != drawable) ? drawable.getFactory() : null; + final GLDrawable _drawable = drawable; + return (null != _drawable) ? _drawable.getFactory() : null; } @Override public String toString() { - final int dw = (null!=drawable) ? drawable.getWidth() : -1; - final int dh = (null!=drawable) ? drawable.getHeight() : -1; + final GLDrawable _drawable = drawable; + final int dw = (null!=_drawable) ? _drawable.getWidth() : -1; + final int dh = (null!=_drawable) ? _drawable.getHeight() : -1; return "AWT-GLCanvas[Realized "+isRealized()+ - ",\n\t"+((null!=drawable)?drawable.getClass().getName():"null-drawable")+ + ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ ",\n\tFactory "+getFactory()+ ",\n\thandle 0x"+Long.toHexString(getHandle())+ ",\n\tDrawable size "+dw+"x"+dh+ @@ -824,7 +806,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // private boolean disposeRegenerate; - private final Runnable postDisposeAction = new Runnable() { + private final Runnable postDisposeOnEDTAction = new Runnable() { @Override public void run() { context=null; @@ -854,7 +836,47 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable disposeOnEDTAction = new Runnable() { @Override public void run() { - helper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final GLAnimatorControl animator = getAnimator(); + + if(DEBUG) { + System.err.println(getThreadName()+": Info: dispose("+disposeRegenerate+") - START, hasContext " + + (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator); + Thread.dumpStack(); + } + + if(null!=drawable && null!=context) { + boolean animatorPaused = false; + if(null!=animator) { + // can't remove us from animator for recreational addNotify() + animatorPaused = animator.pause(); + } + + if(context.isCreated()) { + helper.disposeGL(GLCanvas.this, drawable, context, postDisposeOnEDTAction); + } + + if(animatorPaused) { + animator.resume(); + } + } + + if(!disposeRegenerate) { + if(null != awtConfig) { + disposeAbstractGraphicsDevice(); + } + awtConfig=null; + } + + if(DEBUG) { + System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - END, "+animator); + } + + } finally { + _lock.unlock(); + } } }; @@ -874,7 +896,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if(DEBUG) { System.err.println(getThreadName()+": GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); } - awtConfig=null; } } }; @@ -885,7 +906,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing * * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice) */ - void disposeAbstractGraphicsDevice() { + private void disposeAbstractGraphicsDevice() { if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { disposeAbstractGraphicsDeviceAction.run(); } else { @@ -936,14 +957,30 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable displayOnEDTAction = new Runnable() { @Override public void run() { - helper.invokeGL(drawable, context, displayAction, initAction); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( validateGLDrawable() ) { + helper.invokeGL(drawable, context, displayAction, initAction); + } else if(DEBUG) { + System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet"); + } + } finally { + _lock.unlock(); + } } }; private final Runnable swapBuffersOnEDTAction = new Runnable() { @Override public void run() { - helper.invokeGL(drawable, context, swapBuffersAction, initAction); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + helper.invokeGL(drawable, context, swapBuffersAction, initAction); + } finally { + _lock.unlock(); + } } }; @@ -1026,9 +1063,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { config = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, aScreen); + chooser, aScreen, VisualIDHolder.VID_UNDEFINED); } else { try { final ArrayList<AWTGraphicsConfiguration> bucket = new ArrayList<AWTGraphicsConfiguration>(1); @@ -1036,9 +1073,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void run() { AWTGraphicsConfiguration c = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, aScreen); + chooser, aScreen, VisualIDHolder.VID_UNDEFINED); bucket.add(c); } }); @@ -1070,7 +1107,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // System.err.println(NativeWindowVersion.getInstance()); System.err.println(JoglVersion.getInstance()); - System.err.println(JoglVersion.getDefaultOpenGLInfo(null, true).toString()); + 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"); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index cd18c5098..acb8f2183 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -87,7 +87,7 @@ import jogamp.opengl.awt.Java2D; import jogamp.opengl.awt.Java2DGLContext; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; -import com.jogamp.opengl.util.FBObject; +import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.GLBuffers; // FIXME: Subclasses need to call resetGLFunctionAvailability() on their @@ -251,6 +251,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } @Override + public final Object getUpstreamWidget() { + return this; + } + + @Override public void display() { if (EventQueue.isDispatchThread()) { // Want display() to be synchronous, so call paintImmediately() |