summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--make/build-jogl.xml3
-rw-r--r--make/config/jogl/gl-gl4bc.cfg4
-rwxr-xr-xmake/scripts/tests.sh6
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java23
-rw-r--r--src/jogl/classes/javax/media/opengl/GLContext.java105
-rw-r--r--src/jogl/classes/javax/media/opengl/GLDebugListener.java44
-rw-r--r--src/jogl/classes/javax/media/opengl/GLDebugMessage.java248
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java15
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java18
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java95
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java260
-rw-r--r--src/jogl/classes/jogamp/opengl/GLPbufferImpl.java15
-rw-r--r--src/jogl/classes/jogamp/opengl/ListenerSyncedImplStub.java79
-rw-r--r--src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java11
-rw-r--r--src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java11
-rw-r--r--src/jogl/native/GLDebugMessageHandler.c181
-rw-r--r--src/jogl/native/JoglCommon.c55
-rw-r--r--src/jogl/native/JoglCommon.h15
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java17
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java220
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java189
21 files changed, 1581 insertions, 33 deletions
diff --git a/make/build-jogl.xml b/make/build-jogl.xml
index 6a0eca500..73b61e690 100644
--- a/make/build-jogl.xml
+++ b/make/build-jogl.xml
@@ -1217,6 +1217,8 @@
<condition property="c.compiler.use-debug"><istrue value="${c.compiler.debug}"/></condition>
<patternset id="c.src.files.jogl.desktop">
+ <include name="${rootrel.src.c}/JoglCommon.c"/>
+ <include name="${rootrel.src.c}/GLDebugMessageHandler.c"/>
<include name="${rootrel.src.c}/macosx/MacOSXCustomCGLCode.c" if="isOSX"/>
<include name="${rootrel.src.c}/macosx/MacOSXWindowSystemInterface.m" if="isOSX"/>
<include name="${rootrel.src.c}/macosx/ContextUpdater.m" if="isOSX"/>
@@ -1343,6 +1345,7 @@
</target>
<target name="c.build.jogl.prepare" depends="c.build.jogl.prepare.openMAX">
+ <javah destdir="${build.jogl}/gensrc/native/jogl" classpath="${classes}" class="jogamp.opengl.GLDebugMessageHandler" />
<!-- Generate the waveout Mixer header -->
<!-- FIXME: this is temporary until we move this to another workspace -->
<!--javah destdir="${build.jogl}/gensrc/native/jogl" classpath="${classes}" class="com.jogamp.audio.windows.waveout.Mixer" /-->
diff --git a/make/config/jogl/gl-gl4bc.cfg b/make/config/jogl/gl-gl4bc.cfg
index 06a9c76f1..aafb9166b 100644
--- a/make/config/jogl/gl-gl4bc.cfg
+++ b/make/config/jogl/gl-gl4bc.cfg
@@ -51,6 +51,10 @@ ManuallyImplement glMapNamedBufferEXT
ForceProcAddressGen glMapNamedBufferEXT
JavaEpilogue glNamedBufferDataEXT bufferSizeTracker.setDirectStateBufferSize({0}, this, {1});
+# Manuall implement glDebugMessageCallback* using the proc address resolver
+ForceProcAddressGen glDebugMessageCallbackARB
+ForceProcAddressGen glDebugMessageCallbackAMD
+
# Force all of the methods to be emitted using dynamic linking so we
# don't need to link against any emulation library on the desktop or
# depend on the presence of an import library for a particular device
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 4bb0ee028..a5e81f9cf 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -72,6 +72,8 @@ function jrun() {
#D_ARGS="-Djogl.debug.GraphicsConfiguration"
#D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.GraphicsConfiguration"
#D_ARGS="-Djogl.debug.GLCanvas"
+ #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.TraceGL"
+ #D_ARGS="-Djogl.debug.GLDebugMessageHandler"
#D_ARGS="-Dnativewindow.debug.ToolkitLock.TraceLock"
#D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLState"
@@ -119,6 +121,8 @@ function testawtmt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen01GLPBufferNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen02BitmapNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT $*
#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteWindow01NEWT $*
@@ -199,7 +203,7 @@ function testawtmt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestTransformFeedbackVaryingsBug407NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLSimple01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState01NEWT $*
-testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT $*
#testnoawt com.jogamp.opengl.test.junit.graph.TestRegionRendererNEWT01 $*
#testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT01 $*
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