diff options
author | Sven Gothel <[email protected]> | 2011-04-24 12:21:36 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-04-24 12:21:36 +0200 |
commit | 6c0ad949be979d5fed95a1166d59100f7bf5580f (patch) | |
tree | d69242fabf1f066d43418612209597616fba6cdd | |
parent | ea819ff768d507c37a981c1ab0bdc0cad32c6a87 (diff) |
Add unified support for GL_ARB_debug_output and GL_AMD_debug_output.
If GL_ARB_debug_output is not available, but GL_AMD_debug_output exist, fallback to the latter,
offering generic aliased methods translating the delta (AMD category <-> ARB source/type).
Generic aliased methods reside in GLContext*
Enable/Disable via GLContext and GLAutoDrawable.
To enable the GLDebugOutput feature GLContext.enableGLDebugMessage(true)
or GLContext.setContextCreationFlags(GLContext.CTX_OPTION_DEBUG)
shall be called _before_ context creation via GLContext.makeCurrent()!
In case GLAutoDrawable is being used,
GLAutoDrawable.setContextCreationFlags(GLContext.CTX_OPTION_DEBUG)
shall be issued before context creation via GLContext.makeCurrent()!.
After context creation, the GLDebugOutput feature may be enabled or disabled
at any time using this method.
Verify both unit tests for usability.
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 |