diff options
Diffstat (limited to 'src/jogl/classes/javax/media/opengl/GLContext.java')
-rw-r--r-- | src/jogl/classes/javax/media/opengl/GLContext.java | 1504 |
1 files changed, 1186 insertions, 318 deletions
diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index e23fa74f9..9a4311772 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -42,16 +42,24 @@ package javax.media.opengl; import java.nio.IntBuffer; import java.util.HashMap; -import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import javax.media.nativewindow.AbstractGraphicsDevice; -import com.jogamp.common.util.IntObjectHashMap; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; - import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLContextShareSet; + +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.VersionNumber; +import com.jogamp.common.util.VersionNumberString; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLRendererQuirks; /** Abstraction for an OpenGL rendering context. In order to perform OpenGL rendering, a context must be "made current" on the current @@ -66,144 +74,331 @@ import jogamp.opengl.GLContextImpl; abstraction provides a stable object which clients can use to refer to a given context. */ public abstract class GLContext { - public static final boolean DEBUG = Debug.debug("GLContext"); + + public static final boolean DEBUG = Debug.debug("GLContext"); public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true); - + public static final boolean DEBUG_TRACE_SWITCH = DEBUG || TRACE_SWITCH; + + /** + * If <code>true</code> (default), bootstrapping the available GL profiles + * will use the highest compatible GL context for each profile, + * hence skipping querying lower profiles if a compatible higher one is found: + * <ul> + * <li>4.2-core -> 4.2-core, 3.3-core</li> + * <li>4.2-comp -> 4.2-comp, 3.3-comp, 2</li> + * </ul> + * Otherwise the dedicated GL context would be queried and used: + * <ul> + * <li>4.2-core -> 4.2-core</li> + * <li>3.3-core -> 3.3-core</li> + * <li>4.2-comp -> 4.2-comp</li> + * <li>3.3-comp -> 3.3-comp</li> + * <li>3.0-comp -> 2</li> + * </ul> + * Using aliasing speeds up initialization about: + * <ul> + * <li>Linux x86_64 - Nvidia: 28%, 700ms down to 500ms</li> + * <li>Linux x86_64 - AMD : 40%, 1500ms down to 900ms</li> + * <p> + * Can be turned off with property <code>jogl.debug.GLContext.NoProfileAliasing</code>. + * </p> + */ + public static final boolean PROFILE_ALIASING = !Debug.isPropertyDefined("jogl.debug.GLContext.NoProfileAliasing", true); + + protected static final boolean FORCE_NO_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.none", true); + protected static final boolean FORCE_MIN_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.min", true); + /** Reflects property jogl.debug.DebugGL. If true, the debug pipeline is enabled at context creation. */ - public final static boolean DEBUG_GL = Debug.isPropertyDefined("jogl.debug.DebugGL", true); + public static final boolean DEBUG_GL = Debug.isPropertyDefined("jogl.debug.DebugGL", true); /** Reflects property jogl.debug.TraceGL. If true, the trace pipeline is enabled at context creation. */ - public final static boolean TRACE_GL = Debug.isPropertyDefined("jogl.debug.TraceGL", true); - - /** Indicates that the context was not made current during the last call to {@link #makeCurrent makeCurrent}. */ + public static final boolean TRACE_GL = Debug.isPropertyDefined("jogl.debug.TraceGL", true); + + /** Indicates that the context was not made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */ public static final int CONTEXT_NOT_CURRENT = 0; - /** Indicates that the context was made current during the last call to {@link #makeCurrent makeCurrent}. */ + /** Indicates that the context was made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */ public static final int CONTEXT_CURRENT = 1; - /** Indicates that a newly-created context was made current during the last call to {@link #makeCurrent makeCurrent}. */ + /** Indicates that a newly-created context was made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */ public static final int CONTEXT_CURRENT_NEW = 2; - /** <code>ARB_create_context</code> related: created via ARB_create_context. Cache key value. */ + /** Version 1.00, i.e. GLSL 1.00 for ES 2.0. */ + public static final VersionNumber Version100 = new VersionNumber(1, 0, 0); + /** Version 1.10, i.e. GLSL 1.10 for GL 2.0. */ + public static final VersionNumber Version110 = new VersionNumber(1, 10, 0); + /** Version 1.20, i.e. GLSL 1.20 for GL 2.1. */ + public static final VersionNumber Version120 = new VersionNumber(1, 20, 0); + /** Version 1.30, i.e. GLSL 1.30 for GL 3.0. */ + public static final VersionNumber Version130 = new VersionNumber(1, 30, 0); + /** Version 1.40, i.e. GLSL 1.40 for GL 3.1. */ + public static final VersionNumber Version140 = new VersionNumber(1, 40, 0); + /** Version 1.50, i.e. GLSL 1.50 for GL 3.2. */ + public static final VersionNumber Version150 = new VersionNumber(1, 50, 0); + + /** Version 3.0. As an OpenGL version, it qualifies for desktop {@link #isGL2()} only, or ES 3.0. Or GLSL 3.00 for ES 3.0. */ + public static final VersionNumber Version300 = new VersionNumber(3, 0, 0); + + /** Version 3.1. As an OpenGL version, it qualifies for {@link #isGL3core()}, {@link #isGL3bc()} and {@link #isGL3()} */ + public static final VersionNumber Version310 = new VersionNumber(3, 1, 0); + + /** Version 3.2. As an OpenGL version, it qualifies for geometry shader */ + public static final VersionNumber Version320 = new VersionNumber(3, 2, 0); + + /** Version 4.3. As an OpenGL version, it qualifies for <code>GL_ARB_ES3_compatibility</code> */ + public static final VersionNumber Version430 = new VersionNumber(4, 3, 0); + + protected static final VersionNumber Version800 = new VersionNumber(8, 0, 0); + + // + // Cached keys, bits [0..15] + // + + /** Context option bits, full bit mask covering 16 bits [0..15], i.e. <code>0x0000FFFF</code>, {@value}. */ + protected static final int CTX_IMPL_FULL_MASK = 0x0000FFFF; + + /** Context option bits, cached bit mask covering 10 bits [0..9], i.e. <code>0x000003FF</code>, {@value}. Leaving 6 bits for non cached options, i.e. 10:6. */ + protected static final int CTX_IMPL_CACHE_MASK = 0x000003FF; + + /** <code>ARB_create_context</code> related: created via ARB_create_context. Cache key value. See {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_IS_ARB_CREATED = 1 << 0; - /** <code>ARB_create_context</code> related: compatibility profile. Cache key value. */ + /** <code>ARB_create_context</code> related: desktop compatibility profile. Cache key value. See {@link #isGLCompatibilityProfile()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_PROFILE_COMPAT = 1 << 1; - /** <code>ARB_create_context</code> related: core profile. Cache key value. */ + /** <code>ARB_create_context</code> related: desktop core profile. Cache key value. See {@link #isGLCoreProfile()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_PROFILE_CORE = 1 << 2; - /** <code>ARB_create_context</code> related: ES profile. Cache key value. */ + /** <code>ARB_create_context</code> related: ES profile. Cache key value. See {@link #isGLES()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_PROFILE_ES = 1 << 3; - /** <code>ARB_create_context</code> related: flag forward compatible. Cache key value. */ + /** <code>ARB_create_context</code> related: flag forward compatible. Cache key value. See {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_OPTION_FORWARD = 1 << 4; - /** <code>ARB_create_context</code> related: flag debug. Not a cache key. */ + /** <code>ARB_create_context</code> related: flag debug. Cache key value. See {@link #setContextCreationFlags(int)}, {@link GLAutoDrawable#setContextCreationFlags(int)}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ public static final int CTX_OPTION_DEBUG = 1 << 5; - - /** <code>GL_ARB_ES2_compatibility</code> implementation related: Context is compatible w/ ES2. Not a cache key. */ - protected static final int CTX_IMPL_ES2_COMPAT = 1 << 8; + /** Context uses software rasterizer, otherwise hardware rasterizer. Cache key value. See {@link #isHardwareRasterizer()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 6; + + // + // Non cached keys, 6 bits [10..15] + // - /** Context uses software rasterizer, otherwise hardware rasterizer. Cache key value. */ - protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 15; - - private static ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>(); + /** <code>GL_ARB_ES2_compatibility</code> implementation related: Context is compatible w/ ES2. Not a cache key. See {@link #isGLES2Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + protected static final int CTX_IMPL_ES2_COMPAT = 1 << 10; - private HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>(); - private IntObjectHashMap attachedObjectsByInt = new IntObjectHashMap(); + /** <code>GL_ARB_ES3_compatibility</code> implementation related: Context is compatible w/ ES3. Not a cache key. See {@link #isGLES3Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + protected static final int CTX_IMPL_ES3_COMPAT = 1 << 11; - // RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock. - protected RecursiveLock lock = LockFactory.createRecursiveLock(); + /** + * Context supports basic FBO, details see {@link #hasBasicFBOSupport()}. + * Not a cache key. + * @see #hasBasicFBOSupport() + * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile) + */ + protected static final int CTX_IMPL_FBO = 1 << 12; + + /** + * Context supports <code>OES_single_precision</code>, fp32, fixed function point (FFP) compatibility entry points, + * see {@link #hasFP32CompatAPI()}. + * Not a cache key. + * @see #hasFP32CompatAPI() + * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile) + */ + protected static final int CTX_IMPL_FP32_COMPAT_API = 1 << 13; + + private static final ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>(); + + private final HashMap<String, Object> attachedObjects = new HashMap<String, Object>(); + + // RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock. + protected final RecursiveLock lock = LockFactory.createRecursiveLock(); /** The underlying native OpenGL context */ - protected long contextHandle; + protected volatile long contextHandle; // volatile: avoid locking for read-only access protected GLContext() { - resetStates(); + resetStates(true); } - - protected int ctxMajorVersion; - protected int ctxMinorVersion; + + protected VersionNumber ctxVersion; protected int ctxOptions; protected String ctxVersionString; + protected VersionNumberString ctxVendorVersion; + protected VersionNumber ctxGLSLVersion; private int currentSwapInterval; + protected GLRendererQuirks glRendererQuirks; + + /** Did the drawable association changed ? see {@link GLRendererQuirks#NoSetSwapIntervalPostRetarget} */ + protected boolean drawableRetargeted; - protected void resetStates() { + /** + * @param isInit true if called for class initialization, otherwise false (re-init or destruction). + */ + protected void resetStates(boolean isInit) { if (DEBUG) { - System.err.println(getThreadName() + ": GLContext.resetStates()"); + System.err.println(getThreadName() + ": GLContext.resetStates(isInit "+isInit+")"); // Thread.dumpStack(); } - ctxMajorVersion=-1; - ctxMinorVersion=-1; + ctxVersion = VersionNumberString.zeroVersion; + ctxVendorVersion = VersionNumberString.zeroVersion; ctxOptions=0; ctxVersionString=null; - attachedObjectsByString.clear(); - attachedObjectsByInt.clear(); + ctxGLSLVersion = VersionNumber.zeroVersion; + attachedObjects.clear(); contextHandle=0; currentSwapInterval = -1; + glRendererQuirks = null; + drawableRetargeted = false; + } + + /** Returns true if this GLContext is shared, otherwise false. */ + public final boolean isShared() { + return GLContextShareSet.isShared(this); + } + + /** Returns a new list of created GLContext shared with this GLContext. */ + public final List<GLContext> getCreatedShares() { + return GLContextShareSet.getCreatedShares(this); + } + + /** Returns a new list of destroyed GLContext shared with this GLContext. */ + public final List<GLContext> getDestroyedShares() { + return GLContextShareSet.getDestroyedShares(this); } /** - * Returns the GLDrawable to which this context may be used to - * draw. + * Returns the instance of {@link GLRendererQuirks}, allowing one to determine workarounds. + * @return instance of {@link GLRendererQuirks} if context was made current once, otherwise <code>null</code>. + */ + public final GLRendererQuirks getRendererQuirks() { return glRendererQuirks; } + + /** + * Returns true if the <code>quirk</code> exist in {@link #getRendererQuirks()}, otherwise false. + * <p> + * Convenience method for: + * <pre> + * final GLRendererQuirks glrq = ctx.getRendererQuirks(); + * boolean hasQuirk = null != glrq ? glrq.exist(quirk) : false ; + * </pre> + * </p> + * @param quirk the quirk to be tested, e.g. {@link GLRendererQuirks#NoDoubleBufferedPBuffer}. + * @throws IllegalArgumentException if the quirk is out of range + */ + public final boolean hasRendererQuirk(int quirk) throws IllegalArgumentException { + return null != glRendererQuirks ? glRendererQuirks.exist(quirk) : false ; + } + + /** + * Sets the read/write drawable for framebuffer operations. + * <p> + * If the arguments reflect the current state of this context + * this method is a no-operation and returns the old and current {@link GLDrawable}. + * </p> + * <p> + * If the context was current on this thread, it is being released before switching the drawable + * and made current afterwards. However the user shall take extra care that not other thread + * attempts to make this context current. Otherwise a race condition may happen. + * </p> + * @param readWrite The read/write drawable for framebuffer operations, maybe <code>null</code> to remove association. + * @param setWriteOnly Only change the write-drawable, if <code>setWriteOnly</code> is <code>true</code> and + * if the {@link #getGLReadDrawable() read-drawable} differs + * from the {@link #getGLDrawable() write-drawable}. + * Otherwise set both drawables, read and write. + * @return The previous read/write drawable + * + * @throws GLException in case <code>null</code> is being passed or + * this context is made current on another thread. + * + * @see #isGLReadDrawableAvailable() + * @see #setGLReadDrawable(GLDrawable) + * @see #getGLReadDrawable() + * @see #setGLDrawable(GLDrawable, boolean) + * @see #getGLDrawable() + */ + public abstract GLDrawable setGLDrawable(GLDrawable readWrite, boolean setWriteOnly); + + /** + * Returns the write-drawable this context uses for framebuffer operations. + * <p> + * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)}, + * it equals to the write-drawable (default). + * </p> + * @see #setGLDrawable(GLDrawable, boolean) + * @see #setGLReadDrawable(GLDrawable) */ public abstract GLDrawable getGLDrawable(); /** - * Return availability of GL read drawable. - * @return true if a GL read drawable is supported with your driver, otherwise false. + * Query whether using a distinguished read-drawable is supported. + * @return true if using a read-drawable is supported with your driver/OS, otherwise false. */ public abstract boolean isGLReadDrawableAvailable(); /** - * Set the read GLDrawable for read framebuffer operations.<br> + * Set the read-Drawable for read framebuffer operations.<br> * The caller should query if this feature is supported via {@link #isGLReadDrawableAvailable()}. + * <p> + * If the context was current on this thread, it is being released before switching the drawable + * and made current afterwards. However the user shall take extra care that not other thread + * attempts to make this context current. Otherwise a race condition may happen. + * </p> * - * @param read the read GLDrawable for read framebuffer operations. - * If null is passed, the default write drawable will be set. + * @param read the read-drawable for read framebuffer operations. + * If null is passed, the default write drawable will be set. + * @return the previous read-drawable * - * @throws GLException in case a read drawable is not supported - * and the given drawable is not null and not equal to the internal write drawable. + * @throws GLException in case a read drawable is not supported or + * this context is made current on another thread. * * @see #isGLReadDrawableAvailable() * @see #getGLReadDrawable() */ - public abstract void setGLReadDrawable(GLDrawable read); + public abstract GLDrawable setGLReadDrawable(GLDrawable read); /** - * Returns the read GLDrawable this context uses for read framebuffer operations. + * Returns the read-Drawable this context uses for read framebuffer operations. + * <p> + * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)}, + * it equals to the write-drawable (default). + * </p> * @see #isGLReadDrawableAvailable() - * @see #setGLReadDrawable(javax.media.opengl.GLDrawable) + * @see #setGLReadDrawable(GLDrawable) + * @see #getGLReadDrawable() */ public abstract GLDrawable getGLReadDrawable(); /** * Makes this GLContext current on the calling thread. * <p> + * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported. + * </p> + * <p> * There are two return values that indicate success and one that - * indicates failure. A return value of CONTEXT_CURRENT_NEW - * indicates that that context has been made current, and that - * this is the first time this context has been made current, or - * that the state of the underlying context or drawable may have - * changed since the last time this context was made current. In - * this case, the application may wish to initialize the state. A - * return value of CONTEXT_CURRENT indicates that the context has - * been made currrent, with its previous state restored. + * indicates failure. + * </p> + * <p> + * A return value of {@link #CONTEXT_CURRENT_NEW} + * indicates that that context has been made current for the 1st time, + * or that the state of the underlying context or drawable has + * changed since the last time this context was current. + * In this case, the application may wish to initialize the render state. + * </p> + * <p> + * A return value of {@link #CONTEXT_CURRENT} indicates that the context has + * been made current, with its previous state restored. * </p> * <p> * If the context could not be made current (for example, because * the underlying drawable has not ben realized on the display) , - * a value of CONTEXT_NOT_CURRENT is returned. + * a value of {@link #CONTEXT_NOT_CURRENT} is returned. * </p> - * <p> - * If the context is in use by another thread at the time of the - * call, then if isSynchronized() is true the call will - * block. If isSynchronized() is false, an exception will be - * thrown and the context will remain current on the other thread. + * <p> + * This method is blocking, i.e. waits until another thread has + * released the context. * </p> * <p> * The drawable's surface is being locked at entry - * and unlocked at {@link #release()} + * and unlocked at {@link #release()} * </p> * - * @return CONTEXT_CURRENT if the context was successfully made current - * @return CONTEXT_CURRENT_NEW if the context was successfully made - * current, but need to be initialized. - * - * @return CONTEXT_NOT_CURRENT if the context could not be made current. + * @return <ul> + * <li>{@link #CONTEXT_CURRENT_NEW} if the context was successfully made current the 1st time,</li> + * <li>{@link #CONTEXT_CURRENT} if the context was successfully made current,</li> + * <li>{@link #CONTEXT_NOT_CURRENT} if the context could not be made current.</li> + * </ul> * * @throws GLException if synchronization is disabled and the * context is current on another thread, or because the context @@ -215,8 +410,11 @@ public abstract class GLContext { /** * Releases control of this GLContext from the current thread. * <p> + * Recursive call to {@link #release()} and hence {@link #makeCurrent()} are supported. + * </p> + * <p> * The drawable's surface is being unlocked at exit, - * assumed to be locked by {@link #makeCurrent()}. + * assumed to be locked by {@link #makeCurrent()}. * </p> * * @throws GLException if the context had not previously been made @@ -230,7 +428,7 @@ public abstract class GLContext { * parameter indicates which groups of state variables are to be * copied. <code>mask</code> contains the bitwise OR of the same * symbolic names that are passed to the GL command {@link - * GL#glPushAttrib glPushAttrib}. The single symbolic constant + * GL2#glPushAttrib glPushAttrib}. The single symbolic constant * {@link GL2#GL_ALL_ATTRIB_BITS GL_ALL_ATTRIB_BITS} can be used to * copy the maximum possible portion of rendering state. <P> * @@ -284,41 +482,66 @@ public abstract class GLContext { * @return true if this GLContext is current on this thread */ public final boolean isCurrent() { - return getCurrent() == this ; + return getCurrent() == this ; } /** * @throws GLException if this GLContext is not current on this thread */ - public final void validateCurrent() throws GLException { + public final void validateCurrent() throws GLException { if(getCurrent() != this) { throw new GLException(getThreadName()+": This context is not current. Current context: "+getCurrent()+", this context "+this); } } - + + /** Returns a String representation of the {@link #makeCurrent()} result. */ + public static final String makeCurrentResultToString(int res) { + switch(res) { + case CONTEXT_NOT_CURRENT: return "CONTEXT_NOT_CURRENT"; + case CONTEXT_CURRENT: return "CONTEXT_CURRENT"; + case CONTEXT_CURRENT_NEW: return "CONTEXT_NOT_CURRENT"; + default: return "INVALID_VALUE"; + } + } + /** * Sets the thread-local variable returned by {@link #getCurrent} * and has no other side-effects. For use by third parties adding * new GLContext implementations; not for use by end users. */ protected static void setCurrent(GLContext cur) { - if(TRACE_SWITCH) { - System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - "+cur); + if( TRACE_SWITCH ) { + if(null == cur) { + System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - NULL"); + } else { + System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - obj " + toHexString(cur.hashCode()) + ", ctx " + toHexString(cur.getHandle())); + } } currentContext.set(cur); } - + /** * Destroys this OpenGL context and frees its associated * resources. * <p> * The context may be current w/o recursion when calling <code>destroy()</code>, * in which case this method destroys the context and releases the lock. - * </p> + * </p> */ public abstract void destroy(); /** + * Returns the implementing root GL instance of this GLContext's GL object, + * considering a wrapped pipelined hierarchy, see {@link GLBase#getDownstreamGL()}. + * @throws GLException if the root instance is not a GL implementation + * @see GLBase#getRootGL() + * @see GLBase#getDownstreamGL() + * @see #getGL() + * @see #setGL(GL) + */ + public abstract GL getRootGL(); + + /** * Returns the GL pipeline object for this GLContext. * * @return the aggregated GL instance, or null if this context was not yet made current. @@ -333,12 +556,12 @@ public abstract class GLContext { public abstract GL setGL(GL gl); /** - * Returns the native GL context handle + * Returns the underlying native OpenGL context handle */ public final long getHandle() { return contextHandle; } - /** - * Indicates whether the underlying OpenGL context has been created. + /** + * Indicates whether the underlying native OpenGL context has been created. */ public final boolean isCreated() { return 0 != contextHandle; @@ -347,44 +570,26 @@ public abstract class GLContext { /** * Returns the attached user object for the given name to this GLContext. */ - public final Object getAttachedObject(int name) { - return attachedObjectsByInt.get(name); - } - - /** - * Returns the attached user object for the given name to this GLContext. - */ public final Object getAttachedObject(String name) { - return attachedObjectsByString.get(name); - } - - /** - * Sets the attached user object for the given name to this GLContext. - * Returns the previously set object or null. - */ - public final Object attachObject(int name, Object obj) { - return attachedObjectsByInt.put(name, obj); + return attachedObjects.get(name); } - public final Object detachObject(int name) { - return attachedObjectsByInt.remove(name); - } - /** * Sets the attached user object for the given name to this GLContext. * Returns the previously set object or null. */ public final Object attachObject(String name, Object obj) { - return attachedObjectsByString.put(name, obj); + return attachedObjects.put(name, obj); } public final Object detachObject(String name) { - return attachedObjectsByString.remove(name); + return attachedObjects.remove(name); } - + /** * Classname, GL, GLDrawable */ + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); @@ -395,18 +600,21 @@ public abstract class GLContext { } public final StringBuilder append(StringBuilder sb) { - sb.append("OpenGL "); - sb.append(getGLVersionMajor()); - sb.append("."); - sb.append(getGLVersionMinor()); - sb.append(", options 0x"); + sb.append("Version ").append(getGLVersion()).append(" [GL ").append(getGLVersionNumber()).append(", vendor ").append(getGLVendorVersionNumber()); + sb.append("], options 0x"); sb.append(Integer.toHexString(ctxOptions)); - sb.append(", "); - sb.append(getGLVersion()); + sb.append(", this "); + sb.append(toHexString(hashCode())); sb.append(", handle "); sb.append(toHexString(contextHandle)); - sb.append(", "); + sb.append(", isShared "+isShared()+", "); sb.append(getGL()); + sb.append(",\n\t quirks: "); + if(null != glRendererQuirks) { + glRendererQuirks.toString(sb); + } else { + sb.append("n/a"); + } if(getGLDrawable()!=getGLReadDrawable()) { sb.append(",\n\tRead Drawable : "); sb.append(getGLReadDrawable()); @@ -416,8 +624,6 @@ public abstract class GLContext { sb.append(",\n\tDrawable: "); sb.append(getGLDrawable()); } - sb.append(", lock "); - sb.append(lock.toString()); return sb; } @@ -433,7 +639,7 @@ public abstract class GLContext { * javax.media.opengl.GL#glPolygonOffset(float,float)} is available). */ public abstract boolean isFunctionAvailable(String glFunctionName); - + /** * Returns true if the specified OpenGL extension can be * successfully called using this GL context given the current host (OpenGL @@ -445,10 +651,10 @@ public abstract class GLContext { * "GL_VERTEX_PROGRAM_ARB"). */ public abstract boolean isExtensionAvailable(String glExtensionName); - + /** Returns the number of platform extensions */ public abstract int getPlatformExtensionCount(); - + /** Returns a non-null (but possibly empty) string containing the space-separated list of available platform-dependent (e.g., WGL, GLX) extensions. Can only be called while this context is @@ -457,7 +663,7 @@ public abstract class GLContext { /** Returns the number of OpenGL extensions */ public abstract int getGLExtensionCount(); - + /** Returns a non-null (but possibly empty) string containing the space-separated list of available extensions. Can only be called while this context is current. @@ -479,8 +685,8 @@ public abstract class GLContext { * @see GLAutoDrawable#setContextCreationFlags(int) */ public abstract void setContextCreationFlags(int flags); - - /** + + /** * Returns a valid OpenGL version string, ie<br> * <pre> * major.minor ([option]?[options,]*) - gl-version @@ -509,7 +715,7 @@ public abstract class GLContext { * <td>row 2, cell 1</td> * <td>row 2, cell 2</td> * </tr> - * </table> + * </table> * * <table border="0"> * <tr><td></td> <td>ES2</td> <td><code>2.0 (ES profile, ES2 compatible, hardware) - 2.0 ES Profile</code></td></tr> @@ -520,131 +726,495 @@ public abstract class GLContext { * <tr><td>NV</td><td>GL3</td> <td><code>3.3 (Core profile, arb, hardware) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr> * <tr><td>NV</td><td>GL3bc</td> <td><code>3.3 (Compatibility profile, arb, hardware) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr> * <tr><td>NV</td><td>GL2</td> <td><code>3.0 (Compatibility profile, arb, ES2 compatible, hardware) - 3.0.0 NVIDIA 290.10</code></td></tr> - * </table> + * </table> */ public final String getGLVersion() { return ctxVersionString; } - public final int getGLVersionMajor() { return ctxMajorVersion; } - public final int getGLVersionMinor() { return ctxMinorVersion; } + /** + * Returns this context OpenGL version. + * @see #getGLSLVersionNumber() + **/ + public final VersionNumber getGLVersionNumber() { return ctxVersion; } + /** + * Returns the vendor's version, i.e. version number at the end of <code>GL_VERSION</code> not being the GL version. + * <p> + * In case no such version exists within <code>GL_VERSION</code>, + * the {@link VersionNumberString#zeroVersion zero version} instance is returned. + * </p> + * <p> + * The vendor's version is usually the vendor's OpenGL driver version. + * </p> + */ + public final VersionNumberString getGLVendorVersionNumber() { return ctxVendorVersion; } public final boolean isGLCompatibilityProfile() { return ( 0 != ( CTX_PROFILE_COMPAT & ctxOptions ) ); } public final boolean isGLCoreProfile() { return ( 0 != ( CTX_PROFILE_CORE & ctxOptions ) ); } + public final boolean isGLESProfile() { return ( 0 != ( CTX_PROFILE_ES & ctxOptions ) ); } public final boolean isGLForwardCompatible() { return ( 0 != ( CTX_OPTION_FORWARD & ctxOptions ) ); } public final boolean isGLDebugEnabled() { return ( 0 != ( CTX_OPTION_DEBUG & ctxOptions ) ); } public final boolean isCreatedWithARBMethod() { return ( 0 != ( CTX_IS_ARB_CREATED & ctxOptions ) ); } - + /** - * @return true if this context is an ES2 context or implements - * the extension <code>GL_ARB_ES2_compatibility</code>, otherwise false + * Returns the matching GLSL version number, queried by this context GL + * via {@link GL2ES2#GL_SHADING_LANGUAGE_VERSION} if ≥ ES2.0 or GL2.0, + * otherwise a static match is being utilized. + * <p> + * The context must have been current once, + * otherwise the {@link VersionNumberString#zeroVersion zero version} instance is returned. + * </p> + * <p> + * Examples w/ <code>major.minor</code>: + * <pre> + * 1.00 (ES 2.0), 3.00 (ES 3.0) + * 1.10 (GL 2.0), 1.20 (GL 2.1), 1.50 (GL 3.2), + * 3.30 (GL 3.3), 4.00 (GL 4.0), 4.10 (GL 4.1), 4.20 (GL 4.2) + * </pre > + * </p> + * <p> + * <i>Matching</i> could also refer to the maximum GLSL version usable by this context + * since <i>normal</i> GL implementations are capable of using a lower GLSL version as well. + * The latter is not true on OSX w/ a GL3 context. + * </p> + * + * @return GLSL version number if context has been made current at least once, + * otherwise the {@link VersionNumberString#zeroVersion zero version} instance is returned. + * + * @see #getGLVersionNumber() + */ + public final VersionNumber getGLSLVersionNumber() { + return ctxGLSLVersion; + } + + /** + * Returns the GLSL version string as to be used in a shader program, including a terminating newline '\n', + * i.e. for desktop + * <pre> + * #version 110 + * .. + * #version 150 + * #version 330 + * ... + * </pre> + * And for ES: + * <pre> + * #version 100 + * #version 300 es + * .. + * </pre> + * <p> + * If context has not been made current yet, a string of zero length is returned. + * </p> + * @see #getGLSLVersionNumber() + */ + public final String getGLSLVersionString() { + if( ctxGLSLVersion.isZero() ) { + return ""; + } + final int minor = ctxGLSLVersion.getMinor(); + final String esSuffix = isGLES() && ctxGLSLVersion.compareTo(Version300) >= 0 ? " es" : ""; + return "#version " + ctxGLSLVersion.getMajor() + ( minor < 10 ? "0"+minor : minor ) + esSuffix + "\n" ; + } + + protected static final VersionNumber getStaticGLSLVersionNumber(int glMajorVersion, int glMinorVersion, int ctxOptions) { + if( 0 != ( CTX_PROFILE_ES & ctxOptions ) ) { + if( 3 == glMajorVersion ) { + return Version300; // ES 3.0 -> GLSL 3.00 + } else if( 2 == glMajorVersion ) { + return Version100; // ES 2.0 -> GLSL 1.00 + } + } else if( 1 == glMajorVersion ) { + return Version110; // GL 1.x -> GLSL 1.10 + } else if( 2 == glMajorVersion ) { + switch ( glMinorVersion ) { + case 0: return Version110; // GL 2.0 -> GLSL 1.10 + default: return Version120; // GL 2.1 -> GLSL 1.20 + } + } else if( 3 == glMajorVersion && 2 >= glMinorVersion ) { + switch ( glMinorVersion ) { + case 0: return Version130; // GL 3.0 -> GLSL 1.30 + case 1: return Version140; // GL 3.1 -> GLSL 1.40 + default: return Version150; // GL 3.2 -> GLSL 1.50 + } + } + // The new default: GL >= 3.3, ES >= 3.0 + return new VersionNumber(glMajorVersion, glMinorVersion * 10, 0); // GL M.N -> GLSL M.N + } + + /** + * @return true if this context is an ES2 context or implements + * the extension <code>GL_ARB_ES3_compatibility</code> or <code>GL_ARB_ES2_compatibility</code>, otherwise false */ public final boolean isGLES2Compatible() { - return 0 != ( ctxOptions & CTX_IMPL_ES2_COMPAT ) ; + return 0 != ( ctxOptions & ( CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ) ) ; } - + + /** + * Return true if this context is an ES3 context or implements + * the extension <code>GL_ARB_ES3_compatibility</code>, otherwise false. + * <p> + * Includes [ GL ≥ 4.3, GL ≥ 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ] + * </p> + */ + public final boolean isGLES3Compatible() { + return 0 != ( ctxOptions & CTX_IMPL_ES3_COMPAT ) ; + } + + /** + * @return true if impl. is a hardware rasterizer, otherwise false. + * @see #isHardwareRasterizer(AbstractGraphicsDevice, GLProfile) + * @see GLProfile#isHardwareRasterizer() + */ + public final boolean isHardwareRasterizer() { + return 0 == ( ctxOptions & CTX_IMPL_ACCEL_SOFT ) ; + } + + /** + * @return true if context supports GLSL, i.e. is either {@link #isGLES3()}, {@link #isGLES2()}, {@link #isGL3()} or {@link #isGL2()} <i>and</i> major-version > 1. + * @see GLProfile#hasGLSL() + */ public final boolean hasGLSL() { - return isGL2ES2() ; + return isGLES3() || + isGLES2() || + isGL3() || + isGL2() && ctxVersion.getMajor()>1 ; + } + + /** + * Returns <code>true</code> if basic FBO support is available, otherwise <code>false</code>. + * <p> + * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= 3.0 [core, compat] or implements the extensions + * <code>GL_ARB_ES2_compatibility</code>, <code>GL_ARB_framebuffer_object</code>, <code>GL_EXT_framebuffer_object</code> or <code>GL_OES_framebuffer_object</code>. + * </p> + * <p> + * Basic FBO support may only include one color attachment and no multisampling, + * as well as limited internal formats for renderbuffer. + * </p> + * @see #CTX_IMPL_FBO + */ + public final boolean hasBasicFBOSupport() { + return 0 != ( ctxOptions & CTX_IMPL_FBO ) ; + } + + /** + * Returns <code>true</code> if full FBO support is available, otherwise <code>false</code>. + * <p> + * Full FBO is supported if the context is either GL >= 3.0 [ES, core, compat] or implements the extensions + * <code>ARB_framebuffer_object</code>, or all of + * <code>EXT_framebuffer_object</code>, <code>EXT_framebuffer_multisample</code>, + * <code>EXT_framebuffer_blit</code>, <code>GL_EXT_packed_depth_stencil</code>. + * </p> + * <p> + * Full FBO support includes multiple color attachments and multisampling. + * </p> + */ + public final boolean hasFullFBOSupport() { + return hasBasicFBOSupport() && !hasRendererQuirk(GLRendererQuirks.NoFullFBOSupport) && + ( isGL3ES3() || // GL >= 3.0 [ES, core, compat] + isExtensionAvailable(GLExtensions.ARB_framebuffer_object) || // ARB_framebuffer_object + ( isExtensionAvailable(GLExtensions.EXT_framebuffer_object) && // All EXT_framebuffer_object* + isExtensionAvailable(GLExtensions.EXT_framebuffer_multisample) && + isExtensionAvailable(GLExtensions.EXT_framebuffer_blit) && + isExtensionAvailable(GLExtensions.EXT_packed_depth_stencil) + ) + ) ; } - + + /** + * Returns <code>true</code> if <code>OES_single_precision</code>, fp32, fixed function point (FFP) compatibility entry points available, + * otherwise <code>false</code>. + * @see #CTX_IMPL_FP32_COMPAT_API + */ + public final boolean hasFP32CompatAPI() { + return 0 != ( ctxOptions & CTX_IMPL_FP32_COMPAT_API ) ; + } + + /** + * Returns the maximum number of FBO RENDERBUFFER samples + * if {@link #hasFullFBOSupport() full FBO is supported}, otherwise false. + */ + public final int getMaxRenderbufferSamples() { + if( hasFullFBOSupport() ) { + final GL gl = getGL(); + final int[] val = new int[] { 0 } ; + try { + gl.glGetIntegerv(GL2GL3.GL_MAX_SAMPLES, val, 0); + final int glerr = gl.glGetError(); + if(GL.GL_NO_ERROR == glerr) { + return val[0]; + } else if(DEBUG) { + System.err.println("GLContext.getMaxRenderbufferSamples: GL_MAX_SAMPLES query GL Error 0x"+Integer.toHexString(glerr)); + } + } catch (GLException gle) { gle.printStackTrace(); } + } + return 0; + } + /** Note: The GL impl. may return a const value, ie {@link GLES2#isNPOTTextureAvailable()} always returns <code>true</code>. */ public boolean isNPOTTextureAvailable() { - return isGL3() || isGLES2Compatible() || isExtensionAvailable(GL_ARB_texture_non_power_of_two); + return isGL3() || isGLES2Compatible() || isExtensionAvailable(GLExtensions.ARB_texture_non_power_of_two); } - private static final String GL_ARB_texture_non_power_of_two = "GL_ARB_texture_non_power_of_two"; - + public boolean isTextureFormatBGRA8888Available() { - return isGL2GL3() || - isExtensionAvailable("GL_EXT_texture_format_BGRA8888") || - isExtensionAvailable("GL_IMG_texture_format_BGRA8888") ; + return isGL2GL3() || + isExtensionAvailable(GLExtensions.EXT_texture_format_BGRA8888) || + isExtensionAvailable(GLExtensions.IMG_texture_format_BGRA8888) ; } + /** + * Indicates whether this GLContext is capable of GL4bc. <p>Includes [ GL4bc ].</p> + * @see GLProfile#isGL4bc() + */ public final boolean isGL4bc() { - return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) - && 0 != (ctxOptions & CTX_PROFILE_COMPAT); + return 0 != (ctxOptions & CTX_IS_ARB_CREATED) && + 0 != (ctxOptions & CTX_PROFILE_COMPAT) && + ctxVersion.getMajor() >= 4; } + /** + * Indicates whether this GLContext is capable of GL4. <p>Includes [ GL4bc, GL4 ].</p> + * @see GLProfile#isGL4() + */ public final boolean isGL4() { - return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) - && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + return 0 != (ctxOptions & CTX_IS_ARB_CREATED) && + 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) && + ctxVersion.getMajor() >= 4; } + /** + * Indicates whether this GLContext uses a GL4 core profile. <p>Includes [ GL4 ].</p> + */ + public final boolean isGL4core() { + return 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) && + 0 != ( ctxOptions & CTX_PROFILE_CORE ) && + ctxVersion.getMajor() >= 4; + } + + /** + * Indicates whether this GLContext is capable of GL3bc. <p>Includes [ GL4bc, GL3bc ].</p> + * @see GLProfile#isGL3bc() + */ public final boolean isGL3bc() { - return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) - && 0 != (ctxOptions & CTX_IS_ARB_CREATED) - && 0 != (ctxOptions & CTX_PROFILE_COMPAT); + return 0 != (ctxOptions & CTX_IS_ARB_CREATED) && + 0 != (ctxOptions & CTX_PROFILE_COMPAT) && + ctxVersion.compareTo(Version310) >= 0 ; } + /** + * Indicates whether this GLContext is capable of GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3 ].</p> + * @see GLProfile#isGL3() + */ public final boolean isGL3() { - return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) - && 0 != (ctxOptions & CTX_IS_ARB_CREATED) - && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + return 0 != (ctxOptions & CTX_IS_ARB_CREATED) && + 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) && + ctxVersion.compareTo(Version310) >= 0 ; + } + + /** + * Indicates whether this GLContext uses a GL3 core profile. <p>Includes [ GL4, GL3 ].</p> + */ + public final boolean isGL3core() { + return 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) && + 0 != ( ctxOptions & CTX_PROFILE_CORE ) && + ctxVersion.compareTo(Version310) >= 0; + } + + /** + * Indicates whether this GLContext uses a GL core profile. <p>Includes [ GL4, GL3, GLES3, GLES2 ].</p> + */ + public final boolean isGLcore() { + return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 2 ) || + ( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) && + 0 != ( ctxOptions & CTX_PROFILE_CORE ) && + ctxVersion.compareTo(Version310) >= 0 + ) ; + } + + /** + * Indicates whether this GLContext allows CPU data sourcing (indices, vertices ..) as opposed to using a GPU buffer source (VBO), + * e.g. {@link GL2#glDrawElements(int, int, int, java.nio.Buffer)}. + * <p>Includes [GL2ES1, GLES2] == [ GL4bc, GL3bc, GL2, GLES1, GL2ES1, GLES2 ].</p> + * <p>See Bug 852 - https://jogamp.org/bugzilla/show_bug.cgi?id=852 </p> + */ + public final boolean isCPUDataSourcingAvail() { + return isGL2ES1() || isGLES2(); } + /** + * Indicates whether this GLContext's native profile does not implement a default <i>vertex array object</i> (VAO), + * starting w/ OpenGL 3.1 core and GLES3. + * <p>Includes [ GL4, GL3, GLES3 ].</p> + * <pre> + Due to GL 3.1 core spec: E.1. DEPRECATED AND REMOVED FEATURES (p 296), + GL 3.2 core spec: E.2. DEPRECATED AND REMOVED FEATURES (p 331) + there is no more default VAO buffer 0 bound, hence generating and binding one + to avoid INVALID_OPERATION at VertexAttribPointer. + More clear is GL 4.3 core spec: 10.4 (p 307). + * </pre> + * <pre> + GLES3 is included, since upcoming ES releases > 3.0 may behave the same: + GL ES 3.0 spec F.1. Legacy Features (p 322). + * </pre> + * <p> + * If no default VAO is implemented in the native OpenGL profile, + * an own default VAO is being used, see {@link #getDefaultVAO()}. + * </p> + * @see #getDefaultVAO() + */ + public final boolean hasNoDefaultVAO() { + return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 3 ) || + ( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) && + 0 != ( ctxOptions & CTX_PROFILE_CORE ) && + ctxVersion.compareTo(Version310) >= 0 + ) ; + } + + /** + * If this GLContext does not implement a default VAO, see {@link #hasNoDefaultVAO()}, + * an <i>own default VAO</i> will be created and bound at context creation. + * <p> + * If this GLContext does implement a default VAO, i.e. {@link #hasNoDefaultVAO()} + * returns <code>false</code>, this method returns <code>0</code>. + * </p> + * <p> + * Otherwise this method returns the VAO object name + * representing this GLContext's <i>own default VAO</i>. + * </p> + * @see #hasNoDefaultVAO() + */ + public abstract int getDefaultVAO(); + + /** + * Indicates whether this GLContext is capable of GL2. <p>Includes [ GL4bc, GL3bc, GL2 ].</p> + * @see GLProfile#isGL2() + */ public final boolean isGL2() { - return ctxMajorVersion>=1 && 0!=(ctxOptions & CTX_PROFILE_COMPAT); + return 0 != ( ctxOptions & CTX_PROFILE_COMPAT ) && ctxVersion.getMajor()>=1 ; } + /** + * Indicates whether this GLContext is capable of GL2GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3 ].</p> + * @see GLProfile#isGL2GL3() + */ public final boolean isGL2GL3() { return isGL2() || isGL3(); } + /** + * Indicates whether this GLContext is capable of GLES1. <p>Includes [ GLES1 ].</p> + * @see GLProfile#isGLES1() + */ public final boolean isGLES1() { - return ctxMajorVersion==1 && 0 != ( ctxOptions & CTX_PROFILE_ES ) ; + return 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() == 1 ; } + /** + * Indicates whether this GLContext is capable of GLES2. <p>Includes [ GLES2, GLES3 ].</p> + * @see GLProfile#isGLES2() + */ public final boolean isGLES2() { - return ctxMajorVersion==2 && 0 != ( ctxOptions & CTX_PROFILE_ES ) ; + if( 0 != ( ctxOptions & CTX_PROFILE_ES ) ) { + final int major = ctxVersion.getMajor(); + return 2 == major || 3 == major; + } + return false; } + /** + * Indicates whether this GLContext is capable of GLES3. <p>Includes [ GLES3 ].</p> + * @see GLProfile#isGLES3() + */ + public final boolean isGLES3() { + return 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() == 3 ; + } + + /** + * Indicates whether this GLContext is capable of GLES. <p>Includes [ GLES3, GLES1, GLES2 ].</p> + * @see GLProfile#isGLES() + */ public final boolean isGLES() { return 0 != ( CTX_PROFILE_ES & ctxOptions ) ; } + /** + * Indicates whether this GLContext is capable of GL2ES1. <p>Includes [ GL4bc, GL3bc, GL2, GLES1, GL2ES1 ].</p> + * @see GLProfile#isGL2ES1() + */ public final boolean isGL2ES1() { - return isGL2() || isGLES1() ; + return isGLES1() || isGL2(); } + /** + * Indicates whether this GLContext is capable of GL2ES2. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GL2GL3, GL2ES2, GLES2 ].</p> + * @see GLProfile#isGL2ES2() + */ public final boolean isGL2ES2() { - return isGL2GL3() || isGLES2() ; + return isGLES2() || isGL2GL3(); } /** - * Set the swap interval if the current context. - * @param interval Should be ≥ 0. 0 Disables the vertical synchronisation, + * Indicates whether this GLContext is capable of GL2ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL3ES3, GL2, GL2GL3 ].</p> + * @see GLProfile#isGL2ES3() + * @see #isGL3ES3() + * @see #isGL2GL3() + */ + public final boolean isGL2ES3() { + return isGL3ES3() || isGL2GL3(); + } + + /** + * Indicates whether this GLContext is capable of GL3ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3 ].</p> + * @see GLProfile#isGL3ES3() + */ + public final boolean isGL3ES3() { + return isGL4ES3() || isGL3(); + } + + /** + * Returns true if this profile is capable of GL4ES3, i.e. if {@link #isGLES3Compatible()} returns true. + * <p>Includes [ GL ≥ 4.3, GL ≥ 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]</p> + * @see GLProfile#isGL4ES3() + */ + public final boolean isGL4ES3() { + return isGLES3Compatible() ; + } + + /** + * Set the swap interval of the current context and attached drawable. + * @param interval Should be ≥ 0. 0 disables the vertical synchronization, * where ≥ 1 is the number of vertical refreshes before a swap buffer occurs. * A value < 0 is ignored. - * @return true if the operation was successful, otherwise false - * + * @return true if the operation was successful, otherwise false + * * @throws GLException if the context is not current. */ public final boolean setSwapInterval(int interval) throws GLException { validateCurrent(); if(0<=interval) { - if( setSwapIntervalImpl(interval) ) { - currentSwapInterval = interval; - return true; + if( !drawableRetargeted || !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) ) { + if( setSwapIntervalImpl(interval) ) { + currentSwapInterval = interval; + return true; + } } } return false; } - protected boolean setSwapIntervalImpl(int interval) { - return false; - } - /** Return the current swap interval. + protected boolean setSwapIntervalImpl(int interval) { + return false; + } + /** Return the current swap interval. * <p> * If the context has not been made current at all, * the default value <code>-1</code> is returned. * </p> * <p> - * The default value for a valid context is <code>1</code> for - * an EGL based profile (ES1 or ES2) and <code>-1</code> (undefined) - * for desktop. + * For a valid context the default value is <code>1</code> + * in case of an EGL based profile (ES1 or ES2) and <code>-1</code> + * (undefined) for desktop. * </p> */ public final int getSwapInterval() { - if(-1 == currentSwapInterval && this.isGLES()) { - currentSwapInterval = 1; - } return currentSwapInterval; } protected final void setDefaultSwapInterval() { @@ -652,9 +1222,9 @@ public abstract class GLContext { currentSwapInterval = 1; } else { currentSwapInterval = -1; - } + } } - + public final boolean queryMaxSwapGroups(int[] maxGroups, int maxGroups_offset, int[] maxBarriers, int maxBarriers_offset) { validateCurrent(); @@ -667,147 +1237,286 @@ public abstract class GLContext { return joinSwapGroupImpl(group); } protected boolean joinSwapGroupImpl(int group) { /** nop per default .. **/ return false; } - protected int currentSwapGroup = -1; // default: not set yet .. + protected int currentSwapGroup = -1; // default: not set yet .. public int getSwapGroup() { return currentSwapGroup; } public final boolean bindSwapBarrier(int group, int barrier) { validateCurrent(); - return bindSwapBarrierImpl(group, barrier); + return bindSwapBarrierImpl(group, barrier); } protected boolean bindSwapBarrierImpl(int group, int barrier) { /** nop per default .. **/ return false; } - /** - * @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. + * Return the framebuffer name bound to this context, + * see {@link GL#glBindFramebuffer(int, int)}. + */ + public abstract int getBoundFramebuffer(int target); + + /** + * Return the default draw framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable + * is being used. + * </p> + */ + public abstract int getDefaultDrawFramebuffer(); + + /** + * Return the default read framebuffer name. + * <p> + * May differ from it's default <code>zero</code> + * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable + * is being used. + * </p> + */ + public abstract int getDefaultReadFramebuffer(); + + /** + * Returns the default color buffer within the current bound + * {@link #getDefaultReadFramebuffer()}, i.e. GL_READ_FRAMEBUFFER​, + * which will be used as the source for pixel reading commands, + * like {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels} etc. + * <p> + * For offscreen framebuffer objects this is {@link GL#GL_COLOR_ATTACHMENT0}, + * otherwise this is {@link GL#GL_FRONT} for single buffer configurations + * and {@link GL#GL_BACK} for double buffer configurations. + * </p> + * <p> + * Note-1: Neither ES1 nor ES2 supports selecting the read buffer via glReadBuffer + * and {@link GL#GL_BACK} is the default. + * </p> + * <p> + * Note-2: ES3 only supports {@link GL#GL_BACK}, {@link GL#GL_NONE} or {@link GL#GL_COLOR_ATTACHMENT0}+i + * </p> + * <p> + * Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead} + * for read-pixels and swap-buffers implications. + * </p> + */ + public abstract int getDefaultReadBuffer(); + + /** Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */ + public abstract int getDefaultPixelDataType(); + + /** Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */ + public abstract int getDefaultPixelDataFormat(); + + /** + * @return The extension implementing the GLDebugOutput feature, + * either {@link GLExtensions#ARB_debug_output} or {@link GLExtensions#AMD_debug_output}. + * If unavailable or called before initialized via {@link #makeCurrent()}, <i>null</i> is returned. */ public abstract String getGLDebugMessageExtension(); /** - * @return the current synchronous debug behavior via - * @see #setSynchronous(boolean) + * @return the current synchronous debug behavior, set via {@link #setGLDebugSynchronous(boolean)}. */ public abstract boolean isGLDebugSynchronous(); - + /** * Enables or disables the synchronous debug behavior via - * {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB glEnable/glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB)}, - * if extension is {@link #GL_ARB_debug_output}. - * There is no equivalent for {@link #GL_AMD_debug_output}. - * <p> The default is <code>true</code>, ie {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB}.</p> + * {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS glEnable/glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS)}, + * if extension is {@link GLExtensions#ARB_debug_output}. + * There is no equivalent for {@link GLExtensions#AMD_debug_output}. + * <p> The default is <code>true</code>, ie {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS}.</p> + * @link {@link #isGLDebugSynchronous()} */ public abstract void setGLDebugSynchronous(boolean synchronous); - + /** * @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. - * + * Enables or disables the GLDebugOutput feature of extension {@link GLExtensions#ARB_debug_output} + * or {@link GLExtensions#AMD_debug_output}, 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, + * + * <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) + * + * @param listener {@link GLDebugListener} handling {@link 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) + * + * @param listener {@link GLDebugListener} handling {@link GLDebugMessage}s + * @see #enableGLDebugMessage(boolean) * @see #addGLDebugListener(GLDebugListener) */ public abstract void removeGLDebugListener(GLDebugListener listener); - + /** - * Generic entry for {@link GL2GL3#glDebugMessageControlARB(int, int, int, int, IntBuffer, boolean)} + * Generic entry for {@link GL2GL3#glDebugMessageControl(int, int, int, int, IntBuffer, boolean)} * and {@link GL2GL3#glDebugMessageEnableAMD(int, int, int, IntBuffer, boolean)} of the GLDebugOutput feature. - * @see #enableGLDebugMessage(boolean) + * @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) + * Generic entry for {@link GL2GL3#glDebugMessageControl(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)} + * Generic entry for {@link GL2GL3#glDebugMessageInsert(int, int, int, int, int, String)} * and {@link GL2GL3#glDebugMessageInsertAMD(int, int, int, int, String)} of the GLDebugOutput feature. - * @see #enableGLDebugMessage(boolean) + * @see #enableGLDebugMessage(boolean) */ public abstract void glDebugMessageInsert(int source, int type, int id, int severity, String buf); - + public static final int GL_VERSIONS[][] = { /* 0.*/ { -1 }, /* 1.*/ { 0, 1, 2, 3, 4, 5 }, /* 2.*/ { 0, 1 }, /* 3.*/ { 0, 1, 2, 3 }, - /* 4.*/ { 0, 1, 2 } }; + /* 4.*/ { 0, 1, 2, 3, 4 } }; - public static final int getMaxMajor() { - return GL_VERSIONS.length-1; + public static final int ES_VERSIONS[][] = { + /* 0.*/ { -1 }, + /* 1.*/ { 0, 1 }, + /* 2.*/ { 0 }, + /* 3.*/ { 0 } }; + + public static final int getMaxMajor(int ctxProfile) { + return ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ? ES_VERSIONS.length-1 : GL_VERSIONS.length-1; } - public static final int getMaxMinor(int major) { - if(1>major || major>=GL_VERSIONS.length) return -1; - return GL_VERSIONS[major].length-1; + public static final int getMaxMinor(int ctxProfile, int major) { + if( 1>major ) { + return -1; + } + if( ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ) { + if( major>=ES_VERSIONS.length ) return -1; + return ES_VERSIONS[major].length-1; + } else { + if( major>=GL_VERSIONS.length ) return -1; + return GL_VERSIONS[major].length-1; + } } - public static final boolean isValidGLVersion(int major, int minor) { - if(1>major || major>=GL_VERSIONS.length) return false; - if(0>minor || minor>=GL_VERSIONS[major].length) return false; + /** + * Returns true, if the major.minor is not inferior to the lowest + * valid version and does not exceed the highest known major number by more than one. + * <p> + * The minor version number is ignored by the upper limit validation + * and the major version number may exceed by one. + * </p> + * <p> + * The upper limit check is relaxed since we don't want to cut-off + * unforseen new GL version since the release of JOGL. + * </p> + * <p> + * Hence it is important to iterate through GL version from the upper limit + * and {@link #decrementGLVersion(int, int[], int[])} until invalid. + * </p> + */ + public static final boolean isValidGLVersion(int ctxProfile, int major, int minor) { + if( 1>major || 0>minor ) { + return false; + } + if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) { + if( major >= ES_VERSIONS.length + 1 ) return false; + } else { + if( major>=GL_VERSIONS.length + 1 ) return false; + } return true; } - public static final boolean decrementGLVersion(int major[], int minor[]) { - if(null==major || major.length<1 ||null==minor || minor.length<1) { - throw new GLException("invalid array arguments"); - } - int m = major[0]; - int n = minor[0]; - if(!isValidGLVersion(m, n)) return false; - - // decrement .. - n -= 1; - if(n < 0) { - m -= 1; - n = GL_VERSIONS[m].length-1; + /** + * Clip the given GL version to the maximum known valid version if exceeding. + * @return true if clipped, i.e. given value exceeds maximum, otherwise false. + */ + public static final boolean clipGLVersion(int ctxProfile, int major[], int minor[]) { + final int m = major[0]; + final int n = minor[0]; + + if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) { + if( m >= ES_VERSIONS.length ) { + major[0] = ES_VERSIONS.length - 1; + minor[0] = ES_VERSIONS[major[0]].length - 1; + return true; + } + if( n >= ES_VERSIONS[m].length ) { + minor[0] = ES_VERSIONS[m].length - 1; + return true; + } + } else if( m >= GL_VERSIONS.length ) { // !isES + major[0] = GL_VERSIONS.length - 1; + minor[0] = GL_VERSIONS[major[0]].length - 1; + return true; + } else if( n >= GL_VERSIONS[m].length ) { // !isES + minor[0] = GL_VERSIONS[m].length - 1; + return true; } - if(!isValidGLVersion(m, n)) return false; - major[0]=m; - minor[0]=n; + return false; + } + /** + * Decrement the given GL version by one + * and return true if still valid, otherwise false. + * <p> + * If the given version exceeds the maximum known valid version, + * it is {@link #clipGLVersion(int, int[], int[]) clipped} and + * true is returned. + * </p> + * + * @param ctxProfile + * @param major + * @param minor + * @return + */ + public static final boolean decrementGLVersion(int ctxProfile, int major[], int minor[]) { + if( !clipGLVersion(ctxProfile, major, minor) ) { + int m = major[0]; + int n = minor[0] - 1; + if(n < 0) { + if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) { + if( m >= 3 ) { + m -= 1; + } else { + m = 0; // major decr [1,2] -> 0 + } + n = ES_VERSIONS[m].length-1; + } else { + m -= 1; + n = GL_VERSIONS[m].length-1; + } + } + if( !isValidGLVersion(ctxProfile, m, n) ) { + return false; + } + major[0]=m; + minor[0]=n; + } return true; } @@ -832,48 +1541,53 @@ public abstract class GLContext { // /** - * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) + * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) */ - protected static /*final*/ HashMap<String, Integer> deviceVersionAvailable = new HashMap<String, Integer>(); + protected static final IdentityHashMap<String, Integer> deviceVersionAvailable = new IdentityHashMap<String, Integer>(); /** * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) */ - private static /*final*/ HashSet<String> deviceVersionsAvailableSet = new HashSet<String>(); + private static final IdentityHashMap<String, String> deviceVersionsAvailableSet = new IdentityHashMap<String, String>(); - protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { - return device.getUniqueID() + "-" + toHexString(composeBits(major, profile, 0)); + /** clears the device/context mappings as well as the GL/GLX proc address tables. */ + protected static void shutdown() { + deviceVersionAvailable.clear(); + deviceVersionsAvailableSet.clear(); + GLContextImpl.shutdownImpl(); // well .. } protected static boolean getAvailableGLVersionsSet(AbstractGraphicsDevice device) { synchronized ( deviceVersionsAvailableSet ) { - return deviceVersionsAvailableSet.contains(device.getUniqueID()); + return deviceVersionsAvailableSet.containsKey(device.getUniqueID()); } } protected static void setAvailableGLVersionsSet(AbstractGraphicsDevice device) { synchronized ( deviceVersionsAvailableSet ) { - String devKey = device.getUniqueID(); - if ( deviceVersionsAvailableSet.contains(devKey) ) { + final String devKey = device.getUniqueID(); + if( null != deviceVersionsAvailableSet.put(devKey, devKey) ) { throw new InternalError("Already set: "+devKey); } - deviceVersionsAvailableSet.add(devKey); if (DEBUG) { System.err.println(getThreadName() + ": createContextARB: SET mappedVersionsAvailableSet "+devKey); + System.err.println(GLContext.dumpAvailableGLVersions(null).toString()); } } } - - /** clears the device/context mappings as well as the GL/GLX proc address tables. */ - protected static void shutdown() { - deviceVersionAvailable.clear(); - deviceVersionsAvailableSet.clear(); - GLContextImpl.shutdownImpl(); // well .. + + /** + * Returns a unique String object using {@link String#intern()} for the given arguments, + * which object reference itself can be used as a key. + */ + protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { + final String r = device.getUniqueID() + "-" + toHexString(composeBits(major, profile, 0)); + return r.intern(); } /** - * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable} not intended to be used by - * implementations. However, if {@link #createContextARB} is not being used within + * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable(int,int)} not intended to be used by + * implementations. However, if {@link jogamp.opengl.GLContextImpl#createContextARB(long, boolean)} is not being used within * {@link javax.media.opengl.GLDrawableFactory#getOrCreateSharedContext(javax.media.nativewindow.AbstractGraphicsDevice)}, * GLProfile has to map the available versions. * @@ -889,12 +1603,47 @@ public abstract class GLContext { validateProfileBits(profile, "profile"); validateProfileBits(resCtp, "resCtp"); - String key = getDeviceVersionAvailableKey(device, reqMajor, profile); - Integer val = new Integer(composeBits(resMajor, resMinor, resCtp)); + if(FORCE_NO_FBO_SUPPORT) { + resCtp &= ~CTX_IMPL_FBO ; + } + if(DEBUG) { + System.err.println("GLContext.mapAvailableGLVersion: "+device+": "+getGLVersion(reqMajor, 0, profile, null)+" -> "+getGLVersion(resMajor, resMinor, resCtp, null)); + // Thread.dumpStack(); + } + final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, profile); + final Integer val = new Integer(composeBits(resMajor, resMinor, resCtp)); synchronized(deviceVersionAvailable) { - val = deviceVersionAvailable.put( key, val ); + return deviceVersionAvailable.put( objectKey, val ); } - return val; + } + + protected static StringBuilder dumpAvailableGLVersions(StringBuilder sb) { + if(null == sb) { + sb = new StringBuilder(); + } + synchronized(deviceVersionAvailable) { + final Set<String> keys = deviceVersionAvailable.keySet(); + boolean needsSeparator = false; + for(Iterator<String> i = keys.iterator(); i.hasNext(); ) { + if(needsSeparator) { + sb.append(Platform.getNewline()); + } + final String key = i.next(); + sb.append(key).append(": "); + final Integer valI = deviceVersionAvailable.get(key); + if(null != valI) { + final int bits32 = valI.intValue(); + final int major = ( bits32 & 0xFF000000 ) >>> 24 ; + final int minor = ( bits32 & 0x00FF0000 ) >>> 16 ; + final int ctp = ( bits32 & 0x0000FFFF ) ; + sb.append(GLContext.getGLVersion(major, minor, ctp, null)); + } else { + sb.append("n/a"); + } + needsSeparator = true; + } + } + return sb; } /** @@ -904,10 +1653,10 @@ public abstract class GLContext { * @return the available GL version as encoded with {@link #composeBits(int, int, int), otherwise <code>null</code> */ protected static Integer getAvailableGLVersion(AbstractGraphicsDevice device, int reqMajor, int reqProfile) { - String key = getDeviceVersionAvailableKey(device, reqMajor, reqProfile); + final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, reqProfile); Integer val; synchronized(deviceVersionAvailable) { - val = deviceVersionAvailable.get( key ); + val = deviceVersionAvailable.get( objectKey ); } return val; } @@ -919,55 +1668,109 @@ public abstract class GLContext { * @param minor if not null, returns the used minor version * @param ctp if not null, returns the used context profile */ - protected static boolean getAvailableGLVersion(AbstractGraphicsDevice device, int reqMajor, int reqProfile, + protected static boolean getAvailableGLVersion(AbstractGraphicsDevice device, int reqMajor, int reqProfile, int[] major, int minor[], int ctp[]) { - Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile); + final Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile); if(null==valI) { return false; } - int bits32 = valI.intValue(); + final int bits32 = valI.intValue(); if(null!=major) { - major[0] = ( bits32 & 0xFF000000 ) >> 24 ; + major[0] = ( bits32 & 0xFF000000 ) >>> 24 ; } if(null!=minor) { - minor[0] = ( bits32 & 0x00FF0000 ) >> 16 ; + minor[0] = ( bits32 & 0x00FF0000 ) >>> 16 ; } if(null!=ctp) { ctp[0] = ( bits32 & 0x0000FFFF ) ; } return true; } - - /** + + /** * returns the highest GLProfile string regarding the implementation version and context profile bits. * @throws GLException if version and context profile bits could not be mapped to a GLProfile */ - protected static String getGLProfile(int major, int minor, int ctp) + protected static String getGLProfile(int major, int minor, int ctp) throws GLException { - if(0 != ( CTX_PROFILE_COMPAT & ctp )) { + if(0 != ( CTX_PROFILE_COMPAT & ctp )) { if(major >= 4) { return GLProfile.GL4bc; } else if(major == 3 && minor >= 1) { return GLProfile.GL3bc; } - else { return GLProfile.GL2; } + else { return GLProfile.GL2; } } else if(0 != ( CTX_PROFILE_CORE & ctp )) { if(major >= 4) { return GLProfile.GL4; } - else if(major == 3 && minor >= 1) { return GLProfile.GL3; } + else if(major == 3 && minor >= 1) { return GLProfile.GL3; } } else if(0 != ( CTX_PROFILE_ES & ctp )) { - if(major == 2) { return GLProfile.GLES2; } - else if(major == 1) { return GLProfile.GLES1; } + if(major == 3) { return GLProfile.GLES3; } + else if(major == 2) { return GLProfile.GLES2; } + else if(major == 1) { return GLProfile.GLES1; } } throw new GLException("Unhandled OpenGL version/profile: "+GLContext.getGLVersion(major, minor, ctp, null)); } - - /** + + /** + * Returns the GLProfile's major version number at reqMajorCTP[0] and it's context property (CTP) at reqMajorCTP[1] for availability mapping request. + */ + protected static final void getRequestMajorAndCompat(final GLProfile glp, int[/*2*/] reqMajorCTP) { + final GLProfile glpImpl = glp.getImpl(); + if( glpImpl.isGL4() ) { + reqMajorCTP[0]=4; + } else if ( glpImpl.isGL3() || glpImpl.isGLES3() ) { + reqMajorCTP[0]=3; + } else if (glpImpl.isGLES1()) { + reqMajorCTP[0]=1; + } else /* if (glpImpl.isGL2() || glpImpl.isGLES2()) */ { + reqMajorCTP[0]=2; + } + if( glpImpl.isGLES() ) { + reqMajorCTP[1]=CTX_PROFILE_ES; + } else if( glpImpl.isGL2() ) { // incl GL3bc and GL4bc + reqMajorCTP[1]=CTX_PROFILE_COMPAT; + } else { + reqMajorCTP[1]=CTX_PROFILE_CORE; + } + } + + /** + * @param device the device the context profile is being requested for + * @param GLProfile the GLProfile the context profile is being requested for + * @return the GLProfile's context property (CTP) if available, otherwise <code>0</code> + */ + protected static final int getAvailableContextProperties(final AbstractGraphicsDevice device, final GLProfile glp) { + final int[] reqMajorCTP = new int[] { 0, 0 }; + getRequestMajorAndCompat(glp, reqMajorCTP); + + int _major[] = { 0 }; + int _minor[] = { 0 }; + int _ctp[] = { 0 }; + if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1], _major, _minor, _ctp)) { + return _ctp[0]; + } + return 0; // n/a + } + + /** + * @param device the device the profile is being requested * @param major Key Value either 1, 2, 3 or 4 * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} - * @return the highest GLProfile string regarding the version and profile bits. - * @throws GLException if version and context profile bits could not be mapped to a GLProfile - */ - public static String getAvailableGLProfile(AbstractGraphicsDevice device, int reqMajor, int reqProfile) + * @return the highest GLProfile for the device regarding availability, version and profile bits. + */ + protected static GLProfile getAvailableGLProfile(AbstractGraphicsDevice device, int reqMajor, int reqProfile) + throws GLException { + final String glpName = getAvailableGLProfileName(device, reqMajor, reqProfile); + return null != glpName ? GLProfile.get(device, glpName) : null; + } + + /** + * @param device the device the profile is being requested + * @param major Key Value either 1, 2, 3 or 4 + * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} + * @return the highest GLProfile name for the device regarding availability, version and profile bits. + */ + /* package */ static String getAvailableGLProfileName(AbstractGraphicsDevice device, int reqMajor, int reqProfile) throws GLException { int major[] = { 0 }; int minor[] = { 0 }; @@ -979,13 +1782,63 @@ public abstract class GLContext { } /** + * @param device the device the profile is being requested + * @param major Key Value either 1, 2, 3 or 4 + * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} + */ + protected static String getAvailableGLVersionAsString(AbstractGraphicsDevice device, int major, int profile) { + int _major[] = { 0 }; + int _minor[] = { 0 }; + int _ctp[] = { 0 }; + if(getAvailableGLVersion(device, major, profile, _major, _minor, _ctp)) { + return getGLVersion(_major[0], _minor[0], _ctp[0], null); + } + return null; + } + + /** + * Returns true if it is possible to create an <i>framebuffer object</i> (FBO). + * <p> + * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent. + * </p> + * <p> + * FBO support is queried as described in {@link #hasBasicFBOSupport()}. + * </p> + * + * @param device the device to request whether FBO is available for + * @param glp {@link GLProfile} to check for FBO capabilities + * @see GLContext#hasBasicFBOSupport() + */ + public static final boolean isFBOAvailable(AbstractGraphicsDevice device, GLProfile glp) { + return 0 != ( CTX_IMPL_FBO & getAvailableContextProperties(device, glp) ); + } + + /** + * @return <code>1</code> if using a hardware rasterizer, <code>0</code> if using a software rasterizer and <code>-1</code> if not determined yet. + * @see GLContext#isHardwareRasterizer() + * @see GLProfile#isHardwareRasterizer() + */ + public static final int isHardwareRasterizer(AbstractGraphicsDevice device, GLProfile glp) { + final int r; + final int ctp = getAvailableContextProperties(device, glp); + if(0 == ctp) { + r = -1; + } else if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctp ) ) { + r = 1; + } else { + r = 0; + } + return r; + } + + /** * @param device the device to request whether the profile is available for * @param reqMajor Key Value either 1, 2, 3 or 4 * @param reqProfile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} * @param isHardware return value of one boolean, whether the profile is a hardware rasterizer or not * @return true if the requested GL version is available regardless of a software or hardware rasterizer, otherwise false. */ - public static boolean isGLVersionAvailable(AbstractGraphicsDevice device, int reqMajor, int reqProfile, boolean isHardware[]) { + protected static boolean isGLVersionAvailable(AbstractGraphicsDevice device, int reqMajor, int reqProfile, boolean isHardware[]) { Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile); if(null==valI) { return false; @@ -1002,6 +1855,34 @@ public abstract class GLContext { return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES, isHardware); } + public static boolean isGLES3Available(AbstractGraphicsDevice device, boolean isHardware[]) { + return isGLVersionAvailable(device, 3, GLContext.CTX_PROFILE_ES, isHardware); + } + + /** + * Returns true if a ES3 compatible profile is available, + * i.e. either a ≥ 4.3 context or a ≥ 3.1 context supporting <code>GL_ARB_ES3_compatibility</code>, + * otherwise false. + * <p> + * Includes [ GL ≥ 4.3, GL ≥ 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ] + * </p> + */ + public static final boolean isGLES3CompatibleAvailable(AbstractGraphicsDevice device) { + int major[] = { 0 }; + int minor[] = { 0 }; + int ctp[] = { 0 }; + boolean ok; + + ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_ES, major, minor, ctp); + if( !ok ) { + ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, major, minor, ctp); + } + if( !ok ) { + ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_COMPAT, major, minor, ctp); + } + return 0 != ( ctp[0] & CTX_IMPL_ES3_COMPAT ); + } + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device, boolean isHardware[]) { return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT, isHardware); } @@ -1022,21 +1903,7 @@ public abstract class GLContext { return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT, isHardware); } - /** - * @param major Key Value either 1, 2, 3 or 4 - * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} - */ - public static String getAvailableGLVersionAsString(AbstractGraphicsDevice device, int major, int profile) { - int _major[] = { 0 }; - int _minor[] = { 0 }; - int _ctp[] = { 0 }; - if(getAvailableGLVersion(device, major, profile, _major, _minor, _ctp)) { - return getGLVersion(_major[0], _minor[0], _ctp[0], null); - } - return null; - } - - public static String getGLVersion(int major, int minor, int ctp, String gl_version) { + protected static String getGLVersion(int major, int minor, int ctp, String gl_version) { boolean needColon = false; StringBuilder sb = new StringBuilder(); sb.append(major); @@ -1044,12 +1911,15 @@ public abstract class GLContext { sb.append(minor); sb.append(" ("); needColon = appendString(sb, "ES profile", needColon, 0 != ( CTX_PROFILE_ES & ctp )); - needColon = appendString(sb, "Compatibility profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp )); + needColon = appendString(sb, "Compat profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp )); needColon = appendString(sb, "Core profile", needColon, 0 != ( CTX_PROFILE_CORE & ctp )); - needColon = appendString(sb, "forward", needColon, 0 != ( CTX_OPTION_FORWARD & ctp )); + needColon = appendString(sb, "forward", needColon, 0 != ( CTX_OPTION_FORWARD & ctp )); needColon = appendString(sb, "arb", needColon, 0 != ( CTX_IS_ARB_CREATED & ctp )); - needColon = appendString(sb, "debug", needColon, 0 != ( CTX_OPTION_DEBUG & ctp )); - needColon = appendString(sb, "ES2 compatible", needColon, 0 != ( CTX_IMPL_ES2_COMPAT & ctp )); + needColon = appendString(sb, "debug", needColon, 0 != ( CTX_OPTION_DEBUG & ctp )); + needColon = appendString(sb, "ES2 compat", needColon, 0 != ( CTX_IMPL_ES2_COMPAT & ctp )); + needColon = appendString(sb, "ES3 compat", needColon, 0 != ( CTX_IMPL_ES3_COMPAT & ctp )); + needColon = appendString(sb, "FBO", needColon, 0 != ( CTX_IMPL_FBO & ctp )); + needColon = appendString(sb, "FP32 compat", needColon, 0 != ( CTX_IMPL_FP32_COMPAT_API & ctp )); if( 0 != ( CTX_IMPL_ACCEL_SOFT & ctp ) ) { needColon = appendString(sb, "software", needColon, true); } else { @@ -1064,9 +1934,9 @@ public abstract class GLContext { } // - // internal string utils + // internal string utils // - + protected static String toHexString(int hex) { return "0x" + Integer.toHexString(hex); } @@ -1085,10 +1955,8 @@ public abstract class GLContext { } return needColon; } - - protected static String getThreadName() { - return Thread.currentThread().getName(); - } + + protected static String getThreadName() { return Thread.currentThread().getName(); } } |