diff options
Diffstat (limited to 'src')
18 files changed, 1569 insertions, 32 deletions
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index cf24d1028..90290d882 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -185,14 +185,14 @@ public interface GLAutoDrawable extends GLDrawable { * Enqueues a one-shot {@link javax.media.opengl.GLRunnable}, * which will be executed with the next {@link #display()} call.</p> * <p> - * If a {@link javax.media.opengl.GLAnimatorControl} is registered, or if it's not animating, the default situation,<br> + * If no {@link javax.media.opengl.GLAnimatorControl} is registered, or if it is not animating, the default situation,<br> * or if the current thread is the animator thread,<br> - * a {@link #display()} call has to be issued after enqueue the <code>GLRunnable</code>.<br> - * No extra synchronization must be performed in case <code>wait</code> is true, since it is executed in the current thread.</p> + * a {@link #display()} call is issued after enqueue the <code>GLRunnable</code>.<br> + * No extra synchronization is performed in case <code>wait</code> is true, since it is executed in the current thread.</p> * <p> * If {@link javax.media.opengl.GLAnimatorControl} is registered and is animating,<br> - * no call of {@link #display()} must be issued, since the animator thread will performs it.<br> - * If <code>wait</code> is true, the implementation must wait until the <code>GLRunnable</code> is executed.<br> + * no {@link #display()} call is issued, since the animator thread performs it.<br> + * If <code>wait</code> is true, the implementation waits until the <code>GLRunnable</code> is executed.<br> * </p><br> * * @see #setAnimator(javax.media.opengl.GLAnimatorControl) @@ -255,6 +255,19 @@ public interface GLAutoDrawable extends GLDrawable { drawable. See {@link #setAutoSwapBufferMode}. */ public boolean getAutoSwapBufferMode(); + /** + * @param flags Additional context creation flags. + * + * @see GLContext#setContextCreationFlags(int) + * @see GLContext#enableGLDebugMessage(boolean) + */ + public void setContextCreationFlags(int flags); + + /** + * @return Additional context creation flags + */ + public int getContextCreationFlags(); + /** Returns the {@link GL} pipeline object this GLAutoDrawable uses. If this method is called outside of the {@link GLEventListener}'s callback methods (init, display, etc.) it may diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index a81bc5f27..08bbcbb96 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -40,6 +40,7 @@ package javax.media.opengl; +import java.nio.IntBuffer; import java.util.HashMap; import java.util.HashSet; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -84,10 +85,10 @@ public abstract class GLContext { protected static final int CTX_PROFILE_ES = 1 << 3; /** <code>ARB_create_context</code> related: flag forward compatible */ protected static final int CTX_OPTION_FORWARD = 1 << 4; - /** <code>ARB_create_context</code> related: not flag forward compatible */ + /** <code>ARB_create_context</code> related: flag not forward compatible */ protected static final int CTX_OPTION_ANY = 1 << 5; /** <code>ARB_create_context</code> related: flag debug */ - protected static final int CTX_OPTION_DEBUG = 1 << 6; + public static final int CTX_OPTION_DEBUG = 1 << 6; /** GLContext {@link com.jogamp.gluegen.runtime.ProcAddressTable} caching related: GL software implementation */ protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 0; @@ -419,6 +420,20 @@ public abstract class GLContext { public final boolean isGLForwardCompatible() { return ( 0 != ( CTX_OPTION_FORWARD & ctxOptions ) ); } public final boolean isCreatedWithARBMethod() { return ( 0 != ( CTX_IS_ARB_CREATED & ctxOptions ) ); } + /** + * @return Additional context creation flags, supported: {@link GLContext#CTX_OPTION_DEBUG}. + */ + public abstract int getContextCreationFlags(); + + /** + * @param flags Additional context creation flags, supported: {@link GLContext#CTX_OPTION_DEBUG}. + * Unsupported flags are masked out. + * Only affects this context state if not created yet via {@link #makeCurrent()}. + * @see #enableGLDebugMessage(boolean) + * @see GLAutoDrawable#setContextCreationFlags(int) + */ + public abstract void setContextCreationFlags(int flags); + /** * Returns a valid OpenGL version string, ie<br> * <pre> @@ -516,6 +531,87 @@ public abstract class GLContext { return isGL2ES2() ; } + /** + * @return The extension implementing the GLDebugOutput feature, + * either <i>GL_ARB_debug_output</i> or <i>GL_AMD_debug_output</i>. + * If unavailable or called before initialized via {@link #makeCurrent()}, <i>null</i> is returned. + */ + public abstract String getGLDebugMessageExtension(); + + /** + * @return true if the GLDebugOutput feature is enabled or not. + */ + public abstract boolean isGLDebugMessageEnabled(); + + /** + * Enables or disables the GLDebugOutput feature of extension <i>GL_ARB_debug_output</i> + * or <i>GL_AMD_debug_output</i>, if available. + * + * <p>To enable the GLDebugOutput feature {@link #enableGLDebugMessage(boolean) enableGLDebugMessage(true)} + * or {@link #setContextCreationFlags(int) setContextCreationFlags}({@link GLContext#CTX_OPTION_DEBUG}) + * shall be called <b>before</b> context creation via {@link #makeCurrent()}!</p> + * + * <p>In case {@link GLAutoDrawable} are being used, + * {@link GLAutoDrawable#setContextCreationFlags(int) glAutoDrawable.setContextCreationFlags}({@link GLContext#CTX_OPTION_DEBUG}) + * shall be issued before context creation via {@link #makeCurrent()}!</p> + * + * <p>After context creation, the GLDebugOutput feature may be enabled or disabled at any time using this method.</p> + * + * @param enable If true enables, otherwise disables the GLDebugOutput feature. + * + * @throws GLException if this context is not current or GLDebugOutput registration failed (enable) + * + * @see #setContextCreationFlags(int) + * @see #addGLDebugListener(GLDebugListener) + * @see GLAutoDrawable#setContextCreationFlags(int) + */ + public abstract void enableGLDebugMessage(boolean enable) throws GLException; + + /** + * Add {@link GLDebugListener}.<br> + * + * @param listener {@link GLDebugListener} handling {@GLDebugMessage}s + * @see #enableGLDebugMessage(boolean) + * @see #removeGLDebugListener(GLDebugListener) + */ + public abstract void addGLDebugListener(GLDebugListener listener); + + /** + * Remove {@link GLDebugListener}.<br> + * + * @param listener {@link GLDebugListener} handling {@GLDebugMessage}s + * @see #enableGLDebugMessage(boolean) + * @see #addGLDebugListener(GLDebugListener) + */ + public abstract void removeGLDebugListener(GLDebugListener listener); + + /** + * @return number of added {@link GLDebugListener}. If > 0, the GLDebugFeature is turned on, otherwise off. + * @see #enableGLDebugMessage(boolean) + */ + public abstract int getGLDebugListenerSize(); + + /** + * Generic entry for {@link GL2GL3#glDebugMessageControlARB(int, int, int, int, IntBuffer, boolean)} + * and {@link GL2GL3#glDebugMessageEnableAMD(int, int, int, IntBuffer, boolean)} of the GLDebugOutput feature. + * @see #enableGLDebugMessage(boolean) + */ + public abstract void glDebugMessageControl(int source, int type, int severity, int count, IntBuffer ids, boolean enabled); + + /** + * Generic entry for {@link GL2GL3#glDebugMessageControlARB(int, int, int, int, int[], int, boolean)} + * and {@link GL2GL3#glDebugMessageEnableAMD(int, int, int, int[], int, boolean)} of the GLDebugOutput feature. + * @see #enableGLDebugMessage(boolean) + */ + public abstract void glDebugMessageControl(int source, int type, int severity, int count, int[] ids, int ids_offset, boolean enabled); + + /** + * Generic entry for {@link GL2GL3#glDebugMessageInsertARB(int, int, int, int, int, String)} + * and {@link GL2GL3#glDebugMessageInsertAMD(int, int, int, int, String)} of the GLDebugOutput feature. + * @see #enableGLDebugMessage(boolean) + */ + public abstract void glDebugMessageInsert(int source, int type, int id, int severity, int length, String buf); + public static final int GL_VERSIONS[][] = { /* 0.*/ { -1 }, /* 1.*/ { 0, 1, 2, 3, 4, 5 }, @@ -750,7 +846,7 @@ public abstract class GLContext { public static String getGLVersion(int major, int minor, int ctp, String gl_version) { boolean needColon = false; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(major); sb.append("."); sb.append(minor); @@ -759,6 +855,7 @@ public abstract class GLContext { needColon = appendString(sb, "compatibility profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp )); needColon = appendString(sb, "core profile", needColon, 0 != ( CTX_PROFILE_CORE & ctp )); needColon = appendString(sb, "forward compatible", needColon, 0 != ( CTX_OPTION_FORWARD & ctp )); + needColon = appendString(sb, "debug", needColon, 0 != ( CTX_OPTION_DEBUG & ctp )); needColon = appendString(sb, "any", needColon, 0 != ( CTX_OPTION_ANY & ctp )); needColon = appendString(sb, "new", needColon, 0 != ( CTX_IS_ARB_CREATED & ctp )); needColon = appendString(sb, "old", needColon, 0 == ( CTX_IS_ARB_CREATED & ctp )); @@ -785,7 +882,7 @@ public abstract class GLContext { return "0x" + Long.toHexString(hex); } - private static boolean appendString(StringBuffer sb, String string, boolean needColon, boolean condition) { + private static boolean appendString(StringBuilder sb, String string, boolean needColon, boolean condition) { if(condition) { if(needColon) { sb.append(", "); diff --git a/src/jogl/classes/javax/media/opengl/GLDebugListener.java b/src/jogl/classes/javax/media/opengl/GLDebugListener.java new file mode 100644 index 000000000..8887d022a --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLDebugListener.java @@ -0,0 +1,44 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.opengl; + +/** + * Listener for {@link GLDebugMessage}s. + * + * <p>One can enable GLDebugOutput via {@link GLContext#enableGLDebugMessage(boolean)} + * and add listeners via {@link GLContext#addGLDebugListener(GLDebugListener)}. + */ +public interface GLDebugListener { + /** + * Handle {@link GLDebugMessage} message sent from native GL implementation. + * + * <p>Since this method is invoked directly by the GL implementation, it shall + * return as fast as possible.</p> + */ + void messageSent(GLDebugMessage event); +} diff --git a/src/jogl/classes/javax/media/opengl/GLDebugMessage.java b/src/jogl/classes/javax/media/opengl/GLDebugMessage.java new file mode 100644 index 000000000..3ab0683c6 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLDebugMessage.java @@ -0,0 +1,248 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.opengl; + +import com.jogamp.common.os.Platform; + +public class GLDebugMessage { + final GLContext source; + final long when; + final int dbgSource; + final int dbgType; + final int dbgId; + final int dbgSeverity; + final String dbgMsg; + + /** + * @param source The source of the event + * @param when The time of the event + * @param dbgSource The ARB source + * @param dbgType The ARB type + * @param dbgId The ARB id + * @param dbgSeverity The ARB severity level + * @param dbgMsg The debug message + */ + public GLDebugMessage(GLContext source, long when, int dbgSource, int dbgType, int dbgId, int dbgSeverity, String dbgMsg) { + this.source = source; + this.when = when; + this.dbgSource = dbgSource; + this.dbgType = dbgType; + this.dbgId = dbgId; + this.dbgSeverity = dbgSeverity; + this.dbgMsg = dbgMsg; + } + + /** + * + * @param source + * @param when + * @param dbgId + * @param amdDbgCategory + * @param dbgSeverity AMD severity level equals ARB severity level (value and semantic) + * @param dbgMsg + * @return + */ + public static GLDebugMessage translateAMDEvent(GLContext source, long when, int dbgId, int amdDbgCategory, int dbgSeverity, String dbgMsg) { + int dbgSource, dbgType; + + // AMD category == ARB source/type + switch(amdDbgCategory) { + case GL2GL3.GL_DEBUG_CATEGORY_API_ERROR_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_API_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_ERROR_ARB; + break; + + // + // def source / other type + // + + case GL2GL3.GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_OTHER_ARB; + break; + + case GL2GL3.GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_OTHER_ARB; + break; + + case GL2GL3.GL_DEBUG_CATEGORY_APPLICATION_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_APPLICATION_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_OTHER_ARB; + break; + + + // + // other source / def type + // + + case GL2GL3.GL_DEBUG_CATEGORY_DEPRECATION_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_OTHER_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB; + break; + + case GL2GL3.GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_OTHER_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB; + break; + + case GL2GL3.GL_DEBUG_CATEGORY_PERFORMANCE_AMD: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_OTHER_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_PERFORMANCE_ARB; + break; + + case GL2GL3.GL_DEBUG_CATEGORY_OTHER_AMD: + default: + dbgSource = GL2GL3.GL_DEBUG_SOURCE_OTHER_ARB; + dbgType = GL2GL3.GL_DEBUG_TYPE_OTHER_ARB; + } + + return new GLDebugMessage(source, when, dbgSource, dbgType, dbgId, dbgSeverity, dbgMsg); + } + + public static int translateARB2AMDCategory(int dbgSource, int dbgType) { + switch (dbgSource) { + case GL2GL3.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD; + + case GL2GL3.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD; + + case GL2GL3.GL_DEBUG_SOURCE_APPLICATION_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_APPLICATION_AMD; + } + + switch(dbgType) { + case GL2GL3.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_DEPRECATION_AMD; + + case GL2GL3.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD; + + case GL2GL3.GL_DEBUG_TYPE_PERFORMANCE_ARB: + return GL2GL3.GL_DEBUG_CATEGORY_PERFORMANCE_AMD; + } + + return GL2GL3.GL_DEBUG_CATEGORY_OTHER_AMD; + } + + public GLContext getSource() { + return source; + } + + public long getWhen() { + return when; + } + + public int getDbgSource() { + return dbgSource; + } + + public int getDbgType() { + return dbgType; + } + + public int getDbgId() { + return dbgId; + } + + public int getDbgSeverity() { + return dbgSeverity; + } + + public String getDbgMsg() { + return dbgMsg; + } + + public StringBuilder toString(StringBuilder sb) { + final String crtab = Platform.getNewline()+"\t"; + if(null==sb) { + sb = new StringBuilder(); + } + sb.append("GLDebugEvent[ id "); + toHexString(sb, dbgId) + .append(crtab).append("type ").append(getDbgTypeString(dbgType)) + .append(crtab).append("severity ").append(getDbgSeverityString(dbgSeverity)) + .append(crtab).append("source ").append(getDbgSourceString(dbgSource)) + .append(crtab).append("msg ").append(dbgMsg) + .append(crtab).append("when ").append(when); + if(null != source) { + sb.append(crtab).append("source ").append(source.getGLVersion()).append(" - hash 0x").append(Integer.toHexString(source.hashCode())); + } + sb.append("]"); + return sb; + } + + public String toString() { + return toString(null).toString(); + } + + public static String getDbgSourceString(int dbgSource) { + switch(dbgSource) { + case GL2GL3.GL_DEBUG_SOURCE_API_ARB: return "GL API"; + case GL2GL3.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "GLSL or extension compiler"; + case GL2GL3.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "Native Windowing binding"; + case GL2GL3.GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "Third party"; + case GL2GL3.GL_DEBUG_SOURCE_APPLICATION_ARB: return "Application"; + case GL2GL3.GL_DEBUG_SOURCE_OTHER_ARB: return "generic"; + default: return "Unknown (" + toHexString(dbgSource) + ")"; + } + } + + public static String getDbgTypeString(int dbgType) { + switch(dbgType) { + case GL2GL3.GL_DEBUG_TYPE_ERROR_ARB: return "Error"; + case GL2GL3.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return "Warning: marked for deprecation"; + case GL2GL3.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "Warning: undefined behavior"; + case GL2GL3.GL_DEBUG_TYPE_PERFORMANCE_ARB: return "Warning: implementation dependent performance"; + case GL2GL3.GL_DEBUG_TYPE_PORTABILITY_ARB: return "Warning: vendor-specific extension use"; + case GL2GL3.GL_DEBUG_TYPE_OTHER_ARB: return "Warning: generic"; + default: return "Unknown (" + toHexString(dbgType) + ")"; + } + } + + public static String getDbgSeverityString(int dbgSeverity) { + switch(dbgSeverity) { + case GL2GL3.GL_DEBUG_SEVERITY_HIGH_ARB: return "High: dangerous undefined behavior"; + case GL2GL3.GL_DEBUG_SEVERITY_MEDIUM_ARB: return "Medium: Severe performance/deprecation/other warnings"; + case GL2GL3.GL_DEBUG_SEVERITY_LOW_ARB: return "Low: Performance warnings (redundancy/undefined)"; + default: return "Unknown (" + toHexString(dbgSeverity) + ")"; + } + } + + public static StringBuilder toHexString(StringBuilder sb, int i) { + if(null==sb) { + sb = new StringBuilder(); + } + return sb.append("0x").append(Integer.toHexString(i)); + } + public static String toHexString(int i) { + return "0x"+Integer.toHexString(i); + } + +} diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index dc439f334..160cdce51 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -152,7 +152,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // copy of the cstr args, mainly for recreation private GLCapabilitiesImmutable capsReqUser; private GLCapabilitiesChooser chooser; - private GLContext shareWith; + private GLContext shareWith; + private int additionalCtxCreationFlags = 0; private GraphicsDevice device; private AWTWindowClosingProtocol awtWindowClosingProtocol = @@ -525,6 +526,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing .createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig)); context = (GLContextImpl) drawable.createContext(shareWith); context.setSynchronized(true); + context.setContextCreationFlags(additionalCtxCreationFlags); } // before native peer is valid: X11 @@ -660,6 +662,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing public void setContext(GLContext ctx) { context=(GLContextImpl)ctx; + if(null != context) { + context.setContextCreationFlags(additionalCtxCreationFlags); + } } public GLContext getContext() { @@ -696,6 +701,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction); } + public void setContextCreationFlags(int flags) { + additionalCtxCreationFlags = flags; + } + + public int getContextCreationFlags() { + return additionalCtxCreationFlags; + } + public GLProfile getGLProfile() { return capsReqUser.getGLProfile(); } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index d58ad0304..2d58584f7 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -136,6 +136,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private GLDrawableFactoryImpl factory; private GLCapabilitiesChooser chooser; private GLContext shareWith; + private int additionalCtxCreationFlags = 0; + // Width of the actual GLJPanel private int panelWidth = 0; private int panelHeight = 0; @@ -488,6 +490,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (backend == null) { return; } + if(null != ctx) { + ctx.setContextCreationFlags(additionalCtxCreationFlags); + } backend.setContext(ctx); } @@ -531,7 +536,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Swing portion of the GLJPanel in any of the rendering paths. return true; } - + public void swapBuffers() { // In the current implementation this is a no-op. Both the pbuffer // and pixmap based rendering paths use a single-buffered surface @@ -540,6 +545,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Swing portion of the GLJPanel in any of the rendering paths. } + public void setContextCreationFlags(int flags) { + additionalCtxCreationFlags = flags; + } + + 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 @@ -1023,6 +1036,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing Math.max(1, panelHeight)); offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith); offscreenContext.setSynchronized(true); + offscreenContext.setContextCreationFlags(additionalCtxCreationFlags); + isInitialized = true; } @@ -1108,6 +1123,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing pbufferWidth, pbufferHeight, shareWith); + pbuffer.setContextCreationFlags(additionalCtxCreationFlags); pbuffer.addGLEventListener(updater); isInitialized = true; } catch (GLException e) { diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index dcd42a3b4..167d4c64b 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -41,6 +41,7 @@ package jogamp.opengl; import java.nio.ByteBuffer; +import java.nio.IntBuffer; import java.util.HashMap; import java.util.Map; @@ -58,6 +59,8 @@ import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; +import javax.media.opengl.GLDebugListener; +import javax.media.opengl.GLDebugMessage; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLPipelineFactory; @@ -87,7 +90,10 @@ public abstract class GLContextImpl extends GLContext { private GLBufferSizeTracker bufferSizeTracker; // Singleton - Set by GLContextShareSet private GLBufferStateTracker bufferStateTracker = new GLBufferStateTracker(); private GLStateTracker glStateTracker = new GLStateTracker(); - + /** currently only {@link GLContext#CTX_OPTION_DEBUG} is supported */ + private int additionalCtxCreationFlags = 0; + private GLDebugMessageHandler glDebugHandler = null; + protected GLDrawableImpl drawable; protected GLDrawableImpl drawableRead; @@ -115,6 +121,8 @@ public abstract class GLContextImpl extends GLContext { this.drawable = drawable; this.drawableRead = drawable; + + this.glDebugHandler = new GLDebugMessageHandler(this); } protected void resetStates() { @@ -139,6 +147,7 @@ public abstract class GLContextImpl extends GLContext { glProcAddressTable = null; gl = null; contextFQN = null; + additionalCtxCreationFlags = 0; super.resetStates(); } @@ -233,7 +242,10 @@ public abstract class GLContextImpl extends GLContext { public final void destroy() { if ( lock.isOwner() ) { - // release current context + // release current context + if(null != glDebugHandler) { + glDebugHandler.enable(false); + } release(); } @@ -267,6 +279,7 @@ public abstract class GLContextImpl extends GLContext { try { destroyImpl(); contextHandle = 0; + glDebugHandler = null; GLContextShareSet.contextDestroyed(this); } finally { drawable.unlockSurface(); @@ -385,6 +398,7 @@ public abstract class GLContextImpl extends GLContext { if (res == CONTEXT_NOT_CURRENT) { lock.unlock(); } else { + setCurrent(this); if(res == CONTEXT_CURRENT_NEW) { // check if the drawable's and the GL's GLProfile are equal // throws an GLException if not @@ -396,8 +410,8 @@ public abstract class GLContextImpl extends GLContext { if(TRACE_GL) { gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } + glDebugHandler.init(0 != (additionalCtxCreationFlags & GLContext.CTX_OPTION_DEBUG)); } - setCurrent(this); /* FIXME: refactor dependence on Java 2D / JOGL bridge @@ -520,8 +534,7 @@ public abstract class GLContextImpl extends GLContext { * @see #createContextARBImpl * @see #destroyContextARBImpl */ - protected final long createContextARB(long share, boolean direct, - int major[], int minor[], int ctp[]) + protected final long createContextARB(long share, boolean direct) { AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); @@ -554,6 +567,7 @@ public abstract class GLContextImpl extends GLContext { if( GLContext.getAvailableGLVersion(device, reqMajor, compat?CTX_PROFILE_COMPAT:CTX_PROFILE_CORE, _major, _minor, _ctp)) { + _ctp[0] |= additionalCtxCreationFlags; _ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]); if(0!=_ctx) { setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0]); @@ -1067,5 +1081,76 @@ public abstract class GLContextImpl extends GLContext { public boolean hasWaiters() { return lock.getWaitingThreadQueueSize()>0; } + + //--------------------------------------------------------------------------- + // GL_ARB_debug_output, GL_AMD_debug_output helpers + // + public final String getGLDebugMessageExtension() { + return glDebugHandler.getExtension(); + } + + public final boolean isGLDebugMessageEnabled() { + return glDebugHandler.isEnabled(); + } + + public int getContextCreationFlags() { + return additionalCtxCreationFlags; + } + + public void setContextCreationFlags(int flags) { + if(!isCreated()) { + additionalCtxCreationFlags = flags & GLContext.CTX_OPTION_DEBUG; + } + } + + public void enableGLDebugMessage(boolean enable) throws GLException { + if(!isCreated()) { + if(enable) { + additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG; + } else { + additionalCtxCreationFlags &= ~GLContext.CTX_OPTION_DEBUG; + } + } else if(0 != (additionalCtxCreationFlags & GLContext.CTX_OPTION_DEBUG) && + null != getGLDebugMessageExtension()) { + glDebugHandler.enable(enable); + } + } + + public void addGLDebugListener(GLDebugListener listener) { + glDebugHandler.addListener(listener); + } + + public void removeGLDebugListener(GLDebugListener listener) { + glDebugHandler.removeListener(listener); + } + + public int getGLDebugListenerSize() { + return glDebugHandler.listenerSize(); + } + + public void glDebugMessageControl(int source, int type, int severity, int count, IntBuffer ids, boolean enabled) { + if(glDebugHandler.isExtensionARB()) { + gl.getGL2GL3().glDebugMessageControlARB(source, type, severity, count, ids, enabled); + } else if(glDebugHandler.isExtensionAMD()) { + gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, enabled); + } + } + + public void glDebugMessageControl(int source, int type, int severity, int count, int[] ids, int ids_offset, boolean enabled) { + if(glDebugHandler.isExtensionARB()) { + gl.getGL2GL3().glDebugMessageControlARB(source, type, severity, count, ids, ids_offset, enabled); + } else if(glDebugHandler.isExtensionAMD()) { + gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, ids_offset, enabled); + } + } + + public void glDebugMessageInsert(int source, int type, int id, int severity, int length, String buf) { + if(glDebugHandler.isExtensionARB()) { + gl.getGL2GL3().glDebugMessageInsertARB(source, type, id, severity, length, buf); + } else if(glDebugHandler.isExtensionAMD()) { + if(0>length) { length = 0; } + gl.getGL2GL3().glDebugMessageInsertAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, id, length, buf); + } + } } diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java new file mode 100644 index 000000000..70f523156 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -0,0 +1,260 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl; + +import java.util.ArrayList; + +import javax.media.nativewindow.NativeWindowException; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLDebugListener; +import javax.media.opengl.GLDebugMessage; +import javax.media.opengl.GLException; + +import com.jogamp.gluegen.runtime.ProcAddressTable; +import jogamp.opengl.gl4.GL4bcProcAddressTable; + +/** + * The GLDebugMessageHandler, handling <i>GL_ARB_debug_output</i> or <i>GL_AMD_debug_output</i> + * debug messages.<br> + * + * <p>An instance must be bound to the current thread's GLContext to achieve thread safety.</p> + * + * <p>A native callback function is registered at {@link #enable(boolean) enable(true)}, + * which forwards received messages to the added {@link GLDebugListener} directly. + * Hence the {@link GLDebugListener#messageSent(GLDebugMessage)} implementation shall + * return as fast as possible.</p> + * + * <p>In case no <i>GL_ARB_debug_output</i> is available, but <i>GL_AMD_debug_output</i>, + * the messages are translated to <i>ARB</i> {@link GLDebugMessage}, using {@link GLDebugMessage#translateAMDEvent(javax.media.opengl.GLContext, long, int, int, int, String)}.</p> + */ +public class GLDebugMessageHandler { + /** Extension <i>GL_ARB_debug_output</i> implementing GLDebugMessage */ + public static final String GL_ARB_debug_output = "GL_ARB_debug_output".intern(); + + /** Extension <i>GL_AMD_debug_output</i> implementing GLDebugMessage */ + public static final String GL_AMD_debug_output = "GL_AMD_debug_output".intern(); + + private static final boolean DEBUG = Debug.debug("GLDebugMessageHandler"); + + private static final int EXT_ARB = 1; + private static final int EXT_AMD = 2; + + static { + if ( !initIDs0() ) { + throw new NativeWindowException("Failed to initialize GLDebugMessageHandler jmethodIDs"); + } + } + + private final GLContextImpl ctx; + private final ListenerSyncedImplStub<GLDebugListener> listenerImpl; + + // licefycle: init - EOL + private String extName; + private int extType; + private long glDebugMessageCallbackProcAddress; + private boolean extAvailable; + + // licefycle: enable - disable/EOL + private long handle; + + /** + * @param ctx the associated GLContext + * @param glDebugExtension chosen extension to use + */ + public GLDebugMessageHandler(GLContextImpl ctx) { + this.ctx = ctx; + this.listenerImpl = new ListenerSyncedImplStub<GLDebugListener>(); + this.glDebugMessageCallbackProcAddress = 0; + this.extName = null; + this.extType = 0; + this.extAvailable = false; + this.handle = 0; + } + + public void init(boolean enable) { + init(); + if(isAvailable()) { + enableImpl(enable); + } + } + + public void init() { + ctx.validateCurrent(); + if( isAvailable()) { + return; + } + + if( ctx.isExtensionAvailable(GL_ARB_debug_output) ) { + extName = GL_ARB_debug_output; + extType = EXT_ARB; + } else if( ctx.isExtensionAvailable(GL_AMD_debug_output) ) { + extName = GL_AMD_debug_output; + extType = EXT_AMD; + } + if(DEBUG) { + System.err.println("GLDebugMessageHandler: Using extension: <"+extName+">"); + } + + if(0 == extType) { + if(DEBUG) { + System.err.println("GLDebugMessageHandler: No extension available!"); + } + return; + } + + final ProcAddressTable procAddressTable = ctx.getGLProcAddressTable(); + if( procAddressTable instanceof GL4bcProcAddressTable) { + final GL4bcProcAddressTable desktopProcAddressTable = (GL4bcProcAddressTable)procAddressTable; + switch(extType) { + case EXT_ARB: + glDebugMessageCallbackProcAddress = desktopProcAddressTable._addressof_glDebugMessageCallbackARB; + break; + case EXT_AMD: + glDebugMessageCallbackProcAddress = desktopProcAddressTable._addressof_glDebugMessageCallbackAMD; + break; + } + } else { + if(DEBUG) { + System.err.println("Non desktop context not supported"); + } + } + extAvailable = 0 < extType && null != extName && 0 != glDebugMessageCallbackProcAddress; + + if(DEBUG) { + System.err.println("GLDebugMessageHandler: extAvailable: "+extAvailable+", glDebugMessageCallback* : 0x"+Long.toHexString(glDebugMessageCallbackProcAddress)); + } + + if(!extAvailable) { + glDebugMessageCallbackProcAddress = 0; + } + + handle = 0; + } + + public final boolean isAvailable() { return extAvailable; } + + /** + * @return The extension implementing the GLDebugMessage feature, + * either {@link #GL_ARB_debug_output} or {@link #GL_AMD_debug_output}. + * If unavailable <i>null</i> is returned. + */ + public final String getExtension() { + return extName; + } + + public final boolean isExtensionARB() { + return extName == GL_ARB_debug_output; + } + + public final boolean isExtensionAMD() { + return extName == GL_AMD_debug_output; + } + + /** + * @throws GLException if context not current or callback registration failed (enable) + */ + public final void enable(boolean enable) throws GLException { + ctx.validateCurrent(); + if(!isAvailable()) { + return; + } + enableImpl(enable); + } + final void enableImpl(boolean enable) throws GLException { + if(enable) { + if(0 == handle) { + handle = register0(glDebugMessageCallbackProcAddress, extType); + if(0 == handle) { + throw new GLException("Failed to register via \"glDebugMessageCallback*\" using "+extName); + } + } + } else { + if(0 != handle) { + unregister0(glDebugMessageCallbackProcAddress, handle); + handle = 0; + } + } + if(DEBUG) { + System.err.println("GLDebugMessageHandler: enable("+enable+") -> 0x" + Long.toHexString(handle)); + } + } + + public final boolean isEnabled() { return 0 != handle; } + + public final int listenerSize() { + return listenerImpl.size(); + } + + public final void addListener(GLDebugListener listener) { + listenerImpl.addListener(-1, listener); + } + + public final void addListener(int index, GLDebugListener listener) { + listenerImpl.addListener(index, listener); + } + + public final void removeListener(GLDebugListener listener) { + listenerImpl.removeListener(listener); + } + + private final void sendMessage(GLDebugMessage msg) { + synchronized(listenerImpl) { + if(DEBUG) { + System.err.println("GLDebugMessageHandler: "+msg); + } + final ArrayList<GLDebugListener> listeners = listenerImpl.getListeners(); + for(int i=0; i<listeners.size(); i++) { + listeners.get(i).messageSent(msg); + } + } + } + + // + // native -> java + // + + protected final void glDebugMessageARB(int source, int type, int id, int severity, String msg) { + final GLDebugMessage event = new GLDebugMessage(ctx, System.currentTimeMillis(), source, type, id, severity, msg); + sendMessage(event); + } + + protected final void glDebugMessageAMD(int id, int category, int severity, String msg) { + final GLDebugMessage event = GLDebugMessage.translateAMDEvent(ctx, System.currentTimeMillis(), id, category, severity, msg); + sendMessage(event); + } + + // + // java -> native + // + + private static native boolean initIDs0(); + private native long register0(long glDebugMessageCallbackProcAddress, int extType); + private native void unregister0(long glDebugMessageCallbackProcAddress, long handle); +} + + diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index 671390fbb..1d52bedbb 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -64,6 +64,7 @@ public class GLPbufferImpl implements GLPbuffer { private GLContextImpl context; private GLDrawableHelper drawableHelper = new GLDrawableHelper(); private int floatMode; + private int additionalCtxCreationFlags = 0; public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext parentContext) { @@ -177,6 +178,9 @@ public class GLPbufferImpl implements GLPbuffer { public void setContext(GLContext ctx) { context=(GLContextImpl)ctx; + if(null != context) { + context.setContextCreationFlags(additionalCtxCreationFlags); + } } public GLContext getContext() { @@ -207,6 +211,17 @@ public class GLPbufferImpl implements GLPbuffer { invokeGL(swapBuffersAction); } + public void setContextCreationFlags(int flags) { + additionalCtxCreationFlags = flags; + if(null != context) { + context.setContextCreationFlags(additionalCtxCreationFlags); + } + } + + public int getContextCreationFlags() { + return additionalCtxCreationFlags; + } + public void bindTexture() { // Doesn't make much sense to try to do this on the event dispatch // thread given that it has to be called while the context is current diff --git a/src/jogl/classes/jogamp/opengl/ListenerSyncedImplStub.java b/src/jogl/classes/jogamp/opengl/ListenerSyncedImplStub.java new file mode 100644 index 000000000..1cde551be --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ListenerSyncedImplStub.java @@ -0,0 +1,79 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl; + +import java.util.ArrayList; + +/** + * Simple locked listener implementation stub to be used for listener handler, + * synchronized on it's instance. + * + * <p>Utilizing simple locking via synchronized.</p> + * + * @param <E> The listener type + */ +public class ListenerSyncedImplStub<E> { + private ArrayList<E> listeners; + + public ListenerSyncedImplStub() { + reset(); + } + + public synchronized final void reset() { + listeners = new ArrayList<E>(); + } + + public synchronized final void destroy() { + listeners.clear(); + listeners = null; + } + + public synchronized final int size() { + return listeners.size(); + } + + public synchronized final void addListener(E listener) { + addListener(-1, listener); + } + + public synchronized final void addListener(int index, E listener) { + if(0>index) { + index = listeners.size(); + } + listeners.add(index, listener); + } + + public synchronized final void removeListener(E listener) { + listeners.remove(listener); + } + + public final ArrayList<E> getListeners() { + return listeners; + } +} diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index 91a907a09..55e2e478c 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -273,14 +273,11 @@ public class WindowsWGLContext extends GLContextImpl { } } - int minor[] = new int[1]; - int major[] = new int[1]; - int ctp[] = new int[1]; boolean createContextARBTried = false; // utilize the shared context's GLXExt in case it was using the ARB method and it already exists if( null!=sharedContext && sharedContext.isCreatedWithARBMethod() ) { - contextHandle = createContextARB(share, true, major, minor, ctp); + contextHandle = createContextARB(share, true); createContextARBTried = true; if (DEBUG && 0!=contextHandle) { System.err.println(getThreadName() + ": createImpl: OK (ARB, using sharedContext) share "+share); @@ -306,7 +303,7 @@ public class WindowsWGLContext extends GLContextImpl { if(isCreateContextAttribsARBAvailable && isExtensionAvailable("WGL_ARB_create_context") ) { // initial ARB context creation - contextHandle = createContextARB(share, true, major, minor, ctp); + contextHandle = createContextARB(share, true); createContextARBTried=true; if (DEBUG) { if(0!=contextHandle) { @@ -334,10 +331,10 @@ public class WindowsWGLContext extends GLContextImpl { if(glCaps.getGLProfile().isGL3()) { WGL.wglMakeCurrent(0, 0); WGL.wglDeleteContext(temp_ctx); - throw new GLException("WindowsWGLContext.createContext failed, but context > GL2 requested "+getGLVersion(major[0], minor[0], ctp[0], "@creation")+", "); + throw new GLException("WindowsWGLContext.createContext failed, but context > GL2 requested "+getGLVersion()+", "); } if(DEBUG) { - System.err.println("WindowsWGLContext.createContext failed, fall back to !ARB context "+getGLVersion(major[0], minor[0], ctp[0], "@creation")); + System.err.println("WindowsWGLContext.createContext failed, fall back to !ARB context "+getGLVersion()); } // continue with temp context for GL < 3.0 diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index 119886838..9f6a5cd1a 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -318,14 +318,11 @@ public abstract class X11GLXContext extends GLContextImpl { return true; } - int minor[] = new int[1]; - int major[] = new int[1]; - int ctp[] = new int[1]; boolean createContextARBTried = false; // utilize the shared context's GLXExt in case it was using the ARB method and it already exists if(null!=sharedContext && sharedContext.isCreatedWithARBMethod()) { - contextHandle = createContextARB(share, direct, major, minor, ctp); + contextHandle = createContextARB(share, direct); createContextARBTried = true; if (DEBUG && 0!=contextHandle) { System.err.println(getThreadName() + ": createContextImpl: OK (ARB, using sharedContext) share "+share); @@ -351,7 +348,7 @@ public abstract class X11GLXContext extends GLContextImpl { if ( isCreateContextAttribsARBAvailable && isExtensionAvailable("GLX_ARB_create_context") ) { // initial ARB context creation - contextHandle = createContextARB(share, direct, major, minor, ctp); + contextHandle = createContextARB(share, direct); createContextARBTried=true; if (DEBUG) { if(0!=contextHandle) { @@ -378,10 +375,10 @@ public abstract class X11GLXContext extends GLContextImpl { if(glp.isGL3()) { glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, temp_ctx); - throw new GLException("X11GLXContext.createContextImpl failed, but context > GL2 requested "+getGLVersion(major[0], minor[0], ctp[0], "@creation")+", "); + throw new GLException("X11GLXContext.createContextImpl failed, but context > GL2 requested "+getGLVersion()+", "); } if(DEBUG) { - System.err.println("X11GLXContext.createContextImpl failed, fall back to !ARB context "+getGLVersion(major[0], minor[0], ctp[0], "@creation")); + System.err.println("X11GLXContext.createContextImpl failed, fall back to !ARB context "+getGLVersion()); } // continue with temp context for GL <= 3.0 diff --git a/src/jogl/native/GLDebugMessageHandler.c b/src/jogl/native/GLDebugMessageHandler.c new file mode 100644 index 000000000..22a7433f9 --- /dev/null +++ b/src/jogl/native/GLDebugMessageHandler.c @@ -0,0 +1,181 @@ + +#include "jogamp_opengl_GLDebugMessageHandler.h" +#include "JoglCommon.h" + +#include <GL/gl.h> +#include <GL/glext.h> + +static jmethodID glDebugMessageARB = NULL; // int source, int type, int id, int severity, String msg +static jmethodID glDebugMessageAMD = NULL; // int id, int category, int severity, String msg + +typedef void (GLAPIENTRY* _local_PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); +typedef void (GLAPIENTRY* _local_GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); + +typedef void (GLAPIENTRY* _local_PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, const GLvoid *userParam); +typedef void (GLAPIENTRY* _local_GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); + +/* + * Class: jogamp_opengl_GLDebugMessageHandler + * Method: initIDs0 + * Signature: (V)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_opengl_GLDebugMessageHandler_initIDs0 + (JNIEnv *env, jclass clazz) +{ + JoglCommon_init(env); + + glDebugMessageARB = (*env)->GetMethodID(env, clazz, "glDebugMessageARB", "(IIIILjava/lang/String;)V"); + glDebugMessageAMD = (*env)->GetMethodID(env, clazz, "glDebugMessageAMD", "(IIILjava/lang/String;)V"); + + if ( NULL == glDebugMessageARB || NULL == glDebugMessageAMD ) { + return JNI_FALSE; + } + return JNI_TRUE; +} + +typedef struct { + JavaVM *vm; + int version; + JNIEnv *env; + jobject obj; + int extType; +} DebugHandlerType; + + +// GLDEBUGARB(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +static void GLDebugMessageARBCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar *message, GLvoid *userParam) { + DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) userParam; + JavaVM *vm = handle->vm; + int version = handle->version; + jobject obj = handle->obj; + JNIEnv *curEnv = NULL; + JNIEnv *newEnv = NULL; + int envRes ; + + // retrieve this thread's JNIEnv curEnv - or detect it's detached + envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; + if( JNI_EDETACHED == envRes ) { + // detached thread - attach to JVM + if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { + fprintf(stderr, "GLDebugMessageARBCallback: can't attach thread: %d\n", envRes); + return; + } + curEnv = newEnv; + } else if( JNI_OK != envRes ) { + // oops .. + fprintf(stderr, "GLDebugMessageARBCallback: can't GetEnv: %d\n", envRes); + return; + } + (*curEnv)->CallVoidMethod(curEnv, obj, glDebugMessageARB, + (jint) source, (jint) type, (jint) id, (jint) severity, + (*curEnv)->NewStringUTF(curEnv, message)); + if( NULL != newEnv ) { + // detached attached thread + (*vm)->DetachCurrentThread(vm); + } +} + +// GLDEBUGAMD(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severity, + GLsizei length, const GLchar *message, GLvoid *userParam) { + DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) userParam; + JavaVM *vm = handle->vm; + int version = handle->version; + jobject obj = handle->obj; + JNIEnv *curEnv = NULL; + JNIEnv *newEnv = NULL; + int envRes ; + + // retrieve this thread's JNIEnv curEnv - or detect it's detached + envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; + if( JNI_EDETACHED == envRes ) { + // detached thread - attach to JVM + if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { + fprintf(stderr, "GLDebugMessageAMDCallback: can't attach thread: %d\n", envRes); + return; + } + curEnv = newEnv; + } else if( JNI_OK != envRes ) { + // oops .. + fprintf(stderr, "GLDebugMessageAMDCallback: can't GetEnv: %d\n", envRes); + return; + } + (*curEnv)->CallVoidMethod(curEnv, obj, glDebugMessageAMD, + (jint) id, (jint) category, (jint) severity, + (*curEnv)->NewStringUTF(curEnv, message)); + if( NULL != newEnv ) { + // detached attached thread + (*vm)->DetachCurrentThread(vm); + } +} + + +/* + * Class: jogamp_opengl_GLDebugMessageHandler + * Method: register0 + * Signature: (JI)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_opengl_GLDebugMessageHandler_register0 + (JNIEnv *env, jobject obj, jlong procAddress, jint extType) +{ + JavaVM *vm; + DebugHandlerType * handle = malloc(sizeof(DebugHandlerType)); + if(0 != (*env)->GetJavaVM(env, &vm)) { + vm = NULL; + JoglCommon_throwNewRuntimeException(env, "GetJavaVM failed"); + } + handle->vm = vm; + handle->version = (*env)->GetVersion(env); + handle->env = env; + handle->obj = (*env)->NewGlobalRef(env, obj); + handle->extType = extType; + + if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == extType) { + _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; + ptr_glDebugMessageCallbackARB = (_local_PFNGLDEBUGMESSAGECALLBACKARBPROC) (intptr_t) procAddress; + ptr_glDebugMessageCallbackARB((_local_GLDEBUGPROCARB)GLDebugMessageARBCallback, handle); + } else if(jogamp_opengl_GLDebugMessageHandler_EXT_AMD == extType) { + _local_PFNGLDEBUGMESSAGECALLBACKAMDPROC ptr_glDebugMessageCallbackAMD; + ptr_glDebugMessageCallbackAMD = (_local_PFNGLDEBUGMESSAGECALLBACKAMDPROC) (intptr_t) procAddress; + ptr_glDebugMessageCallbackAMD((_local_GLDEBUGPROCAMD)GLDebugMessageAMDCallback, handle); + } else { + JoglCommon_throwNewRuntimeException(env, "unsupported extension type %d", extType); + } + + return (jlong) (intptr_t) handle; +} + +/* + * Class: jogamp_opengl_GLDebugMessageHandler + * Method: unregister0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_opengl_GLDebugMessageHandler_unregister0 + (JNIEnv *env, jobject obj, jlong procAddress, jlong jhandle) +{ + DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) jhandle; + + if(env != handle->env) { + JoglCommon_throwNewRuntimeException(env, "wrong handle (env doesn't match)"); + } + if(JNI_FALSE == (*env)->IsSameObject(env, obj, handle->obj)) { + JoglCommon_throwNewRuntimeException(env, "wrong handle (obj doesn't match)"); + } + + if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == handle->extType) { + _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; + ptr_glDebugMessageCallbackARB = (_local_PFNGLDEBUGMESSAGECALLBACKARBPROC) (intptr_t) procAddress; + ptr_glDebugMessageCallbackARB((_local_GLDEBUGPROCARB)NULL, NULL); + } else if(jogamp_opengl_GLDebugMessageHandler_EXT_AMD == handle->extType) { + _local_PFNGLDEBUGMESSAGECALLBACKAMDPROC ptr_glDebugMessageCallbackAMD; + ptr_glDebugMessageCallbackAMD = (_local_PFNGLDEBUGMESSAGECALLBACKAMDPROC) (intptr_t) procAddress; + ptr_glDebugMessageCallbackAMD((_local_GLDEBUGPROCAMD)NULL, NULL); + } else { + JoglCommon_throwNewRuntimeException(env, "unsupported extension type %d", handle->extType); + } + + (*env)->DeleteGlobalRef(env, handle->obj); + free(handle); +} + diff --git a/src/jogl/native/JoglCommon.c b/src/jogl/native/JoglCommon.c new file mode 100644 index 000000000..16f60e4e7 --- /dev/null +++ b/src/jogl/native/JoglCommon.c @@ -0,0 +1,55 @@ + +#include "JoglCommon.h" + +static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; +static jclass runtimeExceptionClz=NULL; + +void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...) +{ + char buffer[512]; + va_list ap; + + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + fprintf(stderr, "%s\n", buffer); + (*env)->FatalError(env, buffer); +} + +void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) +{ + char buffer[512]; + va_list ap; + + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); +} + +void JoglCommon_init(JNIEnv *env) { + if(NULL==runtimeExceptionClz) { + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + JoglCommon_FatalError(env, "JOGL: can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + JoglCommon_FatalError(env, "JOGL: can't use %s", ClazzNameRuntimeException); + } + } +} + +jchar* JoglCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) +{ + jchar* strChars = NULL; + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } + return strChars; +} + diff --git a/src/jogl/native/JoglCommon.h b/src/jogl/native/JoglCommon.h new file mode 100644 index 000000000..d82b445ce --- /dev/null +++ b/src/jogl/native/JoglCommon.h @@ -0,0 +1,15 @@ + +#ifndef JOGL_COMMON_H +#define JOGL_COMMON_H 1 + +#include <jni.h> +#include <stdlib.h> + +void JoglCommon_init(JNIEnv *env); + +jchar* JoglCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); + +void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...); +void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); + +#endif diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 2dcb6345e..bc0d67bfc 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -397,6 +397,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC } drawable.setRealized(true); context = drawable.createContext(sharedContext); + context.setContextCreationFlags(additionalCtxCreationFlags); } if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { String msg = "GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin"; @@ -428,6 +429,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC // private GLContext sharedContext = null; + private int additionalCtxCreationFlags = 0; private GLDrawableFactory factory; private GLDrawable drawable; private GLContext context; @@ -455,6 +457,9 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC public void setContext(GLContext newCtx) { context = newCtx; + if(null != context) { + context.setContextCreationFlags(additionalCtxCreationFlags); + } } public GLContext getContext() { @@ -545,7 +550,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC } } } - + /** This implementation uses a static value */ public void setAutoSwapBufferMode(boolean onOrOff) { if(null!=helper) { @@ -560,13 +565,21 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC } return false; } - + public void swapBuffers() { if(drawable!=null && context != null) { drawable.swapBuffers(); } } + public void setContextCreationFlags(int flags) { + additionalCtxCreationFlags = flags; + } + + public int getContextCreationFlags() { + return additionalCtxCreationFlags; + } + private class InitAction implements Runnable { public final void run() { // Lock: Locked Surface/Window by MakeCurrent/Release diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java new file mode 100644 index 000000000..c6e78b219 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java @@ -0,0 +1,220 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDebugListener; +import javax.media.opengl.GLDebugMessage; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestGLDebug00NEWT extends UITestCase { + + static String dbgTstMsg0 = "Hello World"; + static int dbgTstId0 = 42; + + public class WindowContext { + public final Window window; + public final GLContext context; + + public WindowContext(Window w, GLContext c) { + window = w; + context = c; + } + } + + WindowContext createWindow(GLProfile glp, boolean debugGL) { + GLCapabilities caps = new GLCapabilities(glp); + // + // Create native windowing resources .. X11/Win/OSX + // + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + + Window window = NewtFactory.createWindow(screen, caps); + Assert.assertNotNull(window); + window.setSize(128, 128); + window.setVisible(true); + + GLDrawableFactory factory = GLDrawableFactory.getFactory(glp); + GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + + GLContext context = drawable.createContext(null); + Assert.assertNotNull(context); + + context.enableGLDebugMessage(debugGL); + + int res = context.makeCurrent(); + Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); + + return new WindowContext(window, context); + } + + void destroyWindow(WindowContext winctx) { + GLDrawable drawable = winctx.context.getGLDrawable(); + + Assert.assertNotNull(winctx.context); + winctx.context.destroy(); + + Assert.assertNotNull(drawable); + drawable.setRealized(false); + + Assert.assertNotNull(winctx.window); + winctx.window.destroy(); + } + + + void test01GLDebug01EnableDisable(boolean enable, String dbgTstMsg, int dbgTstId) throws InterruptedException { + GLProfile glp = GLProfile.getDefault(); + + WindowContext winctx = createWindow(glp, enable); + MyGLDebugListener myGLDebugListener = new MyGLDebugListener(dbgTstMsg, dbgTstId); + if(enable) { + winctx.context.addGLDebugListener(myGLDebugListener); + } + String glDebugExt = winctx.context.getGLDebugMessageExtension(); + System.err.println("glDebug extension: "+glDebugExt); + System.err.println("glDebug enabled: "+winctx.context.isGLDebugMessageEnabled()); + System.err.println("glDebug listener: "+winctx.context.getGLDebugListenerSize()); + System.err.println("context version: "+winctx.context.getGLVersion()); + + Assert.assertEquals((null == glDebugExt) ? false : enable, winctx.context.isGLDebugMessageEnabled()); + Assert.assertEquals(enable?1:0, winctx.context.getGLDebugListenerSize()); + + if(winctx.context.isGLDebugMessageEnabled() && null != dbgTstMsg && 0 <= dbgTstId) { + winctx.context.glDebugMessageInsert(GL2GL3.GL_DEBUG_SOURCE_APPLICATION_ARB, + GL2GL3.GL_DEBUG_TYPE_OTHER_ARB, + dbgTstId, + GL2GL3.GL_DEBUG_SEVERITY_MEDIUM_ARB, -1, dbgTstMsg); + Assert.assertEquals(true, myGLDebugListener.received()); + } + + destroyWindow(winctx); + } + + @Test + public void test01GLDebug01Disabled() throws InterruptedException { + test01GLDebug01EnableDisable(false, null, -1); + } + + @Test + public void test01GLDebug01Enabled() throws InterruptedException { + test01GLDebug01EnableDisable(true, dbgTstMsg0, dbgTstId0); + } + + @Test + public void test02GLDebug01Error() throws InterruptedException { + GLProfile glp = GLProfile.getDefault(); + + WindowContext winctx = createWindow(glp, true); + + MyGLDebugListener myGLDebugListener = new MyGLDebugListener( + GL2GL3.GL_DEBUG_SOURCE_API_ARB, + GL2GL3.GL_DEBUG_TYPE_ERROR_ARB, + GL2GL3.GL_DEBUG_SEVERITY_HIGH_ARB); + winctx.context.addGLDebugListener(myGLDebugListener); + + GL gl = winctx.context.getGL(); + + gl.glBindFramebuffer(-1, -1); // ERROR ! + + if( winctx.context.isGLDebugMessageEnabled() ) { + Assert.assertEquals(true, myGLDebugListener.received()); + } + + destroyWindow(winctx); + } + + + public static void main(String args[]) throws IOException { + String tstname = TestGLDebug00NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + + public class MyGLDebugListener implements GLDebugListener { + int recSource; + int recType; + int recSeverity; + + String recMsg; + int recId; + boolean received = false; + + public MyGLDebugListener(int recSource, int recType, int recSeverity) { + this.recSource = recSource; + this.recType = recType; + this.recSeverity = recSeverity; + this.recMsg = null; + this.recId = -1; + + } + public MyGLDebugListener(String recMsg, int recId) { + this.recSource = -1; + this.recType = -1; + this.recSeverity = -1; + this.recMsg = recMsg; + this.recId = recId; + } + + public boolean received() { return received; } + + public void messageSent(GLDebugMessage event) { + System.err.println("XXX: "+event); + if(null != recMsg && recMsg.equals(event.getDbgMsg()) && recId == event.getDbgId()) { + received = true; + } else if(0 <= recSource && recSource == event.getDbgSource() && + recType == event.getDbgType() && + recSeverity== event.getDbgSeverity() ) { + received = true; + } + } + } +} +
\ No newline at end of file diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java new file mode 100644 index 000000000..05870ee0d --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java @@ -0,0 +1,189 @@ +/** + * Copyright 2011 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDebugListener; +import javax.media.opengl.GLDebugMessage; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLRunnable; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestGLDebug01NEWT extends UITestCase { + + static String dbgTstMsg0 = "Hello World"; + static int dbgTstId0 = 42; + + GLWindow createWindow(GLProfile glp, boolean debugGL) { + GLCapabilities caps = new GLCapabilities(glp); + // + // Create native windowing resources .. X11/Win/OSX + // + GLWindow window = GLWindow.create(caps); + Assert.assertNotNull(window); + window.setContextCreationFlags(debugGL?GLContext.CTX_OPTION_DEBUG:0); + window.setSize(128, 128); + window.setVisible(true); + + Assert.assertNotNull(window.getContext()); + Assert.assertNotNull(window.getContext().isCreated()); + + return window; + } + + void destroyWindow(GLWindow window) { + window.destroy(); + } + + + void test01GLDebug01EnableDisable(boolean enable, final String dbgTstMsg, final int dbgTstId) throws InterruptedException { + GLProfile glp = GLProfile.getDefault(); + + final GLWindow window = createWindow(glp, enable); + final GLContext ctx = window.getContext(); + MyGLDebugListener myGLDebugListener = new MyGLDebugListener(dbgTstMsg, dbgTstId); + if(enable) { + ctx.addGLDebugListener(myGLDebugListener); + } + String glDebugExt = ctx.getGLDebugMessageExtension(); + System.err.println("glDebug extension: "+glDebugExt); + System.err.println("glDebug enabled: "+ctx.isGLDebugMessageEnabled()); + System.err.println("glDebug listener: "+ctx.getGLDebugListenerSize()); + System.err.println("context version: "+ctx.getGLVersion()); + + Assert.assertEquals((null == glDebugExt) ? false : enable, ctx.isGLDebugMessageEnabled()); + Assert.assertEquals(enable?1:0, ctx.getGLDebugListenerSize()); + if(ctx.isGLDebugMessageEnabled() && null != dbgTstMsg && 0 <= dbgTstId) { + window.invoke(true, new GLRunnable() { + public void run(GLAutoDrawable drawable) { + drawable.getContext().glDebugMessageInsert(GL2GL3.GL_DEBUG_SOURCE_APPLICATION_ARB, + GL2GL3.GL_DEBUG_TYPE_OTHER_ARB, + dbgTstId, + GL2GL3.GL_DEBUG_SEVERITY_MEDIUM_ARB, -1, dbgTstMsg); + } + }); + Assert.assertEquals(true, myGLDebugListener.received()); + } + + destroyWindow(window); + } + + @Test + public void test01GLDebug01Disabled() throws InterruptedException { + test01GLDebug01EnableDisable(false, null, -1); + } + + @Test + public void test01GLDebug01Enabled() throws InterruptedException { + test01GLDebug01EnableDisable(true, dbgTstMsg0, dbgTstId0); + } + + @Test + public void test02GLDebug01Error() throws InterruptedException { + GLProfile glp = GLProfile.getDefault(); + + GLWindow window = createWindow(glp, true); + + MyGLDebugListener myGLDebugListener = new MyGLDebugListener( + GL2GL3.GL_DEBUG_SOURCE_API_ARB, + GL2GL3.GL_DEBUG_TYPE_ERROR_ARB, + GL2GL3.GL_DEBUG_SEVERITY_HIGH_ARB); + window.getContext().addGLDebugListener(myGLDebugListener); + + window.invoke(true, new GLRunnable() { + public void run(GLAutoDrawable drawable) { + drawable.getGL().glBindFramebuffer(-1, -1); // ERROR ! + } + } ); + + if( window.getContext().isGLDebugMessageEnabled() ) { + Assert.assertEquals(true, myGLDebugListener.received()); + } + + destroyWindow(window); + } + + + public static void main(String args[]) throws IOException { + String tstname = TestGLDebug01NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + + public class MyGLDebugListener implements GLDebugListener { + int recSource; + int recType; + int recSeverity; + + String recMsg; + int recId; + boolean received = false; + + public MyGLDebugListener(int recSource, int recType, int recSeverity) { + this.recSource = recSource; + this.recType = recType; + this.recSeverity = recSeverity; + this.recMsg = null; + this.recId = -1; + + } + public MyGLDebugListener(String recMsg, int recId) { + this.recSource = -1; + this.recType = -1; + this.recSeverity = -1; + this.recMsg = recMsg; + this.recId = recId; + } + + public boolean received() { return received; } + + public void messageSent(GLDebugMessage event) { + System.err.println("XXX: "+event); + if(null != recMsg && recMsg.equals(event.getDbgMsg()) && recId == event.getDbgId()) { + received = true; + } else if(0 <= recSource && recSource == event.getDbgSource() && + recType == event.getDbgType() && + recSeverity== event.getDbgSeverity() ) { + received = true; + } + } + } +} +
\ No newline at end of file |